123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- /*
- * 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 <limits>
- #include <random>
- 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 <random> (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 <typename Trng>
- class thread_safe_prng
- : private Trng
- {
- private:
- mpt::mutex m;
- public:
- typedef typename Trng::result_type result_type;
- public:
- template <typename Trd>
- explicit thread_safe_prng(Trd & rd)
- : Trng(mpt::make_prng<Trng>(rd))
- {
- return;
- }
- thread_safe_prng(Trng rng)
- : Trng(rng)
- {
- return;
- }
- public:
- static MPT_CONSTEXPRINLINE typename engine_traits<Trng>::result_type min()
- {
- return Trng::min();
- }
- static MPT_CONSTEXPRINLINE typename engine_traits<Trng>::result_type max()
- {
- return Trng::max();
- }
- static MPT_CONSTEXPRINLINE int result_bits()
- {
- return engine_traits<Trng>::result_bits();
- }
- public:
- typename engine_traits<Trng>::result_type operator()()
- {
- mpt::lock_guard<mpt::mutex> 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<mpt::default_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<mpt::default_prng> *rng);
- #endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT
- } // namespace mpt
- OPENMPT_NAMESPACE_END
|