|
ferencd@0
|
1 #ifndef EFFOLKRONIUM_RANDOM_HPP
|
|
ferencd@0
|
2 #define EFFOLKRONIUM_RANDOM_HPP
|
|
ferencd@0
|
3
|
|
ferencd@0
|
4 #include <random>
|
|
ferencd@0
|
5 #include <chrono> // timed seed
|
|
ferencd@0
|
6 #include <type_traits>
|
|
ferencd@0
|
7 #include <cassert>
|
|
ferencd@0
|
8 #include <initializer_list>
|
|
ferencd@0
|
9 #include <utility> // std::forward, std::declval
|
|
ferencd@0
|
10 #include <algorithm> // std::shuffle, std::next, std::distance
|
|
ferencd@0
|
11 #include <iterator> // std::begin, std::end, std::iterator_traits
|
|
ferencd@0
|
12 #include <limits> // std::numeric_limits
|
|
ferencd@0
|
13 #include <ostream>
|
|
ferencd@0
|
14 #include <istream>
|
|
ferencd@0
|
15
|
|
ferencd@0
|
16 namespace effolkronium {
|
|
ferencd@0
|
17
|
|
ferencd@0
|
18 namespace details {
|
|
ferencd@0
|
19 /// Key type for getting common type numbers or objects
|
|
ferencd@0
|
20 struct common{ };
|
|
ferencd@0
|
21
|
|
ferencd@0
|
22 /// True if type T is applicable by a std::uniform_int_distribution
|
|
ferencd@0
|
23 template<typename T>
|
|
ferencd@0
|
24 struct is_uniform_int {
|
|
ferencd@0
|
25 static constexpr bool value =
|
|
ferencd@0
|
26 std::is_same<T, short>::value
|
|
ferencd@0
|
27 || std::is_same<T, int>::value
|
|
ferencd@0
|
28 || std::is_same<T, long>::value
|
|
ferencd@0
|
29 || std::is_same<T, long long>::value
|
|
ferencd@0
|
30 || std::is_same<T, unsigned short>::value
|
|
ferencd@0
|
31 || std::is_same<T, unsigned int>::value
|
|
ferencd@0
|
32 || std::is_same<T, unsigned long>::value
|
|
ferencd@0
|
33 || std::is_same<T, unsigned long long>::value;
|
|
ferencd@0
|
34 };
|
|
ferencd@0
|
35
|
|
ferencd@0
|
36 /// True if type T is applicable by a std::uniform_real_distribution
|
|
ferencd@0
|
37 template<typename T>
|
|
ferencd@0
|
38 struct is_uniform_real {
|
|
ferencd@0
|
39 static constexpr bool value =
|
|
ferencd@0
|
40 std::is_same<T, float>::value
|
|
ferencd@0
|
41 || std::is_same<T, double>::value
|
|
ferencd@0
|
42 || std::is_same<T, long double>::value;
|
|
ferencd@0
|
43 };
|
|
ferencd@0
|
44
|
|
ferencd@0
|
45 /// True if type T is plain byte
|
|
ferencd@0
|
46 template<typename T>
|
|
ferencd@0
|
47 struct is_byte {
|
|
ferencd@0
|
48 static constexpr bool value =
|
|
ferencd@0
|
49 std::is_same<T, signed char>::value
|
|
ferencd@0
|
50 || std::is_same<T, unsigned char>::value;
|
|
ferencd@0
|
51 };
|
|
ferencd@0
|
52
|
|
ferencd@0
|
53 /// True if type T is plain number type
|
|
ferencd@0
|
54 template<typename T>
|
|
ferencd@0
|
55 struct is_supported_number {
|
|
ferencd@0
|
56 static constexpr bool value =
|
|
ferencd@0
|
57 is_byte <T>::value
|
|
ferencd@0
|
58 || is_uniform_real<T>::value
|
|
ferencd@0
|
59 || is_uniform_int <T>::value;
|
|
ferencd@0
|
60 };
|
|
ferencd@0
|
61
|
|
ferencd@0
|
62 /// True if type T is iterator
|
|
ferencd@0
|
63 template<typename T>
|
|
ferencd@0
|
64 struct is_iterator {
|
|
ferencd@0
|
65 private:
|
|
ferencd@0
|
66 static char test( ... );
|
|
ferencd@0
|
67
|
|
ferencd@0
|
68 template <typename U,
|
|
ferencd@0
|
69 typename = typename std::iterator_traits<U>::difference_type,
|
|
ferencd@0
|
70 typename = typename std::iterator_traits<U>::pointer,
|
|
ferencd@0
|
71 typename = typename std::iterator_traits<U>::reference,
|
|
ferencd@0
|
72 typename = typename std::iterator_traits<U>::value_type,
|
|
ferencd@0
|
73 typename = typename std::iterator_traits<U>::iterator_category
|
|
ferencd@0
|
74 > static long test( U&& );
|
|
ferencd@0
|
75 public:
|
|
ferencd@0
|
76 static constexpr bool value = std::is_same<
|
|
ferencd@0
|
77 decltype( test( std::declval<T>( ) ) ), long>::value;
|
|
ferencd@0
|
78 };
|
|
ferencd@0
|
79
|
|
ferencd@0
|
80 } // namespace details
|
|
ferencd@0
|
81
|
|
ferencd@0
|
82 /// Default seeder for 'random' classes
|
|
ferencd@0
|
83 struct seeder_default {
|
|
ferencd@0
|
84 /// return seed sequence
|
|
ferencd@0
|
85 std::seed_seq& operator() ( ) {
|
|
ferencd@0
|
86 // MinGW issue, std::random_device returns constant value
|
|
ferencd@0
|
87 // Use std::seed_seq with additional seed from C++ chrono
|
|
ferencd@0
|
88 return seed_seq;
|
|
ferencd@0
|
89 }
|
|
ferencd@0
|
90 private:
|
|
ferencd@0
|
91 std::seed_seq seed_seq{ {
|
|
ferencd@0
|
92 static_cast<std::uintmax_t>( std::random_device{ }( ) ),
|
|
ferencd@0
|
93 static_cast<std::uintmax_t>( std::chrono::steady_clock::now( )
|
|
ferencd@0
|
94 .time_since_epoch( ).count( ) ),
|
|
ferencd@0
|
95 } };
|
|
ferencd@0
|
96 };
|
|
ferencd@0
|
97
|
|
ferencd@0
|
98 /**
|
|
ferencd@0
|
99 * \brief Base template class for random
|
|
ferencd@0
|
100 * with static API and static internal member storage
|
|
ferencd@0
|
101 * \note it is NOT thread safe but more efficient then
|
|
ferencd@0
|
102 * basic_random_thread_local
|
|
ferencd@0
|
103 * \param Engine A random engine with interface like in the std::mt19937
|
|
ferencd@0
|
104 * \param Seeder A seeder type which return seed for internal engine
|
|
ferencd@0
|
105 * through operator()
|
|
ferencd@0
|
106 */
|
|
ferencd@0
|
107 template<
|
|
ferencd@0
|
108 typename Engine,
|
|
ferencd@0
|
109 typename Seeder = seeder_default,
|
|
ferencd@0
|
110 template<typename> class IntegerDist = std::uniform_int_distribution,
|
|
ferencd@0
|
111 template<typename> class RealDist = std::uniform_real_distribution,
|
|
ferencd@0
|
112 typename BoolDist = std::bernoulli_distribution
|
|
ferencd@0
|
113 >
|
|
ferencd@0
|
114 class basic_random_static {
|
|
ferencd@0
|
115 public:
|
|
ferencd@0
|
116 basic_random_static( ) = delete;
|
|
ferencd@0
|
117
|
|
ferencd@0
|
118 /// Type of used random number engine
|
|
ferencd@0
|
119 using engine_type = Engine;
|
|
ferencd@0
|
120
|
|
ferencd@0
|
121 /// Type of used random number seeder
|
|
ferencd@0
|
122 using seeder_type = Seeder;
|
|
ferencd@0
|
123
|
|
ferencd@0
|
124 /// Type of used integer distribution
|
|
ferencd@0
|
125 template<typename T>
|
|
ferencd@0
|
126 using integer_dist_t = IntegerDist<T>;
|
|
ferencd@0
|
127
|
|
ferencd@0
|
128 /// Type of used real distribution
|
|
ferencd@0
|
129 template<typename T>
|
|
ferencd@0
|
130 using real_dist_t = RealDist<T>;
|
|
ferencd@0
|
131
|
|
ferencd@0
|
132 /// Type of used bool distribution
|
|
ferencd@0
|
133 using bool_dist_t = BoolDist;
|
|
ferencd@0
|
134
|
|
ferencd@0
|
135 /// Key type for getting common type numbers or objects
|
|
ferencd@0
|
136 using common = details::common;
|
|
ferencd@0
|
137
|
|
ferencd@0
|
138 /**
|
|
ferencd@0
|
139 * \return The minimum value
|
|
ferencd@0
|
140 * potentially generated by the random-number engine
|
|
ferencd@0
|
141 */
|
|
ferencd@0
|
142 static constexpr typename Engine::result_type min( ) {
|
|
ferencd@0
|
143 return Engine::min( );
|
|
ferencd@0
|
144 }
|
|
ferencd@0
|
145
|
|
ferencd@0
|
146 /**
|
|
ferencd@0
|
147 * \return The maximum value
|
|
ferencd@0
|
148 * potentially generated by the random-number engine
|
|
ferencd@0
|
149 */
|
|
ferencd@0
|
150 static constexpr typename Engine::result_type max( ) {
|
|
ferencd@0
|
151 return Engine::max( );
|
|
ferencd@0
|
152 }
|
|
ferencd@0
|
153
|
|
ferencd@0
|
154 /// Advances the internal state by z times
|
|
ferencd@0
|
155 static void discard( const unsigned long long z ) {
|
|
ferencd@0
|
156 engine.discard( z );
|
|
ferencd@0
|
157 }
|
|
ferencd@0
|
158
|
|
ferencd@0
|
159 /// Reseed by Seeder
|
|
ferencd@0
|
160 static void reseed( ) {
|
|
ferencd@0
|
161 Seeder seeder;
|
|
ferencd@0
|
162 seed( seeder( ) );
|
|
ferencd@0
|
163 }
|
|
ferencd@0
|
164
|
|
ferencd@0
|
165 /**
|
|
ferencd@0
|
166 * \brief Reinitializes the internal state
|
|
ferencd@0
|
167 * of the random-number engine using new seed value
|
|
ferencd@0
|
168 * \param value The seed value to use
|
|
ferencd@0
|
169 * in the initialization of the internal state
|
|
ferencd@0
|
170 */
|
|
ferencd@0
|
171 static void seed( const typename Engine::result_type value =
|
|
ferencd@0
|
172 Engine::default_seed ) {
|
|
ferencd@0
|
173 engine.seed( value );
|
|
ferencd@0
|
174 }
|
|
ferencd@0
|
175
|
|
ferencd@0
|
176 /**
|
|
ferencd@0
|
177 * \brief Reinitializes the internal state
|
|
ferencd@0
|
178 * of the random-number engine using new seed value
|
|
ferencd@0
|
179 * \param seq The seed sequence
|
|
ferencd@0
|
180 * to use in the initialization of the internal state
|
|
ferencd@0
|
181 */
|
|
ferencd@0
|
182 template<typename Sseq>
|
|
ferencd@0
|
183 static void seed( Sseq& seq ) {
|
|
ferencd@0
|
184 engine.seed( seq );
|
|
ferencd@0
|
185 }
|
|
ferencd@0
|
186
|
|
ferencd@0
|
187 /// return random number from engine in [min(), max()] range
|
|
ferencd@0
|
188 static typename Engine::result_type get( ) {
|
|
ferencd@0
|
189 return engine( );
|
|
ferencd@0
|
190 }
|
|
ferencd@0
|
191
|
|
ferencd@0
|
192 /**
|
|
ferencd@0
|
193 * \brief Compares internal pseudo-random number engine
|
|
ferencd@0
|
194 * with 'other' pseudo-random number engine.
|
|
ferencd@0
|
195 * Two engines are equal, if their internal states
|
|
ferencd@0
|
196 * are equivalent, that is, if they would generate
|
|
ferencd@0
|
197 * equivalent values for any number of calls of operator()
|
|
ferencd@0
|
198 * \param other The engine, with which the internal engine will be compared
|
|
ferencd@0
|
199 * \return true, if other and internal engine are equal
|
|
ferencd@0
|
200 */
|
|
ferencd@0
|
201 static bool is_equal( const Engine& other ) {
|
|
ferencd@0
|
202 return engine == other;
|
|
ferencd@0
|
203 }
|
|
ferencd@0
|
204
|
|
ferencd@0
|
205 /**
|
|
ferencd@0
|
206 * \brief Serializes the internal state of the
|
|
ferencd@0
|
207 * internal pseudo-random number engine as a sequence
|
|
ferencd@0
|
208 * of decimal numbers separated by one or more spaces,
|
|
ferencd@0
|
209 * and inserts it to the stream ost. The fill character
|
|
ferencd@0
|
210 * and the formatting flags of the stream are
|
|
ferencd@0
|
211 * ignored and unaffected.
|
|
ferencd@0
|
212 * \param ost The output stream to insert the data to
|
|
ferencd@0
|
213 */
|
|
ferencd@0
|
214 template<typename CharT, typename Traits>
|
|
ferencd@0
|
215 static void serialize( std::basic_ostream<CharT, Traits>& ost ) {
|
|
ferencd@0
|
216 ost << engine;
|
|
ferencd@0
|
217 }
|
|
ferencd@0
|
218
|
|
ferencd@0
|
219 /**
|
|
ferencd@0
|
220 * \brief Restores the internal state of the
|
|
ferencd@0
|
221 * internal pseudo-random number engine from
|
|
ferencd@0
|
222 * the serialized representation, which
|
|
ferencd@0
|
223 * was created by an earlier call to 'serialize'
|
|
ferencd@0
|
224 * using a stream with the same imbued locale and
|
|
ferencd@0
|
225 * the same CharT and Traits.
|
|
ferencd@0
|
226 * If the input cannot be deserialized,
|
|
ferencd@0
|
227 * internal engine is left unchanged and failbit is raised on ist
|
|
ferencd@0
|
228 * \param ost The input stream to extract the data from
|
|
ferencd@0
|
229 */
|
|
ferencd@0
|
230 template<typename CharT, typename Traits>
|
|
ferencd@0
|
231 static void deserialize( std::basic_istream<CharT, Traits>& ist ) {
|
|
ferencd@0
|
232 ist >> engine;
|
|
ferencd@0
|
233 }
|
|
ferencd@0
|
234
|
|
ferencd@0
|
235 /**
|
|
ferencd@0
|
236 * \brief Generate a random integer number in a [from; to] range
|
|
ferencd@0
|
237 * by std::uniform_int_distribution
|
|
ferencd@0
|
238 * \param from The first limit number of a random range
|
|
ferencd@0
|
239 * \param to The second limit number of a random range
|
|
ferencd@0
|
240 * \return A random integer number in a [from; to] range
|
|
ferencd@0
|
241 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
242 * \note Prevent implicit type conversion
|
|
ferencd@0
|
243 */
|
|
ferencd@0
|
244 template<typename T>
|
|
ferencd@0
|
245 static typename std::enable_if<details::is_uniform_int<T>::value
|
|
ferencd@0
|
246 , T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
ferencd@0
|
247 T to = std::numeric_limits<T>::max( ) ) {
|
|
ferencd@0
|
248 if( from < to ) // Allow range from higher to lower
|
|
ferencd@0
|
249 return IntegerDist<T>{ from, to }( engine );
|
|
ferencd@0
|
250 return IntegerDist<T>{ to, from }( engine );
|
|
ferencd@0
|
251 }
|
|
ferencd@0
|
252
|
|
ferencd@0
|
253 /**
|
|
ferencd@0
|
254 * \brief Generate a random real number in a [from; to] range
|
|
ferencd@0
|
255 * by std::uniform_real_distribution
|
|
ferencd@0
|
256 * \param from The first limit number of a random range
|
|
ferencd@0
|
257 * \param to The second limit number of a random range
|
|
ferencd@0
|
258 * \return A random real number in a [from; to] range
|
|
ferencd@0
|
259 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
260 * \note Prevent implicit type conversion
|
|
ferencd@0
|
261 */
|
|
ferencd@0
|
262 template<typename T>
|
|
ferencd@0
|
263 static typename std::enable_if<details::is_uniform_real<T>::value
|
|
ferencd@0
|
264 , T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
ferencd@0
|
265 T to = std::numeric_limits<T>::max( ) ) {
|
|
ferencd@0
|
266 if( from < to ) // Allow range from higher to lower
|
|
ferencd@0
|
267 return RealDist<T>{ from, to }( engine );
|
|
ferencd@0
|
268 return RealDist<T>{ to, from }( engine );
|
|
ferencd@0
|
269 }
|
|
ferencd@0
|
270
|
|
ferencd@0
|
271 /**
|
|
ferencd@0
|
272 * \brief Generate a random byte number in a [from; to] range
|
|
ferencd@0
|
273 * \param from The first limit number of a random range
|
|
ferencd@0
|
274 * \param to The second limit number of a random range
|
|
ferencd@0
|
275 * \return A random byte number in a [from; to] range
|
|
ferencd@0
|
276 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
277 * \note Prevent implicit type conversion
|
|
ferencd@0
|
278 */
|
|
ferencd@0
|
279 template<typename T>
|
|
ferencd@0
|
280 static typename std::enable_if<details::is_byte<T>::value
|
|
ferencd@0
|
281 , T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
ferencd@0
|
282 T to = std::numeric_limits<T>::max( ) ) {
|
|
ferencd@0
|
283 // Choose between short and unsigned short for byte conversion
|
|
ferencd@0
|
284 using short_t = typename std::conditional<std::is_signed<T>::value,
|
|
ferencd@0
|
285 short, unsigned short>::type;
|
|
ferencd@0
|
286
|
|
ferencd@0
|
287 return static_cast<T>( get<short_t>( from, to ) );
|
|
ferencd@0
|
288 }
|
|
ferencd@0
|
289
|
|
ferencd@0
|
290 /**
|
|
ferencd@0
|
291 * \brief Generate a random common_type number in a [from; to] range
|
|
ferencd@0
|
292 * \param Key The Key type for this version of 'get' method
|
|
ferencd@0
|
293 * Type should be '(THIS_TYPE)::common' struct
|
|
ferencd@0
|
294 * \param from The first limit number of a random range
|
|
ferencd@0
|
295 * \param to The second limit number of a random range
|
|
ferencd@0
|
296 * \return A random common_type number in a [from; to] range
|
|
ferencd@0
|
297 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
298 * \note Allow implicit type conversion
|
|
ferencd@0
|
299 * \note Prevent implicit type conversion from singed to unsigned types
|
|
ferencd@0
|
300 * Why? std::common_type<Unsigned, Signed> chooses unsigned value,
|
|
ferencd@0
|
301 * then Signed value will be converted to Unsigned value
|
|
ferencd@0
|
302 * which gives us a wrong range for random values.
|
|
ferencd@0
|
303 * https://stackoverflow.com/a/5416498/5734836
|
|
ferencd@0
|
304 */
|
|
ferencd@0
|
305 template<
|
|
ferencd@0
|
306 typename Key,
|
|
ferencd@0
|
307 typename A,
|
|
ferencd@0
|
308 typename B,
|
|
ferencd@0
|
309 typename C = typename std::common_type<A, B>::type
|
|
ferencd@0
|
310 >
|
|
ferencd@0
|
311 static typename std::enable_if<
|
|
ferencd@0
|
312 std::is_same<Key, common>::value
|
|
ferencd@0
|
313 && details::is_supported_number<A>::value
|
|
ferencd@0
|
314 && details::is_supported_number<B>::value
|
|
ferencd@0
|
315 // Prevent implicit type conversion from singed to unsigned types
|
|
ferencd@0
|
316 && std::is_signed<A>::value != std::is_unsigned<B>::value
|
|
ferencd@0
|
317 , C>::type get( A from = std::numeric_limits<A>::min( ),
|
|
ferencd@0
|
318 B to = std::numeric_limits<B>::max( ) ) {
|
|
ferencd@0
|
319 return get( static_cast<C>( from ), static_cast<C>( to ) );
|
|
ferencd@0
|
320 }
|
|
ferencd@0
|
321
|
|
ferencd@0
|
322 /**
|
|
ferencd@0
|
323 * \brief Generate a bool value with specific probability
|
|
ferencd@0
|
324 * by std::bernoulli_distribution
|
|
ferencd@0
|
325 * \param probability The probability of generating true in [0; 1] range
|
|
ferencd@0
|
326 * 0 means always false, 1 means always true
|
|
ferencd@0
|
327 * \return 'true' with 'probability' probability ('false' otherwise)
|
|
ferencd@0
|
328 */
|
|
ferencd@0
|
329 template<typename T>
|
|
ferencd@0
|
330 static typename std::enable_if<std::is_same<T, bool>::value
|
|
ferencd@0
|
331 , bool>::type get( const double probability = 0.5 ) {
|
|
ferencd@0
|
332 assert( 0 <= probability && 1 >= probability ); // out of [0; 1] range
|
|
ferencd@0
|
333 return BoolDist{ probability }( engine );
|
|
ferencd@0
|
334 }
|
|
ferencd@0
|
335
|
|
ferencd@0
|
336 /**
|
|
ferencd@0
|
337 * \brief Return random value from initilizer_list
|
|
ferencd@0
|
338 * \param init_list initilizer_list with values
|
|
ferencd@0
|
339 * \return Random value from initilizer_list
|
|
ferencd@0
|
340 * \note Should be 1 or more elements in initilizer_list
|
|
ferencd@0
|
341 * \note Warning! Elements in initilizer_list can't be moved:
|
|
ferencd@0
|
342 * https://stackoverflow.com/a/8193157/5734836
|
|
ferencd@0
|
343 */
|
|
ferencd@0
|
344 template<typename T>
|
|
ferencd@0
|
345 static T get( std::initializer_list<T> init_list ) {
|
|
ferencd@0
|
346 assert( 0u != init_list.size( ) );
|
|
ferencd@0
|
347 return *get( init_list.begin( ), init_list.end( ) );
|
|
ferencd@0
|
348 }
|
|
ferencd@0
|
349
|
|
ferencd@0
|
350 /**
|
|
ferencd@0
|
351 * \brief Return random iterator from iterator range
|
|
ferencd@0
|
352 * \param first, last - the range of elements
|
|
ferencd@0
|
353 * \return Random iterator from [first, last) range
|
|
ferencd@0
|
354 * \note If first == last, return last
|
|
ferencd@0
|
355 */
|
|
ferencd@0
|
356 template<typename InputIt>
|
|
ferencd@0
|
357 static typename std::enable_if<details::is_iterator<InputIt>::value
|
|
ferencd@0
|
358 , InputIt>::type get( InputIt first, InputIt last ) {
|
|
ferencd@0
|
359 const auto size = std::distance( first, last );
|
|
ferencd@0
|
360 if( 0u == size ) return last;
|
|
ferencd@0
|
361 using diff_t = typename std::iterator_traits<InputIt>::difference_type;
|
|
ferencd@0
|
362 return std::next( first, get<diff_t>( 0, size - 1 ) );
|
|
ferencd@0
|
363 }
|
|
ferencd@0
|
364
|
|
ferencd@0
|
365 /**
|
|
ferencd@0
|
366 * \brief Return random iterator from Container
|
|
ferencd@0
|
367 * \param container The container with elements
|
|
ferencd@0
|
368 * \return Random iterator from container
|
|
ferencd@0
|
369 * \note If container is empty return std::end( container ) iterator
|
|
ferencd@0
|
370 */
|
|
ferencd@0
|
371 template<typename Container>
|
|
ferencd@0
|
372 static typename std::enable_if<details::is_iterator<
|
|
ferencd@0
|
373 decltype( std::begin( std::declval<Container>( ) ) )>::value
|
|
ferencd@0
|
374 , decltype( std::begin( std::declval<Container>( ) ) )
|
|
ferencd@0
|
375 >::type get( Container& container ) {
|
|
ferencd@0
|
376 return get( std::begin( container ), std::end( container ) );
|
|
ferencd@0
|
377 }
|
|
ferencd@0
|
378
|
|
ferencd@0
|
379 /**
|
|
ferencd@0
|
380 * \brief Return value from custom Dist distribution
|
|
ferencd@0
|
381 * seeded by internal random engine
|
|
ferencd@0
|
382 * \param Dist The type of custom distribution with next concept:
|
|
ferencd@0
|
383 * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution
|
|
ferencd@0
|
384 * \param args The arguments which will be forwarded to Dist constructor
|
|
ferencd@0
|
385 * \return Value from custom distribution
|
|
ferencd@0
|
386 */
|
|
ferencd@0
|
387 template<typename Dist, typename... Args>
|
|
ferencd@0
|
388 static typename Dist::result_type get( Args&&... args ) {
|
|
ferencd@0
|
389 return Dist{ std::forward<Args>( args )... }( engine );
|
|
ferencd@0
|
390 }
|
|
ferencd@0
|
391
|
|
ferencd@0
|
392 /**
|
|
ferencd@0
|
393 * \brief Return value from custom 'dist' distribution
|
|
ferencd@0
|
394 * seeded by internal random engine
|
|
ferencd@0
|
395 * \param dist The custom distribution with next concept:
|
|
ferencd@0
|
396 * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution
|
|
ferencd@0
|
397 * \param args The arguments which will be forwarded to Dist constructor
|
|
ferencd@0
|
398 * \return Value from custom 'dist' distribution
|
|
ferencd@0
|
399 */
|
|
ferencd@0
|
400 template<typename Dist>
|
|
ferencd@0
|
401 static typename Dist::result_type get( Dist& dist ) {
|
|
ferencd@0
|
402 return dist( engine );
|
|
ferencd@0
|
403 }
|
|
ferencd@0
|
404
|
|
ferencd@0
|
405 /**
|
|
ferencd@0
|
406 * \brief Reorders the elements in the given range [first, last)
|
|
ferencd@0
|
407 * such that each possible permutation of those elements
|
|
ferencd@0
|
408 * has equal probability of appearance.
|
|
ferencd@0
|
409 * \param first, last - the range of elements to shuffle randomly
|
|
ferencd@0
|
410 */
|
|
ferencd@0
|
411 template<typename RandomIt>
|
|
ferencd@0
|
412 static void shuffle( RandomIt first, RandomIt last ) {
|
|
ferencd@0
|
413 std::shuffle( first, last, engine );
|
|
ferencd@0
|
414 }
|
|
ferencd@0
|
415
|
|
ferencd@0
|
416 /**
|
|
ferencd@0
|
417 * \brief Reorders the elements in the given container
|
|
ferencd@0
|
418 * such that each possible permutation of those elements
|
|
ferencd@0
|
419 * has equal probability of appearance.
|
|
ferencd@0
|
420 * \param container - the container with elements to shuffle randomly
|
|
ferencd@0
|
421 */
|
|
ferencd@0
|
422 template<typename Container>
|
|
ferencd@0
|
423 static void shuffle( Container& container ) {
|
|
ferencd@0
|
424 shuffle( std::begin( container ), std::end( container ) );
|
|
ferencd@0
|
425 }
|
|
ferencd@0
|
426
|
|
ferencd@0
|
427 /// return internal engine by copy
|
|
ferencd@0
|
428 static Engine get_engine( ) {
|
|
ferencd@0
|
429 return engine;
|
|
ferencd@0
|
430 }
|
|
ferencd@0
|
431 protected:
|
|
ferencd@0
|
432 /// return engine seeded by Seeder
|
|
ferencd@0
|
433 static Engine make_seeded_engine( ) {
|
|
ferencd@0
|
434 // Make seeder instance for seed return by reference like std::seed_seq
|
|
ferencd@0
|
435 Seeder seeder;
|
|
ferencd@0
|
436 return Engine{ seeder( ) };
|
|
ferencd@0
|
437 }
|
|
ferencd@0
|
438 protected:
|
|
ferencd@0
|
439 /// The random number engine
|
|
ferencd@0
|
440 static Engine engine;
|
|
ferencd@0
|
441 };
|
|
ferencd@0
|
442
|
|
ferencd@0
|
443 /// Seed random number engine by Seeder
|
|
ferencd@0
|
444 template<
|
|
ferencd@0
|
445 typename Engine,
|
|
ferencd@0
|
446 typename Seeder,
|
|
ferencd@0
|
447 template<typename> class IntegerDist,
|
|
ferencd@0
|
448 template<typename> class RealDist,
|
|
ferencd@0
|
449 typename BoolDist
|
|
ferencd@0
|
450 >
|
|
ferencd@0
|
451 Engine basic_random_static<Engine, Seeder, IntegerDist, RealDist, BoolDist
|
|
ferencd@0
|
452 // VS2017 issue, can't init by Seeder from lambda
|
|
ferencd@0
|
453 >::engine( make_seeded_engine( ) );
|
|
ferencd@0
|
454
|
|
ferencd@0
|
455 /**
|
|
ferencd@0
|
456 * \brief Base template class for random
|
|
ferencd@0
|
457 * with thread_local API and thread_local internal member storage
|
|
ferencd@0
|
458 * \note it IS thread safe but less efficient then
|
|
ferencd@0
|
459 * basic_random_static
|
|
ferencd@0
|
460 * \param Engine A random engine with interface like in the std::mt19937
|
|
ferencd@0
|
461 * \param Seeder A seeder type which return seed for internal engine
|
|
ferencd@0
|
462 * through operator()
|
|
ferencd@0
|
463 */
|
|
ferencd@0
|
464 template<
|
|
ferencd@0
|
465 typename Engine,
|
|
ferencd@0
|
466 typename Seeder = seeder_default,
|
|
ferencd@0
|
467 template<typename> class IntegerDist = std::uniform_int_distribution,
|
|
ferencd@0
|
468 template<typename> class RealDist = std::uniform_real_distribution,
|
|
ferencd@0
|
469 typename BoolDist = std::bernoulli_distribution
|
|
ferencd@0
|
470 >
|
|
ferencd@0
|
471 class basic_random_thread_local {
|
|
ferencd@0
|
472 public:
|
|
ferencd@0
|
473 basic_random_thread_local( ) = delete;
|
|
ferencd@0
|
474
|
|
ferencd@0
|
475 /// Type of used random number engine
|
|
ferencd@0
|
476 using engine_type = Engine;
|
|
ferencd@0
|
477
|
|
ferencd@0
|
478 /// Type of used random number seeder
|
|
ferencd@0
|
479 using seeder_type = Seeder;
|
|
ferencd@0
|
480
|
|
ferencd@0
|
481 /// Type of used integer distribution
|
|
ferencd@0
|
482 template<typename T>
|
|
ferencd@0
|
483 using integer_dist_t = IntegerDist<T>;
|
|
ferencd@0
|
484
|
|
ferencd@0
|
485 /// Type of used real distribution
|
|
ferencd@0
|
486 template<typename T>
|
|
ferencd@0
|
487 using real_dist_t = RealDist<T>;
|
|
ferencd@0
|
488
|
|
ferencd@0
|
489 /// Type of used bool distribution
|
|
ferencd@0
|
490 using bool_dist_t = BoolDist;
|
|
ferencd@0
|
491
|
|
ferencd@0
|
492 /// Key type for getting common type numbers or objects
|
|
ferencd@0
|
493 using common = details::common;
|
|
ferencd@0
|
494
|
|
ferencd@0
|
495 /**
|
|
ferencd@0
|
496 * \return The minimum value
|
|
ferencd@0
|
497 * potentially generated by the random-number engine
|
|
ferencd@0
|
498 */
|
|
ferencd@0
|
499 static constexpr typename Engine::result_type min( ) {
|
|
ferencd@0
|
500 return Engine::min( );
|
|
ferencd@0
|
501 }
|
|
ferencd@0
|
502
|
|
ferencd@0
|
503 /**
|
|
ferencd@0
|
504 * \return The maximum value
|
|
ferencd@0
|
505 * potentially generated by the random-number engine
|
|
ferencd@0
|
506 */
|
|
ferencd@0
|
507 static constexpr typename Engine::result_type max( ) {
|
|
ferencd@0
|
508 return Engine::max( );
|
|
ferencd@0
|
509 }
|
|
ferencd@0
|
510
|
|
ferencd@0
|
511 /// Advances the internal state by z times
|
|
ferencd@0
|
512 static void discard( const unsigned long long z ) {
|
|
ferencd@0
|
513 engine.discard( z );
|
|
ferencd@0
|
514 }
|
|
ferencd@0
|
515
|
|
ferencd@0
|
516 /// Reseed by Seeder
|
|
ferencd@0
|
517 static void reseed( ) {
|
|
ferencd@0
|
518 Seeder seeder;
|
|
ferencd@0
|
519 seed( seeder( ) );
|
|
ferencd@0
|
520 }
|
|
ferencd@0
|
521
|
|
ferencd@0
|
522 /**
|
|
ferencd@0
|
523 * \brief Reinitializes the internal state
|
|
ferencd@0
|
524 * of the random-number engine using new seed value
|
|
ferencd@0
|
525 * \param value The seed value to use
|
|
ferencd@0
|
526 * in the initialization of the internal state
|
|
ferencd@0
|
527 */
|
|
ferencd@0
|
528 static void seed( const typename Engine::result_type value =
|
|
ferencd@0
|
529 Engine::default_seed ) {
|
|
ferencd@0
|
530 engine.seed( value );
|
|
ferencd@0
|
531 }
|
|
ferencd@0
|
532
|
|
ferencd@0
|
533 /**
|
|
ferencd@0
|
534 * \brief Reinitializes the internal state
|
|
ferencd@0
|
535 * of the random-number engine using new seed value
|
|
ferencd@0
|
536 * \param seq The seed sequence
|
|
ferencd@0
|
537 * to use in the initialization of the internal state
|
|
ferencd@0
|
538 */
|
|
ferencd@0
|
539 template<typename Sseq>
|
|
ferencd@0
|
540 static void seed( Sseq& seq ) {
|
|
ferencd@0
|
541 engine.seed( seq );
|
|
ferencd@0
|
542 }
|
|
ferencd@0
|
543
|
|
ferencd@0
|
544 /// return random number from engine in [min(), max()] range
|
|
ferencd@0
|
545 static typename Engine::result_type get( ) {
|
|
ferencd@0
|
546 return engine( );
|
|
ferencd@0
|
547 }
|
|
ferencd@0
|
548
|
|
ferencd@0
|
549 /**
|
|
ferencd@0
|
550 * \brief Compares internal pseudo-random number engine
|
|
ferencd@0
|
551 * with 'other' pseudo-random number engine.
|
|
ferencd@0
|
552 * Two engines are equal, if their internal states
|
|
ferencd@0
|
553 * are equivalent, that is, if they would generate
|
|
ferencd@0
|
554 * equivalent values for any number of calls of operator()
|
|
ferencd@0
|
555 * \param other The engine, with which the internal engine will be compared
|
|
ferencd@0
|
556 * \return true, if other and internal engine are equal
|
|
ferencd@0
|
557 */
|
|
ferencd@0
|
558 static bool is_equal( const Engine& other ) {
|
|
ferencd@0
|
559 return engine == other;
|
|
ferencd@0
|
560 }
|
|
ferencd@0
|
561
|
|
ferencd@0
|
562 /**
|
|
ferencd@0
|
563 * \brief Serializes the internal state of the
|
|
ferencd@0
|
564 * internal pseudo-random number engine as a sequence
|
|
ferencd@0
|
565 * of decimal numbers separated by one or more spaces,
|
|
ferencd@0
|
566 * and inserts it to the stream ost. The fill character
|
|
ferencd@0
|
567 * and the formatting flags of the stream are
|
|
ferencd@0
|
568 * ignored and unaffected.
|
|
ferencd@0
|
569 * \param ost The output stream to insert the data to
|
|
ferencd@0
|
570 */
|
|
ferencd@0
|
571 template<typename CharT, typename Traits>
|
|
ferencd@0
|
572 static void serialize( std::basic_ostream<CharT, Traits>& ost ) {
|
|
ferencd@0
|
573 ost << engine;
|
|
ferencd@0
|
574 }
|
|
ferencd@0
|
575
|
|
ferencd@0
|
576 /**
|
|
ferencd@0
|
577 * \brief Restores the internal state of the
|
|
ferencd@0
|
578 * internal pseudo-random number engine from
|
|
ferencd@0
|
579 * the serialized representation, which
|
|
ferencd@0
|
580 * was created by an earlier call to 'serialize'
|
|
ferencd@0
|
581 * using a stream with the same imbued locale and
|
|
ferencd@0
|
582 * the same CharT and Traits.
|
|
ferencd@0
|
583 * If the input cannot be deserialized,
|
|
ferencd@0
|
584 * internal engine is left unchanged and failbit is raised on ist
|
|
ferencd@0
|
585 * \param ost The input stream to extract the data from
|
|
ferencd@0
|
586 */
|
|
ferencd@0
|
587 template<typename CharT, typename Traits>
|
|
ferencd@0
|
588 static void deserialize( std::basic_istream<CharT, Traits>& ist ) {
|
|
ferencd@0
|
589 ist >> engine;
|
|
ferencd@0
|
590 }
|
|
ferencd@0
|
591
|
|
ferencd@0
|
592 /**
|
|
ferencd@0
|
593 * \brief Generate a random integer number in a [from; to] range
|
|
ferencd@0
|
594 * by std::uniform_int_distribution
|
|
ferencd@0
|
595 * \param from The first limit number of a random range
|
|
ferencd@0
|
596 * \param to The second limit number of a random range
|
|
ferencd@0
|
597 * \return A random integer number in a [from; to] range
|
|
ferencd@0
|
598 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
599 * \note Prevent implicit type conversion
|
|
ferencd@0
|
600 */
|
|
ferencd@0
|
601 template<typename T>
|
|
ferencd@0
|
602 static typename std::enable_if<details::is_uniform_int<T>::value
|
|
ferencd@0
|
603 , T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
ferencd@0
|
604 T to = std::numeric_limits<T>::max( ) ) {
|
|
ferencd@0
|
605 if( from < to ) // Allow range from higher to lower
|
|
ferencd@0
|
606 return IntegerDist<T>{ from, to }( engine );
|
|
ferencd@0
|
607 return IntegerDist<T>{ to, from }( engine );
|
|
ferencd@0
|
608 }
|
|
ferencd@0
|
609
|
|
ferencd@0
|
610 /**
|
|
ferencd@0
|
611 * \brief Generate a random real number in a [from; to] range
|
|
ferencd@0
|
612 * by std::uniform_real_distribution
|
|
ferencd@0
|
613 * \param from The first limit number of a random range
|
|
ferencd@0
|
614 * \param to The second limit number of a random range
|
|
ferencd@0
|
615 * \return A random real number in a [from; to] range
|
|
ferencd@0
|
616 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
617 * \note Prevent implicit type conversion
|
|
ferencd@0
|
618 */
|
|
ferencd@0
|
619 template<typename T>
|
|
ferencd@0
|
620 static typename std::enable_if<details::is_uniform_real<T>::value
|
|
ferencd@0
|
621 , T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
ferencd@0
|
622 T to = std::numeric_limits<T>::max( ) ) {
|
|
ferencd@0
|
623 if( from < to ) // Allow range from higher to lower
|
|
ferencd@0
|
624 return RealDist<T>{ from, to }( engine );
|
|
ferencd@0
|
625 return RealDist<T>{ to, from }( engine );
|
|
ferencd@0
|
626 }
|
|
ferencd@0
|
627
|
|
ferencd@0
|
628 /**
|
|
ferencd@0
|
629 * \brief Generate a random byte number in a [from; to] range
|
|
ferencd@0
|
630 * \param from The first limit number of a random range
|
|
ferencd@0
|
631 * \param to The second limit number of a random range
|
|
ferencd@0
|
632 * \return A random byte number in a [from; to] range
|
|
ferencd@0
|
633 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
634 * \note Prevent implicit type conversion
|
|
ferencd@0
|
635 */
|
|
ferencd@0
|
636 template<typename T>
|
|
ferencd@0
|
637 static typename std::enable_if<details::is_byte<T>::value
|
|
ferencd@0
|
638 , T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
ferencd@0
|
639 T to = std::numeric_limits<T>::max( ) ) {
|
|
ferencd@0
|
640 // Choose between short and unsigned short for byte conversion
|
|
ferencd@0
|
641 using short_t = typename std::conditional<std::is_signed<T>::value,
|
|
ferencd@0
|
642 short, unsigned short>::type;
|
|
ferencd@0
|
643
|
|
ferencd@0
|
644 return static_cast<T>( get<short_t>( from, to ) );
|
|
ferencd@0
|
645 }
|
|
ferencd@0
|
646
|
|
ferencd@0
|
647 /**
|
|
ferencd@0
|
648 * \brief Generate a random common_type number in a [from; to] range
|
|
ferencd@0
|
649 * \param Key The Key type for this version of 'get' method
|
|
ferencd@0
|
650 * Type should be '(THIS_TYPE)::common' struct
|
|
ferencd@0
|
651 * \param from The first limit number of a random range
|
|
ferencd@0
|
652 * \param to The second limit number of a random range
|
|
ferencd@0
|
653 * \return A random common_type number in a [from; to] range
|
|
ferencd@0
|
654 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
655 * \note Allow implicit type conversion
|
|
ferencd@0
|
656 * \note Prevent implicit type conversion from singed to unsigned types
|
|
ferencd@0
|
657 * Why? std::common_type<Unsigned, Signed> chooses unsigned value,
|
|
ferencd@0
|
658 * then Signed value will be converted to Unsigned value
|
|
ferencd@0
|
659 * which gives us a wrong range for random values.
|
|
ferencd@0
|
660 * https://stackoverflow.com/a/5416498/5734836
|
|
ferencd@0
|
661 */
|
|
ferencd@0
|
662 template<
|
|
ferencd@0
|
663 typename Key,
|
|
ferencd@0
|
664 typename A,
|
|
ferencd@0
|
665 typename B,
|
|
ferencd@0
|
666 typename C = typename std::common_type<A, B>::type
|
|
ferencd@0
|
667 >
|
|
ferencd@0
|
668 static typename std::enable_if<
|
|
ferencd@0
|
669 std::is_same<Key, common>::value
|
|
ferencd@0
|
670 && details::is_supported_number<A>::value
|
|
ferencd@0
|
671 && details::is_supported_number<B>::value
|
|
ferencd@0
|
672 // Prevent implicit type conversion from singed to unsigned types
|
|
ferencd@0
|
673 && std::is_signed<A>::value != std::is_unsigned<B>::value
|
|
ferencd@0
|
674 , C>::type get( A from = std::numeric_limits<A>::min( ),
|
|
ferencd@0
|
675 B to = std::numeric_limits<B>::max( ) ) {
|
|
ferencd@0
|
676 return get( static_cast<C>( from ), static_cast<C>( to ) );
|
|
ferencd@0
|
677 }
|
|
ferencd@0
|
678
|
|
ferencd@0
|
679 /**
|
|
ferencd@0
|
680 * \brief Generate a bool value with specific probability
|
|
ferencd@0
|
681 * by std::bernoulli_distribution
|
|
ferencd@0
|
682 * \param probability The probability of generating true in [0; 1] range
|
|
ferencd@0
|
683 * 0 means always false, 1 means always true
|
|
ferencd@0
|
684 * \return 'true' with 'probability' probability ('false' otherwise)
|
|
ferencd@0
|
685 */
|
|
ferencd@0
|
686 template<typename T>
|
|
ferencd@0
|
687 static typename std::enable_if<std::is_same<T, bool>::value
|
|
ferencd@0
|
688 , bool>::type get( const double probability = 0.5 ) {
|
|
ferencd@0
|
689 assert( 0 <= probability && 1 >= probability ); // out of [0; 1] range
|
|
ferencd@0
|
690 return BoolDist{ probability }( engine );
|
|
ferencd@0
|
691 }
|
|
ferencd@0
|
692
|
|
ferencd@0
|
693 /**
|
|
ferencd@0
|
694 * \brief Return random value from initilizer_list
|
|
ferencd@0
|
695 * \param init_list initilizer_list with values
|
|
ferencd@0
|
696 * \return Random value from initilizer_list
|
|
ferencd@0
|
697 * \note Should be 1 or more elements in initilizer_list
|
|
ferencd@0
|
698 * \note Warning! Elements in initilizer_list can't be moved:
|
|
ferencd@0
|
699 * https://stackoverflow.com/a/8193157/5734836
|
|
ferencd@0
|
700 */
|
|
ferencd@0
|
701 template<typename T>
|
|
ferencd@0
|
702 static T get( std::initializer_list<T> init_list ) {
|
|
ferencd@0
|
703 assert( 0u != init_list.size( ) );
|
|
ferencd@0
|
704 return *get( init_list.begin( ), init_list.end( ) );
|
|
ferencd@0
|
705 }
|
|
ferencd@0
|
706
|
|
ferencd@0
|
707 /**
|
|
ferencd@0
|
708 * \brief Return random iterator from iterator range
|
|
ferencd@0
|
709 * \param first, last - the range of elements
|
|
ferencd@0
|
710 * \return Random iterator from [first, last) range
|
|
ferencd@0
|
711 * \note If first == last, return last
|
|
ferencd@0
|
712 */
|
|
ferencd@0
|
713 template<typename InputIt>
|
|
ferencd@0
|
714 static typename std::enable_if<details::is_iterator<InputIt>::value
|
|
ferencd@0
|
715 , InputIt>::type get( InputIt first, InputIt last ) {
|
|
ferencd@0
|
716 const auto size = std::distance( first, last );
|
|
ferencd@0
|
717 if( 0u == size ) return last;
|
|
ferencd@0
|
718 using diff_t = typename std::iterator_traits<InputIt>::difference_type;
|
|
ferencd@0
|
719 return std::next( first, get<diff_t>( 0, size - 1 ) );
|
|
ferencd@0
|
720 }
|
|
ferencd@0
|
721
|
|
ferencd@0
|
722 /**
|
|
ferencd@0
|
723 * \brief Return random iterator from Container
|
|
ferencd@0
|
724 * \param container The container with elements
|
|
ferencd@0
|
725 * \return Random iterator from container
|
|
ferencd@0
|
726 * \note If container is empty return std::end( container ) iterator
|
|
ferencd@0
|
727 */
|
|
ferencd@0
|
728 template<typename Container>
|
|
ferencd@0
|
729 static typename std::enable_if<details::is_iterator<
|
|
ferencd@0
|
730 decltype( std::begin( std::declval<Container>( ) ) )>::value
|
|
ferencd@0
|
731 , decltype( std::begin( std::declval<Container>( ) ) )
|
|
ferencd@0
|
732 >::type get( Container& container ) {
|
|
ferencd@0
|
733 return get( std::begin( container ), std::end( container ) );
|
|
ferencd@0
|
734 }
|
|
ferencd@0
|
735
|
|
ferencd@0
|
736 /**
|
|
ferencd@0
|
737 * \brief Return value from custom Dist distribution
|
|
ferencd@0
|
738 * seeded by internal random engine
|
|
ferencd@0
|
739 * \param Dist The type of custom distribution with next concept:
|
|
ferencd@0
|
740 * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution
|
|
ferencd@0
|
741 * \param args The arguments which will be forwarded to Dist constructor
|
|
ferencd@0
|
742 * \return Value from custom distribution
|
|
ferencd@0
|
743 */
|
|
ferencd@0
|
744 template<typename Dist, typename... Args>
|
|
ferencd@0
|
745 static typename Dist::result_type get( Args&&... args ) {
|
|
ferencd@0
|
746 return Dist{ std::forward<Args>( args )... }( engine );
|
|
ferencd@0
|
747 }
|
|
ferencd@0
|
748
|
|
ferencd@0
|
749 /**
|
|
ferencd@0
|
750 * \brief Return value from custom 'dist' distribution
|
|
ferencd@0
|
751 * seeded by internal random engine
|
|
ferencd@0
|
752 * \param dist The custom distribution with next concept:
|
|
ferencd@0
|
753 * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution
|
|
ferencd@0
|
754 * \param args The arguments which will be forwarded to Dist constructor
|
|
ferencd@0
|
755 * \return Value from custom 'dist' distribution
|
|
ferencd@0
|
756 */
|
|
ferencd@0
|
757 template<typename Dist>
|
|
ferencd@0
|
758 static typename Dist::result_type get( Dist& dist ) {
|
|
ferencd@0
|
759 return dist( engine );
|
|
ferencd@0
|
760 }
|
|
ferencd@0
|
761
|
|
ferencd@0
|
762 /**
|
|
ferencd@0
|
763 * \brief Reorders the elements in the given range [first, last)
|
|
ferencd@0
|
764 * such that each possible permutation of those elements
|
|
ferencd@0
|
765 * has equal probability of appearance.
|
|
ferencd@0
|
766 * \param first, last - the range of elements to shuffle randomly
|
|
ferencd@0
|
767 */
|
|
ferencd@0
|
768 template<typename RandomIt>
|
|
ferencd@0
|
769 static void shuffle( RandomIt first, RandomIt last ) {
|
|
ferencd@0
|
770 std::shuffle( first, last, engine );
|
|
ferencd@0
|
771 }
|
|
ferencd@0
|
772
|
|
ferencd@0
|
773 /**
|
|
ferencd@0
|
774 * \brief Reorders the elements in the given container
|
|
ferencd@0
|
775 * such that each possible permutation of those elements
|
|
ferencd@0
|
776 * has equal probability of appearance.
|
|
ferencd@0
|
777 * \param container - the container with elements to shuffle randomly
|
|
ferencd@0
|
778 */
|
|
ferencd@0
|
779 template<typename Container>
|
|
ferencd@0
|
780 static void shuffle( Container& container ) {
|
|
ferencd@0
|
781 shuffle( std::begin( container ), std::end( container ) );
|
|
ferencd@0
|
782 }
|
|
ferencd@0
|
783
|
|
ferencd@0
|
784 /// return internal engine by copy
|
|
ferencd@0
|
785 static Engine get_engine( ) {
|
|
ferencd@0
|
786 return engine;
|
|
ferencd@0
|
787 }
|
|
ferencd@0
|
788 protected:
|
|
ferencd@0
|
789 /// return engine seeded by Seeder
|
|
ferencd@0
|
790 static Engine make_seeded_engine( ) {
|
|
ferencd@0
|
791 // Make seeder instance for seed return by reference like std::seed_seq
|
|
ferencd@0
|
792 Seeder seeder;
|
|
ferencd@0
|
793 return Engine{ seeder( ) };
|
|
ferencd@0
|
794 }
|
|
ferencd@0
|
795 protected:
|
|
ferencd@0
|
796 /// The random number engine
|
|
ferencd@0
|
797 static thread_local Engine engine;
|
|
ferencd@0
|
798 };
|
|
ferencd@0
|
799
|
|
ferencd@0
|
800 /// Seed random number engine by Seeder
|
|
ferencd@0
|
801 template<
|
|
ferencd@0
|
802 typename Engine,
|
|
ferencd@0
|
803 typename Seeder,
|
|
ferencd@0
|
804 template<typename> class IntegerDist,
|
|
ferencd@0
|
805 template<typename> class RealDist,
|
|
ferencd@0
|
806 typename BoolDist
|
|
ferencd@0
|
807 >
|
|
ferencd@0
|
808 thread_local Engine basic_random_thread_local<Engine, Seeder, IntegerDist, RealDist, BoolDist
|
|
ferencd@0
|
809 // VS2017 issue, can't init by Seeder from lambda
|
|
ferencd@0
|
810 >::engine( make_seeded_engine( ) );
|
|
ferencd@0
|
811
|
|
ferencd@0
|
812 /**
|
|
ferencd@0
|
813 * \brief Base template class for random
|
|
ferencd@0
|
814 * with local API and local internal member storage
|
|
ferencd@0
|
815 * \note it IS thread safe but less efficient then
|
|
ferencd@0
|
816 * basic_random_static
|
|
ferencd@0
|
817 * \param Engine A random engine with interface like in the std::mt19937
|
|
ferencd@0
|
818 * \param Seeder A seeder type which return seed for internal engine
|
|
ferencd@0
|
819 * through operator()
|
|
ferencd@0
|
820 */
|
|
ferencd@0
|
821 template<
|
|
ferencd@0
|
822 typename Engine,
|
|
ferencd@0
|
823 typename Seeder = seeder_default,
|
|
ferencd@0
|
824 template<typename> class IntegerDist = std::uniform_int_distribution,
|
|
ferencd@0
|
825 template<typename> class RealDist = std::uniform_real_distribution,
|
|
ferencd@0
|
826 typename BoolDist = std::bernoulli_distribution
|
|
ferencd@0
|
827 >
|
|
ferencd@0
|
828 class basic_random_local {
|
|
ferencd@0
|
829 public:
|
|
ferencd@0
|
830 /// Type of used random number engine
|
|
ferencd@0
|
831 using engine_type = Engine;
|
|
ferencd@0
|
832
|
|
ferencd@0
|
833 /// Type of used random number seeder
|
|
ferencd@0
|
834 using seeder_type = Seeder;
|
|
ferencd@0
|
835
|
|
ferencd@0
|
836 /// Type of used integer distribution
|
|
ferencd@0
|
837 template<typename T>
|
|
ferencd@0
|
838 using integer_dist_t = IntegerDist<T>;
|
|
ferencd@0
|
839
|
|
ferencd@0
|
840 /// Type of used real distribution
|
|
ferencd@0
|
841 template<typename T>
|
|
ferencd@0
|
842 using real_dist_t = RealDist<T>;
|
|
ferencd@0
|
843
|
|
ferencd@0
|
844 /// Type of used bool distribution
|
|
ferencd@0
|
845 using bool_dist_t = BoolDist;
|
|
ferencd@0
|
846
|
|
ferencd@0
|
847 /// Key type for getting common type numbers or objects
|
|
ferencd@0
|
848 using common = details::common;
|
|
ferencd@0
|
849
|
|
ferencd@0
|
850 /**
|
|
ferencd@0
|
851 * \return The minimum value
|
|
ferencd@0
|
852 * potentially generated by the random-number engine
|
|
ferencd@0
|
853 */
|
|
ferencd@0
|
854 static constexpr typename Engine::result_type min( ) {
|
|
ferencd@0
|
855 return Engine::min( );
|
|
ferencd@0
|
856 }
|
|
ferencd@0
|
857
|
|
ferencd@0
|
858 /**
|
|
ferencd@0
|
859 * \return The maximum value
|
|
ferencd@0
|
860 * potentially generated by the random-number engine
|
|
ferencd@0
|
861 */
|
|
ferencd@0
|
862 static constexpr typename Engine::result_type max( ) {
|
|
ferencd@0
|
863 return Engine::max( );
|
|
ferencd@0
|
864 }
|
|
ferencd@0
|
865
|
|
ferencd@0
|
866 /// Advances the internal state by z times
|
|
ferencd@0
|
867 void discard( const unsigned long long z ) {
|
|
ferencd@0
|
868 engine.discard( z );
|
|
ferencd@0
|
869 }
|
|
ferencd@0
|
870
|
|
ferencd@0
|
871 /// Reseed by Seeder
|
|
ferencd@0
|
872 void reseed( ) {
|
|
ferencd@0
|
873 Seeder seeder;
|
|
ferencd@0
|
874 seed( seeder( ) );
|
|
ferencd@0
|
875 }
|
|
ferencd@0
|
876
|
|
ferencd@0
|
877 /**
|
|
ferencd@0
|
878 * \brief Reinitializes the internal state
|
|
ferencd@0
|
879 * of the random-number engine using new seed value
|
|
ferencd@0
|
880 * \param value The seed value to use
|
|
ferencd@0
|
881 * in the initialization of the internal state
|
|
ferencd@0
|
882 */
|
|
ferencd@0
|
883 void seed( const typename Engine::result_type value =
|
|
ferencd@0
|
884 Engine::default_seed ) {
|
|
ferencd@0
|
885 engine.seed( value );
|
|
ferencd@0
|
886 }
|
|
ferencd@0
|
887
|
|
ferencd@0
|
888 /**
|
|
ferencd@0
|
889 * \brief Reinitializes the internal state
|
|
ferencd@0
|
890 * of the random-number engine using new seed value
|
|
ferencd@0
|
891 * \param seq The seed sequence
|
|
ferencd@0
|
892 * to use in the initialization of the internal state
|
|
ferencd@0
|
893 */
|
|
ferencd@0
|
894 template<typename Sseq>
|
|
ferencd@0
|
895 void seed( Sseq& seq ) {
|
|
ferencd@0
|
896 engine.seed( seq );
|
|
ferencd@0
|
897 }
|
|
ferencd@0
|
898
|
|
ferencd@0
|
899 /// return random number from engine in [min(), max()] range
|
|
ferencd@0
|
900 typename Engine::result_type get( ) {
|
|
ferencd@0
|
901 return engine( );
|
|
ferencd@0
|
902 }
|
|
ferencd@0
|
903
|
|
ferencd@0
|
904 /**
|
|
ferencd@0
|
905 * \brief Compares internal pseudo-random number engine
|
|
ferencd@0
|
906 * with 'other' pseudo-random number engine.
|
|
ferencd@0
|
907 * Two engines are equal, if their internal states
|
|
ferencd@0
|
908 * are equivalent, that is, if they would generate
|
|
ferencd@0
|
909 * equivalent values for any number of calls of operator()
|
|
ferencd@0
|
910 * \param other The engine, with which the internal engine will be compared
|
|
ferencd@0
|
911 * \return true, if other and internal engine are equal
|
|
ferencd@0
|
912 */
|
|
ferencd@0
|
913 bool is_equal( const Engine& other ) {
|
|
ferencd@0
|
914 return engine == other;
|
|
ferencd@0
|
915 }
|
|
ferencd@0
|
916
|
|
ferencd@0
|
917 /**
|
|
ferencd@0
|
918 * \brief Serializes the internal state of the
|
|
ferencd@0
|
919 * internal pseudo-random number engine as a sequence
|
|
ferencd@0
|
920 * of decimal numbers separated by one or more spaces,
|
|
ferencd@0
|
921 * and inserts it to the stream ost. The fill character
|
|
ferencd@0
|
922 * and the formatting flags of the stream are
|
|
ferencd@0
|
923 * ignored and unaffected.
|
|
ferencd@0
|
924 * \param ost The output stream to insert the data to
|
|
ferencd@0
|
925 */
|
|
ferencd@0
|
926 template<typename CharT, typename Traits>
|
|
ferencd@0
|
927 void serialize( std::basic_ostream<CharT, Traits>& ost ) {
|
|
ferencd@0
|
928 ost << engine;
|
|
ferencd@0
|
929 }
|
|
ferencd@0
|
930
|
|
ferencd@0
|
931 /**
|
|
ferencd@0
|
932 * \brief Restores the internal state of the
|
|
ferencd@0
|
933 * internal pseudo-random number engine from
|
|
ferencd@0
|
934 * the serialized representation, which
|
|
ferencd@0
|
935 * was created by an earlier call to 'serialize'
|
|
ferencd@0
|
936 * using a stream with the same imbued locale and
|
|
ferencd@0
|
937 * the same CharT and Traits.
|
|
ferencd@0
|
938 * If the input cannot be deserialized,
|
|
ferencd@0
|
939 * internal engine is left unchanged and failbit is raised on ist
|
|
ferencd@0
|
940 * \param ost The input stream to extract the data from
|
|
ferencd@0
|
941 */
|
|
ferencd@0
|
942 template<typename CharT, typename Traits>
|
|
ferencd@0
|
943 void deserialize( std::basic_istream<CharT, Traits>& ist ) {
|
|
ferencd@0
|
944 ist >> engine;
|
|
ferencd@0
|
945 }
|
|
ferencd@0
|
946
|
|
ferencd@0
|
947 /**
|
|
ferencd@0
|
948 * \brief Generate a random integer number in a [from; to] range
|
|
ferencd@0
|
949 * by std::uniform_int_distribution
|
|
ferencd@0
|
950 * \param from The first limit number of a random range
|
|
ferencd@0
|
951 * \param to The second limit number of a random range
|
|
ferencd@0
|
952 * \return A random integer number in a [from; to] range
|
|
ferencd@0
|
953 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
954 * \note Prevent implicit type conversion
|
|
ferencd@0
|
955 */
|
|
ferencd@0
|
956 template<typename T>
|
|
ferencd@0
|
957 typename std::enable_if<details::is_uniform_int<T>::value
|
|
ferencd@0
|
958 , T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
ferencd@0
|
959 T to = std::numeric_limits<T>::max( ) ) {
|
|
ferencd@0
|
960 if( from < to ) // Allow range from higher to lower
|
|
ferencd@0
|
961 return IntegerDist<T>{ from, to }( engine );
|
|
ferencd@0
|
962 return IntegerDist<T>{ to, from }( engine );
|
|
ferencd@0
|
963 }
|
|
ferencd@0
|
964
|
|
ferencd@0
|
965 /**
|
|
ferencd@0
|
966 * \brief Generate a random real number in a [from; to] range
|
|
ferencd@0
|
967 * by std::uniform_real_distribution
|
|
ferencd@0
|
968 * \param from The first limit number of a random range
|
|
ferencd@0
|
969 * \param to The second limit number of a random range
|
|
ferencd@0
|
970 * \return A random real number in a [from; to] range
|
|
ferencd@0
|
971 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
972 * \note Prevent implicit type conversion
|
|
ferencd@0
|
973 */
|
|
ferencd@0
|
974 template<typename T>
|
|
ferencd@0
|
975 typename std::enable_if<details::is_uniform_real<T>::value
|
|
ferencd@0
|
976 , T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
ferencd@0
|
977 T to = std::numeric_limits<T>::max( ) ) {
|
|
ferencd@0
|
978 if( from < to ) // Allow range from higher to lower
|
|
ferencd@0
|
979 return RealDist<T>{ from, to }( engine );
|
|
ferencd@0
|
980 return RealDist<T>{ to, from }( engine );
|
|
ferencd@0
|
981 }
|
|
ferencd@0
|
982
|
|
ferencd@0
|
983 /**
|
|
ferencd@0
|
984 * \brief Generate a random byte number in a [from; to] range
|
|
ferencd@0
|
985 * \param from The first limit number of a random range
|
|
ferencd@0
|
986 * \param to The second limit number of a random range
|
|
ferencd@0
|
987 * \return A random byte number in a [from; to] range
|
|
ferencd@0
|
988 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
989 * \note Prevent implicit type conversion
|
|
ferencd@0
|
990 */
|
|
ferencd@0
|
991 template<typename T>
|
|
ferencd@0
|
992 typename std::enable_if<details::is_byte<T>::value
|
|
ferencd@0
|
993 , T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
ferencd@0
|
994 T to = std::numeric_limits<T>::max( ) ) {
|
|
ferencd@0
|
995 // Choose between short and unsigned short for byte conversion
|
|
ferencd@0
|
996 using short_t = typename std::conditional<std::is_signed<T>::value,
|
|
ferencd@0
|
997 short, unsigned short>::type;
|
|
ferencd@0
|
998
|
|
ferencd@0
|
999 return static_cast<T>( get<short_t>( from, to ) );
|
|
ferencd@0
|
1000 }
|
|
ferencd@0
|
1001
|
|
ferencd@0
|
1002 /**
|
|
ferencd@0
|
1003 * \brief Generate a random common_type number in a [from; to] range
|
|
ferencd@0
|
1004 * \param Key The Key type for this version of 'get' method
|
|
ferencd@0
|
1005 * Type should be '(THIS_TYPE)::common' struct
|
|
ferencd@0
|
1006 * \param from The first limit number of a random range
|
|
ferencd@0
|
1007 * \param to The second limit number of a random range
|
|
ferencd@0
|
1008 * \return A random common_type number in a [from; to] range
|
|
ferencd@0
|
1009 * \note Allow both: 'from' <= 'to' and 'from' >= 'to'
|
|
ferencd@0
|
1010 * \note Allow implicit type conversion
|
|
ferencd@0
|
1011 * \note Prevent implicit type conversion from singed to unsigned types
|
|
ferencd@0
|
1012 * Why? std::common_type<Unsigned, Signed> chooses unsigned value,
|
|
ferencd@0
|
1013 * then Signed value will be converted to Unsigned value
|
|
ferencd@0
|
1014 * which gives us a wrong range for random values.
|
|
ferencd@0
|
1015 * https://stackoverflow.com/a/5416498/5734836
|
|
ferencd@0
|
1016 */
|
|
ferencd@0
|
1017 template<
|
|
ferencd@0
|
1018 typename Key,
|
|
ferencd@0
|
1019 typename A,
|
|
ferencd@0
|
1020 typename B,
|
|
ferencd@0
|
1021 typename C = typename std::common_type<A, B>::type
|
|
ferencd@0
|
1022 >
|
|
ferencd@0
|
1023 typename std::enable_if<
|
|
ferencd@0
|
1024 std::is_same<Key, common>::value
|
|
ferencd@0
|
1025 && details::is_supported_number<A>::value
|
|
ferencd@0
|
1026 && details::is_supported_number<B>::value
|
|
ferencd@0
|
1027 // Prevent implicit type conversion from singed to unsigned types
|
|
ferencd@0
|
1028 && std::is_signed<A>::value != std::is_unsigned<B>::value
|
|
ferencd@0
|
1029 , C>::type get( A from = std::numeric_limits<A>::min( ),
|
|
ferencd@0
|
1030 B to = std::numeric_limits<B>::max( ) ) {
|
|
ferencd@0
|
1031 return get( static_cast<C>( from ), static_cast<C>( to ) );
|
|
ferencd@0
|
1032 }
|
|
ferencd@0
|
1033
|
|
ferencd@0
|
1034 /**
|
|
ferencd@0
|
1035 * \brief Generate a bool value with specific probability
|
|
ferencd@0
|
1036 * by std::bernoulli_distribution
|
|
ferencd@0
|
1037 * \param probability The probability of generating true in [0; 1] range
|
|
ferencd@0
|
1038 * 0 means always false, 1 means always true
|
|
ferencd@0
|
1039 * \return 'true' with 'probability' probability ('false' otherwise)
|
|
ferencd@0
|
1040 */
|
|
ferencd@0
|
1041 template<typename T>
|
|
ferencd@0
|
1042 typename std::enable_if<std::is_same<T, bool>::value
|
|
ferencd@0
|
1043 , bool>::type get( const double probability = 0.5 ) {
|
|
ferencd@0
|
1044 assert( 0 <= probability && 1 >= probability ); // out of [0; 1] range
|
|
ferencd@0
|
1045 return BoolDist{ probability }( engine );
|
|
ferencd@0
|
1046 }
|
|
ferencd@0
|
1047
|
|
ferencd@0
|
1048 /**
|
|
ferencd@0
|
1049 * \brief Return random value from initilizer_list
|
|
ferencd@0
|
1050 * \param init_list initilizer_list with values
|
|
ferencd@0
|
1051 * \return Random value from initilizer_list
|
|
ferencd@0
|
1052 * \note Should be 1 or more elements in initilizer_list
|
|
ferencd@0
|
1053 * \note Warning! Elements in initilizer_list can't be moved:
|
|
ferencd@0
|
1054 * https://stackoverflow.com/a/8193157/5734836
|
|
ferencd@0
|
1055 */
|
|
ferencd@0
|
1056 template<typename T>
|
|
ferencd@0
|
1057 T get( std::initializer_list<T> init_list ) {
|
|
ferencd@0
|
1058 assert( 0u != init_list.size( ) );
|
|
ferencd@0
|
1059 return *get( init_list.begin( ), init_list.end( ) );
|
|
ferencd@0
|
1060 }
|
|
ferencd@0
|
1061
|
|
ferencd@0
|
1062 /**
|
|
ferencd@0
|
1063 * \brief Return random iterator from iterator range
|
|
ferencd@0
|
1064 * \param first, last - the range of elements
|
|
ferencd@0
|
1065 * \return Random iterator from [first, last) range
|
|
ferencd@0
|
1066 * \note If first == last, return last
|
|
ferencd@0
|
1067 */
|
|
ferencd@0
|
1068 template<typename InputIt>
|
|
ferencd@0
|
1069 typename std::enable_if<details::is_iterator<InputIt>::value
|
|
ferencd@0
|
1070 , InputIt>::type get( InputIt first, InputIt last ) {
|
|
ferencd@0
|
1071 const auto size = std::distance( first, last );
|
|
ferencd@0
|
1072 if( 0u == size ) return last;
|
|
ferencd@0
|
1073 using diff_t = typename std::iterator_traits<InputIt>::difference_type;
|
|
ferencd@0
|
1074 return std::next( first, get<diff_t>( 0, size - 1 ) );
|
|
ferencd@0
|
1075 }
|
|
ferencd@0
|
1076
|
|
ferencd@0
|
1077 /**
|
|
ferencd@0
|
1078 * \brief Return random iterator from Container
|
|
ferencd@0
|
1079 * \param container The container with elements
|
|
ferencd@0
|
1080 * \return Random iterator from container
|
|
ferencd@0
|
1081 * \note If container is empty return std::end( container ) iterator
|
|
ferencd@0
|
1082 */
|
|
ferencd@0
|
1083 template<typename Container>
|
|
ferencd@0
|
1084 typename std::enable_if<details::is_iterator<
|
|
ferencd@0
|
1085 decltype( std::begin( std::declval<Container>( ) ) )>::value
|
|
ferencd@0
|
1086 , decltype( std::begin( std::declval<Container>( ) ) )
|
|
ferencd@0
|
1087 >::type get( Container& container ) {
|
|
ferencd@0
|
1088 return get( std::begin( container ), std::end( container ) );
|
|
ferencd@0
|
1089 }
|
|
ferencd@0
|
1090
|
|
ferencd@0
|
1091 /**
|
|
ferencd@0
|
1092 * \brief Return value from custom Dist distribution
|
|
ferencd@0
|
1093 * seeded by internal random engine
|
|
ferencd@0
|
1094 * \param Dist The type of custom distribution with next concept:
|
|
ferencd@0
|
1095 * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution
|
|
ferencd@0
|
1096 * \param args The arguments which will be forwarded to Dist constructor
|
|
ferencd@0
|
1097 * \return Value from custom distribution
|
|
ferencd@0
|
1098 */
|
|
ferencd@0
|
1099 template<typename Dist, typename... Args>
|
|
ferencd@0
|
1100 typename Dist::result_type get( Args&&... args ) {
|
|
ferencd@0
|
1101 return Dist{ std::forward<Args>( args )... }( engine );
|
|
ferencd@0
|
1102 }
|
|
ferencd@0
|
1103
|
|
ferencd@0
|
1104 /**
|
|
ferencd@0
|
1105 * \brief Return value from custom 'dist' distribution
|
|
ferencd@0
|
1106 * seeded by internal random engine
|
|
ferencd@0
|
1107 * \param dist The custom distribution with next concept:
|
|
ferencd@0
|
1108 * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution
|
|
ferencd@0
|
1109 * \param args The arguments which will be forwarded to Dist constructor
|
|
ferencd@0
|
1110 * \return Value from custom 'dist' distribution
|
|
ferencd@0
|
1111 */
|
|
ferencd@0
|
1112 template<typename Dist>
|
|
ferencd@0
|
1113 typename Dist::result_type get( Dist& dist ) {
|
|
ferencd@0
|
1114 return dist( engine );
|
|
ferencd@0
|
1115 }
|
|
ferencd@0
|
1116
|
|
ferencd@0
|
1117 /**
|
|
ferencd@0
|
1118 * \brief Reorders the elements in the given range [first, last)
|
|
ferencd@0
|
1119 * such that each possible permutation of those elements
|
|
ferencd@0
|
1120 * has equal probability of appearance.
|
|
ferencd@0
|
1121 * \param first, last - the range of elements to shuffle randomly
|
|
ferencd@0
|
1122 */
|
|
ferencd@0
|
1123 template<typename RandomIt>
|
|
ferencd@0
|
1124 void shuffle( RandomIt first, RandomIt last ) {
|
|
ferencd@0
|
1125 std::shuffle( first, last, engine );
|
|
ferencd@0
|
1126 }
|
|
ferencd@0
|
1127
|
|
ferencd@0
|
1128 /**
|
|
ferencd@0
|
1129 * \brief Reorders the elements in the given container
|
|
ferencd@0
|
1130 * such that each possible permutation of those elements
|
|
ferencd@0
|
1131 * has equal probability of appearance.
|
|
ferencd@0
|
1132 * \param container - the container with elements to shuffle randomly
|
|
ferencd@0
|
1133 */
|
|
ferencd@0
|
1134 template<typename Container>
|
|
ferencd@0
|
1135 void shuffle( Container& container ) {
|
|
ferencd@0
|
1136 shuffle( std::begin( container ), std::end( container ) );
|
|
ferencd@0
|
1137 }
|
|
ferencd@0
|
1138
|
|
ferencd@0
|
1139 /// return internal engine by copy
|
|
ferencd@0
|
1140 Engine get_engine( ) const {
|
|
ferencd@0
|
1141 return engine;
|
|
ferencd@0
|
1142 }
|
|
ferencd@0
|
1143 protected:
|
|
ferencd@0
|
1144 /// return engine seeded by Seeder
|
|
ferencd@0
|
1145 static Engine make_seeded_engine( ) {
|
|
ferencd@0
|
1146 // Make seeder instance for seed return by reference like std::seed_seq
|
|
ferencd@0
|
1147 Seeder seeder;
|
|
ferencd@0
|
1148 return Engine{ seeder( ) };
|
|
ferencd@0
|
1149 }
|
|
ferencd@0
|
1150 protected:
|
|
ferencd@0
|
1151 /// The random number engine
|
|
ferencd@0
|
1152 Engine engine{ make_seeded_engine( ) };
|
|
ferencd@0
|
1153 };
|
|
ferencd@0
|
1154
|
|
ferencd@0
|
1155 /**
|
|
ferencd@0
|
1156 * \brief The basic static random alias based on a std::mt19937
|
|
ferencd@0
|
1157 * \note It uses static methods API and data with static storage
|
|
ferencd@0
|
1158 * \note Not thread safe but more prefomance
|
|
ferencd@0
|
1159 */
|
|
ferencd@0
|
1160 using random_static = basic_random_static<std::mt19937>;
|
|
ferencd@0
|
1161
|
|
ferencd@0
|
1162 /**
|
|
ferencd@0
|
1163 * \brief The basic static random alias based on a std::mt19937
|
|
ferencd@0
|
1164 * \note It uses static methods API and data with thread_local storage
|
|
ferencd@0
|
1165 * \note Thread safe but less perfomance
|
|
ferencd@0
|
1166 */
|
|
ferencd@0
|
1167 using random_thread_local = basic_random_thread_local<std::mt19937>;
|
|
ferencd@0
|
1168
|
|
ferencd@0
|
1169 /**
|
|
ferencd@0
|
1170 * \brief The basic static random alias based on a std::mt19937
|
|
ferencd@0
|
1171 * \note It uses non static methods API and data with auto storage
|
|
ferencd@0
|
1172 * \note Not thread safe. Should construct on the stack at local scope
|
|
ferencd@0
|
1173 */
|
|
ferencd@0
|
1174 using random_local = basic_random_local<std::mt19937>;
|
|
ferencd@0
|
1175
|
|
ferencd@0
|
1176 } // namespace effolkronium
|
|
ferencd@0
|
1177
|
|
ferencd@0
|
1178 #endif // #ifndef EFFOLKRONIUM_RANDOM_HPP
|