141 lines
3.4 KiB
C
141 lines
3.4 KiB
C
|
/*
|
||
|
* 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
|