1288 lines
53 KiB
C++
1288 lines
53 KiB
C++
/*
|
|
______ ___ _ _______ ________ __
|
|
| ___ \/ _ \ | \ | | _ \ _ | \/ | Random for modern C++
|
|
| |_/ / /_\ \| \| | | | | | | | . . |
|
|
| /| _ || . ` | | | | | | | |\/| | version 1.3.1
|
|
| |\ \| | | || |\ | |/ /\ \_/ / | | |
|
|
\_| \_\_| |_/\_| \_/___/ \___/\_| |_/ https://github.com/effolkronium/random
|
|
|
|
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
|
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 <random>
|
|
#include <chrono> // timed seed
|
|
#include <type_traits>
|
|
#include <cassert>
|
|
#include <initializer_list>
|
|
#include <utility> // std::forward, std::declval
|
|
#include <algorithm> // std::shuffle, std::next, std::distance
|
|
#include <iterator> // std::begin, std::end, std::iterator_traits
|
|
#include <limits> // std::numeric_limits
|
|
#include <ostream>
|
|
#include <istream>
|
|
|
|
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<typename T>
|
|
struct is_uniform_int {
|
|
static constexpr bool value =
|
|
std::is_same<T, short>::value
|
|
|| std::is_same<T, int>::value
|
|
|| std::is_same<T, long>::value
|
|
|| std::is_same<T, long long>::value
|
|
|| std::is_same<T, unsigned short>::value
|
|
|| std::is_same<T, unsigned int>::value
|
|
|| std::is_same<T, unsigned long>::value
|
|
|| std::is_same<T, unsigned long long>::value;
|
|
};
|
|
|
|
/// True if type T is applicable by a std::uniform_real_distribution
|
|
template<typename T>
|
|
struct is_uniform_real {
|
|
static constexpr bool value =
|
|
std::is_same<T, float>::value
|
|
|| std::is_same<T, double>::value
|
|
|| std::is_same<T, long double>::value;
|
|
};
|
|
|
|
/// True if type T is plain byte
|
|
template<typename T>
|
|
struct is_byte {
|
|
static constexpr bool value =
|
|
std::is_same<T, signed char>::value
|
|
|| std::is_same<T, unsigned char>::value;
|
|
};
|
|
|
|
/// True if type T is plain number type
|
|
template<typename T>
|
|
struct is_supported_number {
|
|
static constexpr bool value =
|
|
is_byte <T>::value
|
|
|| is_uniform_real<T>::value
|
|
|| is_uniform_int <T>::value;
|
|
};
|
|
|
|
/// True if type T is character type
|
|
template<typename T>
|
|
struct is_supported_character {
|
|
static constexpr bool value =
|
|
std::is_same<T, char>::value
|
|
|| std::is_same<T, wchar_t>::value
|
|
|| std::is_same<T, char16_t>::value
|
|
|| std::is_same<T, char32_t>::value;
|
|
};
|
|
|
|
/// True if type T is iterator
|
|
template<typename T>
|
|
struct is_iterator {
|
|
private:
|
|
static char test( ... );
|
|
|
|
template <typename U,
|
|
typename = typename std::iterator_traits<U>::difference_type,
|
|
typename = typename std::iterator_traits<U>::pointer,
|
|
typename = typename std::iterator_traits<U>::reference,
|
|
typename = typename std::iterator_traits<U>::value_type,
|
|
typename = typename std::iterator_traits<U>::iterator_category
|
|
> static long test( U&& );
|
|
public:
|
|
static constexpr bool value = std::is_same<
|
|
decltype( test( std::declval<T>( ) ) ), 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::uintmax_t>( std::random_device{ }( ) ),
|
|
static_cast<std::uintmax_t>( 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<typename> class IntegerDist = std::uniform_int_distribution,
|
|
template<typename> 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<typename T>
|
|
using integer_dist_t = IntegerDist<T>;
|
|
|
|
/// Type of used real distribution
|
|
template<typename T>
|
|
using real_dist_t = RealDist<T>;
|
|
|
|
/// 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<typename Sseq>
|
|
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<typename CharT, typename Traits>
|
|
static void serialize( std::basic_ostream<CharT, Traits>& 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<typename CharT, typename Traits>
|
|
static void deserialize( std::basic_istream<CharT, Traits>& 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<typename T>
|
|
static typename std::enable_if<details::is_uniform_int<T>::value
|
|
, T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
T to = std::numeric_limits<T>::max( ) ) {
|
|
if( from < to ) // Allow range from higher to lower
|
|
return IntegerDist<T>{ from, to }( engine_instance( ) );
|
|
return IntegerDist<T>{ 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<typename T>
|
|
static typename std::enable_if<details::is_uniform_real<T>::value
|
|
, T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
T to = std::numeric_limits<T>::max( ) ) {
|
|
if( from < to ) // Allow range from higher to lower
|
|
return RealDist<T>{ from, to }( engine_instance( ) );
|
|
return RealDist<T>{ 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<typename T>
|
|
static typename std::enable_if<details::is_byte<T>::value
|
|
, T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
T to = std::numeric_limits<T>::max( ) ) {
|
|
// Choose between short and unsigned short for byte conversion
|
|
using short_t = typename std::conditional<std::is_signed<T>::value,
|
|
short, unsigned short>::type;
|
|
|
|
return static_cast<T>( get<short_t>( 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<Unsigned, Signed> 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<A, B>::type
|
|
>
|
|
static typename std::enable_if<
|
|
std::is_same<Key, common>::value
|
|
&& details::is_supported_number<A>::value
|
|
&& details::is_supported_number<B>::value
|
|
// Prevent implicit type conversion from singed to unsigned types
|
|
&& std::is_signed<A>::value != std::is_unsigned<B>::value
|
|
, C>::type get( A from = std::numeric_limits<A>::min( ),
|
|
B to = std::numeric_limits<B>::max( ) ) {
|
|
return get( static_cast<C>( from ), static_cast<C>( 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 T>
|
|
static typename std::enable_if<details::is_supported_character<T>::value
|
|
, T>::type get(T from = std::numeric_limits<T>::min(),
|
|
T to = std::numeric_limits<T>::max()) {
|
|
if (from < to) // Allow range from higher to lower
|
|
return static_cast<T>(IntegerDist<std::int64_t>{ static_cast<std::int64_t>(from), static_cast<std::int64_t>(to) }(engine_instance()));
|
|
return static_cast<T>(IntegerDist<std::int64_t>{ static_cast<std::int64_t>(to), static_cast<std::int64_t>(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<typename T>
|
|
static typename std::enable_if<std::is_same<T, bool>::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<typename T>
|
|
static T get( std::initializer_list<T> 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 InputIt>
|
|
static typename std::enable_if<details::is_iterator<InputIt>::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<InputIt>::difference_type;
|
|
return std::next( first, get<diff_t>( 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<typename Container>
|
|
static auto get( Container& container ) ->
|
|
typename std::enable_if<details::is_iterator<
|
|
decltype(std::begin(container))>::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<typename T, std::size_t N>
|
|
static T* get( T( &array )[ N ] ) {
|
|
return std::addressof( array[ get<std::size_t>( 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, typename... Args>
|
|
static typename Dist::result_type get( Args&&... args ) {
|
|
return Dist{ std::forward<Args>( 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<typename Dist>
|
|
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<typename RandomIt>
|
|
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<typename Container>
|
|
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<typename> class IntegerDist = std::uniform_int_distribution,
|
|
template<typename> 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<typename T>
|
|
using integer_dist_t = IntegerDist<T>;
|
|
|
|
/// Type of used real distribution
|
|
template<typename T>
|
|
using real_dist_t = RealDist<T>;
|
|
|
|
/// 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<typename Sseq>
|
|
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<typename CharT, typename Traits>
|
|
static void serialize( std::basic_ostream<CharT, Traits>& 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<typename CharT, typename Traits>
|
|
static void deserialize( std::basic_istream<CharT, Traits>& 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<typename T>
|
|
static typename std::enable_if<details::is_uniform_int<T>::value
|
|
, T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
T to = std::numeric_limits<T>::max( ) ) {
|
|
if( from < to ) // Allow range from higher to lower
|
|
return IntegerDist<T>{ from, to }( engine_instance( ) );
|
|
return IntegerDist<T>{ 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<typename T>
|
|
static typename std::enable_if<details::is_uniform_real<T>::value
|
|
, T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
T to = std::numeric_limits<T>::max( ) ) {
|
|
if( from < to ) // Allow range from higher to lower
|
|
return RealDist<T>{ from, to }( engine_instance( ) );
|
|
return RealDist<T>{ 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<typename T>
|
|
static typename std::enable_if<details::is_byte<T>::value
|
|
, T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
T to = std::numeric_limits<T>::max( ) ) {
|
|
// Choose between short and unsigned short for byte conversion
|
|
using short_t = typename std::conditional<std::is_signed<T>::value,
|
|
short, unsigned short>::type;
|
|
|
|
return static_cast<T>( get<short_t>( 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<Unsigned, Signed> 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<A, B>::type
|
|
>
|
|
static typename std::enable_if<
|
|
std::is_same<Key, common>::value
|
|
&& details::is_supported_number<A>::value
|
|
&& details::is_supported_number<B>::value
|
|
// Prevent implicit type conversion from singed to unsigned types
|
|
&& std::is_signed<A>::value != std::is_unsigned<B>::value
|
|
, C>::type get( A from = std::numeric_limits<A>::min( ),
|
|
B to = std::numeric_limits<B>::max( ) ) {
|
|
return get( static_cast<C>( from ), static_cast<C>( 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 T>
|
|
static typename std::enable_if<details::is_supported_character<T>::value
|
|
, T>::type get(T from = std::numeric_limits<T>::min(),
|
|
T to = std::numeric_limits<T>::max()) {
|
|
if (from < to) // Allow range from higher to lower
|
|
return static_cast<T>(IntegerDist<std::int64_t>{ static_cast<std::int64_t>(from), static_cast<std::int64_t>(to) }(engine_instance()));
|
|
return static_cast<T>(IntegerDist<std::int64_t>{ static_cast<std::int64_t>(to), static_cast<std::int64_t>(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<typename T>
|
|
static typename std::enable_if<std::is_same<T, bool>::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<typename T>
|
|
static T get( std::initializer_list<T> 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 InputIt>
|
|
static typename std::enable_if<details::is_iterator<InputIt>::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<InputIt>::difference_type;
|
|
return std::next( first, get<diff_t>( 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<typename Container>
|
|
static auto get( Container& container ) ->
|
|
typename std::enable_if<details::is_iterator<
|
|
decltype(std::begin(container))>::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<typename T, std::size_t N>
|
|
static T* get( T( &array )[ N ] ) {
|
|
return std::addressof( array[ get<std::size_t>( 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, typename... Args>
|
|
static typename Dist::result_type get( Args&&... args ) {
|
|
return Dist{ std::forward<Args>( 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<typename Dist>
|
|
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<typename RandomIt>
|
|
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<typename Container>
|
|
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<typename> class IntegerDist = std::uniform_int_distribution,
|
|
template<typename> 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<typename T>
|
|
using integer_dist_t = IntegerDist<T>;
|
|
|
|
/// Type of used real distribution
|
|
template<typename T>
|
|
using real_dist_t = RealDist<T>;
|
|
|
|
/// 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<typename Sseq>
|
|
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<typename CharT, typename Traits>
|
|
void serialize( std::basic_ostream<CharT, Traits>& 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<typename CharT, typename Traits>
|
|
void deserialize( std::basic_istream<CharT, Traits>& 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 T>
|
|
typename std::enable_if<details::is_uniform_int<T>::value
|
|
, T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
T to = std::numeric_limits<T>::max( ) ) {
|
|
if( from < to ) // Allow range from higher to lower
|
|
return IntegerDist<T>{ from, to }( m_engine );
|
|
return IntegerDist<T>{ 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 T>
|
|
typename std::enable_if<details::is_uniform_real<T>::value
|
|
, T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
T to = std::numeric_limits<T>::max( ) ) {
|
|
if( from < to ) // Allow range from higher to lower
|
|
return RealDist<T>{ from, to }( m_engine );
|
|
return RealDist<T>{ 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 T>
|
|
typename std::enable_if<details::is_byte<T>::value
|
|
, T>::type get( T from = std::numeric_limits<T>::min( ),
|
|
T to = std::numeric_limits<T>::max( ) ) {
|
|
// Choose between short and unsigned short for byte conversion
|
|
using short_t = typename std::conditional<std::is_signed<T>::value,
|
|
short, unsigned short>::type;
|
|
|
|
return static_cast<T>( get<short_t>( 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<Unsigned, Signed> 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<A, B>::type
|
|
>
|
|
typename std::enable_if<
|
|
std::is_same<Key, common>::value
|
|
&& details::is_supported_number<A>::value
|
|
&& details::is_supported_number<B>::value
|
|
// Prevent implicit type conversion from singed to unsigned types
|
|
&& std::is_signed<A>::value != std::is_unsigned<B>::value
|
|
, C>::type get( A from = std::numeric_limits<A>::min( ),
|
|
B to = std::numeric_limits<B>::max( ) ) {
|
|
return get( static_cast<C>( from ), static_cast<C>( 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 T>
|
|
typename std::enable_if<details::is_supported_character<T>::value
|
|
, T>::type get(T from = std::numeric_limits<T>::min(),
|
|
T to = std::numeric_limits<T>::max()) {
|
|
if (from < to) // Allow range from higher to lower
|
|
return static_cast<T>(IntegerDist<std::int64_t>{ static_cast<std::int64_t>(from), static_cast<std::int64_t>(to) }(m_engine));
|
|
return static_cast<T>(IntegerDist<std::int64_t>{ static_cast<std::int64_t>(to), static_cast<std::int64_t>(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 T>
|
|
typename std::enable_if<std::is_same<T, bool>::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<typename T>
|
|
T get( std::initializer_list<T> 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 InputIt>
|
|
typename std::enable_if<details::is_iterator<InputIt>::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<InputIt>::difference_type;
|
|
return std::next( first, get<diff_t>( 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<typename Container>
|
|
auto get( Container& container ) ->
|
|
typename std::enable_if<details::is_iterator<
|
|
decltype(std::begin(container))>::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<typename T, std::size_t N>
|
|
T* get( T( &array )[ N ] ) {
|
|
return std::addressof( array[ get<std::size_t>( 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, typename... Args>
|
|
typename Dist::result_type get( Args&&... args ) {
|
|
return Dist{ std::forward<Args>( 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>
|
|
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<typename RandomIt>
|
|
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<typename Container>
|
|
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<std::mt19937>;
|
|
|
|
/**
|
|
* \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<std::mt19937>;
|
|
|
|
/**
|
|
* \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<std::mt19937>;
|
|
|
|
} // namespace effolkronium
|
|
|
|
#endif // #ifndef EFFOLKRONIUM_RANDOM_HPP
|