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