/* * mptRandom.h * ----------- * Purpose: PRNG * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/bit.hpp" #include "mpt/mutex/mutex.hpp" #ifdef MODPLUG_TRACKER #include "mpt/random/crand.hpp" #endif // MODPLUG_TRACKER #include "mpt/random/default_engines.hpp" #include "mpt/random/device.hpp" #include "mpt/random/engine.hpp" #include "mpt/random/engine_lcg.hpp" #include "mpt/random/seed.hpp" #include #include OPENMPT_NAMESPACE_BEGIN // NOTE: // We implement our own PRNG and distribution functions as the implementations // of std::uniform_int_distribution is either wrong (not uniform in MSVC2010) or // not guaranteed to be livelock-free for bad PRNGs (in GCC, Clang, boost). // We resort to a simpler implementation with only power-of-2 result ranges for // both the underlying PRNG and our interface function. This saves us from // complicated code having to deal with partial bits of entropy. // Our interface still somewhat follows the mindset of C++11 (with the // addition of a simple wrapper function mpt::random which saves the caller from // instantiating distribution objects for the common uniform distribution case. // We are still using std::random_device for initial seeding when avalable and // after working around its set of problems. namespace mpt { template class thread_safe_prng : private Trng { private: mpt::mutex m; public: typedef typename Trng::result_type result_type; public: template explicit thread_safe_prng(Trd & rd) : Trng(mpt::make_prng(rd)) { return; } thread_safe_prng(Trng rng) : Trng(rng) { return; } public: static MPT_CONSTEXPRINLINE typename engine_traits::result_type min() { return Trng::min(); } static MPT_CONSTEXPRINLINE typename engine_traits::result_type max() { return Trng::max(); } static MPT_CONSTEXPRINLINE int result_bits() { return engine_traits::result_bits(); } public: typename engine_traits::result_type operator()() { mpt::lock_guard l(m); return Trng::operator()(); } }; #ifdef MPT_BUILD_FUZZER // Use deterministic seeding using random_device = deterministc_random_device; #else // !MPT_BUILD_FUZZER // mpt::random_device always generates 32 bits of entropy using random_device = mpt::sane_random_device; #endif // MPT_BUILD_FUZZER #ifdef MPT_BUILD_FUZZER // Use fast PRNGs in order to not waste time fuzzing more complex PRNG // implementations. using fast_prng = deterministic_fast_engine; using good_prng = deterministic_good_engine; #else // !MPT_BUILD_FUZZER // We cannot use std::minstd_rand here because it has not a power-of-2 sized // output domain which we rely upon. using fast_prng = fast_engine; // about 3 ALU operations, ~32bit of state, suited for inner loops using good_prng = good_engine; #endif // MPT_BUILD_FUZZER using default_prng = mpt::good_prng; mpt::random_device & global_random_device(); mpt::thread_safe_prng & global_prng(); #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) void set_global_random_device(mpt::random_device *rd); void set_global_prng(mpt::thread_safe_prng *rng); #endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT } // namespace mpt OPENMPT_NAMESPACE_END