ferencd@0: #ifndef EFFOLKRONIUM_RANDOM_HPP ferencd@0: #define EFFOLKRONIUM_RANDOM_HPP ferencd@0: ferencd@0: #include ferencd@0: #include // timed seed ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: #include // std::forward, std::declval ferencd@0: #include // std::shuffle, std::next, std::distance ferencd@0: #include // std::begin, std::end, std::iterator_traits ferencd@0: #include // std::numeric_limits ferencd@0: #include ferencd@0: #include ferencd@0: ferencd@0: namespace effolkronium { ferencd@0: ferencd@0: namespace details { ferencd@0: /// Key type for getting common type numbers or objects ferencd@0: struct common{ }; ferencd@0: ferencd@0: /// True if type T is applicable by a std::uniform_int_distribution ferencd@0: template ferencd@0: struct is_uniform_int { ferencd@0: static constexpr bool value = ferencd@0: std::is_same::value ferencd@0: || std::is_same::value ferencd@0: || std::is_same::value ferencd@0: || std::is_same::value ferencd@0: || std::is_same::value ferencd@0: || std::is_same::value ferencd@0: || std::is_same::value ferencd@0: || std::is_same::value; ferencd@0: }; ferencd@0: ferencd@0: /// True if type T is applicable by a std::uniform_real_distribution ferencd@0: template ferencd@0: struct is_uniform_real { ferencd@0: static constexpr bool value = ferencd@0: std::is_same::value ferencd@0: || std::is_same::value ferencd@0: || std::is_same::value; ferencd@0: }; ferencd@0: ferencd@0: /// True if type T is plain byte ferencd@0: template ferencd@0: struct is_byte { ferencd@0: static constexpr bool value = ferencd@0: std::is_same::value ferencd@0: || std::is_same::value; ferencd@0: }; ferencd@0: ferencd@0: /// True if type T is plain number type ferencd@0: template ferencd@0: struct is_supported_number { ferencd@0: static constexpr bool value = ferencd@0: is_byte ::value ferencd@0: || is_uniform_real::value ferencd@0: || is_uniform_int ::value; ferencd@0: }; ferencd@0: ferencd@0: /// True if type T is iterator ferencd@0: template ferencd@0: struct is_iterator { ferencd@0: private: ferencd@0: static char test( ... ); ferencd@0: ferencd@0: template ::difference_type, ferencd@0: typename = typename std::iterator_traits::pointer, ferencd@0: typename = typename std::iterator_traits::reference, ferencd@0: typename = typename std::iterator_traits::value_type, ferencd@0: typename = typename std::iterator_traits::iterator_category ferencd@0: > static long test( U&& ); ferencd@0: public: ferencd@0: static constexpr bool value = std::is_same< ferencd@0: decltype( test( std::declval( ) ) ), long>::value; ferencd@0: }; ferencd@0: ferencd@0: } // namespace details ferencd@0: ferencd@0: /// Default seeder for 'random' classes ferencd@0: struct seeder_default { ferencd@0: /// return seed sequence ferencd@0: std::seed_seq& operator() ( ) { ferencd@0: // MinGW issue, std::random_device returns constant value ferencd@0: // Use std::seed_seq with additional seed from C++ chrono ferencd@0: return seed_seq; ferencd@0: } ferencd@0: private: ferencd@0: std::seed_seq seed_seq{ { ferencd@0: static_cast( std::random_device{ }( ) ), ferencd@0: static_cast( std::chrono::steady_clock::now( ) ferencd@0: .time_since_epoch( ).count( ) ), ferencd@0: } }; ferencd@0: }; ferencd@0: ferencd@0: /** ferencd@0: * \brief Base template class for random ferencd@0: * with static API and static internal member storage ferencd@0: * \note it is NOT thread safe but more efficient then ferencd@0: * basic_random_thread_local ferencd@0: * \param Engine A random engine with interface like in the std::mt19937 ferencd@0: * \param Seeder A seeder type which return seed for internal engine ferencd@0: * through operator() ferencd@0: */ ferencd@0: template< ferencd@0: typename Engine, ferencd@0: typename Seeder = seeder_default, ferencd@0: template class IntegerDist = std::uniform_int_distribution, ferencd@0: template class RealDist = std::uniform_real_distribution, ferencd@0: typename BoolDist = std::bernoulli_distribution ferencd@0: > ferencd@0: class basic_random_static { ferencd@0: public: ferencd@0: basic_random_static( ) = delete; ferencd@0: ferencd@0: /// Type of used random number engine ferencd@0: using engine_type = Engine; ferencd@0: ferencd@0: /// Type of used random number seeder ferencd@0: using seeder_type = Seeder; ferencd@0: ferencd@0: /// Type of used integer distribution ferencd@0: template ferencd@0: using integer_dist_t = IntegerDist; ferencd@0: ferencd@0: /// Type of used real distribution ferencd@0: template ferencd@0: using real_dist_t = RealDist; ferencd@0: ferencd@0: /// Type of used bool distribution ferencd@0: using bool_dist_t = BoolDist; ferencd@0: ferencd@0: /// Key type for getting common type numbers or objects ferencd@0: using common = details::common; ferencd@0: ferencd@0: /** ferencd@0: * \return The minimum value ferencd@0: * potentially generated by the random-number engine ferencd@0: */ ferencd@0: static constexpr typename Engine::result_type min( ) { ferencd@0: return Engine::min( ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \return The maximum value ferencd@0: * potentially generated by the random-number engine ferencd@0: */ ferencd@0: static constexpr typename Engine::result_type max( ) { ferencd@0: return Engine::max( ); ferencd@0: } ferencd@0: ferencd@0: /// Advances the internal state by z times ferencd@0: static void discard( const unsigned long long z ) { ferencd@0: engine.discard( z ); ferencd@0: } ferencd@0: ferencd@0: /// Reseed by Seeder ferencd@0: static void reseed( ) { ferencd@0: Seeder seeder; ferencd@0: seed( seeder( ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reinitializes the internal state ferencd@0: * of the random-number engine using new seed value ferencd@0: * \param value The seed value to use ferencd@0: * in the initialization of the internal state ferencd@0: */ ferencd@0: static void seed( const typename Engine::result_type value = ferencd@0: Engine::default_seed ) { ferencd@0: engine.seed( value ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reinitializes the internal state ferencd@0: * of the random-number engine using new seed value ferencd@0: * \param seq The seed sequence ferencd@0: * to use in the initialization of the internal state ferencd@0: */ ferencd@0: template ferencd@0: static void seed( Sseq& seq ) { ferencd@0: engine.seed( seq ); ferencd@0: } ferencd@0: ferencd@0: /// return random number from engine in [min(), max()] range ferencd@0: static typename Engine::result_type get( ) { ferencd@0: return engine( ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Compares internal pseudo-random number engine ferencd@0: * with 'other' pseudo-random number engine. ferencd@0: * Two engines are equal, if their internal states ferencd@0: * are equivalent, that is, if they would generate ferencd@0: * equivalent values for any number of calls of operator() ferencd@0: * \param other The engine, with which the internal engine will be compared ferencd@0: * \return true, if other and internal engine are equal ferencd@0: */ ferencd@0: static bool is_equal( const Engine& other ) { ferencd@0: return engine == other; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Serializes the internal state of the ferencd@0: * internal pseudo-random number engine as a sequence ferencd@0: * of decimal numbers separated by one or more spaces, ferencd@0: * and inserts it to the stream ost. The fill character ferencd@0: * and the formatting flags of the stream are ferencd@0: * ignored and unaffected. ferencd@0: * \param ost The output stream to insert the data to ferencd@0: */ ferencd@0: template ferencd@0: static void serialize( std::basic_ostream& ost ) { ferencd@0: ost << engine; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Restores the internal state of the ferencd@0: * internal pseudo-random number engine from ferencd@0: * the serialized representation, which ferencd@0: * was created by an earlier call to 'serialize' ferencd@0: * using a stream with the same imbued locale and ferencd@0: * the same CharT and Traits. ferencd@0: * If the input cannot be deserialized, ferencd@0: * internal engine is left unchanged and failbit is raised on ist ferencd@0: * \param ost The input stream to extract the data from ferencd@0: */ ferencd@0: template ferencd@0: static void deserialize( std::basic_istream& ist ) { ferencd@0: ist >> engine; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random integer number in a [from; to] range ferencd@0: * by std::uniform_int_distribution ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random integer number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Prevent implicit type conversion ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , T>::type get( T from = std::numeric_limits::min( ), ferencd@0: T to = std::numeric_limits::max( ) ) { ferencd@0: if( from < to ) // Allow range from higher to lower ferencd@0: return IntegerDist{ from, to }( engine ); ferencd@0: return IntegerDist{ to, from }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random real number in a [from; to] range ferencd@0: * by std::uniform_real_distribution ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random real number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Prevent implicit type conversion ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , T>::type get( T from = std::numeric_limits::min( ), ferencd@0: T to = std::numeric_limits::max( ) ) { ferencd@0: if( from < to ) // Allow range from higher to lower ferencd@0: return RealDist{ from, to }( engine ); ferencd@0: return RealDist{ to, from }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random byte number in a [from; to] range ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random byte number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Prevent implicit type conversion ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , T>::type get( T from = std::numeric_limits::min( ), ferencd@0: T to = std::numeric_limits::max( ) ) { ferencd@0: // Choose between short and unsigned short for byte conversion ferencd@0: using short_t = typename std::conditional::value, ferencd@0: short, unsigned short>::type; ferencd@0: ferencd@0: return static_cast( get( from, to ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random common_type number in a [from; to] range ferencd@0: * \param Key The Key type for this version of 'get' method ferencd@0: * Type should be '(THIS_TYPE)::common' struct ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random common_type number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Allow implicit type conversion ferencd@0: * \note Prevent implicit type conversion from singed to unsigned types ferencd@0: * Why? std::common_type chooses unsigned value, ferencd@0: * then Signed value will be converted to Unsigned value ferencd@0: * which gives us a wrong range for random values. ferencd@0: * https://stackoverflow.com/a/5416498/5734836 ferencd@0: */ ferencd@0: template< ferencd@0: typename Key, ferencd@0: typename A, ferencd@0: typename B, ferencd@0: typename C = typename std::common_type::type ferencd@0: > ferencd@0: static typename std::enable_if< ferencd@0: std::is_same::value ferencd@0: && details::is_supported_number::value ferencd@0: && details::is_supported_number::value ferencd@0: // Prevent implicit type conversion from singed to unsigned types ferencd@0: && std::is_signed::value != std::is_unsigned::value ferencd@0: , C>::type get( A from = std::numeric_limits::min( ), ferencd@0: B to = std::numeric_limits::max( ) ) { ferencd@0: return get( static_cast( from ), static_cast( to ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a bool value with specific probability ferencd@0: * by std::bernoulli_distribution ferencd@0: * \param probability The probability of generating true in [0; 1] range ferencd@0: * 0 means always false, 1 means always true ferencd@0: * \return 'true' with 'probability' probability ('false' otherwise) ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , bool>::type get( const double probability = 0.5 ) { ferencd@0: assert( 0 <= probability && 1 >= probability ); // out of [0; 1] range ferencd@0: return BoolDist{ probability }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return random value from initilizer_list ferencd@0: * \param init_list initilizer_list with values ferencd@0: * \return Random value from initilizer_list ferencd@0: * \note Should be 1 or more elements in initilizer_list ferencd@0: * \note Warning! Elements in initilizer_list can't be moved: ferencd@0: * https://stackoverflow.com/a/8193157/5734836 ferencd@0: */ ferencd@0: template ferencd@0: static T get( std::initializer_list init_list ) { ferencd@0: assert( 0u != init_list.size( ) ); ferencd@0: return *get( init_list.begin( ), init_list.end( ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return random iterator from iterator range ferencd@0: * \param first, last - the range of elements ferencd@0: * \return Random iterator from [first, last) range ferencd@0: * \note If first == last, return last ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , InputIt>::type get( InputIt first, InputIt last ) { ferencd@0: const auto size = std::distance( first, last ); ferencd@0: if( 0u == size ) return last; ferencd@0: using diff_t = typename std::iterator_traits::difference_type; ferencd@0: return std::next( first, get( 0, size - 1 ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return random iterator from Container ferencd@0: * \param container The container with elements ferencd@0: * \return Random iterator from container ferencd@0: * \note If container is empty return std::end( container ) iterator ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if( ) ) )>::value ferencd@0: , decltype( std::begin( std::declval( ) ) ) ferencd@0: >::type get( Container& container ) { ferencd@0: return get( std::begin( container ), std::end( container ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return value from custom Dist distribution ferencd@0: * seeded by internal random engine ferencd@0: * \param Dist The type of custom distribution with next concept: ferencd@0: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution ferencd@0: * \param args The arguments which will be forwarded to Dist constructor ferencd@0: * \return Value from custom distribution ferencd@0: */ ferencd@0: template ferencd@0: static typename Dist::result_type get( Args&&... args ) { ferencd@0: return Dist{ std::forward( args )... }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return value from custom 'dist' distribution ferencd@0: * seeded by internal random engine ferencd@0: * \param dist The custom distribution with next concept: ferencd@0: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution ferencd@0: * \param args The arguments which will be forwarded to Dist constructor ferencd@0: * \return Value from custom 'dist' distribution ferencd@0: */ ferencd@0: template ferencd@0: static typename Dist::result_type get( Dist& dist ) { ferencd@0: return dist( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reorders the elements in the given range [first, last) ferencd@0: * such that each possible permutation of those elements ferencd@0: * has equal probability of appearance. ferencd@0: * \param first, last - the range of elements to shuffle randomly ferencd@0: */ ferencd@0: template ferencd@0: static void shuffle( RandomIt first, RandomIt last ) { ferencd@0: std::shuffle( first, last, engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reorders the elements in the given container ferencd@0: * such that each possible permutation of those elements ferencd@0: * has equal probability of appearance. ferencd@0: * \param container - the container with elements to shuffle randomly ferencd@0: */ ferencd@0: template ferencd@0: static void shuffle( Container& container ) { ferencd@0: shuffle( std::begin( container ), std::end( container ) ); ferencd@0: } ferencd@0: ferencd@0: /// return internal engine by copy ferencd@0: static Engine get_engine( ) { ferencd@0: return engine; ferencd@0: } ferencd@0: protected: ferencd@0: /// return engine seeded by Seeder ferencd@0: static Engine make_seeded_engine( ) { ferencd@0: // Make seeder instance for seed return by reference like std::seed_seq ferencd@0: Seeder seeder; ferencd@0: return Engine{ seeder( ) }; ferencd@0: } ferencd@0: protected: ferencd@0: /// The random number engine ferencd@0: static Engine engine; ferencd@0: }; ferencd@0: ferencd@0: /// Seed random number engine by Seeder ferencd@0: template< ferencd@0: typename Engine, ferencd@0: typename Seeder, ferencd@0: template class IntegerDist, ferencd@0: template class RealDist, ferencd@0: typename BoolDist ferencd@0: > ferencd@0: Engine basic_random_static::engine( make_seeded_engine( ) ); ferencd@0: ferencd@0: /** ferencd@0: * \brief Base template class for random ferencd@0: * with thread_local API and thread_local internal member storage ferencd@0: * \note it IS thread safe but less efficient then ferencd@0: * basic_random_static ferencd@0: * \param Engine A random engine with interface like in the std::mt19937 ferencd@0: * \param Seeder A seeder type which return seed for internal engine ferencd@0: * through operator() ferencd@0: */ ferencd@0: template< ferencd@0: typename Engine, ferencd@0: typename Seeder = seeder_default, ferencd@0: template class IntegerDist = std::uniform_int_distribution, ferencd@0: template class RealDist = std::uniform_real_distribution, ferencd@0: typename BoolDist = std::bernoulli_distribution ferencd@0: > ferencd@0: class basic_random_thread_local { ferencd@0: public: ferencd@0: basic_random_thread_local( ) = delete; ferencd@0: ferencd@0: /// Type of used random number engine ferencd@0: using engine_type = Engine; ferencd@0: ferencd@0: /// Type of used random number seeder ferencd@0: using seeder_type = Seeder; ferencd@0: ferencd@0: /// Type of used integer distribution ferencd@0: template ferencd@0: using integer_dist_t = IntegerDist; ferencd@0: ferencd@0: /// Type of used real distribution ferencd@0: template ferencd@0: using real_dist_t = RealDist; ferencd@0: ferencd@0: /// Type of used bool distribution ferencd@0: using bool_dist_t = BoolDist; ferencd@0: ferencd@0: /// Key type for getting common type numbers or objects ferencd@0: using common = details::common; ferencd@0: ferencd@0: /** ferencd@0: * \return The minimum value ferencd@0: * potentially generated by the random-number engine ferencd@0: */ ferencd@0: static constexpr typename Engine::result_type min( ) { ferencd@0: return Engine::min( ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \return The maximum value ferencd@0: * potentially generated by the random-number engine ferencd@0: */ ferencd@0: static constexpr typename Engine::result_type max( ) { ferencd@0: return Engine::max( ); ferencd@0: } ferencd@0: ferencd@0: /// Advances the internal state by z times ferencd@0: static void discard( const unsigned long long z ) { ferencd@0: engine.discard( z ); ferencd@0: } ferencd@0: ferencd@0: /// Reseed by Seeder ferencd@0: static void reseed( ) { ferencd@0: Seeder seeder; ferencd@0: seed( seeder( ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reinitializes the internal state ferencd@0: * of the random-number engine using new seed value ferencd@0: * \param value The seed value to use ferencd@0: * in the initialization of the internal state ferencd@0: */ ferencd@0: static void seed( const typename Engine::result_type value = ferencd@0: Engine::default_seed ) { ferencd@0: engine.seed( value ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reinitializes the internal state ferencd@0: * of the random-number engine using new seed value ferencd@0: * \param seq The seed sequence ferencd@0: * to use in the initialization of the internal state ferencd@0: */ ferencd@0: template ferencd@0: static void seed( Sseq& seq ) { ferencd@0: engine.seed( seq ); ferencd@0: } ferencd@0: ferencd@0: /// return random number from engine in [min(), max()] range ferencd@0: static typename Engine::result_type get( ) { ferencd@0: return engine( ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Compares internal pseudo-random number engine ferencd@0: * with 'other' pseudo-random number engine. ferencd@0: * Two engines are equal, if their internal states ferencd@0: * are equivalent, that is, if they would generate ferencd@0: * equivalent values for any number of calls of operator() ferencd@0: * \param other The engine, with which the internal engine will be compared ferencd@0: * \return true, if other and internal engine are equal ferencd@0: */ ferencd@0: static bool is_equal( const Engine& other ) { ferencd@0: return engine == other; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Serializes the internal state of the ferencd@0: * internal pseudo-random number engine as a sequence ferencd@0: * of decimal numbers separated by one or more spaces, ferencd@0: * and inserts it to the stream ost. The fill character ferencd@0: * and the formatting flags of the stream are ferencd@0: * ignored and unaffected. ferencd@0: * \param ost The output stream to insert the data to ferencd@0: */ ferencd@0: template ferencd@0: static void serialize( std::basic_ostream& ost ) { ferencd@0: ost << engine; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Restores the internal state of the ferencd@0: * internal pseudo-random number engine from ferencd@0: * the serialized representation, which ferencd@0: * was created by an earlier call to 'serialize' ferencd@0: * using a stream with the same imbued locale and ferencd@0: * the same CharT and Traits. ferencd@0: * If the input cannot be deserialized, ferencd@0: * internal engine is left unchanged and failbit is raised on ist ferencd@0: * \param ost The input stream to extract the data from ferencd@0: */ ferencd@0: template ferencd@0: static void deserialize( std::basic_istream& ist ) { ferencd@0: ist >> engine; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random integer number in a [from; to] range ferencd@0: * by std::uniform_int_distribution ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random integer number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Prevent implicit type conversion ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , T>::type get( T from = std::numeric_limits::min( ), ferencd@0: T to = std::numeric_limits::max( ) ) { ferencd@0: if( from < to ) // Allow range from higher to lower ferencd@0: return IntegerDist{ from, to }( engine ); ferencd@0: return IntegerDist{ to, from }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random real number in a [from; to] range ferencd@0: * by std::uniform_real_distribution ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random real number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Prevent implicit type conversion ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , T>::type get( T from = std::numeric_limits::min( ), ferencd@0: T to = std::numeric_limits::max( ) ) { ferencd@0: if( from < to ) // Allow range from higher to lower ferencd@0: return RealDist{ from, to }( engine ); ferencd@0: return RealDist{ to, from }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random byte number in a [from; to] range ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random byte number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Prevent implicit type conversion ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , T>::type get( T from = std::numeric_limits::min( ), ferencd@0: T to = std::numeric_limits::max( ) ) { ferencd@0: // Choose between short and unsigned short for byte conversion ferencd@0: using short_t = typename std::conditional::value, ferencd@0: short, unsigned short>::type; ferencd@0: ferencd@0: return static_cast( get( from, to ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random common_type number in a [from; to] range ferencd@0: * \param Key The Key type for this version of 'get' method ferencd@0: * Type should be '(THIS_TYPE)::common' struct ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random common_type number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Allow implicit type conversion ferencd@0: * \note Prevent implicit type conversion from singed to unsigned types ferencd@0: * Why? std::common_type chooses unsigned value, ferencd@0: * then Signed value will be converted to Unsigned value ferencd@0: * which gives us a wrong range for random values. ferencd@0: * https://stackoverflow.com/a/5416498/5734836 ferencd@0: */ ferencd@0: template< ferencd@0: typename Key, ferencd@0: typename A, ferencd@0: typename B, ferencd@0: typename C = typename std::common_type::type ferencd@0: > ferencd@0: static typename std::enable_if< ferencd@0: std::is_same::value ferencd@0: && details::is_supported_number::value ferencd@0: && details::is_supported_number::value ferencd@0: // Prevent implicit type conversion from singed to unsigned types ferencd@0: && std::is_signed::value != std::is_unsigned::value ferencd@0: , C>::type get( A from = std::numeric_limits::min( ), ferencd@0: B to = std::numeric_limits::max( ) ) { ferencd@0: return get( static_cast( from ), static_cast( to ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a bool value with specific probability ferencd@0: * by std::bernoulli_distribution ferencd@0: * \param probability The probability of generating true in [0; 1] range ferencd@0: * 0 means always false, 1 means always true ferencd@0: * \return 'true' with 'probability' probability ('false' otherwise) ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , bool>::type get( const double probability = 0.5 ) { ferencd@0: assert( 0 <= probability && 1 >= probability ); // out of [0; 1] range ferencd@0: return BoolDist{ probability }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return random value from initilizer_list ferencd@0: * \param init_list initilizer_list with values ferencd@0: * \return Random value from initilizer_list ferencd@0: * \note Should be 1 or more elements in initilizer_list ferencd@0: * \note Warning! Elements in initilizer_list can't be moved: ferencd@0: * https://stackoverflow.com/a/8193157/5734836 ferencd@0: */ ferencd@0: template ferencd@0: static T get( std::initializer_list init_list ) { ferencd@0: assert( 0u != init_list.size( ) ); ferencd@0: return *get( init_list.begin( ), init_list.end( ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return random iterator from iterator range ferencd@0: * \param first, last - the range of elements ferencd@0: * \return Random iterator from [first, last) range ferencd@0: * \note If first == last, return last ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if::value ferencd@0: , InputIt>::type get( InputIt first, InputIt last ) { ferencd@0: const auto size = std::distance( first, last ); ferencd@0: if( 0u == size ) return last; ferencd@0: using diff_t = typename std::iterator_traits::difference_type; ferencd@0: return std::next( first, get( 0, size - 1 ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return random iterator from Container ferencd@0: * \param container The container with elements ferencd@0: * \return Random iterator from container ferencd@0: * \note If container is empty return std::end( container ) iterator ferencd@0: */ ferencd@0: template ferencd@0: static typename std::enable_if( ) ) )>::value ferencd@0: , decltype( std::begin( std::declval( ) ) ) ferencd@0: >::type get( Container& container ) { ferencd@0: return get( std::begin( container ), std::end( container ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return value from custom Dist distribution ferencd@0: * seeded by internal random engine ferencd@0: * \param Dist The type of custom distribution with next concept: ferencd@0: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution ferencd@0: * \param args The arguments which will be forwarded to Dist constructor ferencd@0: * \return Value from custom distribution ferencd@0: */ ferencd@0: template ferencd@0: static typename Dist::result_type get( Args&&... args ) { ferencd@0: return Dist{ std::forward( args )... }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return value from custom 'dist' distribution ferencd@0: * seeded by internal random engine ferencd@0: * \param dist The custom distribution with next concept: ferencd@0: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution ferencd@0: * \param args The arguments which will be forwarded to Dist constructor ferencd@0: * \return Value from custom 'dist' distribution ferencd@0: */ ferencd@0: template ferencd@0: static typename Dist::result_type get( Dist& dist ) { ferencd@0: return dist( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reorders the elements in the given range [first, last) ferencd@0: * such that each possible permutation of those elements ferencd@0: * has equal probability of appearance. ferencd@0: * \param first, last - the range of elements to shuffle randomly ferencd@0: */ ferencd@0: template ferencd@0: static void shuffle( RandomIt first, RandomIt last ) { ferencd@0: std::shuffle( first, last, engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reorders the elements in the given container ferencd@0: * such that each possible permutation of those elements ferencd@0: * has equal probability of appearance. ferencd@0: * \param container - the container with elements to shuffle randomly ferencd@0: */ ferencd@0: template ferencd@0: static void shuffle( Container& container ) { ferencd@0: shuffle( std::begin( container ), std::end( container ) ); ferencd@0: } ferencd@0: ferencd@0: /// return internal engine by copy ferencd@0: static Engine get_engine( ) { ferencd@0: return engine; ferencd@0: } ferencd@0: protected: ferencd@0: /// return engine seeded by Seeder ferencd@0: static Engine make_seeded_engine( ) { ferencd@0: // Make seeder instance for seed return by reference like std::seed_seq ferencd@0: Seeder seeder; ferencd@0: return Engine{ seeder( ) }; ferencd@0: } ferencd@0: protected: ferencd@0: /// The random number engine ferencd@0: static thread_local Engine engine; ferencd@0: }; ferencd@0: ferencd@0: /// Seed random number engine by Seeder ferencd@0: template< ferencd@0: typename Engine, ferencd@0: typename Seeder, ferencd@0: template class IntegerDist, ferencd@0: template class RealDist, ferencd@0: typename BoolDist ferencd@0: > ferencd@0: thread_local Engine basic_random_thread_local::engine( make_seeded_engine( ) ); ferencd@0: ferencd@0: /** ferencd@0: * \brief Base template class for random ferencd@0: * with local API and local internal member storage ferencd@0: * \note it IS thread safe but less efficient then ferencd@0: * basic_random_static ferencd@0: * \param Engine A random engine with interface like in the std::mt19937 ferencd@0: * \param Seeder A seeder type which return seed for internal engine ferencd@0: * through operator() ferencd@0: */ ferencd@0: template< ferencd@0: typename Engine, ferencd@0: typename Seeder = seeder_default, ferencd@0: template class IntegerDist = std::uniform_int_distribution, ferencd@0: template class RealDist = std::uniform_real_distribution, ferencd@0: typename BoolDist = std::bernoulli_distribution ferencd@0: > ferencd@0: class basic_random_local { ferencd@0: public: ferencd@0: /// Type of used random number engine ferencd@0: using engine_type = Engine; ferencd@0: ferencd@0: /// Type of used random number seeder ferencd@0: using seeder_type = Seeder; ferencd@0: ferencd@0: /// Type of used integer distribution ferencd@0: template ferencd@0: using integer_dist_t = IntegerDist; ferencd@0: ferencd@0: /// Type of used real distribution ferencd@0: template ferencd@0: using real_dist_t = RealDist; ferencd@0: ferencd@0: /// Type of used bool distribution ferencd@0: using bool_dist_t = BoolDist; ferencd@0: ferencd@0: /// Key type for getting common type numbers or objects ferencd@0: using common = details::common; ferencd@0: ferencd@0: /** ferencd@0: * \return The minimum value ferencd@0: * potentially generated by the random-number engine ferencd@0: */ ferencd@0: static constexpr typename Engine::result_type min( ) { ferencd@0: return Engine::min( ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \return The maximum value ferencd@0: * potentially generated by the random-number engine ferencd@0: */ ferencd@0: static constexpr typename Engine::result_type max( ) { ferencd@0: return Engine::max( ); ferencd@0: } ferencd@0: ferencd@0: /// Advances the internal state by z times ferencd@0: void discard( const unsigned long long z ) { ferencd@0: engine.discard( z ); ferencd@0: } ferencd@0: ferencd@0: /// Reseed by Seeder ferencd@0: void reseed( ) { ferencd@0: Seeder seeder; ferencd@0: seed( seeder( ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reinitializes the internal state ferencd@0: * of the random-number engine using new seed value ferencd@0: * \param value The seed value to use ferencd@0: * in the initialization of the internal state ferencd@0: */ ferencd@0: void seed( const typename Engine::result_type value = ferencd@0: Engine::default_seed ) { ferencd@0: engine.seed( value ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reinitializes the internal state ferencd@0: * of the random-number engine using new seed value ferencd@0: * \param seq The seed sequence ferencd@0: * to use in the initialization of the internal state ferencd@0: */ ferencd@0: template ferencd@0: void seed( Sseq& seq ) { ferencd@0: engine.seed( seq ); ferencd@0: } ferencd@0: ferencd@0: /// return random number from engine in [min(), max()] range ferencd@0: typename Engine::result_type get( ) { ferencd@0: return engine( ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Compares internal pseudo-random number engine ferencd@0: * with 'other' pseudo-random number engine. ferencd@0: * Two engines are equal, if their internal states ferencd@0: * are equivalent, that is, if they would generate ferencd@0: * equivalent values for any number of calls of operator() ferencd@0: * \param other The engine, with which the internal engine will be compared ferencd@0: * \return true, if other and internal engine are equal ferencd@0: */ ferencd@0: bool is_equal( const Engine& other ) { ferencd@0: return engine == other; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Serializes the internal state of the ferencd@0: * internal pseudo-random number engine as a sequence ferencd@0: * of decimal numbers separated by one or more spaces, ferencd@0: * and inserts it to the stream ost. The fill character ferencd@0: * and the formatting flags of the stream are ferencd@0: * ignored and unaffected. ferencd@0: * \param ost The output stream to insert the data to ferencd@0: */ ferencd@0: template ferencd@0: void serialize( std::basic_ostream& ost ) { ferencd@0: ost << engine; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Restores the internal state of the ferencd@0: * internal pseudo-random number engine from ferencd@0: * the serialized representation, which ferencd@0: * was created by an earlier call to 'serialize' ferencd@0: * using a stream with the same imbued locale and ferencd@0: * the same CharT and Traits. ferencd@0: * If the input cannot be deserialized, ferencd@0: * internal engine is left unchanged and failbit is raised on ist ferencd@0: * \param ost The input stream to extract the data from ferencd@0: */ ferencd@0: template ferencd@0: void deserialize( std::basic_istream& ist ) { ferencd@0: ist >> engine; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random integer number in a [from; to] range ferencd@0: * by std::uniform_int_distribution ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random integer number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Prevent implicit type conversion ferencd@0: */ ferencd@0: template ferencd@0: typename std::enable_if::value ferencd@0: , T>::type get( T from = std::numeric_limits::min( ), ferencd@0: T to = std::numeric_limits::max( ) ) { ferencd@0: if( from < to ) // Allow range from higher to lower ferencd@0: return IntegerDist{ from, to }( engine ); ferencd@0: return IntegerDist{ to, from }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random real number in a [from; to] range ferencd@0: * by std::uniform_real_distribution ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random real number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Prevent implicit type conversion ferencd@0: */ ferencd@0: template ferencd@0: typename std::enable_if::value ferencd@0: , T>::type get( T from = std::numeric_limits::min( ), ferencd@0: T to = std::numeric_limits::max( ) ) { ferencd@0: if( from < to ) // Allow range from higher to lower ferencd@0: return RealDist{ from, to }( engine ); ferencd@0: return RealDist{ to, from }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random byte number in a [from; to] range ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random byte number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Prevent implicit type conversion ferencd@0: */ ferencd@0: template ferencd@0: typename std::enable_if::value ferencd@0: , T>::type get( T from = std::numeric_limits::min( ), ferencd@0: T to = std::numeric_limits::max( ) ) { ferencd@0: // Choose between short and unsigned short for byte conversion ferencd@0: using short_t = typename std::conditional::value, ferencd@0: short, unsigned short>::type; ferencd@0: ferencd@0: return static_cast( get( from, to ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a random common_type number in a [from; to] range ferencd@0: * \param Key The Key type for this version of 'get' method ferencd@0: * Type should be '(THIS_TYPE)::common' struct ferencd@0: * \param from The first limit number of a random range ferencd@0: * \param to The second limit number of a random range ferencd@0: * \return A random common_type number in a [from; to] range ferencd@0: * \note Allow both: 'from' <= 'to' and 'from' >= 'to' ferencd@0: * \note Allow implicit type conversion ferencd@0: * \note Prevent implicit type conversion from singed to unsigned types ferencd@0: * Why? std::common_type chooses unsigned value, ferencd@0: * then Signed value will be converted to Unsigned value ferencd@0: * which gives us a wrong range for random values. ferencd@0: * https://stackoverflow.com/a/5416498/5734836 ferencd@0: */ ferencd@0: template< ferencd@0: typename Key, ferencd@0: typename A, ferencd@0: typename B, ferencd@0: typename C = typename std::common_type::type ferencd@0: > ferencd@0: typename std::enable_if< ferencd@0: std::is_same::value ferencd@0: && details::is_supported_number::value ferencd@0: && details::is_supported_number::value ferencd@0: // Prevent implicit type conversion from singed to unsigned types ferencd@0: && std::is_signed::value != std::is_unsigned::value ferencd@0: , C>::type get( A from = std::numeric_limits::min( ), ferencd@0: B to = std::numeric_limits::max( ) ) { ferencd@0: return get( static_cast( from ), static_cast( to ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Generate a bool value with specific probability ferencd@0: * by std::bernoulli_distribution ferencd@0: * \param probability The probability of generating true in [0; 1] range ferencd@0: * 0 means always false, 1 means always true ferencd@0: * \return 'true' with 'probability' probability ('false' otherwise) ferencd@0: */ ferencd@0: template ferencd@0: typename std::enable_if::value ferencd@0: , bool>::type get( const double probability = 0.5 ) { ferencd@0: assert( 0 <= probability && 1 >= probability ); // out of [0; 1] range ferencd@0: return BoolDist{ probability }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return random value from initilizer_list ferencd@0: * \param init_list initilizer_list with values ferencd@0: * \return Random value from initilizer_list ferencd@0: * \note Should be 1 or more elements in initilizer_list ferencd@0: * \note Warning! Elements in initilizer_list can't be moved: ferencd@0: * https://stackoverflow.com/a/8193157/5734836 ferencd@0: */ ferencd@0: template ferencd@0: T get( std::initializer_list init_list ) { ferencd@0: assert( 0u != init_list.size( ) ); ferencd@0: return *get( init_list.begin( ), init_list.end( ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return random iterator from iterator range ferencd@0: * \param first, last - the range of elements ferencd@0: * \return Random iterator from [first, last) range ferencd@0: * \note If first == last, return last ferencd@0: */ ferencd@0: template ferencd@0: typename std::enable_if::value ferencd@0: , InputIt>::type get( InputIt first, InputIt last ) { ferencd@0: const auto size = std::distance( first, last ); ferencd@0: if( 0u == size ) return last; ferencd@0: using diff_t = typename std::iterator_traits::difference_type; ferencd@0: return std::next( first, get( 0, size - 1 ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return random iterator from Container ferencd@0: * \param container The container with elements ferencd@0: * \return Random iterator from container ferencd@0: * \note If container is empty return std::end( container ) iterator ferencd@0: */ ferencd@0: template ferencd@0: typename std::enable_if( ) ) )>::value ferencd@0: , decltype( std::begin( std::declval( ) ) ) ferencd@0: >::type get( Container& container ) { ferencd@0: return get( std::begin( container ), std::end( container ) ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return value from custom Dist distribution ferencd@0: * seeded by internal random engine ferencd@0: * \param Dist The type of custom distribution with next concept: ferencd@0: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution ferencd@0: * \param args The arguments which will be forwarded to Dist constructor ferencd@0: * \return Value from custom distribution ferencd@0: */ ferencd@0: template ferencd@0: typename Dist::result_type get( Args&&... args ) { ferencd@0: return Dist{ std::forward( args )... }( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Return value from custom 'dist' distribution ferencd@0: * seeded by internal random engine ferencd@0: * \param dist The custom distribution with next concept: ferencd@0: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution ferencd@0: * \param args The arguments which will be forwarded to Dist constructor ferencd@0: * \return Value from custom 'dist' distribution ferencd@0: */ ferencd@0: template ferencd@0: typename Dist::result_type get( Dist& dist ) { ferencd@0: return dist( engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reorders the elements in the given range [first, last) ferencd@0: * such that each possible permutation of those elements ferencd@0: * has equal probability of appearance. ferencd@0: * \param first, last - the range of elements to shuffle randomly ferencd@0: */ ferencd@0: template ferencd@0: void shuffle( RandomIt first, RandomIt last ) { ferencd@0: std::shuffle( first, last, engine ); ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * \brief Reorders the elements in the given container ferencd@0: * such that each possible permutation of those elements ferencd@0: * has equal probability of appearance. ferencd@0: * \param container - the container with elements to shuffle randomly ferencd@0: */ ferencd@0: template ferencd@0: void shuffle( Container& container ) { ferencd@0: shuffle( std::begin( container ), std::end( container ) ); ferencd@0: } ferencd@0: ferencd@0: /// return internal engine by copy ferencd@0: Engine get_engine( ) const { ferencd@0: return engine; ferencd@0: } ferencd@0: protected: ferencd@0: /// return engine seeded by Seeder ferencd@0: static Engine make_seeded_engine( ) { ferencd@0: // Make seeder instance for seed return by reference like std::seed_seq ferencd@0: Seeder seeder; ferencd@0: return Engine{ seeder( ) }; ferencd@0: } ferencd@0: protected: ferencd@0: /// The random number engine ferencd@0: Engine engine{ make_seeded_engine( ) }; ferencd@0: }; ferencd@0: ferencd@0: /** ferencd@0: * \brief The basic static random alias based on a std::mt19937 ferencd@0: * \note It uses static methods API and data with static storage ferencd@0: * \note Not thread safe but more prefomance ferencd@0: */ ferencd@0: using random_static = basic_random_static; ferencd@0: ferencd@0: /** ferencd@0: * \brief The basic static random alias based on a std::mt19937 ferencd@0: * \note It uses static methods API and data with thread_local storage ferencd@0: * \note Thread safe but less perfomance ferencd@0: */ ferencd@0: using random_thread_local = basic_random_thread_local; ferencd@0: ferencd@0: /** ferencd@0: * \brief The basic static random alias based on a std::mt19937 ferencd@0: * \note It uses non static methods API and data with auto storage ferencd@0: * \note Not thread safe. Should construct on the stack at local scope ferencd@0: */ ferencd@0: using random_local = basic_random_local; ferencd@0: ferencd@0: } // namespace effolkronium ferencd@0: ferencd@0: #endif // #ifndef EFFOLKRONIUM_RANDOM_HPP