79 lines
2.0 KiB
C++
79 lines
2.0 KiB
C++
#pragma once
|
|
|
|
#include <climits> // CHAR_BIT
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <random>
|
|
|
|
namespace base {
|
|
namespace detail {
|
|
template <class T>
|
|
constexpr size_t BitSizeOf() {
|
|
return sizeof(T) * CHAR_BIT;
|
|
}
|
|
|
|
constexpr std::uint64_t splitmix64(std::uint64_t x) {
|
|
std::uint64_t z = (x += 0x9e3779b97f4a7c15uLL);
|
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9uLL;
|
|
z = (z ^ (z >> 27)) * 0x94d049bb133111ebuLL;
|
|
return z ^ (z >> 31);
|
|
}
|
|
|
|
constexpr std::uint64_t rotl(std::uint64_t x, int k) {
|
|
return (x << k) | (x >> (BitSizeOf<std::uint64_t>() - k));
|
|
}
|
|
|
|
struct Xoshiro256ss {
|
|
using result_type = std::uint64_t;
|
|
|
|
std::uint64_t s[4] {};
|
|
|
|
constexpr explicit Xoshiro256ss() : Xoshiro256ss(0) {}
|
|
|
|
constexpr explicit Xoshiro256ss(std::uint64_t seed) {
|
|
s[0] = splitmix64(seed);
|
|
s[1] = splitmix64(seed);
|
|
s[2] = splitmix64(seed);
|
|
s[3] = splitmix64(seed);
|
|
}
|
|
|
|
constexpr explicit Xoshiro256ss(std::random_device& rd) {
|
|
// Get 64 bits out of the random device.
|
|
//
|
|
// This lambda is quite literal, as it fetches
|
|
// 2 iterations of the random engine, and
|
|
// shifts + OR's them into a 64bit value.
|
|
auto get_u64 = [&rd] {
|
|
std::uint64_t the_thing = rd();
|
|
return (the_thing << 32) | rd();
|
|
};
|
|
|
|
// seed with 256 bits of entropy from the random device + splitmix64
|
|
// to ensure we seed it well, as per recommendation.
|
|
s[0] = splitmix64(get_u64());
|
|
s[1] = splitmix64(get_u64());
|
|
s[2] = splitmix64(get_u64());
|
|
s[3] = splitmix64(get_u64());
|
|
}
|
|
|
|
static constexpr result_type min() { return 0; }
|
|
|
|
static constexpr result_type max() { return std::uint64_t(-1); }
|
|
|
|
constexpr result_type operator()() {
|
|
result_type result = rotl(s[1] * 5, 7) * 9;
|
|
result_type t = s[1] << 17;
|
|
s[2] ^= s[0];
|
|
s[3] ^= s[1];
|
|
s[1] ^= s[2];
|
|
s[0] ^= s[3];
|
|
s[2] ^= t;
|
|
s[3] = rotl(s[3], 45);
|
|
return result;
|
|
}
|
|
};
|
|
} // namespace detail
|
|
|
|
using detail::Xoshiro256ss;
|
|
} // namespace base
|