// FastRandom.h // Declares the cFastRandom class representing a fast random number generator /* The cFastRandom alias should be avoided in favor of the result of a call to GetRandomProvider(). The MTRand generator used is faster, has a better range and provides higher quality randomness. Note that MTRand is relatively costly to construct and so instances should be long lived, prefer calls to GetRandomProvider over creating new instances. */ #pragma once namespace Detail { /** Returns a low quality seed. */ UInt32 GetRandomSeed(); /** Aliases true_type if Char is any variant of char ignoring signed-ness. */ template using IsChar = typename std::is_same::type, signed char>::type; template struct cUniformImpl : public std::conditional< IsChar::value, typename std::conditional< // Match signed-ness of IntType std::is_signed::value, std::uniform_int_distribution, std::uniform_int_distribution >::type, std::uniform_int_distribution > { }; /** uniform_int_distribution is undefined so this aliases a valid type. */ template using cUniform = typename cUniformImpl::type; } /** Class to wrap any random engine to provide a more convenient interface. */ template class cRandomWrapper { public: /** Initialize with a low quality seed. */ cRandomWrapper(): m_Engine(Detail::GetRandomSeed()) { } /** Initialize with a SeedSequence. */ template cRandomWrapper(SeedSeq & a_SeedSeq): m_Engine(a_SeedSeq) { } /** Return a random IntType in the range [a_Min, a_Max]. */ template IntType RandInt(IntType a_Min, IntType a_Max) { ASSERT( (a_Max >= a_Min) && (a_Max <= std::numeric_limits::max()) && (a_Min >= std::numeric_limits::min()) ); Detail::cUniform dist( static_cast(a_Min), static_cast(a_Max) ); return static_cast(dist(m_Engine)); } /** Return a random IntType in the range [0, a_Max]. */ template IntType RandInt(IntType a_Max) { ASSERT((a_Max >= 0) && (a_Max <= std::numeric_limits::max())); Detail::cUniform dist(IntType(0), static_cast(a_Max)); return static_cast(dist(m_Engine)); } /** Return a random IntType in the range [0, std::numeric_limits::max()]. */ template IntType RandInt() { Detail::cUniform dist(IntType(0), std::numeric_limits::max()); return static_cast(dist(m_Engine)); } /** Return a random RealType in the range [a_Min, a_Max). */ template RealType RandReal(RealType a_Min, RealType a_Max) { std::uniform_real_distribution dist(a_Min, a_Max); return dist(m_Engine); } /** Return a random RealType in the range [0, a_Max). */ template RealType RandReal(RealType a_Max) { std::uniform_real_distribution dist(RealType(0), a_Max); return dist(m_Engine); } /** Return a random RealType in the range [0, 1). */ template RealType RandReal() { std::uniform_real_distribution dist; return dist(m_Engine); } /** Return a random bool with the given probability of being true. */ bool RandBool(double a_TrueProbability = 0.5) { std::bernoulli_distribution dist(a_TrueProbability); return dist(m_Engine); } /** Returns a reference to the underlying random engine. */ RandomEngine & Engine() { return m_Engine; } private: RandomEngine m_Engine; }; /** Utility to seed a random engine with maximal entropy from random_device. */ struct cRandomDeviceSeeder { using result_type = std::random_device::result_type; template void generate(Itr first, Itr last) { std::random_device rd; std::uniform_int_distribution dist; for (; first != last; ++first) { *first = dist(rd); } } }; using cFastRandom = cRandomWrapper; using MTRand = cRandomWrapper; /** Returns the current thread's random number source. */ MTRand & GetRandomProvider();