From d6827318b395c61108d5509556695f13e2173448 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 04:15:23 -0700 Subject: [PATCH 01/13] Fix `&arr[size]` in subtract_with_carry_engine/mersenne_twister_engine::seed(). --- stl/inc/random | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 90ae36415a5..dcc85763986 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -1092,7 +1092,7 @@ public: template = 0> void seed(_Seed_seq& _Seq) { // reset sequence from seed sequence unsigned long _Arr[_Kx * _Rx]; - _Seq.generate(&_Arr[0], &_Arr[_Kx * _Rx]); + _Seq.generate(_STD begin(_Arr), _STD end(_Arr)); size_t _Idx0 = 0; for (size_t _Ix = 0; _Ix < _Rx; ++_Ix, _Idx0 += _Kx) { // pack _Kx words @@ -1487,7 +1487,7 @@ public: void seed(_Seed_seq& _Seq) { // reset sequence from seed sequence constexpr int _Kx = (_Wx + 31) / 32; unsigned long _Arr[_Kx * _Nx]; - _Seq.generate(&_Arr[0], &_Arr[_Kx * _Nx]); + _Seq.generate(_STD begin(_Arr), _STD end(_Arr)); int _Idx0 = 0; _Ty _Sum = 0; From 733f70d1973b879dc191a2054a2302b56ab2103f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 04:33:33 -0700 Subject: [PATCH 02/13] Move `_Kx` to be local to subtract_with_carry_engine::seed(). --- stl/inc/random | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index dcc85763986..e0a496d59df 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -1087,10 +1087,9 @@ public: _Mybase::seed(_Value); } - static constexpr int _Kx = (8 * sizeof(_Ty) + 31) / 32; - template = 0> void seed(_Seed_seq& _Seq) { // reset sequence from seed sequence + constexpr int _Kx = (8 * sizeof(_Ty) + 31) / 32; unsigned long _Arr[_Kx * _Rx]; _Seq.generate(_STD begin(_Arr), _STD end(_Arr)); From 3d09876e101948e8021d66111df1a8146a76e8ac Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 04:58:37 -0700 Subject: [PATCH 03/13] Overhaul _Swc_traits::_Get_wc() to be private, constexpr, and simplified. Manually tested: ``` template constexpr int old_get_wc() noexcept { int K; if constexpr (M == 0) { K = (8 * sizeof(T) + 31) / 32; } else { unsigned long long Val = 1ULL << 32; for (K = 1; 0 < Val && Val < M; ++K) { Val = Val << 32; } } return K; } template constexpr int new_get_wc() noexcept { if constexpr (M == 0) { return (8 * sizeof(T) + 31) / 32; } else if constexpr (M > (1ULL << 32)) { return 2; } else { return 1; } } template constexpr bool test() { return old_get_wc() == new_get_wc(); } static_assert(test<0>()); static_assert(test<1>()); static_assert(test<2>()); static_assert(test<(1ULL << 31)>()); static_assert(test<(1ULL << 32) - 2>()); static_assert(test<(1ULL << 32) - 1>()); static_assert(test<(1ULL << 32)>()); static_assert(test<(1ULL << 32) + 1>()); static_assert(test<(1ULL << 32) + 2>()); static_assert(test<(1ULL << 33)>()); static_assert(test<(1ULL << 63)>()); static_assert(test<0xFFFF'FFFF'FFFF'FFFFULL>()); C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /c meow.cpp meow.cpp C:\Temp> ``` --- stl/inc/random | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index e0a496d59df..302347addd4 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -959,26 +959,23 @@ struct _Swc_traits { // traits for subtract_with_carry generator static constexpr _Mod_t _Mod = _Mx; static constexpr _Ty _Max = static_cast<_Ty>(_Mx - 1); - static int _Get_wc() noexcept { // compute number of 32-bit words per element - int _Kx; - +private: + static constexpr int _Get_wc() noexcept { // compute number of 32-bit words per element if constexpr (_Mx == 0) { - _Kx = (8 * sizeof(_Ty) + 31) / 32; - } else { // compute number of 32-bit words required - unsigned long long _Val = 1ULL << 32; - for (_Kx = 1; 0 < _Val && _Val < _Mx; ++_Kx) { - _Val = _Val << 32; - } + return (8 * sizeof(_Ty) + 31) / 32; + } else if constexpr (_Mx > (1ULL << 32)) { + return 2; + } else { + return 1; } - - return _Kx; } +public: template static _Cy_t _Reset(_Gen& _Gx, _Ty* _Ax, bool _Readcy) { // set initial values of _Ax from generator _Gx // return value of _Cy from range if _Readcy is true, // otherwise compute from last value - int _Kx = _Get_wc(); + constexpr int _Kx = _Get_wc(); for (size_t _Ix = 0; _Ix < _Nw; ++_Ix) { // pack _Kx words _Ax[_Ix] = _Gx(); @@ -1011,7 +1008,7 @@ struct _Swc_traits { // traits for subtract_with_carry generator template static void _Write( basic_ostream<_Elem, _Traits>& _Ostr, const _Circ_buf<_Ty, _Nw>& _Buf, _Cy_t _Cy) { // write state to _Ostr - int _Kx = _Get_wc(); + constexpr int _Kx = _Get_wc(); for (size_t _Ix = 0; _Ix < _Nw; ++_Ix) { for (int _Jx = 0; _Jx < _Kx; ++_Jx) { // unpack into _Kx words From cb08cc24fe2da4f0ad9121f378f927913f983075 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 05:29:50 -0700 Subject: [PATCH 04/13] Fuse subtract_with_carry into subtract_with_carry_engine. We no longer need to suppress the deprecation warning. We inherit directly from _Swc_base now. (After TR1 removal, we can fuse that away too, which will be a much larger simplification.) Drop a pointless comment. We now directly say that _Traits is an _Swc_traits. subtract_with_carry's default constructor passed 0u to _Swc_base's constructor, so we do that. Cleanup: Simplify operator!=(). --- stl/inc/random | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 302347addd4..8060fc9f56b 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -1049,11 +1049,9 @@ public: subtract_with_carry(_Gen& _Gx) : _Mybase(_Gx) {} }; -_STL_DISABLE_DEPRECATED_WARNING _EXPORT_STD template class subtract_with_carry_engine - : private subtract_with_carry<_Ty, static_cast<_Ty>((_Ty{1} << (_Wx - 1)) << 1), _Sx, _Rx> { - // subtract_with_carry generator + : private _Swc_base<_Ty, _Sx, _Rx, _Swc_traits<_Ty, static_cast<_Ty>((_Ty{1} << (_Wx - 1)) << 1), _Rx>> { public: _RNG_REQUIRE_UINTTYPE(subtract_with_carry_engine, _Ty); @@ -1065,8 +1063,8 @@ public: static constexpr size_t short_lag = _Sx; static constexpr size_t long_lag = _Rx; - using _Mybase = subtract_with_carry<_Ty, _Mx, _Sx, _Rx>; - using _Traits = typename _Mybase::_Traits; + using _Traits = _Swc_traits<_Ty, _Mx, _Rx>; + using _Mybase = _Swc_base<_Ty, _Sx, _Rx, _Traits>; using result_type = _Ty; using _Mybase::default_seed; @@ -1076,7 +1074,7 @@ public: explicit subtract_with_carry_engine(_Ty _Xx0) : _Mybase(_Xx0) {} template = 0> - explicit subtract_with_carry_engine(_Seed_seq& _Seq) : _Mybase() { + explicit subtract_with_carry_engine(_Seed_seq& _Seq) : _Mybase(0u) { seed(_Seq); } @@ -1123,7 +1121,7 @@ public: #if !_HAS_CXX20 _NODISCARD friend bool operator!=( const subtract_with_carry_engine& _Left, const subtract_with_carry_engine& _Right) noexcept /* strengthened */ { - return static_cast(_Left) != static_cast(_Right); + return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -1173,7 +1171,6 @@ public: return _Istr; } }; -_STL_RESTORE_DEPRECATED_WARNING #if _HAS_TR1_NAMESPACE constexpr double _Cx_exp2(const int _Exp) noexcept { From 05fd750d04a3e01a30a15364e4569eceed995580 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 06:38:02 -0700 Subject: [PATCH 05/13] Make more subtract_with_carry_engine machinery private. --- stl/inc/random | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 8060fc9f56b..19f8a5b70a6 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -1052,19 +1052,22 @@ public: _EXPORT_STD template class subtract_with_carry_engine : private _Swc_base<_Ty, _Sx, _Rx, _Swc_traits<_Ty, static_cast<_Ty>((_Ty{1} << (_Wx - 1)) << 1), _Rx>> { +private: + static constexpr _Ty _Mx = static_cast<_Ty>((_Ty{1} << (_Wx - 1)) << 1); + + using _Traits = _Swc_traits<_Ty, _Mx, _Rx>; + using _Mybase = _Swc_base<_Ty, _Sx, _Rx, _Traits>; + public: _RNG_REQUIRE_UINTTYPE(subtract_with_carry_engine, _Ty); static_assert(0U < _Sx && _Sx < _Rx && 0 < _Wx && _Wx <= numeric_limits<_Ty>::digits, "invalid template argument for subtract_with_carry_engine"); - static constexpr _Ty _Mx = static_cast<_Ty>((_Ty{1} << (_Wx - 1)) << 1); static constexpr size_t word_size = _Wx; static constexpr size_t short_lag = _Sx; static constexpr size_t long_lag = _Rx; - using _Traits = _Swc_traits<_Ty, _Mx, _Rx>; - using _Mybase = _Swc_base<_Ty, _Sx, _Rx, _Traits>; using result_type = _Ty; using _Mybase::default_seed; From 9c0ca4018383834848b22a193efab55be86c0aa3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 06:20:43 -0700 Subject: [PATCH 06/13] Fuse mersenne_twister into mersenne_twister_engine. We no longer need to suppress the deprecation warning. We inherit directly from _Circ_buf now. That inheritance continues to be private, whereas mersenne_twister inherits from _Circ_buf publicly. We no longer need a _Mybase alias. When constructing `mersenne_twister_engine(_Seed_seq& _Seq)`, avoid redundantly calling `seed(default_seed)` before `seed(_Seq)`. `_WMSK` is a direct member now. Cleanup: Simplify operator!=(). Note that operator>>() for mersenne_twister calls `_Eng.seed(_Gen)` which is radically different from mersenne_twister_engine's `seed(_Seed_seq& _Seq)`. Accordingly I've inlined the old implementation (which directly loads the serialized values). operator<<() for mersenne_twister uses mersenne_twister::state_size as a bound. This is just _Nx, which I've chosen to use for increased symmetry with the other operator. _Refill_lower() etc. are private (same as before when they were inherited privately). --- stl/inc/random | 122 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 16 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 19f8a5b70a6..28229130f6a 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -1433,10 +1433,9 @@ protected: static constexpr int _M_mod_n = _Mx % _Nx; }; -_STL_DISABLE_DEPRECATED_WARNING _EXPORT_STD template -class mersenne_twister_engine : private mersenne_twister<_Ty, _Wx, _Nx, _Mx, _Rx, _Px, _Ux, _Sx, _Bx, _Tx, _Cx, _Lx> { +class mersenne_twister_engine : private _Circ_buf<_Ty, _Nx> { public: static constexpr unsigned long long _Max = (((1ULL << (_Wx - 1)) - 1) << 1) + 1; @@ -1447,7 +1446,6 @@ public: && _Dx <= _Max && _Fx <= _Max, "invalid template argument for mersenne_twister_engine"); - using _Mybase = mersenne_twister<_Ty, _Wx, _Nx, _Mx, _Rx, _Px, _Ux, _Sx, _Bx, _Tx, _Cx, _Lx>; using result_type = _Ty; static constexpr size_t word_size = _Wx; @@ -1466,17 +1464,26 @@ public: static constexpr result_type default_seed = 5489U; - mersenne_twister_engine() : _Mybase(default_seed, _Dx, _Fx) {} + mersenne_twister_engine() : _Dxval(_Dx) { + seed(default_seed); + } - explicit mersenne_twister_engine(result_type _Xx0) : _Mybase(_Xx0, _Dx, _Fx) {} + explicit mersenne_twister_engine(result_type _Xx0) : _Dxval(_Dx) { + seed(_Xx0); + } template = 0> - explicit mersenne_twister_engine(_Seed_seq& _Seq) : _Mybase(default_seed, _Dx, _Fx) { + explicit mersenne_twister_engine(_Seed_seq& _Seq) : _Dxval(_Dx) { seed(_Seq); } void seed(result_type _Xx0 = default_seed) { // set initial values from specified value - _Mybase::seed(_Xx0, _Fx); + _Ty _Prev = this->_Ax[0] = _Xx0 & _WMSK; + for (size_t _Ix = 1; _Ix < _Nx; ++_Ix) { + _Prev = this->_Ax[_Ix] = (_Ix + _Fx * (_Prev ^ (_Prev >> (_Wx - 2)))) & _WMSK; + } + + this->_Idx = _Nx; } template = 0> @@ -1493,7 +1500,7 @@ public: this->_Ax[_Ix] |= static_cast<_Ty>(_Arr[_Idx0 + _Jx]) << (32 * _Jx); } - this->_Ax[_Ix] &= this->_WMSK; + this->_Ax[_Ix] &= _WMSK; if (_Ix == 0) { _Sum = this->_Ax[_Ix] >> _Rx; @@ -1514,42 +1521,125 @@ public: } _NODISCARD static constexpr result_type(max)() noexcept /* strengthened */ { - return _Mybase::_WMSK; + return _WMSK; } _NODISCARD friend bool operator==( const mersenne_twister_engine& _Left, const mersenne_twister_engine& _Right) noexcept /* strengthened */ { - return static_cast(_Left) == static_cast(_Right); + return _Left._Equals(_Right); } #if !_HAS_CXX20 _NODISCARD friend bool operator!=( const mersenne_twister_engine& _Left, const mersenne_twister_engine& _Right) noexcept /* strengthened */ { - return static_cast(_Left) != static_cast(_Right); + return !(_Left == _Right); } #endif // !_HAS_CXX20 template friend basic_istream<_Elem, _S_Traits>& operator>>( basic_istream<_Elem, _S_Traits>& _Istr, mersenne_twister_engine& _Eng) { - return _Istr >> static_cast<_Mybase&>(_Eng); + _Wrap_istream<_Elem, _S_Traits, _Ty> _Gen(_Istr); + + for (size_t _Ix = 0; _Ix < _Nx; ++_Ix) { + _Eng._Ax[_Ix] = _Gen() & _WMSK; + } + + _Eng._Idx = _Nx; + + return _Istr; } template friend basic_ostream<_Elem, _S_Traits>& operator<<( basic_ostream<_Elem, _S_Traits>& _Ostr, const mersenne_twister_engine& _Eng) { - return _Ostr << static_cast(_Eng); + _Ostr << _Eng._At(0); + + for (size_t _Ix = 1; _Ix < _Nx; ++_Ix) { + _Ostr << ' ' << _Eng._At(_Ix); + } + + return _Ostr; } _NODISCARD result_type operator()() { - return _Mybase::operator()(); + if (this->_Idx == _Nx) { + _Refill_upper(); + } else if (2 * _Nx <= this->_Idx) { + _Refill_lower(); + } + + _Ty _Res = this->_Ax[this->_Idx++] & _WMSK; + _Res ^= (_Res >> _Ux) & _Dxval; + _Res ^= (_Res << _Sx) & _Bx; + _Res ^= (_Res << _Tx) & _Cx; + _Res ^= (_Res & _WMSK) >> _Lx; + return _Res; } void discard(unsigned long long _Nskip) { - _Mybase::discard(_Nskip); + for (; 0 < _Nskip; --_Nskip) { + (void) (*this)(); + } + } + +private: + _Post_satisfies_(this->_Idx == 0) void _Refill_lower() { + // compute values for the lower half of the history array + constexpr size_t _Wrap_bound_one = _Nx - _One_mod_n; + constexpr size_t _Wrap_bound_m = _Nx - _M_mod_n; + + if constexpr (_M_mod_n == 0) { + for (size_t _Ix = 0; _Ix < _Wrap_bound_one; ++_Ix) { // fill in values + const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix + _Nx + _One_mod_n] & _LMSK); + this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix + _Nx + _M_mod_n]; + } + + if constexpr (_One_mod_n == 1) { // fill in _Ax[_Nx - 1] + constexpr size_t _Ix = _Wrap_bound_one; + + const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix - _Nx + _One_mod_n] & _LMSK); + this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix + _Nx + _M_mod_n]; + } + } else { + for (size_t _Ix = 0; _Ix < _Wrap_bound_m; ++_Ix) { // fill in lower region + const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix + _Nx + _One_mod_n] & _LMSK); + this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix + _Nx + _M_mod_n]; + } + + for (size_t _Ix = _Wrap_bound_m; _Ix < _Wrap_bound_one; ++_Ix) { + // fill in upper region (avoids modulus operation) + const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix + _Nx + _One_mod_n] & _LMSK); + this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix - _Nx + _M_mod_n]; + } + + if constexpr (_One_mod_n == 1) { // fill in _Ax[_Nx - 1] + constexpr size_t _Ix = _Wrap_bound_one; + + const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix - _Nx + _One_mod_n] & _LMSK); + this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix - _Nx + _M_mod_n]; + } + } + + this->_Idx = 0; + } + + void _Refill_upper() { // compute values for the upper half of the history array + for (size_t _Ix = _Nx; _Ix < 2 * _Nx; ++_Ix) { // fill in values + const _Ty _Tmp = (this->_Ax[_Ix - _Nx] & _HMSK) | (this->_Ax[_Ix - _Nx + _One_mod_n] & _LMSK); + this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix - _Nx + _M_mod_n]; + } } + + _Ty _Dxval; + + static constexpr _Ty _WMSK = ~((~_Ty{0} << (_Wx - 1)) << 1); + static constexpr _Ty _HMSK = (_WMSK << _Rx) & _WMSK; + static constexpr _Ty _LMSK = ~_HMSK & _WMSK; + + static constexpr int _One_mod_n = 1 % _Nx; // either 0 or 1 + static constexpr int _M_mod_n = _Mx % _Nx; }; -_STL_RESTORE_DEPRECATED_WARNING template class _DEPRECATE_TR1_RANDOM discard_block { // discard_block compound engine From 0c9aaeffa296cf3a566e3e4930b47f4acbaf2f70 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 06:39:39 -0700 Subject: [PATCH 07/13] Make more mersenne_twister_engine machinery private. --- stl/inc/random | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/random b/stl/inc/random index 28229130f6a..4ca36debcc1 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -1436,9 +1436,10 @@ protected: _EXPORT_STD template class mersenne_twister_engine : private _Circ_buf<_Ty, _Nx> { -public: +private: static constexpr unsigned long long _Max = (((1ULL << (_Wx - 1)) - 1) << 1) + 1; +public: _RNG_REQUIRE_UINTTYPE(mersenne_twister_engine, _Ty); static_assert(0 < _Mx && _Mx <= _Nx && 2U < _Wx && _Rx <= _Wx && _Ux <= _Wx && _Sx <= _Wx && _Tx <= _Wx From 89de79cfe029893e86fb17057d6e802769901ade Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 06:42:48 -0700 Subject: [PATCH 08/13] mersenne_twister_engine: _Dxval is always _Dx; hardcode it, and note that the data member is retained for bincompat. --- stl/inc/random | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 4ca36debcc1..8da59be7137 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -1465,16 +1465,16 @@ public: static constexpr result_type default_seed = 5489U; - mersenne_twister_engine() : _Dxval(_Dx) { + mersenne_twister_engine() { seed(default_seed); } - explicit mersenne_twister_engine(result_type _Xx0) : _Dxval(_Dx) { + explicit mersenne_twister_engine(result_type _Xx0) { seed(_Xx0); } template = 0> - explicit mersenne_twister_engine(_Seed_seq& _Seq) : _Dxval(_Dx) { + explicit mersenne_twister_engine(_Seed_seq& _Seq) { seed(_Seq); } @@ -1571,7 +1571,7 @@ public: } _Ty _Res = this->_Ax[this->_Idx++] & _WMSK; - _Res ^= (_Res >> _Ux) & _Dxval; + _Res ^= (_Res >> _Ux) & _Dx; _Res ^= (_Res << _Sx) & _Bx; _Res ^= (_Res << _Tx) & _Cx; _Res ^= (_Res & _WMSK) >> _Lx; @@ -1632,7 +1632,7 @@ private: } } - _Ty _Dxval; + _Ty _Dxval{_Dx}; // TRANSITION, ABI: _Dxval must be initialized to _Dx but is unused by the current implementation static constexpr _Ty _WMSK = ~((~_Ty{0} << (_Wx - 1)) << 1); static constexpr _Ty _HMSK = (_WMSK << _Rx) & _WMSK; From dab1204c628ef8a9ce960d245c8e9fa6476b0aba Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 07:23:49 -0700 Subject: [PATCH 09/13] Fuse _Discard_block_base into discard_block_engine. This was very close to the finish line. Instead of switching between the old discard_block and the newer _Discard_block_base (introduced by GH 4066), simply make _Nx's type vary. Introduce _Block_type (commented with TRANSITION, ABI) and static_cast to avoid sign-comparison warnings, which was previously achieved by switching between the base classes. We know the constants are within range, so this is value-preserving. As usual, we no longer need to suppress the deprecation warning. --- stl/inc/random | 58 +++++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 8da59be7137..ab11701ac85 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -1819,55 +1819,66 @@ private: size_t _Nx; }; -_STL_DISABLE_DEPRECATED_WARNING _EXPORT_STD template -class discard_block_engine // discard_block_engine compound engine - : private conditional_t<_Px <= INT_MAX, discard_block<_Engine, static_cast(_Px), static_cast(_Rx)>, - _Discard_block_base<_Engine, _Px, _Rx>> { +class discard_block_engine { +private: + using _Block_type = conditional_t<_Px <= INT_MAX, int, size_t>; // TRANSITION, ABI: Should always be size_t + public: static_assert(0 < _Rx && _Rx <= _Px, "invalid template argument for discard_block_engine"); - using _Mybase = conditional_t<_Px <= INT_MAX, discard_block<_Engine, static_cast(_Px), static_cast(_Rx)>, - _Discard_block_base<_Engine, _Px, _Rx>>; using result_type = typename _Engine::result_type; static constexpr size_t block_size = _Px; static constexpr size_t used_block = _Rx; - discard_block_engine() : _Mybase() {} + discard_block_engine() : _Eng(), _Nx(0) {} - explicit discard_block_engine(const _Engine& _Ex) : _Mybase(_Ex) {} + explicit discard_block_engine(const _Engine& _Ex) : _Eng(_Ex), _Nx(0) {} - explicit discard_block_engine(_Engine&& _Ex) : _Mybase(_STD move(_Ex)) {} + explicit discard_block_engine(_Engine&& _Ex) : _Eng(_STD move(_Ex)), _Nx(0) {} - explicit discard_block_engine(result_type _Xx0) : _Mybase(_Xx0) {} + explicit discard_block_engine(result_type _Xx0) : _Eng(_Xx0), _Nx(0) {} template = 0> - explicit discard_block_engine(_Seed_seq& _Seq) : _Mybase(_Seq) {} + explicit discard_block_engine(_Seed_seq& _Seq) : _Eng(_Seq), _Nx(0) {} void seed() { - _Mybase::seed(); + _Eng.seed(); + _Nx = 0; } void seed(result_type _Xx0) { - _Mybase::seed(_Xx0); + _Eng.seed(_Xx0); + _Nx = 0; } template = 0> void seed(_Seed_seq& _Seq) { - _Mybase::seed(_Seq); + _Eng.seed(_Seq); + _Nx = 0; } _NODISCARD const _Engine& base() const noexcept { - return _Mybase::base(); + return _Eng; } _NODISCARD result_type operator()() { - return _Mybase::operator()(); + if (static_cast<_Block_type>(_Rx) <= _Nx) { // discard values + while (_Nx++ < static_cast<_Block_type>(_Px)) { + (void) _Eng(); + } + + _Nx = 0; + } + ++_Nx; + return _Eng(); } void discard(unsigned long long _Nskip) { - _Mybase::discard(_Nskip); + for (; 0 < _Nskip; --_Nskip) { + (void) (*this)(); + } } _NODISCARD static constexpr result_type(min)() noexcept /* strengthened */ { @@ -1879,27 +1890,30 @@ public: } _NODISCARD friend bool operator==(const discard_block_engine& _Left, const discard_block_engine& _Right) { - return static_cast(_Left) == static_cast(_Right); + return _Left._Eng == _Right._Eng && _Left._Nx == _Right._Nx; } #if !_HAS_CXX20 _NODISCARD friend bool operator!=(const discard_block_engine& _Left, const discard_block_engine& _Right) { - return static_cast(_Left) != static_cast(_Right); + return !(_Left == _Right); } #endif // !_HAS_CXX20 template friend basic_istream<_Elem, _Traits>& operator>>(basic_istream<_Elem, _Traits>& _Istr, discard_block_engine& _Eng) { - return _Istr >> static_cast<_Mybase&>(_Eng); + return _Istr >> _Eng._Eng >> _Eng._Nx; } template friend basic_ostream<_Elem, _Traits>& operator<<( basic_ostream<_Elem, _Traits>& _Ostr, const discard_block_engine& _Eng) { - return _Ostr << static_cast(_Eng); + return _Ostr << _Eng._Eng << ' ' << _Eng._Nx; } + +private: + _Engine _Eng; + _Block_type _Nx; }; -_STL_RESTORE_DEPRECATED_WARNING _EXPORT_STD template class independent_bits_engine { // independent_bits_engine compound engine From 94a4a6f37f0b070144b9d459b5be949025ebd005 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 07:29:00 -0700 Subject: [PATCH 10/13] Remove _Discard_block_base. This is a separate commit to improve the previous commit's diff. --- stl/inc/random | 81 -------------------------------------------------- 1 file changed, 81 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index ab11701ac85..69a1d071257 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -1738,87 +1738,6 @@ private: int _Nx; }; -template -class _Discard_block_base { // TRANSITION, ABI, should be merged into discard_block_engine -public: - using result_type = typename _Engine::result_type; - - _Discard_block_base() : _Eng(), _Nx(0) {} - - explicit _Discard_block_base(const _Engine& _Ex) : _Eng(_Ex), _Nx(0) {} - - explicit _Discard_block_base(_Engine&& _Ex) : _Eng(_STD move(_Ex)), _Nx(0) {} - - explicit _Discard_block_base(result_type _Seed) : _Eng(_Seed), _Nx(0) {} - - template = 0> - explicit _Discard_block_base(_Seed_seq& _Seq) : _Eng(_Seq), _Nx(0) {} - - void seed() { // seed engine from default value - _Eng.seed(); - _Nx = 0; - } - - void seed(result_type _Xx0) { // seed engine from specified value - _Eng.seed(_Xx0); - _Nx = 0; - } - - template = 0> - void seed(_Seed_seq& _Seq) { // seed engine from seed sequence - _Eng.seed(_Seq); - _Nx = 0; - } - - _NODISCARD const _Engine& base() const noexcept { - return _Eng; - } - - _NODISCARD result_type operator()() { - if (_Rx <= _Nx) { // discard values - while (_Nx++ < _Px) { - (void) _Eng(); - } - - _Nx = 0; - } - ++_Nx; - return _Eng(); - } - - void discard(unsigned long long _Nskip) { // discard _Nskip elements - for (; 0 < _Nskip; --_Nskip) { - (void) (*this)(); - } - } - - _NODISCARD friend bool operator==(const _Discard_block_base& _Left, const _Discard_block_base& _Right) { - return _Left._Eng == _Right._Eng && _Left._Nx == _Right._Nx; - } - -#if !_HAS_CXX20 - _NODISCARD friend bool operator!=(const _Discard_block_base& _Left, const _Discard_block_base& _Right) { - return !(_Left == _Right); - } -#endif // !_HAS_CXX20 - - template - friend basic_istream<_Elem, _Traits>& operator>>( - basic_istream<_Elem, _Traits>& _Istr, _Discard_block_base& _Eng) { // read state from _Istr - return _Istr >> _Eng._Eng >> _Eng._Nx; - } - - template - friend basic_ostream<_Elem, _Traits>& operator<<( - basic_ostream<_Elem, _Traits>& _Ostr, const _Discard_block_base& _Eng) { // write state to _Ostr - return _Ostr << _Eng._Eng << ' ' << _Eng._Nx; - } - -private: - _Engine _Eng; - size_t _Nx; -}; - _EXPORT_STD template class discard_block_engine { private: From ea808397ced4f6b1bc9484342df8dabd53791932 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 07:56:58 -0700 Subject: [PATCH 11/13] Fuse uniform_int into uniform_int_distribution. _Eval can always use _Rng_from_urng_v2 for Standard engines. Make equality slightly more efficient in debug mode. --- stl/inc/random | 115 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 27 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 69a1d071257..a3a2fb24648 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -2372,89 +2372,119 @@ private: param_type _Par; }; -_STL_DISABLE_DEPRECATED_WARNING _EXPORT_STD template -class uniform_int_distribution : private uniform_int<_Ty> { // uniform integer distribution +class uniform_int_distribution { // uniform integer distribution public: _RNG_REQUIRE_INTTYPE(uniform_int_distribution, _Ty); - using _Mybase = uniform_int<_Ty>; - using _Mypbase = typename _Mybase::param_type; - using result_type = typename _Mybase::result_type; + using result_type = _Ty; - struct param_type : _Mypbase { // parameter package + struct param_type { // parameter package using distribution_type = uniform_int_distribution; - param_type() noexcept // strengthened - : _Mypbase(0, (numeric_limits<_Ty>::max)()) {} + param_type() noexcept /* strengthened */ { + _Init(0, (numeric_limits<_Ty>::max)()); + } - explicit param_type( - result_type _Min0, result_type _Max0 = (numeric_limits<_Ty>::max)()) noexcept // strengthened - : _Mypbase(_Min0, _Max0) {} + explicit param_type(result_type _Min0, result_type _Max0 = (numeric_limits<_Ty>::max)()) noexcept + /* strengthened */ { + _Init(_Min0, _Max0); + } - param_type(const _Mypbase& _Right) noexcept : _Mypbase(_Right) {} + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept + /* strengthened */ { + return _Left._Min == _Right._Min && _Left._Max == _Right._Max; + } + +#if !_HAS_CXX20 + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + /* strengthened */ { + return !(_Left == _Right); + } +#endif // !_HAS_CXX20 + + _NODISCARD result_type a() const noexcept /* strengthened */ { + return _Min; + } + + _NODISCARD result_type b() const noexcept /* strengthened */ { + return _Max; + } + + void _Init(_Ty _Min0, _Ty _Max0) noexcept { // set internal state + _STL_ASSERT(_Min0 <= _Max0, "invalid min and max arguments for uniform_int_distribution"); + _Min = _Min0; + _Max = _Max0; + } + + result_type _Min; + result_type _Max; }; uniform_int_distribution() noexcept // strengthened - : _Mybase(0, (numeric_limits<_Ty>::max)()) {} + : _Par(0, (numeric_limits<_Ty>::max)()) {} explicit uniform_int_distribution(_Ty _Min0, _Ty _Max0 = (numeric_limits<_Ty>::max)()) noexcept // strengthened - : _Mybase(_Min0, _Max0) {} + : _Par(_Min0, _Max0) {} explicit uniform_int_distribution(const param_type& _Par0) noexcept // strengthened - : _Mybase(_Par0) {} + : _Par(_Par0) {} _NODISCARD result_type a() const noexcept /* strengthened */ { - return _Mybase::a(); + return _Par.a(); } _NODISCARD result_type b() const noexcept /* strengthened */ { - return _Mybase::b(); + return _Par.b(); } _NODISCARD param_type param() const noexcept /* strengthened */ { - return _Mybase::param(); + return _Par; } void param(const param_type& _Par0) noexcept /* strengthened */ { - _Mybase::param(_Par0); + _Par = _Par0; } _NODISCARD result_type(min)() const noexcept /* strengthened */ { - return (_Mybase::min)(); + return _Par._Min; } _NODISCARD result_type(max)() const noexcept /* strengthened */ { - return (_Mybase::max)(); + return _Par._Max; } void reset() noexcept /* strengthened */ {} template _NODISCARD result_type operator()(_Engine& _Eng) _DISTRIBUTION_CONST { - return _Mybase::operator()(_Eng); + return _Eval(_Eng, _Par._Min, _Par._Max); } template _NODISCARD result_type operator()(_Engine& _Eng, const param_type& _Par0) _DISTRIBUTION_CONST { - return _Mybase::operator()(_Eng, _Par0); + return _Eval(_Eng, _Par0._Min, _Par0._Max); } template friend basic_istream<_Elem, _Traits>& operator>>( basic_istream<_Elem, _Traits>& _Istr, uniform_int_distribution& _Dist) { - return _Istr >> static_cast<_Mybase&>(_Dist); + uniform_int_distribution::result_type _Min0; + uniform_int_distribution::result_type _Max0; + _Istr >> _Min0 >> _Max0; + _Dist._Par._Init(_Min0, _Max0); + return _Istr; } template friend basic_ostream<_Elem, _Traits>& operator<<( basic_ostream<_Elem, _Traits>& _Ostr, const uniform_int_distribution& _Dist) { - return _Ostr << static_cast(_Dist); + return _Ostr << _Dist._Par._Min << ' ' << _Dist._Par._Max; } _NODISCARD friend bool operator==( const uniform_int_distribution& _Left, const uniform_int_distribution& _Right) noexcept /* strengthened */ { - return _Left.param() == _Right.param(); + return _Left._Par == _Right._Par; } #if !_HAS_CXX20 @@ -2463,8 +2493,39 @@ public: return !(_Left == _Right); } #endif // !_HAS_CXX20 + +private: + using _Uty = make_unsigned_t<_Ty>; + + template + result_type _Eval(_Engine& _Eng, _Ty _Min, _Ty _Max) const { // compute next value in range [_Min, _Max] + _Rng_from_urng_v2<_Uty, _Engine> _Generator(_Eng); + + const _Uty _Umin = _Adjust(static_cast<_Uty>(_Min)); + const _Uty _Umax = _Adjust(static_cast<_Uty>(_Max)); + + _Uty _Uret; + + if (_Umax - _Umin == static_cast<_Uty>(-1)) { + _Uret = static_cast<_Uty>(_Generator._Get_all_bits()); + } else { + _Uret = static_cast<_Uty>(_Generator(static_cast<_Uty>(_Umax - _Umin + 1))); + } + + return static_cast<_Ty>(_Adjust(static_cast<_Uty>(_Uret + _Umin))); + } + + static _Uty _Adjust(_Uty _Uval) noexcept { // convert signed ranges to unsigned ranges and vice versa + if constexpr (is_signed_v<_Ty>) { + constexpr _Uty _Adjuster = (static_cast<_Uty>(-1) >> 1) + 1; // 2^(N-1) + return static_cast<_Uty>(_Uval ^ _Adjuster); + } else { // _Ty is already unsigned, do nothing + return _Uval; + } + } + + param_type _Par; }; -_STL_RESTORE_DEPRECATED_WARNING _EXPORT_STD class bernoulli_distribution { // class for bernoulli distribution public: From 17dc272daea8bc65e6dac77f111e0ed61ae02ded Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 08:04:54 -0700 Subject: [PATCH 12/13] Fuse uniform_real into uniform_real_distribution. Make equality slightly more efficient in debug mode. Note that _Read and _Write are public in uniform_real, but remain private in uniform_real_distribution. --- stl/inc/random | 103 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 26 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index a3a2fb24648..a290efb5416 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -3330,88 +3330,115 @@ private: param_type _Par; }; -_STL_DISABLE_DEPRECATED_WARNING _EXPORT_STD template -class uniform_real_distribution : private uniform_real<_Ty> { // uniform real distribution +class uniform_real_distribution { // uniform real distribution public: _RNG_REQUIRE_REALTYPE(uniform_real_distribution, _Ty); - using _Mybase = uniform_real<_Ty>; - using _Mypbase = typename _Mybase::param_type; - using result_type = typename _Mybase::result_type; + using result_type = _Ty; - struct param_type : _Mypbase { // parameter package + struct param_type { // parameter package using distribution_type = uniform_real_distribution; - param_type() noexcept // strengthened - : _Mypbase(_Ty{0}, _Ty{1}) {} + param_type() noexcept /* strengthened */ { + _Init(_Ty{0}, _Ty{1}); + } + + explicit param_type(_Ty _Min0, _Ty _Max0 = _Ty{1}) noexcept /* strengthened */ { + _Init(_Min0, _Max0); + } + + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept + /* strengthened */ { + return _Left._Min == _Right._Min && _Left._Max == _Right._Max; + } + +#if !_HAS_CXX20 + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + /* strengthened */ { + return !(_Left == _Right); + } +#endif // !_HAS_CXX20 + + _NODISCARD result_type a() const noexcept /* strengthened */ { + return _Min; + } + + _NODISCARD result_type b() const noexcept /* strengthened */ { + return _Max; + } - explicit param_type(_Ty _Min0, _Ty _Max0 = _Ty{1}) noexcept // strengthened - : _Mypbase(_Min0, _Max0) {} + void _Init(_Ty _Min0, _Ty _Max0) noexcept { // set internal state + _STL_ASSERT(_Min0 <= _Max0 && (0 <= _Min0 || _Max0 <= _Min0 + (numeric_limits<_Ty>::max)()), + "invalid min and max arguments for uniform_real_distribution"); + _Min = _Min0; + _Max = _Max0; + } - param_type(const _Mypbase& _Right) noexcept : _Mypbase(_Right) {} + result_type _Min; + result_type _Max; }; uniform_real_distribution() noexcept // strengthened - : _Mybase(_Ty{0}, _Ty{1}) {} + : _Par(_Ty{0}, _Ty{1}) {} explicit uniform_real_distribution(_Ty _Min0, _Ty _Max0 = _Ty{1}) noexcept // strengthened - : _Mybase(_Min0, _Max0) {} + : _Par(_Min0, _Max0) {} explicit uniform_real_distribution(const param_type& _Par0) noexcept // strengthened - : _Mybase(_Par0) {} + : _Par(_Par0) {} _NODISCARD result_type a() const noexcept /* strengthened */ { - return _Mybase::a(); + return _Par.a(); } _NODISCARD result_type b() const noexcept /* strengthened */ { - return _Mybase::b(); + return _Par.b(); } _NODISCARD param_type param() const noexcept /* strengthened */ { - return _Mybase::param(); + return _Par; } void param(const param_type& _Par0) noexcept /* strengthened */ { - _Mybase::param(_Par0); + _Par = _Par0; } _NODISCARD result_type(min)() const noexcept /* strengthened */ { - return (_Mybase::min)(); + return _Par._Min; } _NODISCARD result_type(max)() const noexcept /* strengthened */ { - return (_Mybase::max)(); + return _Par._Max; } void reset() noexcept /* strengthened */ {} template _NODISCARD result_type operator()(_Engine& _Eng) _DISTRIBUTION_CONST { - return _Mybase::operator()(_Eng); + return _Eval(_Eng, _Par); } template _NODISCARD result_type operator()(_Engine& _Eng, const param_type& _Par0) _DISTRIBUTION_CONST { - return _Mybase::operator()(_Eng, _Par0); + return _Eval(_Eng, _Par0); } template friend basic_istream<_Elem, _Traits>& operator>>( basic_istream<_Elem, _Traits>& _Istr, uniform_real_distribution& _Dist) { - return _Istr >> static_cast<_Mybase&>(_Dist); + return _Dist._Read(_Istr); } template friend basic_ostream<_Elem, _Traits>& operator<<( basic_ostream<_Elem, _Traits>& _Ostr, const uniform_real_distribution& _Dist) { - return _Ostr << static_cast(_Dist); + return _Dist._Write(_Ostr); } _NODISCARD friend bool operator==( const uniform_real_distribution& _Left, const uniform_real_distribution& _Right) noexcept /* strengthened */ { - return _Left.param() == _Right.param(); + return _Left._Par == _Right._Par; } #if !_HAS_CXX20 @@ -3420,8 +3447,32 @@ public: return !(_Left == _Right); } #endif // !_HAS_CXX20 + +private: + template + basic_istream<_Elem, _Traits>& _Read(basic_istream<_Elem, _Traits>& _Istr) { // read state from _Istr + _Ty _Min0; + _Ty _Max0; + _In(_Istr, _Min0); + _In(_Istr, _Max0); + _Par._Init(_Min0, _Max0); + return _Istr; + } + + template + basic_ostream<_Elem, _Traits>& _Write(basic_ostream<_Elem, _Traits>& _Ostr) const { // write state to _Ostr + _Out(_Ostr, _Par._Min); + _Out(_Ostr, _Par._Max); + return _Ostr; + } + + template + result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { + return _Nrand_impl<_Ty>(_Eng) * (_Par0._Max - _Par0._Min) + _Par0._Min; + } + + param_type _Par; }; -_STL_RESTORE_DEPRECATED_WARNING _EXPORT_STD template class exponential_distribution { // exponential distribution From 1948b4aef662247609d9e48aee8d85dd3a2ac1ab Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 7 Sep 2025 10:20:41 -0700 Subject: [PATCH 13/13] Guard old classes and test coverage with _HAS_TR1_NAMESPACE. Dev09_181509_tr1_inf_loop_uniform_int_ull: Update comment to describe the Standard machinery being tested. (I know the test name is old.) Wacky min()/max() needs to be constexpr. P0952R2_new_generate_canonical: These tests are comparing tr1 and Standard generators. As they aren't testing absolute behavior, just identical behavior, they're meaningless when the tr1 generators are missing. VSO_0000000_instantiate_iterators_misc: The linear_congruential type being formed is effectively equivalent to minstd_rand0 which is already covered. Now guard the tr1_engine_test_impl() helper. Update comments for searchability. tests/tr1: Switch between tr1 and Standard types. This will continue to serve as a minimal check that the tr1 types keep working until they're ultimately removed soon. tr1/tests/random1 has some coverage for old interfaces that don't apply to the Standard types. We also need to test mersenne_twister_engine's differently-named constants. We need static_cast to avoid sign comparison warnings with discard_block_engine. tr1/tests/random2 has to handle the Standard's different default max for uniform_int_distribution. --- stl/inc/random | 16 ++++- .../test.cpp | 8 +-- .../P0952R2_new_generate_canonical/test.cpp | 5 ++ .../test.compile.pass.cpp | 11 ++-- tests/tr1/include/tspec_random.h | 6 ++ tests/tr1/include/tspec_random_defs.h | 38 ++++++++++++ tests/tr1/tests/random1/test.cpp | 58 ++++++++++++++++++- tests/tr1/tests/random2/test.cpp | 16 ++++- 8 files changed, 142 insertions(+), 16 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index a290efb5416..6d6e2baa544 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -24,6 +24,7 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new +#if _HAS_TR1_NAMESPACE // TRANSITION, GH-183 #pragma push_macro("discard_block") #pragma push_macro("linear_congruential") @@ -37,6 +38,7 @@ _STL_DISABLE_CLANG_WARNINGS #undef subtract_with_carry #undef uniform_int #undef uniform_real +#endif // _HAS_TR1_NAMESPACE #ifdef _ALLOW_RANDOM_DISTRIBUTION_CONST_OPERATOR #define _DISTRIBUTION_CONST const @@ -670,6 +672,7 @@ private: result_type _Prev; }; +#if _HAS_TR1_NAMESPACE template class _DEPRECATE_TR1_RANDOM linear_congruential { // linear congruential random engine public: @@ -757,6 +760,7 @@ public: private: _Uint _Prev; }; +#endif // _HAS_TR1_NAMESPACE template struct _Circ_buf { // holds historical values for generators @@ -1031,6 +1035,7 @@ public: } }; +#if _HAS_TR1_NAMESPACE template class _DEPRECATE_TR1_RANDOM subtract_with_carry : public _Swc_base<_Ty, _Sx, _Rx, _Swc_traits<_Ty, _Mx, _Rx>> { // subtract_with_carry generator @@ -1048,6 +1053,7 @@ public: template = 0> subtract_with_carry(_Gen& _Gx) : _Mybase(_Gx) {} }; +#endif // _HAS_TR1_NAMESPACE _EXPORT_STD template class subtract_with_carry_engine @@ -1260,7 +1266,6 @@ public: template = 0> subtract_with_carry_01(_Gen& _Gx) : _Mybase(_Gx) {} }; -#endif // _HAS_TR1_NAMESPACE template class _DEPRECATE_TR1_RANDOM mersenne_twister : public _Circ_buf<_Ty, _Nx> { // mersenne twister generator @@ -1432,6 +1437,7 @@ protected: static constexpr int _One_mod_n = 1 % _Nx; // either 0 or 1 static constexpr int _M_mod_n = _Mx % _Nx; }; +#endif // _HAS_TR1_NAMESPACE _EXPORT_STD template @@ -1642,6 +1648,7 @@ private: static constexpr int _M_mod_n = _Mx % _Nx; }; +#if _HAS_TR1_NAMESPACE template class _DEPRECATE_TR1_RANDOM discard_block { // discard_block compound engine public: @@ -1737,6 +1744,7 @@ private: _Engine _Eng; int _Nx; }; +#endif // _HAS_TR1_NAMESPACE _EXPORT_STD template class discard_block_engine { @@ -2229,6 +2237,7 @@ private: static constexpr _Udiff _Bmask = static_cast<_Udiff>(-1) >> (_Udiff_bits - _Bits); // 2^_Bits - 1 }; +#if _HAS_TR1_NAMESPACE template class _DEPRECATE_TR1_RANDOM uniform_int { // uniform integer distribution public: @@ -2371,6 +2380,7 @@ private: param_type _Par; }; +#endif // _HAS_TR1_NAMESPACE _EXPORT_STD template class uniform_int_distribution { // uniform integer distribution @@ -3203,6 +3213,7 @@ private: param_type _Par; }; +#if _HAS_TR1_NAMESPACE template class _DEPRECATE_TR1_RANDOM uniform_real { // uniform real distribution public: @@ -3329,6 +3340,7 @@ private: param_type _Par; }; +#endif // _HAS_TR1_NAMESPACE _EXPORT_STD template class uniform_real_distribution { // uniform real distribution @@ -5857,6 +5869,7 @@ _STD_END #undef _DISTRIBUTION_CONST +#if _HAS_TR1_NAMESPACE // TRANSITION, GH-183 #pragma pop_macro("uniform_real") #pragma pop_macro("uniform_int") @@ -5864,6 +5877,7 @@ _STD_END #pragma pop_macro("mersenne_twister") #pragma pop_macro("linear_congruential") #pragma pop_macro("discard_block") +#endif // _HAS_TR1_NAMESPACE #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS diff --git a/tests/std/tests/Dev09_181509_tr1_inf_loop_uniform_int_ull/test.cpp b/tests/std/tests/Dev09_181509_tr1_inf_loop_uniform_int_ull/test.cpp index 134b48978ca..8cfb375b721 100644 --- a/tests/std/tests/Dev09_181509_tr1_inf_loop_uniform_int_ull/test.cpp +++ b/tests/std/tests/Dev09_181509_tr1_inf_loop_uniform_int_ull/test.cpp @@ -63,8 +63,8 @@ void add_tests(vector& tests) { microtest, microtest, microtest, - microtest, // Test DDB-181509 "TR1 VC9 SP1: Infinite loop in - // uniform_int::_Eval()". + microtest, // Test DDB-181509 (infinite loop in + // uniform_int_distribution) microtest, microtest, @@ -95,11 +95,11 @@ class Wacky { typedef unsigned long result_type; - static result_type min() { + static constexpr result_type min() { return 0; } - static result_type max() { + static constexpr result_type max() { return 90000; } diff --git a/tests/std/tests/P0952R2_new_generate_canonical/test.cpp b/tests/std/tests/P0952R2_new_generate_canonical/test.cpp index 527faf8aee1..3778db5d592 100644 --- a/tests/std/tests/P0952R2_new_generate_canonical/test.cpp +++ b/tests/std/tests/P0952R2_new_generate_canonical/test.cpp @@ -20,6 +20,7 @@ void test_lwg2524() { assert((generate_canonical) (mt2) < 1.0f); } +#if _HAS_TR1_NAMESPACE void test_tr1_16() { using E_std = linear_congruential_engine; using E_tr1 = linear_congruential; @@ -98,6 +99,7 @@ void test_tr1_64() { assert(dist_64(std_eng) == dist_64(tr1_eng)); } } +#endif // _HAS_TR1_NAMESPACE template Real generate_with_ibe() { @@ -197,9 +199,12 @@ int main() { assert((generate_canonical) (eng) == expected); } +#if _HAS_TR1_NAMESPACE test_tr1_16(); test_tr1_32(); test_tr1_64(); +#endif // _HAS_TR1_NAMESPACE + test_lwg2524(); return 0; diff --git a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp index 8352292398b..d73e84653fc 100644 --- a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp @@ -1073,12 +1073,14 @@ void engine_test_impl() { common_engine_test_impl(ss); } +#if _HAS_TR1_NAMESPACE template void tr1_engine_test_impl() { random_device rd{}; mt19937 gen(rd()); common_engine_test_impl(gen); } +#endif // _HAS_TR1_NAMESPACE void random_test() { seed_seq ss0({1, 2, 3, 4, 5, 6}); @@ -1091,22 +1093,21 @@ void random_test() { mt19937 gen(rd()); (void) generate_canonical(gen); - engine_test_impl(); // linear congruential engine - engine_test_impl(); // mersenne twister engine + engine_test_impl(); // linear_congruential_engine + engine_test_impl(); // mersenne_twister_engine engine_test_impl(); // subtract_with_carry_engine - engine_test_impl(); // discard block engine + engine_test_impl(); // discard_block_engine engine_test_impl(); // shuffle_order_engine engine_test_impl>(); engine_test_impl(); engine_test_impl(); engine_test_impl(); +#if _HAS_TR1_NAMESPACE linear_congruential minstd_rand_eng(gen); minstd_rand_eng.seed(gen); tr1_engine_test_impl>(); - -#if _HAS_TR1_NAMESPACE tr1_engine_test_impl(); tr1_engine_test_impl(); tr1_engine_test_impl(); diff --git a/tests/tr1/include/tspec_random.h b/tests/tr1/include/tspec_random.h index 9be4e7a6ba7..e600c6a8a46 100644 --- a/tests/tr1/include/tspec_random.h +++ b/tests/tr1/include/tspec_random.h @@ -129,8 +129,14 @@ void test_random() { // test all of the distributions TESTR(geometric_distribution); TESTR(normal_distribution); TESTR(poisson_distribution); + +#if _HAS_TR1_NAMESPACE TESTR(uniform_int); TESTR(uniform_real); +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + TESTR(uniform_int_distribution); + TESTR(uniform_real_distribution); +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ TESTR(cauchy_distribution); TESTR(chi_squared_distribution); diff --git a/tests/tr1/include/tspec_random_defs.h b/tests/tr1/include/tspec_random_defs.h index d4283411993..ac01067f733 100644 --- a/tests/tr1/include/tspec_random_defs.h +++ b/tests/tr1/include/tspec_random_defs.h @@ -129,6 +129,7 @@ One_arg poisson_distribution_vals[] = { {FLIT(99.0), FLIT(0.03986496337366227799), FLIT(0.0)}, }; +#if _HAS_TR1_NAMESPACE typedef unsigned int uniform_int_type; uniform_int uniform_int_dist(10, 90); int uniform_int_smaller_ok = 0; @@ -164,6 +165,43 @@ One_arg uniform_real_vals[] = { {FLIT(88.0), FLIT(0.0), FLIT(0.0)}, {FLIT(99.0), FLIT(0.0), FLIT(0.0)}, }; +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv +typedef unsigned int uniform_int_distribution_type; +uniform_int_distribution uniform_int_distribution_dist(10, 90); +int uniform_int_distribution_smaller_ok = 0; +int uniform_int_distribution_larger_ok = 0; + +One_arg uniform_int_distribution_vals[] = { + {FLIT(0.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(11.0), FLIT(0.012345679012345678328), FLIT(0.0)}, + {FLIT(22.0), FLIT(0.012345679012345678328), FLIT(0.0)}, + {FLIT(33.0), FLIT(0.012345679012345678328), FLIT(0.0)}, + {FLIT(44.0), FLIT(0.012345679012345678328), FLIT(0.0)}, + {FLIT(55.0), FLIT(0.012345679012345678328), FLIT(0.0)}, + {FLIT(66.0), FLIT(0.012345679012345678328), FLIT(0.0)}, + {FLIT(77.0), FLIT(0.012345679012345678328), FLIT(0.0)}, + {FLIT(88.0), FLIT(0.012345679012345678328), FLIT(0.0)}, + {FLIT(99.0), FLIT(0.0), FLIT(0.0)}, +}; + +typedef double uniform_real_distribution_type; +uniform_real_distribution uniform_real_distribution_dist(40.2, 60.5); +int uniform_real_distribution_smaller_ok = 0; +int uniform_real_distribution_larger_ok = 0; + +One_arg uniform_real_distribution_vals[] = { + {FLIT(0.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(11.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(22.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(33.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(44.0), FLIT(0.049261083743842366821), FLIT(0.0)}, + {FLIT(55.0), FLIT(0.049261083743842366821), FLIT(0.0)}, + {FLIT(66.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(77.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(88.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(99.0), FLIT(0.0), FLIT(0.0)}, +}; +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ typedef double cauchy_distribution_type; cauchy_distribution cauchy_distribution_dist(50.0, 20.0); diff --git a/tests/tr1/tests/random1/test.cpp b/tests/tr1/tests/random1/test.cpp index 1a3af256c8b..e8f842a64f4 100644 --- a/tests/tr1/tests/random1/test.cpp +++ b/tests/tr1/tests/random1/test.cpp @@ -60,8 +60,12 @@ struct test_globals { // tests engine global functions } }; -static void tlinear() { // test linear_congruential +static void tlinear() { +#if _HAS_TR1_NAMESPACE typedef STD linear_congruential rng_t; +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + typedef STD linear_congruential_engine rng_t; +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ CHECK_INT(rng_t::multiplier, 16807); CHECK_INT(rng_t::increment, 0); @@ -79,6 +83,7 @@ static void tlinear() { // test linear_congruential CHECK_INT(rng1.max(), 2147483646); CHECK_INT(rng1(), 33614); +#if _HAS_TR1_NAMESPACE generator g; Uint32 init[] = {1, 2}; g.reset(init, 2); @@ -94,6 +99,7 @@ static void tlinear() { // test linear_congruential CHECK_INT(rng3.max(), 2147483646); CHECK_INT(rng3(), 33614); CHECK_INT(g.index(), 2); +#endif // ^^^ _HAS_TR1_NAMESPACE ^^^ rng.seed(1); CHECK_INT(rng.min(), 1); @@ -105,6 +111,7 @@ static void tlinear() { // test linear_congruential CHECK_INT(rng.max(), 2147483646); CHECK_INT(rng(), 33614); +#if _HAS_TR1_NAMESPACE g.reset(init, 2); rng3.seed(g); CHECK_INT(rng3.min(), 1); @@ -117,6 +124,7 @@ static void tlinear() { // test linear_congruential CHECK_INT(rng3.max(), 2147483646); CHECK_INT(rng3(), 33614); CHECK_INT(g.index(), 2); +#endif // ^^^ _HAS_TR1_NAMESPACE ^^^ test_globals::test(); @@ -124,7 +132,11 @@ static void tlinear() { // test linear_congruential typedef unsigned long long int_type; const int_type max_val = (int_type) -1; +#if _HAS_TR1_NAMESPACE typedef STD linear_congruential rng4_t; +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + typedef STD linear_congruential_engine rng4_t; +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ rng4_t rng4(1); CHECK(rng4() == max_val - 1); CHECK(rng4() == 1); @@ -157,11 +169,16 @@ static void tminstd_rand() { } static void tmersenne() { +#if _HAS_TR1_NAMESPACE typedef STD mersenne_twister rng_t; +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + typedef STD mt19937 rng_t; +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ CHECK_INT(rng_t::word_size, 32); CHECK_INT(rng_t::state_size, 624); CHECK_INT(rng_t::shift_size, 397); CHECK_INT(rng_t::mask_bits, 31); +#if _HAS_TR1_NAMESPACE CHECK_INT((int) rng_t::parameter_a, (int) 0x9908b0df); CHECK_INT(rng_t::output_u, 11); CHECK_INT(rng_t::output_s, 7); @@ -169,6 +186,17 @@ static void tmersenne() { CHECK_INT(rng_t::output_t, 15); CHECK_INT((int) rng_t::output_c, (int) 0xefc60000); CHECK_INT(rng_t::output_l, 18); +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + CHECK_INT(rng_t::xor_mask, 0x9908b0df); + CHECK_INT(rng_t::tempering_u, 11); + CHECK_INT(rng_t::tempering_d, 0xffffffff); + CHECK_INT(rng_t::tempering_s, 7); + CHECK_INT(rng_t::tempering_b, 0x9d2c5680); + CHECK_INT(rng_t::tempering_t, 15); + CHECK_INT(rng_t::tempering_c, 0xefc60000); + CHECK_INT(rng_t::tempering_l, 18); + CHECK_INT(rng_t::initialization_multiplier, 1812433253); +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ bool st = STD is_same::value; CHECK(st); @@ -182,6 +210,7 @@ static void tmersenne() { CHECK_INT(ptr_rng1->max(), 0xffffffff); CHECK_INT((*ptr_rng1)(), 1791095845); +#if _HAS_TR1_NAMESPACE STD linear_congruential init_gen(4357); const auto ptr_rng2 = STD make_unique(init_gen); @@ -193,6 +222,7 @@ static void tmersenne() { CHECK_INT(rng3.min(), 0); CHECK_INT(rng3.max(), 0xffffffff); CHECK_INT(rng3(), (int) 2649890907u); +#endif // ^^^ _HAS_TR1_NAMESPACE ^^^ rng.seed(1); CHECK_INT(rng.min(), 0); @@ -204,6 +234,7 @@ static void tmersenne() { CHECK_INT(rng.max(), 0xffffffff); CHECK_INT(rng(), 1872583848); +#if _HAS_TR1_NAMESPACE init_gen.seed(4357); rng3.seed(init_gen); CHECK_INT(rng3.min(), 0); @@ -214,6 +245,7 @@ static void tmersenne() { CHECK_INT(rng3.min(), 0); CHECK_INT(rng3.max(), 0xffffffff); CHECK_INT(rng3(), (int) 2649890907u); +#endif // ^^^ _HAS_TR1_NAMESPACE ^^^ test_globals::test(); } @@ -274,8 +306,13 @@ static void tmt19937() { } static void tsubtract() { +#if _HAS_TR1_NAMESPACE typedef STD subtract_with_carry rng_t; CHECK_INT(rng_t::modulus, 1 << 24); +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + typedef STD subtract_with_carry_engine rng_t; + CHECK_INT(rng_t::word_size, 24); +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ CHECK_INT(rng_t::short_lag, 10); CHECK_INT(rng_t::long_lag, 24); bool st = STD is_same::value; @@ -291,6 +328,7 @@ static void tsubtract() { CHECK_INT(rng1.max(), (1 << 24) - 1); CHECK_INT(rng1(), 8871692); +#if _HAS_TR1_NAMESPACE STD linear_congruential init_gen(19780503); rng_t rng2(init_gen); @@ -302,6 +340,7 @@ static void tsubtract() { CHECK_INT(rng3.min(), 0); CHECK_INT(rng3.max(), (1 << 24) - 1); CHECK_INT(rng3(), 6319224); +#endif // ^^^ _HAS_TR1_NAMESPACE ^^^ rng.seed(1); CHECK_INT(rng.min(), 0); @@ -313,6 +352,7 @@ static void tsubtract() { CHECK_INT(rng.max(), (1 << 24) - 1); CHECK_INT(rng(), 966168); +#if _HAS_TR1_NAMESPACE init_gen.seed(19780503); rng3.seed(init_gen); CHECK_INT(rng3.min(), 0); @@ -323,6 +363,7 @@ static void tsubtract() { CHECK_INT(rng3.min(), 0); CHECK_INT(rng3.max(), (1 << 24) - 1); CHECK_INT(rng3(), 6319224); +#endif // ^^^ _HAS_TR1_NAMESPACE ^^^ test_globals::test(); } @@ -377,7 +418,11 @@ static void tsubtract_01() { CHECK_DOUBLE(rng1.max(), 1.0); CHECK_DOUBLE(rng1(), 8871692 * factor); +#if _HAS_TR1_NAMESPACE STD linear_congruential init_gen(19780503); +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + STD linear_congruential_engine init_gen(19780503); +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ rng_t rng2(init_gen); CHECK_DOUBLE(rng2.min(), 0.0); @@ -464,8 +509,13 @@ static void tranlux4_01() { static void tdiscard() { int i; +#if _HAS_TR1_NAMESPACE typedef STD subtract_with_carry rng_base_t; typedef STD discard_block rng_t; +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + typedef STD subtract_with_carry_engine rng_base_t; + typedef STD discard_block_engine rng_t; +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ CHECK_INT(rng_t::block_size, 223); CHECK_INT(rng_t::used_block, 24); #if _HAS_TR1_NAMESPACE @@ -481,6 +531,7 @@ static void tdiscard() { CHECK_INT(rng.max(), (1 << 24) - 1); CHECK_INT(rng(), 15039276); +#if _HAS_TR1_NAMESPACE STD linear_congruential init_gen(19780503); rng_t rng2(init_gen); @@ -503,14 +554,15 @@ static void tdiscard() { CHECK_INT(rng3.min(), 0); CHECK_INT(rng3.max(), (1 << 24) - 1); CHECK_INT(rng3(), 6319224); +#endif // ^^^ _HAS_TR1_NAMESPACE ^^^ rng_base_t rng4; rng_t rng5; - for (i = 0; i < rng_t::used_block; ++i) { + for (i = 0; i < static_cast(rng_t::used_block); ++i) { CHECK_INT(rng4(), rng5()); } CHECK(rng4() != rng5()); - for (; i < rng_t::block_size; ++i) { + for (; i < static_cast(rng_t::block_size); ++i) { (void) rng4(); } diff --git a/tests/tr1/tests/random2/test.cpp b/tests/tr1/tests/random2/test.cpp index 641605e1760..fa99589f4f6 100644 --- a/tests/tr1/tests/random2/test.cpp +++ b/tests/tr1/tests/random2/test.cpp @@ -45,17 +45,23 @@ struct test_globals { }; static void tuniform_int() { +#if _HAS_TR1_NAMESPACE typedef STD uniform_int dist_t; + constexpr int default_max = 9; +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + typedef STD uniform_int_distribution dist_t; + constexpr int default_max = STD numeric_limits::max(); +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ bool st = STD is_same::value; CHECK(st); dist_t dist0; CHECK_INT(dist0.min(), 0); - CHECK_INT(dist0.max(), 9); + CHECK_INT(dist0.max(), default_max); dist0.reset(); dist_t dist1(1); CHECK_INT(dist1.min(), 1); - CHECK_INT(dist1.max(), 9); + CHECK_INT(dist1.max(), default_max); dist_t dist2(2, 8); CHECK_INT(dist2.min(), 2); CHECK_INT(dist2.max(), 8); @@ -63,7 +69,7 @@ static void tuniform_int() { str << dist0; str >> dist2; CHECK_INT(dist2.min(), 0); - CHECK_INT(dist2.max(), 9); + CHECK_INT(dist2.max(), default_max); test_globals::test(); } @@ -206,7 +212,11 @@ static void tbinomial_distribution() { } static void tuniform_real() { +#if _HAS_TR1_NAMESPACE typedef STD uniform_real dist_t; +#else // ^^^ _HAS_TR1_NAMESPACE / !_HAS_TR1_NAMESPACE vvv + typedef STD uniform_real_distribution dist_t; +#endif // ^^^ !_HAS_TR1_NAMESPACE ^^^ bool st = STD is_same::value; CHECK(st);