| #pragma once
|
|
|
| #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 random
|
| {
|
| namespace details {
|
| /// Key type for getting common type numbers or objects
|
| struct common{ };
|
|
|
| /// Key type for weighted random number generation
|
| struct weight{ };
|
|
|
| /// 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;
|
| };
|
|
|
| template <typename T>
|
| class has_reserve
|
| {
|
| private:
|
| template <typename C>
|
| static char test(...);
|
|
|
| template <typename C>
|
| static long test(decltype(&C::reserve));
|
| public:
|
| static constexpr bool value = std::is_same<
|
| decltype(test<T>(0)), long>::value;
|
| };
|
|
|
| template <typename T>
|
| class has_insert
|
| {
|
| private:
|
| template <typename C>
|
| static char test(...);
|
|
|
| template <typename C>
|
| static long test(decltype(&C::insert));
|
| public:
|
| static constexpr bool value = std::is_same<
|
| decltype(test<T>(0)), long>::value;
|
| };
|
|
|
| template<typename...>
|
| using void_t = void;
|
|
|
| template<typename Type, typename = void>
|
| struct is_map : public std::false_type {};
|
|
|
| template<typename Type>
|
| struct is_map<Type, void_t<typename Type::key_type, typename Type::mapped_type, typename Type::value_type>> : public std::true_type{};
|
|
|
| } // 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 Derived,
|
| 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_base {
|
| 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;
|
|
|
| /// Key type for weighted random number generation
|
| using weight = details::weight;
|
|
|
| /**
|
| * \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 signed to unsigned types
|
| */
|
| 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 signed 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 initializer_list
|
| * \param init_list initializer_list with values
|
| * \return Random value from initializer_list
|
| * \note Should be 1 or more elements in initializer_list
|
| * \note Warning! Elements in initializer_list can't be moved
|
| */
|
| 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 container filled with random values
|
| * \param from The first limit number of a random range
|
| * \param to The second limit number of a random range
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| * \note Container "reserve" method will be called before generation
|
| */
|
| template<template<typename...> class Container, typename A>
|
| static typename std::enable_if<
|
| details::has_reserve<Container<A>>::value
|
| , Container<A>>::type get(A from, A to, std::size_t size) {
|
| Container<A> container;
|
|
|
| container.reserve(size);
|
| for (std::size_t i = 0; i < size; ++i)
|
| container.insert(std::end(container), get(from, to));
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return container filled with random common_type values
|
| * \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
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| * \note Container "reserve" method will be called before generation
|
| */
|
| template<
|
| template<typename...> class Container,
|
| 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::has_reserve<Container<A>>::value
|
| , Container<C>>::type get(A start, B end, std::size_t size) {
|
| Container<C> container;
|
|
|
| container.reserve(size);
|
| for (std::size_t i = 0; i < size; ++i)
|
| container.insert(std::end(container), get<common>(start, end));
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return container filled with random values
|
| * \param from The first limit number of a random range
|
| * \param to The second limit number of a random range
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| */
|
| template<template<typename...> class Container, typename A>
|
| static typename std::enable_if<
|
| !details::has_reserve<Container<A>>::value
|
| , Container<A>>::type get(A start, A end, std::size_t size) {
|
| Container<A> container;
|
|
|
| for (std::size_t i = 0; i < size; ++i)
|
| container.insert(std::end(container), get(start, end));
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return container filled with random common_type values
|
| * \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
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| */
|
| template<
|
| template<typename...> class Container,
|
| 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::has_reserve<Container<C>>::value
|
| , Container<C>>::type get(A start, B end, std::size_t size) {
|
| Container<C> container;
|
|
|
| for (std::size_t i = 0; i < size; ++i)
|
| container.insert(std::end(container), get<common>(start, end));
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return array-like container filled with random values
|
| * \param from The first limit number of a random range
|
| * \param to The second limit number of a random range
|
| * \param N The number of elements in resulting container
|
| * \return Container filled with random values
|
| */
|
| template<template<typename AA, std::size_t NN, typename...> class Container, std::size_t N, typename A>
|
| static typename std::enable_if<
|
| !details::has_insert<Container<A, N>>::value
|
| , Container<A, N>>::type get(A start, A end) {
|
| Container<A, N> container = {{ 0 }};
|
|
|
| for (std::size_t i = 0; i < N; ++i)
|
| container[i] = get(start, end);
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return array-like container filled with random common_type values
|
| * \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
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| */
|
| template<
|
| template<typename AA, std::size_t NN, typename...> class Container,
|
| std::size_t N,
|
| 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::has_insert<Container<C, N>>::value
|
| , Container<C, N>>::type get(A start, B end) {
|
| Container<C, N> container = {{ 0 }};
|
|
|
| for (std::size_t i = 0; i < N; ++i)
|
| container[i] = get<common>(start, end);
|
|
|
| return 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 Type of custom distribution
|
| * \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 Custom distribution
|
| * \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 Return a random iterator from given map container by
|
| * utilizing the values of the map container as weights
|
| * for weighted random number generation
|
| * \param Key The Key type for this version of 'get' method
|
| * Type should be '(THIS_TYPE)::common' struct
|
| * \param map_container A container that has mapped_type,
|
| * value_type and key_type defined
|
| * \note return the end iterator if the iterator is empty or total weight is equals to sum
|
| */
|
| template<
|
| typename Key,
|
| class MapContainer
|
| >
|
| static auto get(const MapContainer& map_container) -> typename std::enable_if<
|
| details::is_map<MapContainer>::value &&
|
| details::is_iterator<decltype(std::begin(map_container))>::value &&
|
| !std::is_signed<typename MapContainer::mapped_type>::value &&
|
| std::is_same<Key, details::weight>::value,
|
| decltype(std::begin(map_container))>::type {
|
| using MappedType = typename MapContainer::mapped_type;
|
| using IteratorType = decltype(std::begin(map_container));
|
|
|
| MappedType total_weight = 0;
|
| for (IteratorType it = std::begin(map_container); it != std::end(map_container); ++it) {
|
| total_weight += it->second;
|
| }
|
| if(total_weight == MappedType(0)) return std::end(map_container);
|
|
|
| MappedType random_weight = get(MappedType(0), total_weight - 1);
|
| MappedType sum = 0;
|
|
|
| for(IteratorType it = std::begin(map_container); it != std::end(map_container); ++it)
|
| {
|
| sum += it->second;
|
| if(sum > random_weight) return it;
|
| }
|
| return std::end(map_container);
|
| }
|
|
|
| /**
|
| * \brief Return a random iterator from given map container by
|
| * utilizing the values of the map container as weights
|
| * for weighted random number generation
|
| * \param Key The Key type for this version of 'get' method
|
| * Type should be '(THIS_TYPE)::common' struct
|
| * \param map_container A container that has mapped_type,
|
| * value_type and key_type defined
|
| * \note return the end iterator if the iterator is empty
|
| */
|
| template<
|
| typename Key,
|
| class MapContainer
|
| >
|
| static auto get(const MapContainer& map_container) -> typename std::enable_if<
|
| details::is_map<MapContainer>::value &&
|
| details::is_iterator<decltype(std::begin(map_container))>::value &&
|
| details::is_uniform_real<typename MapContainer::mapped_type>::value &&
|
| std::is_same<Key, details::weight>::value,
|
| decltype(std::begin(map_container))>::type {
|
| using MappedType = typename MapContainer::mapped_type;
|
| using IteratorType = decltype(std::begin(map_container));
|
|
|
| MappedType total_weight = 0;
|
| for (IteratorType it = std::begin(map_container); it != std::end(map_container); ++it) {
|
| assert(it->second >= MappedType(0));
|
| total_weight += it->second;
|
| }
|
| if(total_weight == MappedType(0)) return std::end(map_container);
|
|
|
| MappedType random_weight = get(MappedType(0), std::nextafter(total_weight, (std::numeric_limits<MappedType>::min)( )));
|
| MappedType sum = 0;
|
|
|
| for(IteratorType it = std::begin(map_container); it != std::end(map_container); ++it)
|
| {
|
| sum += it->second;
|
| if(sum > random_weight) return it;
|
| }
|
| return std::end(map_container);
|
| }
|
|
|
| /**
|
| * \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 ) );
|
| }
|
| private:
|
| static Engine& engine_instance( ) {
|
| return Derived::engine();
|
| }
|
| };
|
|
|
| /**
|
| * \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_base<basic_random_static<Engine, Seeder,
|
| IntegerDist, RealDist, BoolDist>,
|
| Engine, Seeder, IntegerDist, RealDist, BoolDist> {
|
| public:
|
| /// 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;
|
|
|
| /// Key type for weighted random number generation
|
| using weight = details::weight;
|
|
|
| basic_random_static() = delete;
|
|
|
| /// return internal engine by copy
|
| static Engine get_engine( ) {
|
| return engine_instance( );
|
| }
|
|
|
| /// return internal engine by ref
|
| static Engine& engine() {
|
| return engine_instance();
|
| }
|
| private:
|
| /// 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_base<basic_random_thread_local<Engine, Seeder,
|
| IntegerDist, RealDist, BoolDist>,
|
| Engine, Seeder, IntegerDist, RealDist, BoolDist> {
|
| public:
|
| /// 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;
|
|
|
| /// Key type for weighted random number generation
|
| using weight = details::weight;
|
|
|
| basic_random_thread_local( ) = delete;
|
|
|
| /// return internal engine by copy
|
| static Engine get_engine( ) {
|
| return engine_instance( );
|
| }
|
|
|
| /// return internal engine by ref
|
| static Engine& engine() {
|
| return engine_instance();
|
| }
|
| private:
|
| /// 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 basic_random_base<basic_random_local<Engine, Seeder,
|
| IntegerDist, RealDist, BoolDist>,
|
| Engine, Seeder, IntegerDist, RealDist, BoolDist> {
|
| public:
|
| /// 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;
|
|
|
| /// Key type for weighted random number generation
|
| using weight = details::weight;
|
|
|
| /// 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 signed to unsigned types
|
| */
|
| 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 signed 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 initializer_list
|
| * \param init_list initializer_list with values
|
| * \return Random value from initializer_list
|
| * \note Should be 1 or more elements in initializer_list
|
| * \note Warning! Elements in initializer_list can't be moved
|
| */
|
| 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 container filled with random values
|
| * \param from The first limit number of a random range
|
| * \param to The second limit number of a random range
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| * \note Container "reserve" method will be called before generation
|
| */
|
| template<template<typename...> class Container, typename A>
|
| typename std::enable_if<
|
| details::has_reserve<Container<A>>::value
|
| , Container<A>>::type get(A from, A to, std::size_t size) {
|
| Container<A> container;
|
|
|
| container.reserve(size);
|
| for (std::size_t i = 0; i < size; ++i)
|
| container.insert(std::end(container), get(from, to));
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return container filled with random common_type values
|
| * \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
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| * \note Container "reserve" method will be called before generation
|
| */
|
| template<
|
| template<typename...> class Container,
|
| 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::has_reserve<Container<A>>::value
|
| , Container<C>>::type get(A start, B end, std::size_t size) {
|
| Container<C> container;
|
|
|
| container.reserve(size);
|
| for (std::size_t i = 0; i < size; ++i)
|
| container.insert(std::end(container), get<common>(start, end));
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return container filled with random values
|
| * \param from The first limit number of a random range
|
| * \param to The second limit number of a random range
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| */
|
| template<template<typename...> class Container, typename A>
|
| typename std::enable_if<
|
| !details::has_reserve<Container<A>>::value
|
| , Container<A>>::type get(A start, A end, std::size_t size) {
|
| Container<A> container;
|
|
|
| for (std::size_t i = 0; i < size; ++i)
|
| container.insert(std::end(container), get(start, end));
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return container filled with random common_type values
|
| * \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
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| */
|
| template<
|
| template<typename...> class Container,
|
| 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::has_reserve<Container<C>>::value
|
| , Container<C>>::type get(A start, B end, std::size_t size) {
|
| Container<C> container;
|
|
|
| for (std::size_t i = 0; i < size; ++i)
|
| container.insert(std::end(container), get<common>(start, end));
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return array-like container filled with random values
|
| * \param from The first limit number of a random range
|
| * \param to The second limit number of a random range
|
| * \param N The number of elements in resulting container
|
| * \return Container filled with random values
|
| */
|
| template<template<typename AA, std::size_t NN, typename...> class Container, std::size_t N, typename A>
|
| typename std::enable_if<
|
| !details::has_insert<Container<A, N>>::value
|
| , Container<A, N>>::type get(A start, A end) {
|
| Container<A, N> container = {{ 0 }};
|
|
|
| for (std::size_t i = 0; i < N; ++i)
|
| container[i] = get(start, end);
|
|
|
| return container;
|
| }
|
|
|
| /**
|
| * \brief Return array-like container filled with random common_type values
|
| * \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
|
| * \param size The number of elements in resulting container
|
| * \return Container filled with random values
|
| */
|
| template<
|
| template<typename AA, std::size_t NN, typename...> class Container,
|
| std::size_t N,
|
| 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::has_insert<Container<C, N>>::value
|
| , Container<C, N>>::type get(A start, B end) {
|
| Container<C, N> container = {{ 0 }};
|
|
|
| for (std::size_t i = 0; i < N; ++i)
|
| container[i] = get<common>(start, end);
|
|
|
| return 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 Type of custom distribution
|
| * \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 Custom distribution
|
| * \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 Return a random iterator from given map container by
|
| * utilizing the values of the map container as weights
|
| * for weighted random number generation
|
| * \param Key The Key type for this version of 'get' method
|
| * Type should be '(THIS_TYPE)::common' struct
|
| * \param map_container A container that has mapped_type,
|
| * value_type and key_type defined
|
| * \note return the end iterator if the iterator is empty or total weight is equals to sum
|
| */
|
| template<
|
| typename Key,
|
| class MapContainer
|
| >
|
| auto get(const MapContainer& map_container) -> typename std::enable_if<
|
| details::is_map<MapContainer>::value &&
|
| details::is_iterator<decltype(std::begin(map_container))>::value &&
|
| !std::is_signed<typename MapContainer::mapped_type>::value &&
|
| std::is_same<Key, details::weight>::value,
|
| decltype(std::begin(map_container))>::type {
|
| using MappedType = typename MapContainer::mapped_type;
|
| using IteratorType = decltype(std::begin(map_container));
|
|
|
| MappedType total_weight = 0;
|
| for (IteratorType it = std::begin(map_container); it != std::end(map_container); ++it) {
|
| total_weight += it->second;
|
| }
|
| if(total_weight == MappedType(0)) return std::end(map_container);
|
|
|
| MappedType random_weight = get(MappedType(0), total_weight - 1);
|
| MappedType sum = 0;
|
|
|
| for(IteratorType it = std::begin(map_container); it != std::end(map_container); ++it)
|
| {
|
| sum += it->second;
|
| if(sum > random_weight) return it;
|
| }
|
| return std::end(map_container);
|
| }
|
|
|
| /**
|
| * \brief Return a random iterator from given map container by
|
| * utilizing the values of the map container as weights
|
| * for weighted random number generation
|
| * \param Key The Key type for this version of 'get' method
|
| * Type should be '(THIS_TYPE)::common' struct
|
| * \param map_container A container that has mapped_type,
|
| * value_type and key_type defined
|
| * \note return the end iterator if the iterator is empty
|
| */
|
| template<
|
| typename Key,
|
| class MapContainer
|
| >
|
| auto get(const MapContainer& map_container) -> typename std::enable_if<
|
| details::is_map<MapContainer>::value &&
|
| details::is_iterator<decltype(std::begin(map_container))>::value &&
|
| details::is_uniform_real<typename MapContainer::mapped_type>::value &&
|
| std::is_same<Key, details::weight>::value,
|
| decltype(std::begin(map_container))>::type {
|
| using MappedType = typename MapContainer::mapped_type;
|
| using IteratorType = decltype(std::begin(map_container));
|
|
|
| MappedType total_weight = 0;
|
| for (IteratorType it = std::begin(map_container); it != std::end(map_container); ++it) {
|
| assert(it->second >= MappedType(0));
|
| total_weight += it->second;
|
| }
|
| if(total_weight == MappedType(0)) return std::end(map_container);
|
|
|
| MappedType random_weight = get(MappedType(0), std::nextafter(total_weight, (std::numeric_limits<MappedType>::min)( )));
|
| MappedType sum = 0;
|
|
|
| for(IteratorType it = std::begin(map_container); it != std::end(map_container); ++it)
|
| {
|
| sum += it->second;
|
| if(sum > random_weight) return it;
|
| }
|
| return std::end(map_container);
|
| }
|
|
|
| /**
|
| * \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;
|
| }
|
| private:
|
| /// 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{ }( ) };
|
| }
|
| private:
|
| /// 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 performance
|
| */
|
| 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 performance
|
| */
|
| 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 random
|
| |