1344cef66SArthur O'Dwyer //===----------------------------------------------------------------------===// 2344cef66SArthur O'Dwyer // 3344cef66SArthur O'Dwyer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4344cef66SArthur O'Dwyer // See https://llvm.org/LICENSE.txt for license information. 5344cef66SArthur O'Dwyer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6344cef66SArthur O'Dwyer // 7344cef66SArthur O'Dwyer //===----------------------------------------------------------------------===// 8344cef66SArthur O'Dwyer 9344cef66SArthur O'Dwyer #ifndef _LIBCPP___RANDOM_SUBTRACT_WITH_CARRY_ENGINE_H 10344cef66SArthur O'Dwyer #define _LIBCPP___RANDOM_SUBTRACT_WITH_CARRY_ENGINE_H 11344cef66SArthur O'Dwyer 12344cef66SArthur O'Dwyer #include <__algorithm/equal.h> 13344cef66SArthur O'Dwyer #include <__algorithm/min.h> 14344cef66SArthur O'Dwyer #include <__config> 15e99c4906SNikolas Klauser #include <__cstddef/size_t.h> 16344cef66SArthur O'Dwyer #include <__random/is_seed_sequence.h> 17344cef66SArthur O'Dwyer #include <__random/linear_congruential_engine.h> 18d6832a61SLouis Dionne #include <__type_traits/enable_if.h> 19344cef66SArthur O'Dwyer #include <cstdint> 20344cef66SArthur O'Dwyer #include <iosfwd> 21344cef66SArthur O'Dwyer #include <limits> 22344cef66SArthur O'Dwyer 23344cef66SArthur O'Dwyer #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 24344cef66SArthur O'Dwyer # pragma GCC system_header 25344cef66SArthur O'Dwyer #endif 26344cef66SArthur O'Dwyer 27344cef66SArthur O'Dwyer _LIBCPP_PUSH_MACROS 28344cef66SArthur O'Dwyer #include <__undef_macros> 29344cef66SArthur O'Dwyer 30344cef66SArthur O'Dwyer _LIBCPP_BEGIN_NAMESPACE_STD 31344cef66SArthur O'Dwyer 32344cef66SArthur O'Dwyer template <class _UIntType, size_t __w, size_t __s, size_t __r> 33344cef66SArthur O'Dwyer class _LIBCPP_TEMPLATE_VIS subtract_with_carry_engine; 34344cef66SArthur O'Dwyer 35344cef66SArthur O'Dwyer template <class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 369783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI bool operator==(const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x, 37344cef66SArthur O'Dwyer const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __y); 38344cef66SArthur O'Dwyer 39344cef66SArthur O'Dwyer template <class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 409783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI bool operator!=(const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x, 41344cef66SArthur O'Dwyer const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __y); 42344cef66SArthur O'Dwyer 439783f28cSLouis Dionne template <class _CharT, class _Traits, class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 4480c7e93aSNikolas Klauser _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 459783f28cSLouis Dionne operator<<(basic_ostream<_CharT, _Traits>& __os, const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x); 46344cef66SArthur O'Dwyer 479783f28cSLouis Dionne template <class _CharT, class _Traits, class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 4880c7e93aSNikolas Klauser _LIBCPP_HIDE_FROM_ABI basic_istream<_CharT, _Traits>& 499783f28cSLouis Dionne operator>>(basic_istream<_CharT, _Traits>& __is, subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x); 50344cef66SArthur O'Dwyer 51344cef66SArthur O'Dwyer template <class _UIntType, size_t __w, size_t __s, size_t __r> 529783f28cSLouis Dionne class _LIBCPP_TEMPLATE_VIS subtract_with_carry_engine { 53344cef66SArthur O'Dwyer public: 54344cef66SArthur O'Dwyer // types 55344cef66SArthur O'Dwyer typedef _UIntType result_type; 56344cef66SArthur O'Dwyer 57344cef66SArthur O'Dwyer private: 58344cef66SArthur O'Dwyer result_type __x_[__r]; 59344cef66SArthur O'Dwyer result_type __c_; 60344cef66SArthur O'Dwyer size_t __i_; 61344cef66SArthur O'Dwyer 62344cef66SArthur O'Dwyer static _LIBCPP_CONSTEXPR const result_type _Dt = numeric_limits<result_type>::digits; 63344cef66SArthur O'Dwyer static_assert(0 < __w, "subtract_with_carry_engine invalid parameters"); 64344cef66SArthur O'Dwyer static_assert(__w <= _Dt, "subtract_with_carry_engine invalid parameters"); 65344cef66SArthur O'Dwyer static_assert(0 < __s, "subtract_with_carry_engine invalid parameters"); 66344cef66SArthur O'Dwyer static_assert(__s < __r, "subtract_with_carry_engine invalid parameters"); 679783f28cSLouis Dionne 68344cef66SArthur O'Dwyer public: 69344cef66SArthur O'Dwyer static _LIBCPP_CONSTEXPR const result_type _Min = 0; 709783f28cSLouis Dionne static _LIBCPP_CONSTEXPR const result_type _Max = 719783f28cSLouis Dionne __w == _Dt ? result_type(~0) : (result_type(1) << __w) - result_type(1); 72344cef66SArthur O'Dwyer static_assert(_Min < _Max, "subtract_with_carry_engine invalid parameters"); 73344cef66SArthur O'Dwyer 74344cef66SArthur O'Dwyer // engine characteristics 75*b69ddbc6SNikolas Klauser static inline _LIBCPP_CONSTEXPR const size_t word_size = __w; 76*b69ddbc6SNikolas Klauser static inline _LIBCPP_CONSTEXPR const size_t short_lag = __s; 77*b69ddbc6SNikolas Klauser static inline _LIBCPP_CONSTEXPR const size_t long_lag = __r; 789783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR result_type min() { return _Min; } 799783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR result_type max() { return _Max; } 80*b69ddbc6SNikolas Klauser static inline _LIBCPP_CONSTEXPR const result_type default_seed = 19780503u; 81344cef66SArthur O'Dwyer 82344cef66SArthur O'Dwyer // constructors and seeding functions 83344cef66SArthur O'Dwyer #ifndef _LIBCPP_CXX03_LANG 849783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI subtract_with_carry_engine() : subtract_with_carry_engine(default_seed) {} 859783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI explicit subtract_with_carry_engine(result_type __sd) { seed(__sd); } 86344cef66SArthur O'Dwyer #else 879783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI explicit subtract_with_carry_engine(result_type __sd = default_seed) { seed(__sd); } 88344cef66SArthur O'Dwyer #endif 894da76ea7SNikolas Klauser template <class _Sseq, __enable_if_t<__is_seed_sequence<_Sseq, subtract_with_carry_engine>::value, int> = 0> 909783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI explicit subtract_with_carry_engine(_Sseq& __q) { 919783f28cSLouis Dionne seed(__q); 929783f28cSLouis Dionne } 939783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI void seed(result_type __sd = default_seed) { 949783f28cSLouis Dionne seed(__sd, integral_constant<unsigned, 1 + (__w - 1) / 32>()); 959783f28cSLouis Dionne } 96475bd19eSNikolas Klauser template <class _Sseq, __enable_if_t<__is_seed_sequence<_Sseq, subtract_with_carry_engine>::value, int> = 0> 979783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI void seed(_Sseq& __q) { 989783f28cSLouis Dionne __seed(__q, integral_constant<unsigned, 1 + (__w - 1) / 32>()); 999783f28cSLouis Dionne } 100344cef66SArthur O'Dwyer 101344cef66SArthur O'Dwyer // generating functions 10283ce1397SNikolas Klauser _LIBCPP_HIDE_FROM_ABI result_type operator()(); 1039783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI void discard(unsigned long long __z) { 1049783f28cSLouis Dionne for (; __z; --__z) 1059783f28cSLouis Dionne operator()(); 1069783f28cSLouis Dionne } 107344cef66SArthur O'Dwyer 108344cef66SArthur O'Dwyer template <class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 1099783f28cSLouis Dionne friend bool operator==(const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x, 110344cef66SArthur O'Dwyer const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __y); 111344cef66SArthur O'Dwyer 112344cef66SArthur O'Dwyer template <class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 1139783f28cSLouis Dionne friend bool operator!=(const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x, 114344cef66SArthur O'Dwyer const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __y); 115344cef66SArthur O'Dwyer 1169783f28cSLouis Dionne template <class _CharT, class _Traits, class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 1179783f28cSLouis Dionne friend basic_ostream<_CharT, _Traits>& 1189783f28cSLouis Dionne operator<<(basic_ostream<_CharT, _Traits>& __os, const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x); 119344cef66SArthur O'Dwyer 1209783f28cSLouis Dionne template <class _CharT, class _Traits, class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 1219783f28cSLouis Dionne friend basic_istream<_CharT, _Traits>& 1229783f28cSLouis Dionne operator>>(basic_istream<_CharT, _Traits>& __is, subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x); 123344cef66SArthur O'Dwyer 124344cef66SArthur O'Dwyer private: 12583ce1397SNikolas Klauser _LIBCPP_HIDE_FROM_ABI void seed(result_type __sd, integral_constant<unsigned, 1>); 12683ce1397SNikolas Klauser _LIBCPP_HIDE_FROM_ABI void seed(result_type __sd, integral_constant<unsigned, 2>); 127344cef66SArthur O'Dwyer template <class _Sseq> 12883ce1397SNikolas Klauser _LIBCPP_HIDE_FROM_ABI void __seed(_Sseq& __q, integral_constant<unsigned, 1>); 129344cef66SArthur O'Dwyer template <class _Sseq> 13083ce1397SNikolas Klauser _LIBCPP_HIDE_FROM_ABI void __seed(_Sseq& __q, integral_constant<unsigned, 2>); 131344cef66SArthur O'Dwyer }; 132344cef66SArthur O'Dwyer 133344cef66SArthur O'Dwyer template <class _UIntType, size_t __w, size_t __s, size_t __r> 1349783f28cSLouis Dionne void subtract_with_carry_engine<_UIntType, __w, __s, __r>::seed(result_type __sd, integral_constant<unsigned, 1>) { 1359783f28cSLouis Dionne linear_congruential_engine<result_type, 40014u, 0u, 2147483563u> __e(__sd == 0u ? default_seed : __sd); 136344cef66SArthur O'Dwyer for (size_t __i = 0; __i < __r; ++__i) 137344cef66SArthur O'Dwyer __x_[__i] = static_cast<result_type>(__e() & _Max); 138344cef66SArthur O'Dwyer __c_ = __x_[__r - 1] == 0; 139344cef66SArthur O'Dwyer __i_ = 0; 140344cef66SArthur O'Dwyer } 141344cef66SArthur O'Dwyer 142344cef66SArthur O'Dwyer template <class _UIntType, size_t __w, size_t __s, size_t __r> 1439783f28cSLouis Dionne void subtract_with_carry_engine<_UIntType, __w, __s, __r>::seed(result_type __sd, integral_constant<unsigned, 2>) { 1449783f28cSLouis Dionne linear_congruential_engine<result_type, 40014u, 0u, 2147483563u> __e(__sd == 0u ? default_seed : __sd); 1459783f28cSLouis Dionne for (size_t __i = 0; __i < __r; ++__i) { 146344cef66SArthur O'Dwyer result_type __e0 = __e(); 1479783f28cSLouis Dionne __x_[__i] = static_cast<result_type>((__e0 + ((uint64_t)__e() << 32)) & _Max); 148344cef66SArthur O'Dwyer } 149344cef66SArthur O'Dwyer __c_ = __x_[__r - 1] == 0; 150344cef66SArthur O'Dwyer __i_ = 0; 151344cef66SArthur O'Dwyer } 152344cef66SArthur O'Dwyer 153344cef66SArthur O'Dwyer template <class _UIntType, size_t __w, size_t __s, size_t __r> 154344cef66SArthur O'Dwyer template <class _Sseq> 1559783f28cSLouis Dionne void subtract_with_carry_engine<_UIntType, __w, __s, __r>::__seed(_Sseq& __q, integral_constant<unsigned, 1>) { 156344cef66SArthur O'Dwyer const unsigned __k = 1; 157344cef66SArthur O'Dwyer uint32_t __ar[__r * __k]; 158344cef66SArthur O'Dwyer __q.generate(__ar, __ar + __r * __k); 159344cef66SArthur O'Dwyer for (size_t __i = 0; __i < __r; ++__i) 160344cef66SArthur O'Dwyer __x_[__i] = static_cast<result_type>(__ar[__i] & _Max); 161344cef66SArthur O'Dwyer __c_ = __x_[__r - 1] == 0; 162344cef66SArthur O'Dwyer __i_ = 0; 163344cef66SArthur O'Dwyer } 164344cef66SArthur O'Dwyer 165344cef66SArthur O'Dwyer template <class _UIntType, size_t __w, size_t __s, size_t __r> 166344cef66SArthur O'Dwyer template <class _Sseq> 1679783f28cSLouis Dionne void subtract_with_carry_engine<_UIntType, __w, __s, __r>::__seed(_Sseq& __q, integral_constant<unsigned, 2>) { 168344cef66SArthur O'Dwyer const unsigned __k = 2; 169344cef66SArthur O'Dwyer uint32_t __ar[__r * __k]; 170344cef66SArthur O'Dwyer __q.generate(__ar, __ar + __r * __k); 171344cef66SArthur O'Dwyer for (size_t __i = 0; __i < __r; ++__i) 1729783f28cSLouis Dionne __x_[__i] = static_cast<result_type>((__ar[2 * __i] + ((uint64_t)__ar[2 * __i + 1] << 32)) & _Max); 173344cef66SArthur O'Dwyer __c_ = __x_[__r - 1] == 0; 174344cef66SArthur O'Dwyer __i_ = 0; 175344cef66SArthur O'Dwyer } 176344cef66SArthur O'Dwyer 177344cef66SArthur O'Dwyer template <class _UIntType, size_t __w, size_t __s, size_t __r> 1789783f28cSLouis Dionne _UIntType subtract_with_carry_engine<_UIntType, __w, __s, __r>::operator()() { 179344cef66SArthur O'Dwyer const result_type& __xs = __x_[(__i_ + (__r - __s)) % __r]; 180344cef66SArthur O'Dwyer result_type& __xr = __x_[__i_]; 181344cef66SArthur O'Dwyer result_type __new_c = __c_ == 0 ? __xs < __xr : __xs != 0 ? __xs <= __xr : 1; 182344cef66SArthur O'Dwyer __xr = (__xs - __xr - __c_) & _Max; 183344cef66SArthur O'Dwyer __c_ = __new_c; 184344cef66SArthur O'Dwyer __i_ = (__i_ + 1) % __r; 185344cef66SArthur O'Dwyer return __xr; 186344cef66SArthur O'Dwyer } 187344cef66SArthur O'Dwyer 188344cef66SArthur O'Dwyer template <class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 1899783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI bool operator==(const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x, 1909783f28cSLouis Dionne const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __y) { 191344cef66SArthur O'Dwyer if (__x.__c_ != __y.__c_) 192344cef66SArthur O'Dwyer return false; 193344cef66SArthur O'Dwyer if (__x.__i_ == __y.__i_) 19477a00c0dSLouis Dionne return std::equal(__x.__x_, __x.__x_ + _Rp, __y.__x_); 1959783f28cSLouis Dionne if (__x.__i_ == 0 || __y.__i_ == 0) { 19677a00c0dSLouis Dionne size_t __j = std::min(_Rp - __x.__i_, _Rp - __y.__i_); 1979783f28cSLouis Dionne if (!std::equal(__x.__x_ + __x.__i_, __x.__x_ + __x.__i_ + __j, __y.__x_ + __y.__i_)) 198344cef66SArthur O'Dwyer return false; 199344cef66SArthur O'Dwyer if (__x.__i_ == 0) 20077a00c0dSLouis Dionne return std::equal(__x.__x_ + __j, __x.__x_ + _Rp, __y.__x_); 20177a00c0dSLouis Dionne return std::equal(__x.__x_, __x.__x_ + (_Rp - __j), __y.__x_ + __j); 202344cef66SArthur O'Dwyer } 2039783f28cSLouis Dionne if (__x.__i_ < __y.__i_) { 204344cef66SArthur O'Dwyer size_t __j = _Rp - __y.__i_; 2059783f28cSLouis Dionne if (!std::equal(__x.__x_ + __x.__i_, __x.__x_ + (__x.__i_ + __j), __y.__x_ + __y.__i_)) 206344cef66SArthur O'Dwyer return false; 2079783f28cSLouis Dionne if (!std::equal(__x.__x_ + (__x.__i_ + __j), __x.__x_ + _Rp, __y.__x_)) 208344cef66SArthur O'Dwyer return false; 2099783f28cSLouis Dionne return std::equal(__x.__x_, __x.__x_ + __x.__i_, __y.__x_ + (_Rp - (__x.__i_ + __j))); 210344cef66SArthur O'Dwyer } 211344cef66SArthur O'Dwyer size_t __j = _Rp - __x.__i_; 2129783f28cSLouis Dionne if (!std::equal(__y.__x_ + __y.__i_, __y.__x_ + (__y.__i_ + __j), __x.__x_ + __x.__i_)) 213344cef66SArthur O'Dwyer return false; 2149783f28cSLouis Dionne if (!std::equal(__y.__x_ + (__y.__i_ + __j), __y.__x_ + _Rp, __x.__x_)) 215344cef66SArthur O'Dwyer return false; 2169783f28cSLouis Dionne return std::equal(__y.__x_, __y.__x_ + __y.__i_, __x.__x_ + (_Rp - (__y.__i_ + __j))); 217344cef66SArthur O'Dwyer } 218344cef66SArthur O'Dwyer 219344cef66SArthur O'Dwyer template <class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 2209783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x, 2219783f28cSLouis Dionne const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __y) { 222344cef66SArthur O'Dwyer return !(__x == __y); 223344cef66SArthur O'Dwyer } 224344cef66SArthur O'Dwyer 2259783f28cSLouis Dionne template <class _CharT, class _Traits, class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 22680c7e93aSNikolas Klauser _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 2279783f28cSLouis Dionne operator<<(basic_ostream<_CharT, _Traits>& __os, const subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x) { 228344cef66SArthur O'Dwyer __save_flags<_CharT, _Traits> __lx(__os); 229344cef66SArthur O'Dwyer typedef basic_ostream<_CharT, _Traits> _Ostream; 230344cef66SArthur O'Dwyer __os.flags(_Ostream::dec | _Ostream::left); 231344cef66SArthur O'Dwyer _CharT __sp = __os.widen(' '); 232344cef66SArthur O'Dwyer __os.fill(__sp); 233344cef66SArthur O'Dwyer __os << __x.__x_[__x.__i_]; 234344cef66SArthur O'Dwyer for (size_t __j = __x.__i_ + 1; __j < _Rp; ++__j) 235344cef66SArthur O'Dwyer __os << __sp << __x.__x_[__j]; 236344cef66SArthur O'Dwyer for (size_t __j = 0; __j < __x.__i_; ++__j) 237344cef66SArthur O'Dwyer __os << __sp << __x.__x_[__j]; 238344cef66SArthur O'Dwyer __os << __sp << __x.__c_; 239344cef66SArthur O'Dwyer return __os; 240344cef66SArthur O'Dwyer } 241344cef66SArthur O'Dwyer 2429783f28cSLouis Dionne template <class _CharT, class _Traits, class _UInt, size_t _Wp, size_t _Sp, size_t _Rp> 24380c7e93aSNikolas Klauser _LIBCPP_HIDE_FROM_ABI basic_istream<_CharT, _Traits>& 2449783f28cSLouis Dionne operator>>(basic_istream<_CharT, _Traits>& __is, subtract_with_carry_engine<_UInt, _Wp, _Sp, _Rp>& __x) { 245344cef66SArthur O'Dwyer __save_flags<_CharT, _Traits> __lx(__is); 246344cef66SArthur O'Dwyer typedef basic_istream<_CharT, _Traits> _Istream; 247344cef66SArthur O'Dwyer __is.flags(_Istream::dec | _Istream::skipws); 248344cef66SArthur O'Dwyer _UInt __t[_Rp + 1]; 249344cef66SArthur O'Dwyer for (size_t __i = 0; __i < _Rp + 1; ++__i) 250344cef66SArthur O'Dwyer __is >> __t[__i]; 2519783f28cSLouis Dionne if (!__is.fail()) { 252344cef66SArthur O'Dwyer for (size_t __i = 0; __i < _Rp; ++__i) 253344cef66SArthur O'Dwyer __x.__x_[__i] = __t[__i]; 254344cef66SArthur O'Dwyer __x.__c_ = __t[_Rp]; 255344cef66SArthur O'Dwyer __x.__i_ = 0; 256344cef66SArthur O'Dwyer } 257344cef66SArthur O'Dwyer return __is; 258344cef66SArthur O'Dwyer } 259344cef66SArthur O'Dwyer 260344cef66SArthur O'Dwyer _LIBCPP_END_NAMESPACE_STD 261344cef66SArthur O'Dwyer 262344cef66SArthur O'Dwyer _LIBCPP_POP_MACROS 263344cef66SArthur O'Dwyer 264344cef66SArthur O'Dwyer #endif // _LIBCPP___RANDOM_SUBTRACT_WITH_CARRY_ENGINE_H 265