110 lines
4.7 KiB
C++
110 lines
4.7 KiB
C++
#ifndef ARBUTILS_RANDOM_HPP
|
|
#define ARBUTILS_RANDOM_HPP
|
|
|
|
// PCG uses unsigned shifts, and overflows a lot. Disable the sanitizer for that.
|
|
#if defined(__clang__)
|
|
// If we don't ignore this diagnostic, and the sanitizer is not known yet in the clang version, this spams tens of
|
|
// thousands of warnings. Hence we disable it for a bit.
|
|
#pragma GCC diagnostic push
|
|
#pragma clang diagnostic ignored "-Wunknown-sanitizers"
|
|
#pragma clang attribute push(__attribute__((no_sanitize("unsigned-shift-base", "unsigned-integer-overflow"))), \
|
|
apply_to = function)
|
|
#endif
|
|
|
|
#include <pcg_random.hpp>
|
|
|
|
#if defined(__clang__)
|
|
#pragma clang attribute pop
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <random>
|
|
#include "Ensure.hpp"
|
|
|
|
namespace ArbUt {
|
|
/// @brief A helper class for getting random numbers.
|
|
/// @tparam RandomT A type for the desired random number generator.
|
|
template <class RandomT> class BaseRandom {
|
|
private:
|
|
uint_fast32_t _seed;
|
|
RandomT _rng;
|
|
std::uniform_real_distribution<double> _distribution;
|
|
|
|
public:
|
|
inline constexpr BaseRandom() noexcept
|
|
: _seed(std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
std::chrono::system_clock::now().time_since_epoch())
|
|
.count()),
|
|
_rng(_seed), _distribution(0.0, 1.0) {}
|
|
|
|
/// @brief Instantiate random class with a specific seed.
|
|
/// @param seed The seed the random number generator should be instantiated with.
|
|
explicit inline constexpr BaseRandom(uint_fast32_t seed) noexcept
|
|
: _seed(seed), _rng(seed), _distribution(0.0, 1.0){};
|
|
|
|
/// @brief The random number generator that is backing the random class.
|
|
inline RandomT& GetRandomEngine() noexcept { return _rng; }
|
|
|
|
/// @brief Gets a random float between 0.0 and 1.0.
|
|
[[nodiscard]] inline constexpr f32 GetFloat() noexcept { return static_cast<float>(GetDouble()); }
|
|
|
|
/// @brief Gets a random double between 0.0 and 1.0.
|
|
[[nodiscard]] inline constexpr f64 GetDouble() noexcept { return _distribution(_rng); }
|
|
|
|
/// @brief Gets a random 32 bit integer
|
|
inline constexpr i32 Get() noexcept { return static_cast<i32>(_rng()); }
|
|
|
|
/// @brief Gets a random 32 bit integer between 0, and given max parameter.
|
|
/// @param max The exclusive max value the random value should be.
|
|
[[nodiscard]] inline i32 Get(i32 max) {
|
|
Ensure(max > 0);
|
|
std::uniform_int_distribution<i32> distribution(0, max - 1);
|
|
return distribution(_rng);
|
|
}
|
|
|
|
/// @brief Gets a random 32 bit integer between given min and max parameters.
|
|
/// @param min The inclusive min value the random value should be.
|
|
/// @param max The exclusive max value the random value should be.
|
|
[[nodiscard]] inline i32 Get(i32 min, i32 max) {
|
|
Ensure(max > min);
|
|
std::uniform_int_distribution<i32> distribution(min, max - 1);
|
|
return distribution(_rng);
|
|
}
|
|
|
|
/// @brief Gets a random 32 bit unsigned integer between 0 and max unsigned int.
|
|
[[nodiscard]] inline constexpr u32 GetUnsigned() noexcept { return _rng(); }
|
|
|
|
/// @brief Gets a random 32 bit unsigned integer between 0, and given max parameter.
|
|
/// @param max The exclusive max value the random value should be.
|
|
[[nodiscard]] inline u32 GetUnsigned(u32 max) noexcept {
|
|
std::uniform_int_distribution<u32> distribution(0, max - 1);
|
|
return distribution(_rng);
|
|
}
|
|
|
|
/// @brief Gets a random 32 bit unsigned integer between given min and max parameters.
|
|
/// @param min The inclusive min value the random value should be.
|
|
/// @param max The exclusive max value the random value should be.
|
|
[[nodiscard]] inline u32 GetUnsigned(u32 min, u32 max) {
|
|
Ensure(max > min);
|
|
std::uniform_int_distribution<u32> distribution(min, max - 1);
|
|
return distribution(_rng);
|
|
}
|
|
|
|
/// @brief The seed the random class is generating from.
|
|
[[nodiscard]] inline constexpr uint_fast32_t GetSeed() const noexcept { return _seed; }
|
|
};
|
|
|
|
/// @brief Implementation of the BaseRandom class with pcg32 as random number generator.
|
|
class Random : public BaseRandom<pcg32> {
|
|
public:
|
|
constexpr Random() noexcept : BaseRandom() {}
|
|
/// @brief Instantiate random class with a specific seed.
|
|
/// @param seed The seed the random number generator should be instantiated with.
|
|
explicit constexpr Random(uint_fast32_t seed) noexcept : BaseRandom(seed) {}
|
|
};
|
|
}
|
|
|
|
#endif // ARBUTILS_RANDOM_HPP
|