/* ______ ___ _ _______ ________ __ | ___ \/ _ \ | \ | | _ \ _ | \/ | Random for modern C++ | |_/ / /_\ \| \| | | | | | | | . . | | /| _ || . ` | | | | | | | |\/| | version 1.3.1 | |\ \| | | || |\ | |/ /\ \_/ / | | | \_| \_\_| |_/\_| \_/___/ \___/\_| |_/ https://github.com/effolkronium/random Licensed under the MIT License . Copyright (c) 2019 effolkronium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files( the "Software" ), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef EFFOLKRONIUM_RANDOM_HPP #define EFFOLKRONIUM_RANDOM_HPP #include #include // timed seed #include #include #include #include // std::forward, std::declval #include // std::shuffle, std::next, std::distance #include // std::begin, std::end, std::iterator_traits #include // std::numeric_limits #include #include namespace effolkronium { namespace details { /// Key type for getting common type numbers or objects struct common{ }; /// True if type T is applicable by a std::uniform_int_distribution template struct is_uniform_int { static constexpr bool value = std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value; }; /// True if type T is applicable by a std::uniform_real_distribution template struct is_uniform_real { static constexpr bool value = std::is_same::value || std::is_same::value || std::is_same::value; }; /// True if type T is plain byte template struct is_byte { static constexpr bool value = std::is_same::value || std::is_same::value; }; /// True if type T is plain number type template struct is_supported_number { static constexpr bool value = is_byte ::value || is_uniform_real::value || is_uniform_int ::value; }; /// True if type T is character type template struct is_supported_character { static constexpr bool value = std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value; }; /// True if type T is iterator template struct is_iterator { private: static char test( ... ); template ::difference_type, typename = typename std::iterator_traits::pointer, typename = typename std::iterator_traits::reference, typename = typename std::iterator_traits::value_type, typename = typename std::iterator_traits::iterator_category > static long test( U&& ); public: static constexpr bool value = std::is_same< decltype( test( std::declval( ) ) ), long>::value; }; } // namespace details /// Default seeder for 'random' classes struct seeder_default { /// return seed sequence std::seed_seq& operator() ( ) { // MinGW issue, std::random_device returns constant value // Use std::seed_seq with additional seed from C++ chrono return seed_seq; } private: std::seed_seq seed_seq{ { static_cast( std::random_device{ }( ) ), static_cast( std::chrono::steady_clock::now( ) .time_since_epoch( ).count( ) ), } }; }; /** * \brief Base template class for random * with static API and static internal member storage * \note it is NOT thread safe but more efficient then * basic_random_thread_local * \param Engine A random engine with interface like in the std::mt19937 * \param Seeder A seeder type which return seed for internal engine * through operator() */ template< typename Engine, typename Seeder = seeder_default, template class IntegerDist = std::uniform_int_distribution, template class RealDist = std::uniform_real_distribution, typename BoolDist = std::bernoulli_distribution > class basic_random_static { public: basic_random_static( ) = delete; /// Type of used random number engine using engine_type = Engine; /// Type of used random number seeder using seeder_type = Seeder; /// Type of used integer distribution template using integer_dist_t = IntegerDist; /// Type of used real distribution template using real_dist_t = RealDist; /// Type of used bool distribution using bool_dist_t = BoolDist; /// Key type for getting common type numbers or objects using common = details::common; /** * \return The minimum value * potentially generated by the random-number engine */ static constexpr typename Engine::result_type min( ) { return Engine::min( ); } /** * \return The maximum value * potentially generated by the random-number engine */ static constexpr typename Engine::result_type max( ) { return Engine::max( ); } /// Advances the internal state by z times static void discard( const unsigned long long z ) { engine_instance( ).discard( z ); } /// Reseed by Seeder static void reseed( ) { Seeder seeder; seed( seeder( ) ); } /** * \brief Reinitializes the internal state * of the random-number engine using new seed value * \param value The seed value to use * in the initialization of the internal state */ static void seed( const typename Engine::result_type value = Engine::default_seed ) { engine_instance( ).seed( value ); } /** * \brief Reinitializes the internal state * of the random-number engine using new seed value * \param seq The seed sequence * to use in the initialization of the internal state */ template static void seed( Sseq& seq ) { engine_instance( ).seed( seq ); } /// return random number from engine in [min(), max()] range static typename Engine::result_type get( ) { return engine_instance( )( ); } /** * \brief Compares internal pseudo-random number engine * with 'other' pseudo-random number engine. * Two engines are equal, if their internal states * are equivalent, that is, if they would generate * equivalent values for any number of calls of operator() * \param other The engine, with which the internal engine will be compared * \return true, if other and internal engine are equal */ static bool is_equal( const Engine& other ) { return engine_instance( ) == other; } /** * \brief Serializes the internal state of the * internal pseudo-random number engine as a sequence * of decimal numbers separated by one or more spaces, * and inserts it to the stream ost. The fill character * and the formatting flags of the stream are * ignored and unaffected. * \param ost The output stream to insert the data to */ template static void serialize( std::basic_ostream& ost ) { ost << engine_instance( ); } /** * \brief Restores the internal state of the * internal pseudo-random number engine from * the serialized representation, which * was created by an earlier call to 'serialize' * using a stream with the same imbued locale and * the same CharT and Traits. * If the input cannot be deserialized, * internal engine is left unchanged and failbit is raised on ist * \param ost The input stream to extract the data from */ template static void deserialize( std::basic_istream& ist ) { ist >> engine_instance( ); } /** * \brief Generate a random integer number in a [from; to] range * by std::uniform_int_distribution * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random integer number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template static typename std::enable_if::value , T>::type get( T from = std::numeric_limits::min( ), T to = std::numeric_limits::max( ) ) { if( from < to ) // Allow range from higher to lower return IntegerDist{ from, to }( engine_instance( ) ); return IntegerDist{ to, from }( engine_instance( ) ); } /** * \brief Generate a random real number in a [from; to] range * by std::uniform_real_distribution * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random real number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template static typename std::enable_if::value , T>::type get( T from = std::numeric_limits::min( ), T to = std::numeric_limits::max( ) ) { if( from < to ) // Allow range from higher to lower return RealDist{ from, to }( engine_instance( ) ); return RealDist{ to, from }( engine_instance( ) ); } /** * \brief Generate a random byte number in a [from; to] range * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random byte number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template static typename std::enable_if::value , T>::type get( T from = std::numeric_limits::min( ), T to = std::numeric_limits::max( ) ) { // Choose between short and unsigned short for byte conversion using short_t = typename std::conditional::value, short, unsigned short>::type; return static_cast( get( from, to ) ); } /** * \brief Generate a random common_type number in a [from; to] range * \param Key The Key type for this version of 'get' method * Type should be '(THIS_TYPE)::common' struct * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random common_type number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Allow implicit type conversion * \note Prevent implicit type conversion from singed to unsigned types * Why? std::common_type chooses unsigned value, * then Signed value will be converted to Unsigned value * which gives us a wrong range for random values. * https://stackoverflow.com/a/5416498/5734836 */ template< typename Key, typename A, typename B, typename C = typename std::common_type::type > static typename std::enable_if< std::is_same::value && details::is_supported_number::value && details::is_supported_number::value // Prevent implicit type conversion from singed to unsigned types && std::is_signed::value != std::is_unsigned::value , C>::type get( A from = std::numeric_limits::min( ), B to = std::numeric_limits::max( ) ) { return get( static_cast( from ), static_cast( to ) ); } /** * \brief Generate a random character in a [from; to] range * by std::uniform_int_distribution * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random character in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template static typename std::enable_if::value , T>::type get(T from = std::numeric_limits::min(), T to = std::numeric_limits::max()) { if (from < to) // Allow range from higher to lower return static_cast(IntegerDist{ static_cast(from), static_cast(to) }(engine_instance())); return static_cast(IntegerDist{ static_cast(to), static_cast(from) }(engine_instance())); } /** * \brief Generate a bool value with specific probability * by std::bernoulli_distribution * \param probability The probability of generating true in [0; 1] range * 0 means always false, 1 means always true * \return 'true' with 'probability' probability ('false' otherwise) */ template static typename std::enable_if::value , bool>::type get( const double probability = 0.5 ) { assert( 0 <= probability && 1 >= probability ); // out of [0; 1] range return BoolDist{ probability }( engine_instance( ) ); } /** * \brief Return random value from initilizer_list * \param init_list initilizer_list with values * \return Random value from initilizer_list * \note Should be 1 or more elements in initilizer_list * \note Warning! Elements in initilizer_list can't be moved: * https://stackoverflow.com/a/8193157/5734836 */ template static T get( std::initializer_list init_list ) { assert( 0u != init_list.size( ) ); return *get( init_list.begin( ), init_list.end( ) ); } /** * \brief Return random iterator from iterator range * \param first, last - the range of elements * \return Random iterator from [first, last) range * \note If first == last, return last */ template static typename std::enable_if::value , InputIt>::type get( InputIt first, InputIt last ) { const auto size = std::distance( first, last ); if( 0 == size ) return last; using diff_t = typename std::iterator_traits::difference_type; return std::next( first, get( 0, size - 1 ) ); } /** * \brief Return random iterator from Container * \param container The container with elements * \return Random iterator from container * \note If container is empty return std::end( container ) iterator */ template static auto get( Container& container ) -> typename std::enable_if::value , decltype(std::begin(container)) >::type { return get( std::begin( container ), std::end( container ) ); } /** * \brief Return random pointer from built-in array * \param array The built-in array with elements * \return Pointer to random element in array */ template static T* get( T( &array )[ N ] ) { return std::addressof( array[ get( 0, N - 1 ) ] ); } /** * \brief Return value from custom Dist distribution * seeded by internal random engine * \param Dist The type of custom distribution with next concept: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution * \param args The arguments which will be forwarded to Dist constructor * \return Value from custom distribution */ template static typename Dist::result_type get( Args&&... args ) { return Dist{ std::forward( args )... }( engine_instance( ) ); } /** * \brief Return value from custom 'dist' distribution * seeded by internal random engine * \param dist The custom distribution with next concept: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution * \param args The arguments which will be forwarded to Dist constructor * \return Value from custom 'dist' distribution */ template static typename Dist::result_type get( Dist& dist ) { return dist( engine_instance( ) ); } /** * \brief Reorders the elements in the given range [first, last) * such that each possible permutation of those elements * has equal probability of appearance. * \param first, last - the range of elements to shuffle randomly */ template static void shuffle( RandomIt first, RandomIt last ) { std::shuffle( first, last, engine_instance( ) ); } /** * \brief Reorders the elements in the given container * such that each possible permutation of those elements * has equal probability of appearance. * \param container - the container with elements to shuffle randomly */ template static void shuffle( Container& container ) { shuffle( std::begin( container ), std::end( container ) ); } /// return internal engine by copy static Engine get_engine( ) { return engine_instance( ); } /// return internal engine by ref static Engine& engine() { return engine_instance(); } protected: /// get reference to the static engine instance static Engine& engine_instance( ) { static Engine engine{ Seeder{ }( ) }; return engine; } }; /** * \brief Base template class for random * with thread_local API and thread_local internal member storage * \note it IS thread safe but less efficient then * basic_random_static * \param Engine A random engine with interface like in the std::mt19937 * \param Seeder A seeder type which return seed for internal engine * through operator() */ template< typename Engine, typename Seeder = seeder_default, template class IntegerDist = std::uniform_int_distribution, template class RealDist = std::uniform_real_distribution, typename BoolDist = std::bernoulli_distribution > class basic_random_thread_local { public: basic_random_thread_local( ) = delete; /// Type of used random number engine using engine_type = Engine; /// Type of used random number seeder using seeder_type = Seeder; /// Type of used integer distribution template using integer_dist_t = IntegerDist; /// Type of used real distribution template using real_dist_t = RealDist; /// Type of used bool distribution using bool_dist_t = BoolDist; /// Key type for getting common type numbers or objects using common = details::common; /** * \return The minimum value * potentially generated by the random-number engine */ static constexpr typename Engine::result_type min( ) { return Engine::min( ); } /** * \return The maximum value * potentially generated by the random-number engine */ static constexpr typename Engine::result_type max( ) { return Engine::max( ); } /// Advances the internal state by z times static void discard( const unsigned long long z ) { engine_instance( ).discard( z ); } /// Reseed by Seeder static void reseed( ) { Seeder seeder; seed( seeder( ) ); } /** * \brief Reinitializes the internal state * of the random-number engine using new seed value * \param value The seed value to use * in the initialization of the internal state */ static void seed( const typename Engine::result_type value = Engine::default_seed ) { engine_instance( ).seed( value ); } /** * \brief Reinitializes the internal state * of the random-number engine using new seed value * \param seq The seed sequence * to use in the initialization of the internal state */ template static void seed( Sseq& seq ) { engine_instance( ).seed( seq ); } /// return random number from engine in [min(), max()] range static typename Engine::result_type get( ) { return engine_instance( )( ); } /** * \brief Compares internal pseudo-random number engine * with 'other' pseudo-random number engine. * Two engines are equal, if their internal states * are equivalent, that is, if they would generate * equivalent values for any number of calls of operator() * \param other The engine, with which the internal engine will be compared * \return true, if other and internal engine are equal */ static bool is_equal( const Engine& other ) { return engine_instance( ) == other; } /** * \brief Serializes the internal state of the * internal pseudo-random number engine as a sequence * of decimal numbers separated by one or more spaces, * and inserts it to the stream ost. The fill character * and the formatting flags of the stream are * ignored and unaffected. * \param ost The output stream to insert the data to */ template static void serialize( std::basic_ostream& ost ) { ost << engine_instance( ); } /** * \brief Restores the internal state of the * internal pseudo-random number engine from * the serialized representation, which * was created by an earlier call to 'serialize' * using a stream with the same imbued locale and * the same CharT and Traits. * If the input cannot be deserialized, * internal engine is left unchanged and failbit is raised on ist * \param ost The input stream to extract the data from */ template static void deserialize( std::basic_istream& ist ) { ist >> engine_instance( ); } /** * \brief Generate a random integer number in a [from; to] range * by std::uniform_int_distribution * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random integer number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template static typename std::enable_if::value , T>::type get( T from = std::numeric_limits::min( ), T to = std::numeric_limits::max( ) ) { if( from < to ) // Allow range from higher to lower return IntegerDist{ from, to }( engine_instance( ) ); return IntegerDist{ to, from }( engine_instance( ) ); } /** * \brief Generate a random real number in a [from; to] range * by std::uniform_real_distribution * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random real number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template static typename std::enable_if::value , T>::type get( T from = std::numeric_limits::min( ), T to = std::numeric_limits::max( ) ) { if( from < to ) // Allow range from higher to lower return RealDist{ from, to }( engine_instance( ) ); return RealDist{ to, from }( engine_instance( ) ); } /** * \brief Generate a random byte number in a [from; to] range * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random byte number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template static typename std::enable_if::value , T>::type get( T from = std::numeric_limits::min( ), T to = std::numeric_limits::max( ) ) { // Choose between short and unsigned short for byte conversion using short_t = typename std::conditional::value, short, unsigned short>::type; return static_cast( get( from, to ) ); } /** * \brief Generate a random common_type number in a [from; to] range * \param Key The Key type for this version of 'get' method * Type should be '(THIS_TYPE)::common' struct * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random common_type number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Allow implicit type conversion * \note Prevent implicit type conversion from singed to unsigned types * Why? std::common_type chooses unsigned value, * then Signed value will be converted to Unsigned value * which gives us a wrong range for random values. * https://stackoverflow.com/a/5416498/5734836 */ template< typename Key, typename A, typename B, typename C = typename std::common_type::type > static typename std::enable_if< std::is_same::value && details::is_supported_number::value && details::is_supported_number::value // Prevent implicit type conversion from singed to unsigned types && std::is_signed::value != std::is_unsigned::value , C>::type get( A from = std::numeric_limits::min( ), B to = std::numeric_limits::max( ) ) { return get( static_cast( from ), static_cast( to ) ); } /** * \brief Generate a random character in a [from; to] range * by std::uniform_int_distribution * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random character in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template static typename std::enable_if::value , T>::type get(T from = std::numeric_limits::min(), T to = std::numeric_limits::max()) { if (from < to) // Allow range from higher to lower return static_cast(IntegerDist{ static_cast(from), static_cast(to) }(engine_instance())); return static_cast(IntegerDist{ static_cast(to), static_cast(from) }(engine_instance())); } /** * \brief Generate a bool value with specific probability * by std::bernoulli_distribution * \param probability The probability of generating true in [0; 1] range * 0 means always false, 1 means always true * \return 'true' with 'probability' probability ('false' otherwise) */ template static typename std::enable_if::value , bool>::type get( const double probability = 0.5 ) { assert( 0 <= probability && 1 >= probability ); // out of [0; 1] range return BoolDist{ probability }( engine_instance( ) ); } /** * \brief Return random value from initilizer_list * \param init_list initilizer_list with values * \return Random value from initilizer_list * \note Should be 1 or more elements in initilizer_list * \note Warning! Elements in initilizer_list can't be moved: * https://stackoverflow.com/a/8193157/5734836 */ template static T get( std::initializer_list init_list ) { assert( 0u != init_list.size( ) ); return *get( init_list.begin( ), init_list.end( ) ); } /** * \brief Return random iterator from iterator range * \param first, last - the range of elements * \return Random iterator from [first, last) range * \note If first == last, return last */ template static typename std::enable_if::value , InputIt>::type get( InputIt first, InputIt last ) { const auto size = std::distance( first, last ); if( 0 == size ) return last; using diff_t = typename std::iterator_traits::difference_type; return std::next( first, get( 0, size - 1 ) ); } /** * \brief Return random iterator from Container * \param container The container with elements * \return Random iterator from container * \note If container is empty return std::end( container ) iterator */ template static auto get( Container& container ) -> typename std::enable_if::value , decltype(std::begin(container)) >::type { return get( std::begin( container ), std::end( container ) ); } /** * \brief Return random pointer from built-in array * \param array The built-in array with elements * \return Pointer to random element in array */ template static T* get( T( &array )[ N ] ) { return std::addressof( array[ get( 0, N - 1 ) ] ); } /** * \brief Return value from custom Dist distribution * seeded by internal random engine * \param Dist The type of custom distribution with next concept: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution * \param args The arguments which will be forwarded to Dist constructor * \return Value from custom distribution */ template static typename Dist::result_type get( Args&&... args ) { return Dist{ std::forward( args )... }( engine_instance( ) ); } /** * \brief Return value from custom 'dist' distribution * seeded by internal random engine * \param dist The custom distribution with next concept: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution * \param args The arguments which will be forwarded to Dist constructor * \return Value from custom 'dist' distribution */ template static typename Dist::result_type get( Dist& dist ) { return dist( engine_instance( ) ); } /** * \brief Reorders the elements in the given range [first, last) * such that each possible permutation of those elements * has equal probability of appearance. * \param first, last - the range of elements to shuffle randomly */ template static void shuffle( RandomIt first, RandomIt last ) { std::shuffle( first, last, engine_instance( ) ); } /** * \brief Reorders the elements in the given container * such that each possible permutation of those elements * has equal probability of appearance. * \param container - the container with elements to shuffle randomly */ template static void shuffle( Container& container ) { shuffle( std::begin( container ), std::end( container ) ); } /// return internal engine by copy static Engine get_engine( ) { return engine_instance( ); } /// return internal engine by ref static Engine& engine() { return engine_instance(); } protected: /// get reference to the thread local engine instance static Engine& engine_instance( ) { thread_local Engine engine{ Seeder{ }( ) }; return engine; } }; /** * \brief Base template class for random * with local API and local internal member storage * \note it IS thread safe but less efficient then * basic_random_static * \param Engine A random engine with interface like in the std::mt19937 * \param Seeder A seeder type which return seed for internal engine * through operator() */ template< typename Engine, typename Seeder = seeder_default, template class IntegerDist = std::uniform_int_distribution, template class RealDist = std::uniform_real_distribution, typename BoolDist = std::bernoulli_distribution > class basic_random_local { public: /// Type of used random number engine using engine_type = Engine; /// Type of used random number seeder using seeder_type = Seeder; /// Type of used integer distribution template using integer_dist_t = IntegerDist; /// Type of used real distribution template using real_dist_t = RealDist; /// Type of used bool distribution using bool_dist_t = BoolDist; /// Key type for getting common type numbers or objects using common = details::common; /** * \return The minimum value * potentially generated by the random-number engine */ static constexpr typename Engine::result_type min( ) { return Engine::min( ); } /** * \return The maximum value * potentially generated by the random-number engine */ static constexpr typename Engine::result_type max( ) { return Engine::max( ); } /// Advances the internal state by z times void discard( const unsigned long long z ) { m_engine.discard( z ); } /// Reseed by Seeder void reseed( ) { Seeder seeder; seed( seeder( ) ); } /** * \brief Reinitializes the internal state * of the random-number engine using new seed value * \param value The seed value to use * in the initialization of the internal state */ void seed( const typename Engine::result_type value = Engine::default_seed ) { m_engine.seed( value ); } /** * \brief Reinitializes the internal state * of the random-number engine using new seed value * \param seq The seed sequence * to use in the initialization of the internal state */ template void seed( Sseq& seq ) { m_engine.seed( seq ); } /// return random number from engine in [min(), max()] range typename Engine::result_type get( ) { return m_engine( ); } /** * \brief Compares internal pseudo-random number engine * with 'other' pseudo-random number engine. * Two engines are equal, if their internal states * are equivalent, that is, if they would generate * equivalent values for any number of calls of operator() * \param other The engine, with which the internal engine will be compared * \return true, if other and internal engine are equal */ bool is_equal( const Engine& other ) { return m_engine == other; } /** * \brief Serializes the internal state of the * internal pseudo-random number engine as a sequence * of decimal numbers separated by one or more spaces, * and inserts it to the stream ost. The fill character * and the formatting flags of the stream are * ignored and unaffected. * \param ost The output stream to insert the data to */ template void serialize( std::basic_ostream& ost ) { ost << m_engine; } /** * \brief Restores the internal state of the * internal pseudo-random number engine from * the serialized representation, which * was created by an earlier call to 'serialize' * using a stream with the same imbued locale and * the same CharT and Traits. * If the input cannot be deserialized, * internal engine is left unchanged and failbit is raised on ist * \param ost The input stream to extract the data from */ template void deserialize( std::basic_istream& ist ) { ist >> m_engine; } /** * \brief Generate a random integer number in a [from; to] range * by std::uniform_int_distribution * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random integer number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template typename std::enable_if::value , T>::type get( T from = std::numeric_limits::min( ), T to = std::numeric_limits::max( ) ) { if( from < to ) // Allow range from higher to lower return IntegerDist{ from, to }( m_engine ); return IntegerDist{ to, from }( m_engine ); } /** * \brief Generate a random real number in a [from; to] range * by std::uniform_real_distribution * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random real number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template typename std::enable_if::value , T>::type get( T from = std::numeric_limits::min( ), T to = std::numeric_limits::max( ) ) { if( from < to ) // Allow range from higher to lower return RealDist{ from, to }( m_engine ); return RealDist{ to, from }( m_engine ); } /** * \brief Generate a random byte number in a [from; to] range * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random byte number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template typename std::enable_if::value , T>::type get( T from = std::numeric_limits::min( ), T to = std::numeric_limits::max( ) ) { // Choose between short and unsigned short for byte conversion using short_t = typename std::conditional::value, short, unsigned short>::type; return static_cast( get( from, to ) ); } /** * \brief Generate a random common_type number in a [from; to] range * \param Key The Key type for this version of 'get' method * Type should be '(THIS_TYPE)::common' struct * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random common_type number in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Allow implicit type conversion * \note Prevent implicit type conversion from singed to unsigned types * Why? std::common_type chooses unsigned value, * then Signed value will be converted to Unsigned value * which gives us a wrong range for random values. * https://stackoverflow.com/a/5416498/5734836 */ template< typename Key, typename A, typename B, typename C = typename std::common_type::type > typename std::enable_if< std::is_same::value && details::is_supported_number::value && details::is_supported_number::value // Prevent implicit type conversion from singed to unsigned types && std::is_signed::value != std::is_unsigned::value , C>::type get( A from = std::numeric_limits::min( ), B to = std::numeric_limits::max( ) ) { return get( static_cast( from ), static_cast( to ) ); } /** * \brief Generate a random character in a [from; to] range * by std::uniform_int_distribution * \param from The first limit number of a random range * \param to The second limit number of a random range * \return A random character in a [from; to] range * \note Allow both: 'from' <= 'to' and 'from' >= 'to' * \note Prevent implicit type conversion */ template typename std::enable_if::value , T>::type get(T from = std::numeric_limits::min(), T to = std::numeric_limits::max()) { if (from < to) // Allow range from higher to lower return static_cast(IntegerDist{ static_cast(from), static_cast(to) }(m_engine)); return static_cast(IntegerDist{ static_cast(to), static_cast(from) }(m_engine)); } /** * \brief Generate a bool value with specific probability * by std::bernoulli_distribution * \param probability The probability of generating true in [0; 1] range * 0 means always false, 1 means always true * \return 'true' with 'probability' probability ('false' otherwise) */ template typename std::enable_if::value , bool>::type get( const double probability = 0.5 ) { assert( 0 <= probability && 1 >= probability ); // out of [0; 1] range return BoolDist{ probability }( m_engine ); } /** * \brief Return random value from initilizer_list * \param init_list initilizer_list with values * \return Random value from initilizer_list * \note Should be 1 or more elements in initilizer_list * \note Warning! Elements in initilizer_list can't be moved: * https://stackoverflow.com/a/8193157/5734836 */ template T get( std::initializer_list init_list ) { assert( 0u != init_list.size( ) ); return *get( init_list.begin( ), init_list.end( ) ); } /** * \brief Return random iterator from iterator range * \param first, last - the range of elements * \return Random iterator from [first, last) range * \note If first == last, return last */ template typename std::enable_if::value , InputIt>::type get( InputIt first, InputIt last ) { const auto size = std::distance( first, last ); if( 0 == size ) return last; using diff_t = typename std::iterator_traits::difference_type; return std::next( first, get( 0, size - 1 ) ); } /** * \brief Return random iterator from Container * \param container The container with elements * \return Random iterator from container * \note If container is empty return std::end( container ) iterator */ template auto get( Container& container ) -> typename std::enable_if::value , decltype(std::begin(container)) >::type { return get( std::begin( container ), std::end( container ) ); } /** * \brief Return random pointer from built-in array * \param array The built-in array with elements * \return Pointer to random element in array */ template T* get( T( &array )[ N ] ) { return std::addressof( array[ get( 0, N - 1 ) ] ); } /** * \brief Return value from custom Dist distribution * seeded by internal random engine * \param Dist The type of custom distribution with next concept: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution * \param args The arguments which will be forwarded to Dist constructor * \return Value from custom distribution */ template typename Dist::result_type get( Args&&... args ) { return Dist{ std::forward( args )... }( m_engine ); } /** * \brief Return value from custom 'dist' distribution * seeded by internal random engine * \param dist The custom distribution with next concept: * http://en.cppreference.com/w/cpp/concept/RandomNumberDistribution * \param args The arguments which will be forwarded to Dist constructor * \return Value from custom 'dist' distribution */ template typename Dist::result_type get( Dist& dist ) { return dist( m_engine ); } /** * \brief Reorders the elements in the given range [first, last) * such that each possible permutation of those elements * has equal probability of appearance. * \param first, last - the range of elements to shuffle randomly */ template void shuffle( RandomIt first, RandomIt last ) { std::shuffle( first, last, m_engine ); } /** * \brief Reorders the elements in the given container * such that each possible permutation of those elements * has equal probability of appearance. * \param container - the container with elements to shuffle randomly */ template void shuffle( Container& container ) { shuffle( std::begin( container ), std::end( container ) ); } /// return internal engine by copy Engine get_engine( ) const { return m_engine; } /// return internal engine by ref Engine& engine() { return m_engine; } protected: /// return engine seeded by Seeder static Engine make_seeded_engine( ) { // Make seeder instance for seed return by reference like std::seed_seq return Engine{ Seeder{ }( ) }; } protected: /// The random number engine Engine m_engine{ make_seeded_engine( ) }; }; /** * \brief The basic static random alias based on a std::mt19937 * \note It uses static methods API and data with static storage * \note Not thread safe but more prefomance */ using random_static = basic_random_static; /** * \brief The basic static random alias based on a std::mt19937 * \note It uses static methods API and data with thread_local storage * \note Thread safe but less perfomance */ using random_thread_local = basic_random_thread_local; /** * \brief The basic static random alias based on a std::mt19937 * \note It uses non static methods API and data with auto storage * \note Not thread safe. Should construct on the stack at local scope */ using random_local = basic_random_local; } // namespace effolkronium #endif // #ifndef EFFOLKRONIUM_RANDOM_HPP