blob: 905d183917c7a93722b3187a783b3253eab0b348 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
/*
* 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
|