annotate 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
rev   line source
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