14824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 24824e7fdSDimitry Andric // 34824e7fdSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44824e7fdSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 54824e7fdSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64824e7fdSDimitry Andric // 74824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 84824e7fdSDimitry Andric 94824e7fdSDimitry Andric #ifndef _LIBCPP___RANDOM_SHUFFLE_ORDER_ENGINE_H 104824e7fdSDimitry Andric #define _LIBCPP___RANDOM_SHUFFLE_ORDER_ENGINE_H 114824e7fdSDimitry Andric 124824e7fdSDimitry Andric #include <__algorithm/equal.h> 134824e7fdSDimitry Andric #include <__config> 144824e7fdSDimitry Andric #include <__random/is_seed_sequence.h> 1506c3fb27SDimitry Andric #include <__type_traits/enable_if.h> 1606c3fb27SDimitry Andric #include <__type_traits/integral_constant.h> 1706c3fb27SDimitry Andric #include <__type_traits/is_convertible.h> 184824e7fdSDimitry Andric #include <__utility/move.h> 1906c3fb27SDimitry Andric #include <cstddef> 204824e7fdSDimitry Andric #include <cstdint> 214824e7fdSDimitry Andric #include <iosfwd> 224824e7fdSDimitry Andric 234824e7fdSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 244824e7fdSDimitry Andric # pragma GCC system_header 254824e7fdSDimitry Andric #endif 264824e7fdSDimitry Andric 274824e7fdSDimitry Andric _LIBCPP_PUSH_MACROS 284824e7fdSDimitry Andric #include <__undef_macros> 294824e7fdSDimitry Andric 304824e7fdSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 314824e7fdSDimitry Andric 324824e7fdSDimitry Andric template <uint64_t _Xp, uint64_t _Yp> 33*cb14a3feSDimitry Andric struct __ugcd { 344824e7fdSDimitry Andric static _LIBCPP_CONSTEXPR const uint64_t value = __ugcd<_Yp, _Xp % _Yp>::value; 354824e7fdSDimitry Andric }; 364824e7fdSDimitry Andric 374824e7fdSDimitry Andric template <uint64_t _Xp> 38*cb14a3feSDimitry Andric struct __ugcd<_Xp, 0> { 394824e7fdSDimitry Andric static _LIBCPP_CONSTEXPR const uint64_t value = _Xp; 404824e7fdSDimitry Andric }; 414824e7fdSDimitry Andric 424824e7fdSDimitry Andric template <uint64_t _Np, uint64_t _Dp> 43*cb14a3feSDimitry Andric class __uratio { 444824e7fdSDimitry Andric static_assert(_Dp != 0, "__uratio divide by 0"); 454824e7fdSDimitry Andric static _LIBCPP_CONSTEXPR const uint64_t __gcd = __ugcd<_Np, _Dp>::value; 46*cb14a3feSDimitry Andric 474824e7fdSDimitry Andric public: 484824e7fdSDimitry Andric static _LIBCPP_CONSTEXPR const uint64_t num = _Np / __gcd; 494824e7fdSDimitry Andric static _LIBCPP_CONSTEXPR const uint64_t den = _Dp / __gcd; 504824e7fdSDimitry Andric 514824e7fdSDimitry Andric typedef __uratio<num, den> type; 524824e7fdSDimitry Andric }; 534824e7fdSDimitry Andric 544824e7fdSDimitry Andric template <class _Engine, size_t __k> 55*cb14a3feSDimitry Andric class _LIBCPP_TEMPLATE_VIS shuffle_order_engine { 564824e7fdSDimitry Andric static_assert(0 < __k, "shuffle_order_engine invalid parameters"); 57*cb14a3feSDimitry Andric 584824e7fdSDimitry Andric public: 594824e7fdSDimitry Andric // types 604824e7fdSDimitry Andric typedef typename _Engine::result_type result_type; 614824e7fdSDimitry Andric 624824e7fdSDimitry Andric private: 634824e7fdSDimitry Andric _Engine __e_; 64bdd1243dSDimitry Andric result_type __v_[__k]; 65bdd1243dSDimitry Andric result_type __y_; 664824e7fdSDimitry Andric 674824e7fdSDimitry Andric public: 684824e7fdSDimitry Andric // engine characteristics 694824e7fdSDimitry Andric static _LIBCPP_CONSTEXPR const size_t table_size = __k; 704824e7fdSDimitry Andric 714824e7fdSDimitry Andric #ifdef _LIBCPP_CXX03_LANG 724824e7fdSDimitry Andric static const result_type _Min = _Engine::_Min; 734824e7fdSDimitry Andric static const result_type _Max = _Engine::_Max; 744824e7fdSDimitry Andric #else 754824e7fdSDimitry Andric static _LIBCPP_CONSTEXPR const result_type _Min = _Engine::min(); 764824e7fdSDimitry Andric static _LIBCPP_CONSTEXPR const result_type _Max = _Engine::max(); 774824e7fdSDimitry Andric #endif 784824e7fdSDimitry Andric static_assert(_Min < _Max, "shuffle_order_engine invalid parameters"); 79*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR result_type min() { return _Min; } 80*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR result_type max() { return _Max; } 814824e7fdSDimitry Andric 824824e7fdSDimitry Andric static _LIBCPP_CONSTEXPR const unsigned long long _Rp = _Max - _Min + 1ull; 834824e7fdSDimitry Andric 844824e7fdSDimitry Andric // constructors and seeding functions 85*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI shuffle_order_engine() { __init(); } 86*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit shuffle_order_engine(const _Engine& __e) : __e_(__e) { __init(); } 874824e7fdSDimitry Andric #ifndef _LIBCPP_CXX03_LANG 88*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit shuffle_order_engine(_Engine&& __e) : __e_(std::move(__e)) { __init(); } 894824e7fdSDimitry Andric #endif // _LIBCPP_CXX03_LANG 90*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit shuffle_order_engine(result_type __sd) : __e_(__sd) { __init(); } 91*cb14a3feSDimitry Andric template < 92*cb14a3feSDimitry Andric class _Sseq, 93*cb14a3feSDimitry Andric __enable_if_t<__is_seed_sequence<_Sseq, shuffle_order_engine>::value && !is_convertible<_Sseq, _Engine>::value, 94*cb14a3feSDimitry Andric int> = 0> 95*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit shuffle_order_engine(_Sseq& __q) : __e_(__q) { 96*cb14a3feSDimitry Andric __init(); 97*cb14a3feSDimitry Andric } 98*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI void seed() { 99*cb14a3feSDimitry Andric __e_.seed(); 100*cb14a3feSDimitry Andric __init(); 101*cb14a3feSDimitry Andric } 102*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI void seed(result_type __sd) { 103*cb14a3feSDimitry Andric __e_.seed(__sd); 104*cb14a3feSDimitry Andric __init(); 105*cb14a3feSDimitry Andric } 1065f757f3fSDimitry Andric template <class _Sseq, __enable_if_t<__is_seed_sequence<_Sseq, shuffle_order_engine>::value, int> = 0> 107*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI void seed(_Sseq& __q) { 108*cb14a3feSDimitry Andric __e_.seed(__q); 109*cb14a3feSDimitry Andric __init(); 110*cb14a3feSDimitry Andric } 1114824e7fdSDimitry Andric 1124824e7fdSDimitry Andric // generating functions 113*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type operator()() { return __eval(integral_constant<bool, _Rp != 0>()); } 114*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI void discard(unsigned long long __z) { 115*cb14a3feSDimitry Andric for (; __z; --__z) 116*cb14a3feSDimitry Andric operator()(); 117*cb14a3feSDimitry Andric } 1184824e7fdSDimitry Andric 1194824e7fdSDimitry Andric // property functions 120*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI const _Engine& base() const _NOEXCEPT { return __e_; } 1214824e7fdSDimitry Andric 1224824e7fdSDimitry Andric private: 1234824e7fdSDimitry Andric template <class _Eng, size_t _Kp> 124*cb14a3feSDimitry Andric friend bool operator==(const shuffle_order_engine<_Eng, _Kp>& __x, const shuffle_order_engine<_Eng, _Kp>& __y); 1254824e7fdSDimitry Andric 1264824e7fdSDimitry Andric template <class _Eng, size_t _Kp> 127*cb14a3feSDimitry Andric friend bool operator!=(const shuffle_order_engine<_Eng, _Kp>& __x, const shuffle_order_engine<_Eng, _Kp>& __y); 1284824e7fdSDimitry Andric 129*cb14a3feSDimitry Andric template <class _CharT, class _Traits, class _Eng, size_t _Kp> 130*cb14a3feSDimitry Andric friend basic_ostream<_CharT, _Traits>& 131*cb14a3feSDimitry Andric operator<<(basic_ostream<_CharT, _Traits>& __os, const shuffle_order_engine<_Eng, _Kp>& __x); 1324824e7fdSDimitry Andric 133*cb14a3feSDimitry Andric template <class _CharT, class _Traits, class _Eng, size_t _Kp> 134*cb14a3feSDimitry Andric friend basic_istream<_CharT, _Traits>& 135*cb14a3feSDimitry Andric operator>>(basic_istream<_CharT, _Traits>& __is, shuffle_order_engine<_Eng, _Kp>& __x); 1364824e7fdSDimitry Andric 137*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __init() { 1384824e7fdSDimitry Andric for (size_t __i = 0; __i < __k; ++__i) 139bdd1243dSDimitry Andric __v_[__i] = __e_(); 140bdd1243dSDimitry Andric __y_ = __e_(); 1414824e7fdSDimitry Andric } 1424824e7fdSDimitry Andric 143*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type __eval(false_type) { return __eval2(integral_constant<bool, __k & 1>()); } 144*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type __eval(true_type) { return __eval(__uratio<__k, _Rp>()); } 1454824e7fdSDimitry Andric 146*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type __eval2(false_type) { return __eval(__uratio<__k / 2, 0x8000000000000000ull>()); } 147*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type __eval2(true_type) { return __evalf<__k, 0>(); } 1484824e7fdSDimitry Andric 149*cb14a3feSDimitry Andric template <uint64_t _Np, 150*cb14a3feSDimitry Andric uint64_t _Dp, 151*cb14a3feSDimitry Andric __enable_if_t<(__uratio<_Np, _Dp>::num > 0xFFFFFFFFFFFFFFFFull / (_Max - _Min)), int> = 0> 152*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type __eval(__uratio<_Np, _Dp>) { 153*cb14a3feSDimitry Andric return __evalf<__uratio<_Np, _Dp>::num, __uratio<_Np, _Dp>::den>(); 154*cb14a3feSDimitry Andric } 1554824e7fdSDimitry Andric 156*cb14a3feSDimitry Andric template <uint64_t _Np, 157*cb14a3feSDimitry Andric uint64_t _Dp, 158*cb14a3feSDimitry Andric __enable_if_t<__uratio<_Np, _Dp>::num <= 0xFFFFFFFFFFFFFFFFull / (_Max - _Min), int> = 0> 159*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type __eval(__uratio<_Np, _Dp>) { 160*cb14a3feSDimitry Andric const size_t __j = static_cast<size_t>(__uratio<_Np, _Dp>::num * (__y_ - _Min) / __uratio<_Np, _Dp>::den); 161bdd1243dSDimitry Andric __y_ = __v_[__j]; 162bdd1243dSDimitry Andric __v_[__j] = __e_(); 163bdd1243dSDimitry Andric return __y_; 1644824e7fdSDimitry Andric } 1654824e7fdSDimitry Andric 1664824e7fdSDimitry Andric template <uint64_t __n, uint64_t __d> 167*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type __evalf() { 168*cb14a3feSDimitry Andric const double __fp = __d == 0 ? __n / (2. * 0x8000000000000000ull) : __n / (double)__d; 16906c3fb27SDimitry Andric const size_t __j = static_cast<size_t>(__fp * (__y_ - _Min)); 170bdd1243dSDimitry Andric __y_ = __v_[__j]; 171bdd1243dSDimitry Andric __v_[__j] = __e_(); 172bdd1243dSDimitry Andric return __y_; 1734824e7fdSDimitry Andric } 1744824e7fdSDimitry Andric }; 1754824e7fdSDimitry Andric 1764824e7fdSDimitry Andric template <class _Engine, size_t __k> 1774824e7fdSDimitry Andric _LIBCPP_CONSTEXPR const size_t shuffle_order_engine<_Engine, __k>::table_size; 1784824e7fdSDimitry Andric 1794824e7fdSDimitry Andric template <class _Eng, size_t _Kp> 180bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI bool 181*cb14a3feSDimitry Andric operator==(const shuffle_order_engine<_Eng, _Kp>& __x, const shuffle_order_engine<_Eng, _Kp>& __y) { 182*cb14a3feSDimitry Andric return __x.__y_ == __y.__y_ && std::equal(__x.__v_, __x.__v_ + _Kp, __y.__v_) && __x.__e_ == __y.__e_; 1834824e7fdSDimitry Andric } 1844824e7fdSDimitry Andric 1854824e7fdSDimitry Andric template <class _Eng, size_t _Kp> 186*cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI bool 187*cb14a3feSDimitry Andric operator!=(const shuffle_order_engine<_Eng, _Kp>& __x, const shuffle_order_engine<_Eng, _Kp>& __y) { 1884824e7fdSDimitry Andric return !(__x == __y); 1894824e7fdSDimitry Andric } 1904824e7fdSDimitry Andric 191*cb14a3feSDimitry Andric template <class _CharT, class _Traits, class _Eng, size_t _Kp> 192bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 193*cb14a3feSDimitry Andric operator<<(basic_ostream<_CharT, _Traits>& __os, const shuffle_order_engine<_Eng, _Kp>& __x) { 1944824e7fdSDimitry Andric __save_flags<_CharT, _Traits> __lx(__os); 1954824e7fdSDimitry Andric typedef basic_ostream<_CharT, _Traits> _Ostream; 1964824e7fdSDimitry Andric __os.flags(_Ostream::dec | _Ostream::left); 1974824e7fdSDimitry Andric _CharT __sp = __os.widen(' '); 1984824e7fdSDimitry Andric __os.fill(__sp); 199bdd1243dSDimitry Andric __os << __x.__e_ << __sp << __x.__v_[0]; 2004824e7fdSDimitry Andric for (size_t __i = 1; __i < _Kp; ++__i) 201bdd1243dSDimitry Andric __os << __sp << __x.__v_[__i]; 202bdd1243dSDimitry Andric return __os << __sp << __x.__y_; 2034824e7fdSDimitry Andric } 2044824e7fdSDimitry Andric 205*cb14a3feSDimitry Andric template <class _CharT, class _Traits, class _Eng, size_t _Kp> 206bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_istream<_CharT, _Traits>& 207*cb14a3feSDimitry Andric operator>>(basic_istream<_CharT, _Traits>& __is, shuffle_order_engine<_Eng, _Kp>& __x) { 2084824e7fdSDimitry Andric typedef typename shuffle_order_engine<_Eng, _Kp>::result_type result_type; 2094824e7fdSDimitry Andric __save_flags<_CharT, _Traits> __lx(__is); 2104824e7fdSDimitry Andric typedef basic_istream<_CharT, _Traits> _Istream; 2114824e7fdSDimitry Andric __is.flags(_Istream::dec | _Istream::skipws); 2124824e7fdSDimitry Andric _Eng __e; 21306c3fb27SDimitry Andric result_type __vp[_Kp + 1]; 2144824e7fdSDimitry Andric __is >> __e; 2154824e7fdSDimitry Andric for (size_t __i = 0; __i < _Kp + 1; ++__i) 21606c3fb27SDimitry Andric __is >> __vp[__i]; 217*cb14a3feSDimitry Andric if (!__is.fail()) { 2184824e7fdSDimitry Andric __x.__e_ = __e; 2194824e7fdSDimitry Andric for (size_t __i = 0; __i < _Kp; ++__i) 22006c3fb27SDimitry Andric __x.__v_[__i] = __vp[__i]; 22106c3fb27SDimitry Andric __x.__y_ = __vp[_Kp]; 2224824e7fdSDimitry Andric } 2234824e7fdSDimitry Andric return __is; 2244824e7fdSDimitry Andric } 2254824e7fdSDimitry Andric 2264824e7fdSDimitry Andric _LIBCPP_END_NAMESPACE_STD 2274824e7fdSDimitry Andric 2284824e7fdSDimitry Andric _LIBCPP_POP_MACROS 2294824e7fdSDimitry Andric 2304824e7fdSDimitry Andric #endif // _LIBCPP___RANDOM_SHUFFLE_ORDER_ENGINE_H 231