/*============================================================================= Copyright (c) 2011-2019 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #ifndef SPROUT_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP #define SPROUT_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP #include #include #include #include #include #include #include #include #include #include #ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE # include #endif namespace sprout { namespace random { namespace detail { template struct generate_uniform_int_result { public: T result; Engine engine; }; template inline SPROUT_CXX14_CONSTEXPR T generate_uniform_int_cxx14( Engine& eng, T min_value, T max_value, std::true_type ) { typedef T result_type; typedef typename std::make_unsigned::type range_type; typedef typename Engine::result_type base_result; typedef typename std::make_unsigned::type base_unsigned; range_type const range = sprout::random::detail::subtract()(max_value, min_value); base_result const bmin = eng.min(); base_unsigned const brange = sprout::random::detail::subtract()(eng.max(), eng.min()); if (range == 0) { return min_value; } else if (brange == range) { base_unsigned v = sprout::random::detail::subtract()(static_cast(eng()), bmin); return sprout::random::detail::add()( static_cast(sprout::random::detail::subtract()(static_cast(eng()), bmin)), min_value ); } else if (brange < range) { for (; ; ) { range_type limit = range_type(); if (range == sprout::numeric_limits::max()) { limit = range / (range_type(brange) + 1); if (range % (range_type(brange) + 1) == range_type(brange)) { ++limit; } } else { limit = (range + 1) / (range_type(brange) + 1); } range_type result = range_type(0); range_type mult = range_type(1); while (mult <= limit) { result += static_cast(sprout::random::detail::subtract()(static_cast(eng()), bmin) * mult); if (mult * range_type(brange) == range - mult + 1) { return result; } mult *= range_type(brange) + range_type(1); } range_type result_increment = sprout::random::detail::generate_uniform_int_cxx14( eng, static_cast(0), static_cast(range / mult), std::true_type() ); if (sprout::numeric_limits::max() / mult < result_increment) { continue; } result_increment *= mult; result += result_increment; if (result < result_increment) { continue; } if (result > range) { continue; } return sprout::random::detail::add()(result, min_value); } } else { base_unsigned bucket_size = base_unsigned(); if (brange == sprout::numeric_limits::max()) { bucket_size = brange / (static_cast(range) + 1); if (brange % (static_cast(range) + 1) == static_cast(range)) { ++bucket_size; } } else { bucket_size = (brange + 1) / (static_cast(range) + 1); } for (; ; ) { base_unsigned result = sprout::random::detail::subtract()(static_cast(eng()), bmin) / bucket_size; if (result <= static_cast(range)) { return sprout::random::detail::add()(result, min_value); } } } } template inline SPROUT_CXX14_CONSTEXPR T generate_uniform_int_cxx14( Engine& eng, T min_value, T max_value, std::false_type ) { sprout::random::detail::uniform_int_float wrapper(eng); return sprout::random::detail::generate_uniform_int_cxx14(wrapper, min_value, max_value, std::true_type()); } template inline SPROUT_CXX14_CONSTEXPR T generate_uniform_int( Engine& eng, T min_value, T max_value ) { return sprout::random::detail::generate_uniform_int_cxx14( eng, min_value, max_value, std::is_integral() ); } #ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE template SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int(Engine const& eng, T min_value, T max_value, std::true_type); template SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int(Engine const& eng, T min_value, T max_value, std::true_type); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1( EngineResult const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size ); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1( EngineResult const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size ); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1_1( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size, BaseUnsigned result ) { typedef T result_type; return result <= static_cast(range) ? sprout::random::detail::generate_uniform_int_result{ sprout::random::detail::add()(result, min_value), eng } : sprout::random::detail::generate_uniform_int_true_3_1( eng(), min_value, range, bmin, brange, bucket_size ) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1_1( Engine const&, T, RangeType, BaseResult, BaseUnsigned, BaseUnsigned, BaseUnsigned ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1( EngineResult const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size ) { return sprout::random::detail::generate_uniform_int_true_3_1_1( sprout::random::next(rnd), min_value, range, bmin, brange, bucket_size, sprout::random::detail::subtract()(sprout::random::result(rnd), bmin) / bucket_size ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1( EngineResult const&, T, RangeType, BaseResult, BaseUnsigned, BaseUnsigned ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange ) { return sprout::random::detail::generate_uniform_int_true_3_1( eng(), min_value, range, bmin, brange, brange == sprout::numeric_limits::max() ? brange / (static_cast(range) + 1) + ( brange % (static_cast(range) + 1) == static_cast(range) ? 1 : 0 ) : (brange + 1) / (static_cast(range) + 1) ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3( Engine const&, T, RangeType, BaseResult, BaseUnsigned ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange ); template SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange ); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_4( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType result, RangeType result_increment ) { typedef T result_type; return result < result_increment || result > range ? sprout::random::detail::generate_uniform_int_true_2(eng, min_value, range, bmin, brange) : sprout::random::detail::generate_uniform_int_result{ random::detail::add()(result, min_value), eng } ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_4( Engine const&, T, RangeType, BaseResult, BaseUnsigned, RangeType, RangeType ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_3( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType result, RangeType mult, RangeType result_increment ) { return sprout::numeric_limits::max() / mult < result_increment ? sprout::random::detail::generate_uniform_int_true_2(eng, min_value, range, bmin, brange) : sprout::random::detail::generate_uniform_int_true_2_4( eng, min_value, range, bmin, brange, result + (result_increment * mult), result_increment * mult ) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_3( Engine const&, T, RangeType, BaseResult, BaseUnsigned, RangeType, RangeType, RangeType ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_2( Engine const&, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType result, RangeType mult, Result const& result_increment_base ) { return sprout::random::detail::generate_uniform_int_true_2_3( result_increment_base.engine, min_value, range, bmin, brange, result, mult, result_increment_base.result ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_2( Engine const&, T, RangeType, BaseResult, BaseUnsigned, RangeType, RangeType, Result const& ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result = RangeType(0), RangeType mult = RangeType(1) ); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result = RangeType(0), RangeType mult = RangeType(1) ); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1_1( EngineResult const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result, RangeType mult ) { return mult * RangeType(brange) == range - mult + 1 ? sprout::random::detail::generate_uniform_int_result{ static_cast( result + static_cast(sprout::random::detail::subtract()(sprout::random::result(rnd), bmin) * mult) ), sprout::random::next(rnd) } : sprout::random::detail::generate_uniform_int_true_2_1( sprout::random::next(rnd), min_value, range, bmin, brange, limit, result + static_cast(sprout::random::detail::subtract()(sprout::random::result(rnd), bmin) * mult), mult * (RangeType(brange) + RangeType(1)) ) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1_1( EngineResult const&, T, RangeType, BaseResult, BaseUnsigned, RangeType, RangeType, RangeType ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result, RangeType mult ) { return mult <= limit ? sprout::random::detail::generate_uniform_int_true_2_1_1( eng(), min_value, range, bmin, brange, limit, result, mult ) : sprout::random::detail::generate_uniform_int_true_2_2( eng, min_value, range, bmin, brange, result, mult, sprout::random::detail::generate_uniform_int( eng, static_cast(0), static_cast(range / mult), std::true_type() ) ) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1( Engine const&, T, RangeType, BaseResult, BaseUnsigned, RangeType, RangeType, RangeType ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange ) { return sprout::random::detail::generate_uniform_int_true_2_1( eng, min_value, range, bmin, brange, range == sprout::numeric_limits::max() ? range / (RangeType(brange) + 1) + ( range % (RangeType(brange) + 1) == RangeType(brange) ? 1 : 0 ) : (range + 1) / (RangeType(brange) + 1) ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2( Engine const&, T, RangeType, BaseResult, BaseUnsigned ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_1_1( EngineResult const& rnd, T min_value, BaseResult bmin ) { typedef T result_type; typedef typename std::make_unsigned::type base_unsigned; return sprout::random::detail::generate_uniform_int_result{ sprout::random::detail::add()( base_unsigned(sprout::random::detail::subtract()(sprout::random::result(rnd), bmin)), min_value ), sprout::random::next(rnd) }; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_1_1( EngineResult const&, T, BaseResult ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_1( Engine const& eng, T min_value, T, RangeType range, BaseResult bmin, BaseUnsigned brange ) { return range == 0 ? sprout::random::detail::generate_uniform_int_result{min_value, eng} : brange == range ? sprout::random::detail::generate_uniform_int_true_1_1(eng(), min_value, bmin) : brange < range ? sprout::random::detail::generate_uniform_int_true_2(eng, min_value, range, bmin, brange) : sprout::random::detail::generate_uniform_int_true_3(eng, min_value, range, bmin, brange) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_1( Engine const&, T, T, RangeType, BaseResult, BaseUnsigned ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( Engine const& eng, T min_value, T max_value, std::true_type ) { typedef T result_type; typedef typename std::make_unsigned::type range_type; typedef typename Engine::result_type base_result; typedef typename std::make_unsigned::type base_unsigned; return sprout::random::detail::generate_uniform_int_true_1( eng, min_value, max_value, range_type(sprout::random::detail::subtract()(max_value, min_value)), base_result(eng.min()), base_unsigned(sprout::random::detail::subtract()(eng.max(), eng.min())) ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( Engine const&, T, T, std::true_type ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_false_1(Result const& rnd) { return sprout::random::detail::generate_uniform_int_result{ rnd.result, rnd.engine.base() }; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_false_1(Result const& rnd) { return sprout::random::detail::generate_uniform_int_result{ rnd.result, rnd.engine.base() }; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( Engine const& eng, T min_value, T max_value, std::false_type ) { return sprout::random::detail::generate_uniform_int_false_1( sprout::random::detail::generate_uniform_int( sprout::random::detail::uniform_int_float(eng), min_value, max_value, std::true_type() ) ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( Engine const&, T, T, std::false_type ) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } #else template SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int(Engine const& eng, T min_value, T max_value, std::true_type); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1( EngineResult const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size ); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1_1( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size, BaseUnsigned result ) { typedef T result_type; return result <= static_cast(range) ? sprout::random::detail::generate_uniform_int_result{ sprout::random::detail::add()(result, min_value), eng } : sprout::random::detail::generate_uniform_int_true_3_1( eng(), min_value, range, bmin, brange, bucket_size ) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3_1( EngineResult const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size ) { return sprout::random::detail::generate_uniform_int_true_3_1_1( sprout::random::next(rnd), min_value, range, bmin, brange, bucket_size, sprout::random::detail::subtract()(sprout::random::result(rnd), bmin) / bucket_size ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_3( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange ) { return sprout::random::detail::generate_uniform_int_true_3_1( eng(), min_value, range, bmin, brange, brange == sprout::numeric_limits::max() ? brange / (static_cast(range) + 1) + ( brange % (static_cast(range) + 1) == static_cast(range) ? 1 : 0 ) : (brange + 1) / (static_cast(range) + 1) ); } template SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange ); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_4( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType result, RangeType result_increment ) { typedef T result_type; return result < result_increment || result > range ? sprout::random::detail::generate_uniform_int_true_2(eng, min_value, range, bmin, brange) : sprout::random::detail::generate_uniform_int_result{ random::detail::add()(result, min_value), eng } ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_3( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType result, RangeType mult, RangeType result_increment ) { return sprout::numeric_limits::max() / mult < result_increment ? sprout::random::detail::generate_uniform_int_true_2(eng, min_value, range, bmin, brange) : sprout::random::detail::generate_uniform_int_true_2_4( eng, min_value, range, bmin, brange, result + (result_increment * mult), result_increment * mult ) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_2( Engine const&, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType result, RangeType mult, Result const& result_increment_base ) { return sprout::random::detail::generate_uniform_int_true_2_3( result_increment_base.engine, min_value, range, bmin, brange, result, mult, result_increment_base.result ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result = RangeType(0), RangeType mult = RangeType(1) ); template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1_1( EngineResult const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result, RangeType mult ) { return mult * RangeType(brange) == range - mult + 1 ? sprout::random::detail::generate_uniform_int_result{ static_cast( result + static_cast(sprout::random::detail::subtract()(sprout::random::result(rnd), bmin) * mult) ), sprout::random::next(rnd) } : sprout::random::detail::generate_uniform_int_true_2_1( sprout::random::next(rnd), min_value, range, bmin, brange, limit, result + static_cast(sprout::random::detail::subtract()(sprout::random::result(rnd), bmin) * mult), mult * (RangeType(brange) + RangeType(1)) ) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2_1( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result, RangeType mult ) { return mult <= limit ? sprout::random::detail::generate_uniform_int_true_2_1_1( eng(), min_value, range, bmin, brange, limit, result, mult ) : sprout::random::detail::generate_uniform_int_true_2_2( eng, min_value, range, bmin, brange, result, mult, sprout::random::detail::generate_uniform_int( eng, static_cast(0), static_cast(range / mult), std::true_type() ) ) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_2( Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange ) { return sprout::random::detail::generate_uniform_int_true_2_1( eng, min_value, range, bmin, brange, range == sprout::numeric_limits::max() ? range / (RangeType(brange) + 1) + ( range % (RangeType(brange) + 1) == RangeType(brange) ? 1 : 0 ) : (range + 1) / (RangeType(brange) + 1) ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_1_1( EngineResult const& rnd, T min_value, BaseResult bmin ) { typedef T result_type; typedef typename std::make_unsigned::type base_unsigned; return sprout::random::detail::generate_uniform_int_result{ sprout::random::detail::add()( base_unsigned(sprout::random::detail::subtract()(sprout::random::result(rnd), bmin)), min_value ), sprout::random::next(rnd) }; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_true_1( Engine const& eng, T min_value, T, RangeType range, BaseResult bmin, BaseUnsigned brange ) { return range == 0 ? sprout::random::detail::generate_uniform_int_result{min_value, eng} : brange == range ? sprout::random::detail::generate_uniform_int_true_1_1(eng(), min_value, bmin) : brange < range ? sprout::random::detail::generate_uniform_int_true_2(eng, min_value, range, bmin, brange) : sprout::random::detail::generate_uniform_int_true_3(eng, min_value, range, bmin, brange) ; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( Engine const& eng, T min_value, T max_value, std::true_type ) { typedef T result_type; typedef typename std::make_unsigned::type range_type; typedef typename Engine::result_type base_result; typedef typename std::make_unsigned::type base_unsigned; return sprout::random::detail::generate_uniform_int_true_1( eng, min_value, max_value, range_type(sprout::random::detail::subtract()(max_value, min_value)), base_result(eng.min()), base_unsigned(sprout::random::detail::subtract()(eng.max(), eng.min())) ); } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int_false_1(Result const& rnd) { return sprout::random::detail::generate_uniform_int_result{ rnd.result, rnd.engine.base() }; } template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( Engine const& eng, T min_value, T max_value, std::false_type ) { return sprout::random::detail::generate_uniform_int_false_1( sprout::random::detail::generate_uniform_int( sprout::random::detail::uniform_int_float(eng), min_value, max_value, std::true_type() ) ); } #endif template inline SPROUT_CONSTEXPR sprout::random::detail::generate_uniform_int_result generate_uniform_int( Engine const& eng, T min_value, T max_value ) { return sprout::random::detail::generate_uniform_int( eng, min_value, max_value, std::is_integral() ); } } // namespace detail // // uniform_int_distribution // template class uniform_int_distribution { public: typedef IntType input_type; typedef IntType result_type; public: // // param_type // class param_type { public: typedef uniform_int_distribution distribution_type; private: IntType min_; IntType max_; public: SPROUT_CONSTEXPR param_type() : min_(0) , max_(sprout::numeric_limits::max()) {} param_type(param_type const&) = default; explicit SPROUT_CONSTEXPR param_type(IntType min_arg, IntType max_arg = sprout::numeric_limits::max()) : min_((SPROUT_ASSERT(min_arg <= max_arg), min_arg)) , max_(max_arg) {} SPROUT_CONSTEXPR IntType a() const SPROUT_NOEXCEPT { return min_; } SPROUT_CONSTEXPR IntType b() const SPROUT_NOEXCEPT { return max_; } template friend SPROUT_NON_CONSTEXPR std::basic_istream& operator>>( std::basic_istream& lhs, param_type& rhs ) { IntType min; IntType max; if (lhs >> min >> std::ws >> max) { if (min <= max) { rhs.min_ = min; rhs.max_ = max; } else { lhs.setstate(std::ios_base::failbit); } } return lhs; } template friend SPROUT_NON_CONSTEXPR std::basic_ostream& operator<<( std::basic_ostream& lhs, param_type const& rhs ) { return lhs << rhs.min_ << " " << rhs.max_; } friend SPROUT_CONSTEXPR bool operator==(param_type const& lhs, param_type const& rhs) SPROUT_NOEXCEPT { return lhs.min_ == rhs.min_ && lhs.max_ == rhs.max_; } friend SPROUT_CONSTEXPR bool operator!=(param_type const& lhs, param_type const& rhs) SPROUT_NOEXCEPT { return !(lhs == rhs); } }; private: IntType min_; IntType max_; private: template SPROUT_CONSTEXPR sprout::random::random_result generate(Result const& rnd) const { return sprout::random::random_result( rnd.result, rnd.engine, *this ); } public: SPROUT_CONSTEXPR uniform_int_distribution() SPROUT_NOEXCEPT : min_(0) , max_(sprout::numeric_limits::max()) {} uniform_int_distribution(uniform_int_distribution const&) = default; explicit SPROUT_CONSTEXPR uniform_int_distribution(IntType min_arg, IntType max_arg = sprout::numeric_limits::max()) : min_((SPROUT_ASSERT(min_arg <= max_arg), min_arg)) , max_(max_arg) {} explicit SPROUT_CONSTEXPR uniform_int_distribution(param_type const& parm) SPROUT_NOEXCEPT : min_(parm.a()) , max_(parm.b()) {} SPROUT_CONSTEXPR result_type a() const SPROUT_NOEXCEPT { return min_; } SPROUT_CONSTEXPR result_type b() const SPROUT_NOEXCEPT { return max_; } SPROUT_CONSTEXPR result_type min() const SPROUT_NOEXCEPT { return min_; } SPROUT_CONSTEXPR result_type max() const SPROUT_NOEXCEPT { return max_; } SPROUT_CXX14_CONSTEXPR void reset() SPROUT_NOEXCEPT {} SPROUT_CONSTEXPR param_type param() const SPROUT_NOEXCEPT { return param_type(min_, max_); } SPROUT_CXX14_CONSTEXPR void param(param_type const& parm) { min_ = parm.a(); max_ = parm.b(); } template SPROUT_CXX14_CONSTEXPR result_type operator()(Engine& eng) const { return sprout::random::detail::generate_uniform_int(eng, min_, max_); } template SPROUT_CONSTEXPR sprout::random::random_result const operator()(Engine const& eng) const { return generate(sprout::random::detail::generate_uniform_int(eng, min_, max_)); } template SPROUT_CXX14_CONSTEXPR result_type operator()(Engine& eng, param_type const& parm) const { return sprout::random::detail::generate_uniform_int(eng, parm.a(), parm.b()); } template SPROUT_CONSTEXPR sprout::random::random_result const operator()(Engine const& eng, param_type const& parm) const { return generate(sprout::random::detail::generate_uniform_int(eng, parm.a(), parm.b())); } template friend SPROUT_NON_CONSTEXPR std::basic_istream& operator>>( std::basic_istream& lhs, uniform_int_distribution& rhs ) { param_type parm; if (lhs >> parm) { rhs.param(parm); } return lhs; } template friend SPROUT_NON_CONSTEXPR std::basic_ostream& operator<<( std::basic_ostream& lhs, uniform_int_distribution const& rhs ) { return lhs << rhs.param(); } friend SPROUT_CONSTEXPR bool operator==(uniform_int_distribution const& lhs, uniform_int_distribution const& rhs) SPROUT_NOEXCEPT { return lhs.param() == rhs.param(); } friend SPROUT_CONSTEXPR bool operator!=(uniform_int_distribution const& lhs, uniform_int_distribution const& rhs) SPROUT_NOEXCEPT { return !(lhs == rhs); } }; } // namespace random using sprout::random::uniform_int_distribution; } // namespace sprout #endif // #ifndef SPROUT_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP