You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libexopt/include/rng.hh

54 lines
2.2 KiB

#pragma once
#include <bit>
#include <array>
#include <cstdint>
#include "util.hh"
#include "exopt.h"
namespace exopt::rng {
[[gnu::visibility("internal")]]
constexpr inline auto COMPILED_ENTROPY{
#if __has_include("compiled_entropy.dat")
#embed "compiled_entropy.dat"
#else
nullptr
#endif
};
constexpr inline auto has_compiled_entropy_v = !std::is_same_v<std::nullptr_t, decltype(COMPILED_ENTROPY)>;
// XXX: The usage of __COUNTER__ *might* work as wanted if we wrap it in _EO_CONSTANT_VALUE() and take `util::comptime<uint64_t> auto = _EO_CONSTANT_VALUE(__COUNTER__)` as default argument instead. Maybe... I don't know..
template<typename T = unsigned char>
consteval decltype(auto) comptime_rand_next() noexcept {
std::array<unsigned char, sizeof(T)> v;
for(int i=0;i<v.size();i++) v[i] = comptime_rand_next<unsigned char>();
return util::comptime_value(std::bit_cast<T>(std::move(v)));
}
template<>
consteval decltype(auto) comptime_rand_next<unsigned char>(uint64_t counter = __COUNTER__) noexcept {
return _EO_CONSTANT_VALUE(COMPILED_ENTROPY[counter % sizeof(COMPILED_ENTROPY)]);
}
consteval uint64_t seed_linear(uint64_t counter = __COUNTER__) noexcept { return uint64_t(counter); } //XXX: This is kinda a dumb experiment, the __TIME__ TU-specific seed should be fine, but __COUNTER__ is a token evaluated regardless of calling context, so... Unless it's used before the #include<>, it'll always be the same.
consteval uint64_t seed_translation() noexcept { return uint64_t(__TIME__); }
// Seed: __TIME__ or __COUNTER__
[[gnu::const]]
constexpr uint64_t splitmix64_once(uint64_t x) noexcept {
//TODO: implement splitmix64 here for constexpr/consteval contexts
}
constexpr inline uint64_t translation_unit_fixed_seed = splitmit64_once(seed_translation());
constexpr inline uint64_t linear_fixed_seed = splitmit64_once(seed_linear()); // ODR dependant?? When is __COUNTER__ evaluated? In preprocessing, right? So, before any compilation?
constexpr inline auto translation_unit_rolling_seed = ([] () {
struct {
constexpr operator uint64_t() const noexcept { return splitmix64_once(translation_unit_fixed_seed ^ seed_linear()) ^ _EO_CONSTANT_VALUE(splitmix64_once(__COUNTER__)); }
} inner;
return inner;
})();
}