Program Listing for File RngThread.hpp
↰ Return to documentation for file (src/utils/RngThread.hpp)
#ifndef RNGUTILS_HPP
#define RNGUTILS_HPP
#include "ThreadVec.hpp"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdlib>
#include <exception>
#include <iostream>
#include <memory>
#ifdef _OPENMP
# include <omp.h>
#endif
#include <pcg_extras.hpp>
#include <pcg_random.hpp>
#include <random>
#include <sstream>
#include <stdexcept>
#include <string>
namespace utils {
using RngType = pcg64;
inline constexpr size_t rngStateWidth = 128;
using RngState = std::array<char, rngStateWidth>;
class RngThread {
public:
RngThread()
{
for (auto& r : rngEngines_)
{
pcg_extras::seed_seq_from<std::random_device> seedSource;
r = std::make_unique<RngType>(seedSource);
}
}
RngThread(const RngType::state_type seed)
{
for (int i = 0; i < rngEngines_.size(); ++i)
{
rngEngines_[i] = std::make_unique<RngType>(seed + i); // NOLINT(cppcoreguidelines-pro-bounds-avoid-unchecked-container-access)
}
}
~RngThread() = default;
// Disable copy and move constructors and assignment operators
RngThread(const RngThread&) = delete;
RngThread(RngThread&&) = delete;
auto operator=(const RngThread&) -> RngThread& = delete;
auto operator=(RngThread&&) -> RngThread& = delete;
void seed(const RngType::state_type seed)
{
for (int i = 0; i < rngEngines_.size(); ++i)
{
rngEngines_[i]->seed(seed+i); // NOLINT(cppcoreguidelines-pro-bounds-avoid-unchecked-container-access)
}
}
auto operator()() const -> RngType& { return *rngEngines_(); }
[[nodiscard]] auto getState() const -> RngState
{
std::ostringstream stateStream;
stateStream << *rngEngines_();
const std::string state = stateStream.str();
if (state.size() >= rngStateWidth)
{
throw std::runtime_error(
"RngThread: serialized state does not fit in the "
"fixed-width RngState buffer");
}
RngState buf{};
std::ranges::copy(state, buf.begin());
return buf;
}
void setState(const RngState& state)
{
std::istringstream stateStream{std::string(state.data())};
stateStream >> *rngEngines_();
}
private:
ThreadVec<std::unique_ptr<pcg64> > rngEngines_;
};
inline auto rng() -> RngThread&
{
try
{
static RngThread instance;
return instance;
}
catch (const std::exception& error)
{
std::cerr << "FATAL: random number generator initialization "
"failed: " << error.what() << "\n";
std::exit(1); // NOLINT(concurrency-mt-unsafe) -- the program is terminating regardless; thread-safety of the shutdown path doesn't matter
}
}
} // namespace utils
#endif // RNGUTILS_HPP