| Message ID | oqVcTPu_NirEu9vjJ0EqX46twZPeeTZ1JGKQ3u1WPHyxb4HGclVm4MMsPIzFhbcYOTgZ48ZPAO_-Um5qPlj4zT2nldQmIdD6CtrsshqExHQ=@protonmail.com |
|---|---|
| State | New |
| Headers | show |
| Series | [v4] libstdc++: Implement Philox Engine [PR119794] | expand |
On Sat, 19 Jul 2025, 1nfocalypse wrote: > Implements Philox Engine (P2075R6) and associated tests. > > Implements additional feedback from v3 from Patrick Palka. > > I went ahead and qualified the STL functions to avoid ADL ambiguity, > as recommended. However, if this was erroneous, I'd be happy to go > back and change it. > > Additionally, the suspicion expressed by Patrick was correct, and the > issue with the extra paren was corrected. > > Thank you once again for the review, and if further changes are required, > please let me know. > > Built and tested on x86_64-linux-gnu. > > > Subject: [PATCH] [PATCH v4] libstdc++: Implement Philox Engine [PR119794] > > Implemented additional changes according to feedback from Patrick Palka. > _charT, _traits -> _CharT, _Traits in stream operator templates > Removed accidental whitespace in random.tcc > Removed unnecessary this-> qualifiers > Removed unnecessary {} wrappers in multiline variable definitions > Removed {} in single-line for loops > Qualified STL functions with std:: to avoid ADL ambiguity; > Left data structures (i.e. std::array) unqualified per v2 feedback > Bug in seed with sseq fixed - should now correctly compute integer ceil > Removed accidental whitespace in include/std/random > Removed duplicate test (covers removal of copyright header) > > Still implements LWG4143, LWG4153 errata for Philox Engine. > > Additionally altered pr60037-neg.cc to correctly suppress error. > > PR libstdc++/119794 > --- > libstdc++-v3/include/bits/random.h | 298 ++++++++++++++++++ > libstdc++-v3/include/bits/random.tcc | 186 +++++++++++ > libstdc++-v3/include/bits/version.def | 9 + > libstdc++-v3/include/bits/version.h | 10 + > libstdc++-v3/include/std/random | 3 + > .../26_numerics/random/philox4x32.cc | 23 ++ > .../26_numerics/random/philox4x64.cc | 23 ++ > .../random/philox_engine/cons/119794.cc | 39 +++ > .../random/philox_engine/cons/copy.cc | 25 ++ > .../random/philox_engine/cons/default.cc | 27 ++ > .../random/philox_engine/cons/seed.cc | 20 ++ > .../random/philox_engine/cons/seed_seq.cc | 22 ++ > .../random/philox_engine/operators/equal.cc | 30 ++ > .../random/philox_engine/operators/inequal.cc | 30 ++ > .../philox_engine/operators/serialize.cc | 49 +++ > .../philox_engine/requirements/constants.cc | 26 ++ > .../requirements/constexpr_data.cc | 50 +++ > .../requirements/constexpr_functions.cc | 41 +++ > .../philox_engine/requirements/typedefs.cc | 26 ++ > .../26_numerics/random/pr60037-neg.cc | 2 +- > 20 files changed, 938 insertions(+), 1 deletion(-) > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc > > diff --git a/libstdc++-v3/include/bits/random.h b/libstdc++-v3/include/bits/random.h > index 1fdaf51934f..0930008cd90 100644 > --- a/libstdc++-v3/include/bits/random.h > +++ b/libstdc++-v3/include/bits/random.h > @@ -1688,6 +1688,286 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > { return !(__lhs == __rhs); } > #endif > > +#if __cpp_lib_philox_engine > + > + /** > + * @brief: A discrete pseudorandom number generator based off of weakened > + * cryptographic primitives. > + * > + * This algorithm was intended to be used for highly parallel random number > + * generation, and is capable of immensely long periods. It provides "Crush- > + * resistance", denoting an ability to pass the TestU01 Suite's "Big Crush" > + * test, demonstrating significant apparent entropy. It is not intended for > + * cryptographic use and should not be used for such, despite being based on > + * cryptographic primitives. > + * > + * The two four-word definitions are likely the best use for this algorithm, > + * and are given below as defaults. > + * > + * This algorithm was created by John Salmon, Mark Moraes, Ron Dror, and > + * David Shaw as a product of D.E. Shaw Research. > + * > + * @tparam __w Word size > + * @tparam __n Buffer size > + * @tparam __r Rounds > + * @tparam __consts Multiplication and round constant pack, ordered as > + * M_{0}, C_{0}, M_{1}, C_{1}, ... , M_{N/2-1}, C_{N/2-1} > + * > + * @headerfile random > + * @since C++26 > + */ > + template<class _UIntType, size_t __w, > + size_t __n, size_t __r, > + _UIntType... __consts> > + class philox_engine > + { > + static_assert(__n == 2 || __n == 4, > + "template argument N must be either 2 or 4"); > + static_assert(sizeof...(__consts) == __n, > + "length of consts array must match specified N"); > + static_assert(0 < __r, "a number of rounds must be specified"); > + static_assert((0 < __w && __w <= numeric_limits<_UIntType>::digits), > + "specified bitlength must match input type"); > + template<typename _Sseq> > + using _If_seed_seq > + = __detail::_If_seed_seq_for<_Sseq, philox_engine, _UIntType>; > + > + private: > + // the ordering here is essential to functionality. > + /** @brief an internal unpacking function for %philox_engine. */ > + template <size_t __ind0, size_t __ind1> > + static constexpr > + array<_UIntType, __n / 2> > + _S_popArray() > + { > + if constexpr (__n == 4) > + return {__consts...[__ind0], __consts...[__ind1]}; > + else > + return {__consts...[__ind0]}; > + } > + > + public: > + /** Type of template param. */ > + using result_type = _UIntType; > + // public members > + static constexpr size_t word_size = __w; > + static constexpr size_t word_count = __n; > + static constexpr size_t round_count = __r; > + static constexpr array<result_type, __n / 2> multipliers = > + philox_engine::_S_popArray<0,2>(); > + static constexpr array<result_type, __n / 2> round_consts = > + philox_engine::_S_popArray<1,3>(); > + > + /** @brief returns the minimum value possible. */ > + static constexpr result_type > + min() > + { return 0; } > + > + /** @brief returns the maximum value possible. */ > + static constexpr result_type > + max() > + { > + return ((1ull << (__w - 1)) | ((1ull << (__w - 1)) - 1)); > + } > + // default key value > + static constexpr result_type default_seed = 20111115u; > + > + // constructors > + philox_engine() > + : philox_engine(default_seed) > + {} > + > + explicit > + philox_engine(result_type __value); > + > + /** @brief seed sequence constructor for %philox_engine > + * > + * @params __q the seed sequence > + */ > + template<typename _Sseq, typename = _If_seed_seq<_Sseq>> > + explicit > + philox_engine(_Sseq& __q) > + { > + seed(__q); > + } > + > + > + void > + seed(result_type value = default_seed); > + > + /** @brief seeds %philox_engine by seed sequence > + * > + * @params __q the seed sequence > + */ > + template<typename _Sseq> > + _If_seed_seq<_Sseq> > + seed(_Sseq& __q); > + > + /** @brief sets the internal counter "cleartext" > + * > + * @params __counter std::array of len N > + */ > + void > + set_counter(const array<result_type, __n>& __counter); > + > + /** @brief compares two %philox_engine objects > + * > + * @params __x A %philox_engine object > + * @params __y A %philox_engine object > + * > + * @returns true if the objects will produce an identical stream, false > + * otherwise > + */ > + friend bool > + operator==(const philox_engine& __x, const philox_engine& __y) > + { > + return (std::equal(__x._M_x.begin(), __x._M_x.end(), > + __y._M_x.begin(), __y._M_x.end()) > + && std::equal(__x._M_y.begin(), __x._M_y.end(), > + __y._M_y.begin(), __y._M_y.end()) > + && std::equal(__x._M_k.begin(), __x._M_k.end(), > + __y._M_k.begin(), __y._M_k.end()) > + && __x._M_i == __y._M_i); > + } > + > + /** @brief outputs a single w-bit number and handles state advancement > + * > + * @returns return_type > + */ > + _UIntType > + operator()(); > + > + /** @brief discards __z numbers > + * > + * @params __z number of iterations to discard > + */ > + void > + discard(unsigned long long __z); > + > + /** @brief outputs the state of the generator > + * > + * @param __os An output stream. > + * @param __x A %philox_engine object reference > + * > + * @returns the state of the Philox Engine in __os > + */ > + template<typename _CharT, typename _Traits> > + friend basic_ostream<_CharT, _Traits>& > + operator<<(basic_ostream<_CharT, _Traits>& __os, > + const philox_engine& __x) > + { > + using __ios_base = ios_base; > + const typename __ios_base::fmtflags __flags = __os.flags(); > + const _CharT __fill = __os.fill(); > + __os.flags(__ios_base::dec | __ios_base::left); > + __os.fill(__os.widen(' ')); > + auto __it = __x._M_k.begin(); > + while (__it != __x._M_k.end()) > + { > + __os << *__it << ' '; > + ++__it; > + } > + auto __it2 = __x._M_x.begin(); > + while (__it2 != __x._M_x.end()) > + { > + __os << *__it2 << ' '; > + ++__it2; > + } > + __os << __x._M_i; > + __os.flags(__flags); > + __os.fill(__fill); > + return __os; > + } > + > + /** @brief takes input to set the state of the %philox_engine object > + * > + * @param __is An input stream. > + * @param __x A %philox_engine object reference > + * > + * @returns %philox_engine object is set with values from instream > + */ > + template <typename _CharT, typename _Traits> > + friend basic_istream<_CharT, _Traits>& > + operator>>(basic_istream<_CharT, _Traits>& __is, > + philox_engine& __x) > + { > + using __ios_base = ios_base; > + const typename __ios_base::fmtflags __flags = __is.flags(); > + __is.flags(__ios_base::dec | __ios_base::skipws); > + for (size_t __j = 0; __j < __x._M_k.size(); ++__j) > + { > + __is >> __x._M_k[__j]; > + } > + for (size_t __j = 0; __j < __x._M_x.size(); ++__j) > + { > + __is >> __x._M_x[__j]; > + } > + array<_UIntType, __n> __tmpCtr = __x._M_x; > + unsigned char __setIndex = 0; > + for (size_t __j = 0; __j < __x._M_x.size(); ++__j) > + { > + if (__x._M_x[__j] > 0) > + { > + __setIndex = __j; > + break; > + } > + } > + for (size_t __j = 0; __j <= __setIndex; ++__j) > + { > + if (__j != __setIndex) > + { > + __x._M_x[__j] = max(); > + } else > + { > + --__x._M_x[__j]; > + } > + } > + __x._M_philox(); > + __x._M_x = __tmpCtr; > + __is >> __x._M_i; > + __is.flags(__flags); > + return __is; > + } > + private: > + // private state variables > + array<_UIntType, __n> _M_x; > + array<_UIntType, __n / 2> _M_k; > + array<_UIntType, __n> _M_y; > + unsigned long long _M_i = 0; > + > + /** @brief Takes the high values of the product of __a, __b > + * > + * @params __a an unsigned integer > + * @params __b an unsigned integer > + * > + * @returns an unsigned integer of at most bitlength W > + */ > + _UIntType > + _M_mulhi(_UIntType __a, _UIntType __b); // (A*B)/2^W > + > + /** @brief Takes the low values of the product of __a, __b > + * > + * @params __a an unsigned integer > + * @params __b an unsigned integer > + * > + * @returns an unsigned integer of at most bitlength W > + */ > + _UIntType > + _M_mullo(_UIntType __a, _UIntType __b); // (A*B)%2^W > + > + /** @brief an R-round substitution/Feistel Network hybrid for > + * %philox_engine > + */ > + void > + _M_philox(); > + > + /** @brief an internal transition function for the %philox_engine. */ > + void > + _M_transition(); > + }; > + > +#endif > + > /** > * The classic Minimum Standard rand0 of Lewis, Goodman, and Miller. > */ > @@ -1742,6 +2022,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > typedef minstd_rand0 default_random_engine; > > +#if __cpp_lib_philox_engine > + > + typedef philox_engine< > + uint_fast32_t, > + 32, 4, 10, > + 0xCD9E8D57, 0x9E3779B9, > + 0xD2511F53, 0xBB67AE85> philox4x32; > + > + /** > + * Alternative Philox instance (64 bit) > + */ > + typedef philox_engine< > + uint_fast64_t, > + 64, 4, 10, > + 0xCA5A826395121157, 0x9E3779B97F4A7C15, > + 0xD2E7470EE14C6C93, 0xBB67AE8584CAA73B> philox4x64; > +#endif > + > /** > * A standard interface to a platform-specific non-deterministic > * random number generator (if any are available). > diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc > index 53ccacb2e38..de066cf3932 100644 > --- a/libstdc++-v3/include/bits/random.tcc > +++ b/libstdc++-v3/include/bits/random.tcc > @@ -907,6 +907,192 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > return __is; > } > > +#if __cpp_lib_philox_engine > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + _UIntType > + philox_engine<_UIntType, > + __w, __n, __r, __consts...>::_M_mulhi(_UIntType __a, _UIntType __b) Let's turn this into a static member function and rename to _S_mulhi. > + { > + const __uint128_t __num = > + static_cast<__uint128_t>(__a) * static_cast<__uint128_t>(__b); > + return static_cast<_UIntType>((__num >> __w) & max()); > + } > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + _UIntType > + philox_engine<_UIntType, > + __w, __n, __r, __consts...>::_M_mullo(_UIntType __a, _UIntType __b) Same. > + { > + return ((__a * __b) & max()); > + } > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + void > + philox_engine<_UIntType, __w, __n, __r, __consts...>::_M_transition() > + { > + ++_M_i; > + if (_M_i == __n) > + { > + _M_philox(); > + if (__n == 4) Let's make this an 'if constexpr' since the condition is a compile-time constant. > + { > + __uint128_t __uh = > + (static_cast<__uint128_t>(_M_x[1]) << __w) > + | ((_M_x[0]) + 1); > + __uint128_t __lh = > + ((static_cast<__uint128_t>(_M_x[3]) << __w) > + | (_M_x[2])); > + if (!(__uh & max())) > + { > + ++__lh; > + __uh = 0; > + } > + _M_x[0] = __uh & max(); > + _M_x[1] = (__uh >> (__w)) & max(); > + _M_x[2] = __lh & max(); > + _M_x[3] = (__lh >> (__w)) & max(); > + } else > + { > + __uint128_t __num = ((_M_x[1] << __w)) | ((_M_x[0]) + 1); Does this do the right thing if _M_x[0] + 1 overflows (or more generally if ((_M_x[0] + 1) & max()) == 0)? It seems the carry bit won't be properly propagated in thas case. The __n == 4 code has the same issue I think? > + _M_x[0] = __num & max(); > + _M_x[1] = (__num >> __w) & max(); > + } > + _M_i = 0; > + } > + } > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + void > + philox_engine<_UIntType, __w, __n, __r, __consts...>::_M_philox() > + { > + array<_UIntType, __n> __outputSeq{}; > + for (size_t __j = 0; __j < __n; ++__j) > + __outputSeq[__j] = _M_x[__j]; > + for (unsigned long __j = 0; __j < __r; ++__j) > + { > + array<_UIntType, __n> __intermedSeq{}; > + if (__n == 4) if constexpr Besides that looks good I think! It'd be nice to have fallback implementations of _M_mulhi and _M_transition for non-int128 targets, but that could be done in a separate patch as a follow-up if anything. > + { > + __intermedSeq[0] = __outputSeq[2]; > + __intermedSeq[1] = __outputSeq[1]; > + __intermedSeq[2] = __outputSeq[0]; > + __intermedSeq[3] = __outputSeq[3]; > + } else > + { > + __intermedSeq[0] = __outputSeq[0]; > + __intermedSeq[1] = __outputSeq[1]; > + } > + for (unsigned long __k = 0; __k < (__n/2); ++__k) > + { > + __outputSeq[2*__k]= _M_mulhi(__intermedSeq[2*__k], multipliers[__k]) > + ^ (((_M_k[__k] + (__j * round_consts[__k])) & max())) > + ^ __intermedSeq[2*__k+1]; > + > + __outputSeq[(2*__k)+1]= _M_mullo(__intermedSeq[2*__k], > + multipliers[__k]); > + } > + } > + for (unsigned long __j = 0; __j < __n; ++__j) > + _M_y[__j] = __outputSeq[__j]; > + } > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + philox_engine<_UIntType, > + __w, __n, __r, __consts...>::philox_engine(result_type __value) > + { > + std::fill(_M_x.begin(), _M_x.end(), 0); > + std::fill(_M_k.begin(), _M_k.end(), 0); > + std::fill(_M_y.begin(), _M_y.end(), 0); > + _M_k[0] = __value & max(); > + _M_i = __n - 1; > + } > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + void > + philox_engine<_UIntType, > + __w, __n, __r, __consts...>::seed(result_type __value) > + { > + std::fill(_M_x.begin(), _M_x.end(), 0); > + std::fill(_M_k.begin(), _M_k.end(), 0); > + std::fill(_M_y.begin(), _M_y.end(), 0); > + _M_k[0] = __value & max(); > + _M_i = __n - 1; > + } > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + void > + philox_engine<_UIntType, __w, > + __n, __r, __consts...>::set_counter(const array<result_type, __n>& __counter) > + { > + for (unsigned long long __j = 0; __j < __n; ++__j) > + _M_x[__j] = __counter[__n - 1 - __j] & max(); > + _M_i = __n - 1; > + } > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + template<typename _Sseq> > + auto > + philox_engine<_UIntType, __w, __n, __r, __consts...>::seed(_Sseq& __q) > + -> _If_seed_seq<_Sseq> > + { > + std::fill(_M_k.begin(), _M_k.end(), 0); > + const unsigned long long __p = 1 + ((__w - 1)/ 32); > + uint_least32_t __tmpArr[(__n / 2) * __p]; > + __q.generate(__tmpArr + 0, __tmpArr + ((__n / 2) *__p)); > + for (unsigned long long __k = 0; __k < (__n/2); ++__k) > + { > + unsigned long long __precalc = 0; > + for (unsigned long long __j = 0; __j < __p; ++__j) > + { > + unsigned long long __multiplicand = (1ull << (32 * __j)); > + __precalc += (__tmpArr[__k*__p + __j] * __multiplicand) & max(); > + } > + _M_k[__k] = __precalc; > + } > + std::fill(_M_x.begin(), _M_x.end(), 0); > + std::fill(_M_y.begin(), _M_y.end(), 0); > + _M_i = __n - 1; > + } > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + void > + philox_engine<_UIntType, > + __w, __n, __r, __consts...>::discard(unsigned long long __z) > + { > + for (unsigned long long __j = 0; __j < __z; ++__j) > + _M_transition(); > + } > + > + template<class _UIntType, > + size_t __w, size_t __n, > + size_t __r, _UIntType... __consts> > + _UIntType > + philox_engine<_UIntType, __w, __n, __r, __consts...>::operator()() > + { > + _M_transition(); > + return _M_y[_M_i]; > + } > + > +#endif > > template<typename _IntType, typename _CharT, typename _Traits> > std::basic_ostream<_CharT, _Traits>& > diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def > index cf0672b4822..32eedb89bcf 100644 > --- a/libstdc++-v3/include/bits/version.def > +++ b/libstdc++-v3/include/bits/version.def > @@ -2059,6 +2059,15 @@ ftms = { > }; > }; > > +ftms = { > + name = philox_engine; > + values = { > + v = 202406; > + cxxmin = 26; > + extra_cond = "__SIZEOF_INT128__"; > + }; > +}; > + > // Standard test specifications. > stds[97] = ">= 199711L"; > stds[03] = ">= 199711L"; > diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h > index c01ddf14dd5..f90280b4dce 100644 > --- a/libstdc++-v3/include/bits/version.h > +++ b/libstdc++-v3/include/bits/version.h > @@ -2309,4 +2309,14 @@ > #endif /* !defined(__cpp_lib_constexpr_exceptions) && defined(__glibcxx_want_constexpr_exceptions) */ > #undef __glibcxx_want_constexpr_exceptions > > +#if !defined(__cpp_lib_philox_engine) > +# if (__cplusplus > 202302L) && (__SIZEOF_INT128__) > +# define __glibcxx_philox_engine 202406L > +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_philox_engine) > +# define __cpp_lib_philox_engine 202406L > +# endif > +# endif > +#endif /* !defined(__cpp_lib_philox_engine) && defined(__glibcxx_want_philox_engine) */ > +#undef __glibcxx_want_philox_engine > + > #undef __glibcxx_want_all > diff --git a/libstdc++-v3/include/std/random b/libstdc++-v3/include/std/random > index 0e058a04bd9..8a02ade4b75 100644 > --- a/libstdc++-v3/include/std/random > +++ b/libstdc++-v3/include/std/random > @@ -39,6 +39,9 @@ > # include <bits/c++0x_warning.h> > #else > > +#define __glibcxx_want_philox_engine > +#include <bits/version.h> > + > #include <cmath> > #include <cstdint> // For uint_fast32_t, uint_fast64_t, uint_least32_t > #include <cstdlib> > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc > new file mode 100644 > index 00000000000..d5a8ca078ef > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc > @@ -0,0 +1,23 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <random> > +#include <testsuite_hooks.h> > + > +void > +test01() > +{ > + std::philox4x32 a; > + a.discard(9999); > + > + VERIFY( a() == 1955073260 ); > +} > + > +int main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc > new file mode 100644 > index 00000000000..131f094cb28 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc > @@ -0,0 +1,23 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <random> > +#include <testsuite_hooks.h> > + > +void > +test01() > +{ > + std::philox4x64 a; > + a.discard(9999); > + > + VERIFY( a() == 3409172418970261260 ); > +} > + > +int main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc > new file mode 100644 > index 00000000000..c3a5a0eb754 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc > @@ -0,0 +1,39 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +#include <random> > +#include <testsuite_hooks.h> > + > +int f(int x) > +{ > + std::seed_seq sq(&x, &x + 1); > + auto rnd = std::philox4x32(sq); > + return std::uniform_int_distribution<int>()(rnd); > +} > + > +int g(int x) > +{ > + std::seed_seq sq(&x, &x + 1); > + auto rnd = std::philox4x32(); > + rnd.seed(sq); > + return std::uniform_int_distribution<int>()(rnd); > +} > + > +void test01() > +{ > + const int f1 = f(0); > + const int f2 = f(0); > + > + const int g1 = g(0); > + const int g2 = g(0); > + > + VERIFY( f1 == f2 ); > + VERIFY( g1 == g2 ); > + VERIFY( f1 == g1 ); > +} > + > +int main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc > new file mode 100644 > index 00000000000..4f61928a157 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc > @@ -0,0 +1,25 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <random> > + > +void > +test01() > +{ > + > + std::philox_engine<std::uint_fast32_t, 32, 4, 10, 0xCD9E8D57, > + 0x9E3779B9, 0xD2511F53, 0xBB67AE85> e(1ul); > + > + const auto f(e); > + auto g(f); > + g = g; // Suppress unused warning > +} > + > +int main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc > new file mode 100644 > index 00000000000..9f9ae94db0f > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc > @@ -0,0 +1,27 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <random> > +#include <testsuite_hooks.h> > + > +void > +test01() > +{ > + std::philox_engine<std::uint_fast32_t, > + 32, 4, 10, 0xCD9E8D57, > + 0x9E3779B9, 0xD2511F53, > + 0xBB67AE85> philox4x32nullkey(0); > + > + VERIFY( philox4x32nullkey.min() == 0 ); > + VERIFY( philox4x32nullkey.max() == (1ul << 31 | (1ul << 31) - 1) ); > + VERIFY( philox4x32nullkey() == 0x6627e8d5ul ); > +} > + > +int main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc > new file mode 100644 > index 00000000000..5cb914f4b45 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc > @@ -0,0 +1,20 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +#include <random> > + > +void > +test01() > +{ > + unsigned long seed = 2; > + std::philox_engine<std::uint_fast32_t, > + 32, 4, 10, 0xCD9E8D57, > + 0x9E3779B9, 0xD2511F53, > + 0xBB67AE85> philox4x32seeded(seed); > +} > + > +int main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc > new file mode 100644 > index 00000000000..033667616f9 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc > @@ -0,0 +1,22 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +void > +test01() > +{ > + std::seed_seq sseq{ 1, 2, 3, 4 }; > + std::philox_engine<std::uint_fast32_t, > + 32, 4, 10, 0xCD9E8D57, > + 0x9E3779B9, 0xD2511F53, > + 0xBB67AE85> philox4x32sseq(sseq); > +} > + > +int > +main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc > new file mode 100644 > index 00000000000..4f62bfbbd88 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc > @@ -0,0 +1,30 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <random> > +#include <testsuite_hooks.h> > + > +void > +test01() > +{ > + std::philox_engine<std::uint_fast32_t, > + 32, 4, 10, 0xCD9E8D57, > + 0x9E3779B9, 0xD2511F53, > + 0xBB67AE85> x, y; > + > + VERIFY ( x == y); > + x.discard(100); > + y.discard(100); > + > + VERIFY (x == y); > +} > + > +int > +main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc > new file mode 100644 > index 00000000000..86d757db904 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc > @@ -0,0 +1,30 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <random> > +#include <testsuite_hooks.h> > + > +void > +test01() > +{ > + std::philox_engine<std::uint_fast32_t, > + 32, 4, 10, 0xCD9E8D57, > + 0x9E3779B9, 0xD2511F53, > + 0xBB67AE85> x, y; > + > + VERIFY ( !(x != y) ); > + x.discard(100); > + y.discard(100); > + > + VERIFY ( !(x != y) ); > +} > + > +int > +main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc > new file mode 100644 > index 00000000000..bec4b172512 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc > @@ -0,0 +1,49 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <sstream> > +#include <random> > +#include <testsuite_hooks.h> > +#include <iostream> > + > +void > +test01() > +{ > + std::stringstream str; > + std::philox_engine<std::uint_fast32_t, > + 32, 4, 10, 0xCD9E8D57, > + 0x9E3779B9, 0xD2511F53, > + 0xBB67AE85> x, y; > + > + x(); > + str << x; > + > + VERIFY ( !(x == y) ); > + str >> y; > + VERIFY ( x == y ); > + for (unsigned long i = 0; i < 100; ++i) > + { > + VERIFY (x() == y()); > + } > + str.clear(); > + str << y; > + x(); > + x(); > + x(); > + str >> x; > + VERIFY ( x == y ); > + for (unsigned long i = 0; i < 1000; ++i) > + { > + VERIFY (x() == y()); > + } > +} > + > +int > +main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc > new file mode 100644 > index 00000000000..c242056e0a4 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc > @@ -0,0 +1,26 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <random> > + > +void test01() > +{ > + std::philox4x32 philox; > + const void* p = &philox.word_size; > + p = &philox.word_count; > + p = &philox.round_count; > + p = &philox.multipliers; > + p = &philox.round_consts; > + p = &philox.default_seed; > + p = p; // Suppress unused warning. > +} > + > +int > +main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc > new file mode 100644 > index 00000000000..5be0108c88c > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc > @@ -0,0 +1,50 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <random> > +#include <testsuite_common_types.h> > + > +namespace __gnu_test > +{ > + struct constexpr_member_data > + { > + template<typename _Ttesttype> > + void > + operator()() > + { > + struct _Concept > + { > + void __constraint() > + { > + constexpr auto v1 __attribute__((unused)) > + = _Ttesttype::word_size; > + constexpr auto v2 __attribute__((unused)) > + = _Ttesttype::word_count; > + constexpr auto v3 __attribute__((unused)) > + = _Ttesttype::round_count; > + constexpr auto v4 __attribute__((unused)) > + = _Ttesttype::multipliers; > + constexpr auto v5 __attribute__((unused)) > + = _Ttesttype::round_consts; > + constexpr auto v6 __attribute__((unused)) > + = _Ttesttype::default_seed; > + } > + }; > + > + _Concept c; > + c.__constraint(); > + } > + }; > +}; > + > +int > +main() > +{ > + __gnu_test::constexpr_member_data test; > + typedef std::philox4x32 type; > + test.operator()<type>(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc > new file mode 100644 > index 00000000000..eb61d15568a > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc > @@ -0,0 +1,41 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > +#include <random> > +#include <testsuite_common_types.h> > + > +namespace __gnu_test > +{ > + struct constexpr_member_functions > + { > + template<typename _Ttesttype> > + void > + operator()() > + { > + struct _Concept > + { > + void __constraint() > + { > + constexpr auto v1 __attribute__((unused)) > + = _Ttesttype::min(); > + constexpr auto v2 __attribute__((unused)) > + = _Ttesttype::max(); > + } > + }; > + _Concept c; > + c.__constraint(); > + } > + }; > +} > + > +int > +main() > +{ > + __gnu_test::constexpr_member_functions test; > + typedef std::philox4x32 type; > + test.operator()<type>(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc > new file mode 100644 > index 00000000000..b368ee74106 > --- /dev/null > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc > @@ -0,0 +1,26 @@ > +// { dg-do run { target c++26 } } > +// { dg-require-cstdint "" } > + > +// 29.5.4 Random Number Engine Class Templates > +// 29.5.4.5 Class Template philox_engine > + > + > +#include <random> > + > +void > +test01() > +{ > + typedef std::philox_engine<std::uint_fast32_t, > + 32, 4, 10, 0xCD9E8D57, > + 0x9E3779B9, 0xD2511F53, > + 0xBB67AE85> testType; > + > + typedef testType::result_type result_type; > +} > + > +int > +main() > +{ > + test01(); > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc > index 0afba654152..f5d8492c16b 100644 > --- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc > +++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc > @@ -12,4 +12,4 @@ auto x = std::generate_canonical<std::size_t, > > // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 270 } > > -// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3357 } > +// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3543 } > -- > 2.49.0 >
From 08c131c76e75848f282389e21f61c3a47422be67 Mon Sep 17 00:00:00 2001
From: 1nfocalypse <1nfocalypse@protonmail.com>
Date: Sat, 19 Jul 2025 02:08:07 +0000
Subject: [PATCH] [PATCH v4] libstdc++: Implement Philox Engine [PR119794]
Implemented additional changes according to feedback from Patrick Palka.
_charT, _traits -> _CharT, _Traits in stream operator templates
Removed accidental whitespace in random.tcc
Removed unnecessary this-> qualifiers
Removed unnecessary {} wrappers in multiline variable definitions
Removed {} in single-line for loops
Qualified STL functions with std:: to avoid ADL ambiguity;
Left data structures (i.e. std::array) unqualified per v2 feedback
Bug in seed with sseq fixed - should now correctly compute integer ceil
Removed accidental whitespace in include/std/random
Removed duplicate test (covers removal of copyright header)
Still implements LWG4143, LWG4153 errata for Philox Engine.
Additionally altered pr60037-neg.cc to correctly suppress error.
PR libstdc++/119794
---
libstdc++-v3/include/bits/random.h | 298 ++++++++++++++++++
libstdc++-v3/include/bits/random.tcc | 186 +++++++++++
libstdc++-v3/include/bits/version.def | 9 +
libstdc++-v3/include/bits/version.h | 10 +
libstdc++-v3/include/std/random | 3 +
.../26_numerics/random/philox4x32.cc | 23 ++
.../26_numerics/random/philox4x64.cc | 23 ++
.../random/philox_engine/cons/119794.cc | 39 +++
.../random/philox_engine/cons/copy.cc | 25 ++
.../random/philox_engine/cons/default.cc | 27 ++
.../random/philox_engine/cons/seed.cc | 20 ++
.../random/philox_engine/cons/seed_seq.cc | 22 ++
.../random/philox_engine/operators/equal.cc | 30 ++
.../random/philox_engine/operators/inequal.cc | 30 ++
.../philox_engine/operators/serialize.cc | 49 +++
.../philox_engine/requirements/constants.cc | 26 ++
.../requirements/constexpr_data.cc | 50 +++
.../requirements/constexpr_functions.cc | 41 +++
.../philox_engine/requirements/typedefs.cc | 26 ++
.../26_numerics/random/pr60037-neg.cc | 2 +-
20 files changed, 938 insertions(+), 1 deletion(-)
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
create mode 100644 libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
diff --git a/libstdc++-v3/include/bits/random.h b/libstdc++-v3/include/bits/random.h
index 1fdaf51934f..0930008cd90 100644
--- a/libstdc++-v3/include/bits/random.h
+++ b/libstdc++-v3/include/bits/random.h
@@ -1688,6 +1688,286 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return !(__lhs == __rhs); }
#endif
+#if __cpp_lib_philox_engine
+
+ /**
+ * @brief: A discrete pseudorandom number generator based off of weakened
+ * cryptographic primitives.
+ *
+ * This algorithm was intended to be used for highly parallel random number
+ * generation, and is capable of immensely long periods. It provides "Crush-
+ * resistance", denoting an ability to pass the TestU01 Suite's "Big Crush"
+ * test, demonstrating significant apparent entropy. It is not intended for
+ * cryptographic use and should not be used for such, despite being based on
+ * cryptographic primitives.
+ *
+ * The two four-word definitions are likely the best use for this algorithm,
+ * and are given below as defaults.
+ *
+ * This algorithm was created by John Salmon, Mark Moraes, Ron Dror, and
+ * David Shaw as a product of D.E. Shaw Research.
+ *
+ * @tparam __w Word size
+ * @tparam __n Buffer size
+ * @tparam __r Rounds
+ * @tparam __consts Multiplication and round constant pack, ordered as
+ * M_{0}, C_{0}, M_{1}, C_{1}, ... , M_{N/2-1}, C_{N/2-1}
+ *
+ * @headerfile random
+ * @since C++26
+ */
+ template<class _UIntType, size_t __w,
+ size_t __n, size_t __r,
+ _UIntType... __consts>
+ class philox_engine
+ {
+ static_assert(__n == 2 || __n == 4,
+ "template argument N must be either 2 or 4");
+ static_assert(sizeof...(__consts) == __n,
+ "length of consts array must match specified N");
+ static_assert(0 < __r, "a number of rounds must be specified");
+ static_assert((0 < __w && __w <= numeric_limits<_UIntType>::digits),
+ "specified bitlength must match input type");
+ template<typename _Sseq>
+ using _If_seed_seq
+ = __detail::_If_seed_seq_for<_Sseq, philox_engine, _UIntType>;
+
+ private:
+ // the ordering here is essential to functionality.
+ /** @brief an internal unpacking function for %philox_engine. */
+ template <size_t __ind0, size_t __ind1>
+ static constexpr
+ array<_UIntType, __n / 2>
+ _S_popArray()
+ {
+ if constexpr (__n == 4)
+ return {__consts...[__ind0], __consts...[__ind1]};
+ else
+ return {__consts...[__ind0]};
+ }
+
+ public:
+ /** Type of template param. */
+ using result_type = _UIntType;
+ // public members
+ static constexpr size_t word_size = __w;
+ static constexpr size_t word_count = __n;
+ static constexpr size_t round_count = __r;
+ static constexpr array<result_type, __n / 2> multipliers =
+ philox_engine::_S_popArray<0,2>();
+ static constexpr array<result_type, __n / 2> round_consts =
+ philox_engine::_S_popArray<1,3>();
+
+ /** @brief returns the minimum value possible. */
+ static constexpr result_type
+ min()
+ { return 0; }
+
+ /** @brief returns the maximum value possible. */
+ static constexpr result_type
+ max()
+ {
+ return ((1ull << (__w - 1)) | ((1ull << (__w - 1)) - 1));
+ }
+ // default key value
+ static constexpr result_type default_seed = 20111115u;
+
+ // constructors
+ philox_engine()
+ : philox_engine(default_seed)
+ {}
+
+ explicit
+ philox_engine(result_type __value);
+
+ /** @brief seed sequence constructor for %philox_engine
+ *
+ * @params __q the seed sequence
+ */
+ template<typename _Sseq, typename = _If_seed_seq<_Sseq>>
+ explicit
+ philox_engine(_Sseq& __q)
+ {
+ seed(__q);
+ }
+
+
+ void
+ seed(result_type value = default_seed);
+
+ /** @brief seeds %philox_engine by seed sequence
+ *
+ * @params __q the seed sequence
+ */
+ template<typename _Sseq>
+ _If_seed_seq<_Sseq>
+ seed(_Sseq& __q);
+
+ /** @brief sets the internal counter "cleartext"
+ *
+ * @params __counter std::array of len N
+ */
+ void
+ set_counter(const array<result_type, __n>& __counter);
+
+ /** @brief compares two %philox_engine objects
+ *
+ * @params __x A %philox_engine object
+ * @params __y A %philox_engine object
+ *
+ * @returns true if the objects will produce an identical stream, false
+ * otherwise
+ */
+ friend bool
+ operator==(const philox_engine& __x, const philox_engine& __y)
+ {
+ return (std::equal(__x._M_x.begin(), __x._M_x.end(),
+ __y._M_x.begin(), __y._M_x.end())
+ && std::equal(__x._M_y.begin(), __x._M_y.end(),
+ __y._M_y.begin(), __y._M_y.end())
+ && std::equal(__x._M_k.begin(), __x._M_k.end(),
+ __y._M_k.begin(), __y._M_k.end())
+ && __x._M_i == __y._M_i);
+ }
+
+ /** @brief outputs a single w-bit number and handles state advancement
+ *
+ * @returns return_type
+ */
+ _UIntType
+ operator()();
+
+ /** @brief discards __z numbers
+ *
+ * @params __z number of iterations to discard
+ */
+ void
+ discard(unsigned long long __z);
+
+ /** @brief outputs the state of the generator
+ *
+ * @param __os An output stream.
+ * @param __x A %philox_engine object reference
+ *
+ * @returns the state of the Philox Engine in __os
+ */
+ template<typename _CharT, typename _Traits>
+ friend basic_ostream<_CharT, _Traits>&
+ operator<<(basic_ostream<_CharT, _Traits>& __os,
+ const philox_engine& __x)
+ {
+ using __ios_base = ios_base;
+ const typename __ios_base::fmtflags __flags = __os.flags();
+ const _CharT __fill = __os.fill();
+ __os.flags(__ios_base::dec | __ios_base::left);
+ __os.fill(__os.widen(' '));
+ auto __it = __x._M_k.begin();
+ while (__it != __x._M_k.end())
+ {
+ __os << *__it << ' ';
+ ++__it;
+ }
+ auto __it2 = __x._M_x.begin();
+ while (__it2 != __x._M_x.end())
+ {
+ __os << *__it2 << ' ';
+ ++__it2;
+ }
+ __os << __x._M_i;
+ __os.flags(__flags);
+ __os.fill(__fill);
+ return __os;
+ }
+
+ /** @brief takes input to set the state of the %philox_engine object
+ *
+ * @param __is An input stream.
+ * @param __x A %philox_engine object reference
+ *
+ * @returns %philox_engine object is set with values from instream
+ */
+ template <typename _CharT, typename _Traits>
+ friend basic_istream<_CharT, _Traits>&
+ operator>>(basic_istream<_CharT, _Traits>& __is,
+ philox_engine& __x)
+ {
+ using __ios_base = ios_base;
+ const typename __ios_base::fmtflags __flags = __is.flags();
+ __is.flags(__ios_base::dec | __ios_base::skipws);
+ for (size_t __j = 0; __j < __x._M_k.size(); ++__j)
+ {
+ __is >> __x._M_k[__j];
+ }
+ for (size_t __j = 0; __j < __x._M_x.size(); ++__j)
+ {
+ __is >> __x._M_x[__j];
+ }
+ array<_UIntType, __n> __tmpCtr = __x._M_x;
+ unsigned char __setIndex = 0;
+ for (size_t __j = 0; __j < __x._M_x.size(); ++__j)
+ {
+ if (__x._M_x[__j] > 0)
+ {
+ __setIndex = __j;
+ break;
+ }
+ }
+ for (size_t __j = 0; __j <= __setIndex; ++__j)
+ {
+ if (__j != __setIndex)
+ {
+ __x._M_x[__j] = max();
+ } else
+ {
+ --__x._M_x[__j];
+ }
+ }
+ __x._M_philox();
+ __x._M_x = __tmpCtr;
+ __is >> __x._M_i;
+ __is.flags(__flags);
+ return __is;
+ }
+ private:
+ // private state variables
+ array<_UIntType, __n> _M_x;
+ array<_UIntType, __n / 2> _M_k;
+ array<_UIntType, __n> _M_y;
+ unsigned long long _M_i = 0;
+
+ /** @brief Takes the high values of the product of __a, __b
+ *
+ * @params __a an unsigned integer
+ * @params __b an unsigned integer
+ *
+ * @returns an unsigned integer of at most bitlength W
+ */
+ _UIntType
+ _M_mulhi(_UIntType __a, _UIntType __b); // (A*B)/2^W
+
+ /** @brief Takes the low values of the product of __a, __b
+ *
+ * @params __a an unsigned integer
+ * @params __b an unsigned integer
+ *
+ * @returns an unsigned integer of at most bitlength W
+ */
+ _UIntType
+ _M_mullo(_UIntType __a, _UIntType __b); // (A*B)%2^W
+
+ /** @brief an R-round substitution/Feistel Network hybrid for
+ * %philox_engine
+ */
+ void
+ _M_philox();
+
+ /** @brief an internal transition function for the %philox_engine. */
+ void
+ _M_transition();
+ };
+
+#endif
+
/**
* The classic Minimum Standard rand0 of Lewis, Goodman, and Miller.
*/
@@ -1742,6 +2022,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef minstd_rand0 default_random_engine;
+#if __cpp_lib_philox_engine
+
+ typedef philox_engine<
+ uint_fast32_t,
+ 32, 4, 10,
+ 0xCD9E8D57, 0x9E3779B9,
+ 0xD2511F53, 0xBB67AE85> philox4x32;
+
+ /**
+ * Alternative Philox instance (64 bit)
+ */
+ typedef philox_engine<
+ uint_fast64_t,
+ 64, 4, 10,
+ 0xCA5A826395121157, 0x9E3779B97F4A7C15,
+ 0xD2E7470EE14C6C93, 0xBB67AE8584CAA73B> philox4x64;
+#endif
+
/**
* A standard interface to a platform-specific non-deterministic
* random number generator (if any are available).
diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc
index 53ccacb2e38..de066cf3932 100644
--- a/libstdc++-v3/include/bits/random.tcc
+++ b/libstdc++-v3/include/bits/random.tcc
@@ -907,6 +907,192 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __is;
}
+#if __cpp_lib_philox_engine
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ _UIntType
+ philox_engine<_UIntType,
+ __w, __n, __r, __consts...>::_M_mulhi(_UIntType __a, _UIntType __b)
+ {
+ const __uint128_t __num =
+ static_cast<__uint128_t>(__a) * static_cast<__uint128_t>(__b);
+ return static_cast<_UIntType>((__num >> __w) & max());
+ }
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ _UIntType
+ philox_engine<_UIntType,
+ __w, __n, __r, __consts...>::_M_mullo(_UIntType __a, _UIntType __b)
+ {
+ return ((__a * __b) & max());
+ }
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ void
+ philox_engine<_UIntType, __w, __n, __r, __consts...>::_M_transition()
+ {
+ ++_M_i;
+ if (_M_i == __n)
+ {
+ _M_philox();
+ if (__n == 4)
+ {
+ __uint128_t __uh =
+ (static_cast<__uint128_t>(_M_x[1]) << __w)
+ | ((_M_x[0]) + 1);
+ __uint128_t __lh =
+ ((static_cast<__uint128_t>(_M_x[3]) << __w)
+ | (_M_x[2]));
+ if (!(__uh & max()))
+ {
+ ++__lh;
+ __uh = 0;
+ }
+ _M_x[0] = __uh & max();
+ _M_x[1] = (__uh >> (__w)) & max();
+ _M_x[2] = __lh & max();
+ _M_x[3] = (__lh >> (__w)) & max();
+ } else
+ {
+ __uint128_t __num = ((_M_x[1] << __w)) | ((_M_x[0]) + 1);
+ _M_x[0] = __num & max();
+ _M_x[1] = (__num >> __w) & max();
+ }
+ _M_i = 0;
+ }
+ }
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ void
+ philox_engine<_UIntType, __w, __n, __r, __consts...>::_M_philox()
+ {
+ array<_UIntType, __n> __outputSeq{};
+ for (size_t __j = 0; __j < __n; ++__j)
+ __outputSeq[__j] = _M_x[__j];
+ for (unsigned long __j = 0; __j < __r; ++__j)
+ {
+ array<_UIntType, __n> __intermedSeq{};
+ if (__n == 4)
+ {
+ __intermedSeq[0] = __outputSeq[2];
+ __intermedSeq[1] = __outputSeq[1];
+ __intermedSeq[2] = __outputSeq[0];
+ __intermedSeq[3] = __outputSeq[3];
+ } else
+ {
+ __intermedSeq[0] = __outputSeq[0];
+ __intermedSeq[1] = __outputSeq[1];
+ }
+ for (unsigned long __k = 0; __k < (__n/2); ++__k)
+ {
+ __outputSeq[2*__k]= _M_mulhi(__intermedSeq[2*__k], multipliers[__k])
+ ^ (((_M_k[__k] + (__j * round_consts[__k])) & max()))
+ ^ __intermedSeq[2*__k+1];
+
+ __outputSeq[(2*__k)+1]= _M_mullo(__intermedSeq[2*__k],
+ multipliers[__k]);
+ }
+ }
+ for (unsigned long __j = 0; __j < __n; ++__j)
+ _M_y[__j] = __outputSeq[__j];
+ }
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ philox_engine<_UIntType,
+ __w, __n, __r, __consts...>::philox_engine(result_type __value)
+ {
+ std::fill(_M_x.begin(), _M_x.end(), 0);
+ std::fill(_M_k.begin(), _M_k.end(), 0);
+ std::fill(_M_y.begin(), _M_y.end(), 0);
+ _M_k[0] = __value & max();
+ _M_i = __n - 1;
+ }
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ void
+ philox_engine<_UIntType,
+ __w, __n, __r, __consts...>::seed(result_type __value)
+ {
+ std::fill(_M_x.begin(), _M_x.end(), 0);
+ std::fill(_M_k.begin(), _M_k.end(), 0);
+ std::fill(_M_y.begin(), _M_y.end(), 0);
+ _M_k[0] = __value & max();
+ _M_i = __n - 1;
+ }
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ void
+ philox_engine<_UIntType, __w,
+ __n, __r, __consts...>::set_counter(const array<result_type, __n>& __counter)
+ {
+ for (unsigned long long __j = 0; __j < __n; ++__j)
+ _M_x[__j] = __counter[__n - 1 - __j] & max();
+ _M_i = __n - 1;
+ }
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ template<typename _Sseq>
+ auto
+ philox_engine<_UIntType, __w, __n, __r, __consts...>::seed(_Sseq& __q)
+ -> _If_seed_seq<_Sseq>
+ {
+ std::fill(_M_k.begin(), _M_k.end(), 0);
+ const unsigned long long __p = 1 + ((__w - 1)/ 32);
+ uint_least32_t __tmpArr[(__n / 2) * __p];
+ __q.generate(__tmpArr + 0, __tmpArr + ((__n / 2) *__p));
+ for (unsigned long long __k = 0; __k < (__n/2); ++__k)
+ {
+ unsigned long long __precalc = 0;
+ for (unsigned long long __j = 0; __j < __p; ++__j)
+ {
+ unsigned long long __multiplicand = (1ull << (32 * __j));
+ __precalc += (__tmpArr[__k*__p + __j] * __multiplicand) & max();
+ }
+ _M_k[__k] = __precalc;
+ }
+ std::fill(_M_x.begin(), _M_x.end(), 0);
+ std::fill(_M_y.begin(), _M_y.end(), 0);
+ _M_i = __n - 1;
+ }
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ void
+ philox_engine<_UIntType,
+ __w, __n, __r, __consts...>::discard(unsigned long long __z)
+ {
+ for (unsigned long long __j = 0; __j < __z; ++__j)
+ _M_transition();
+ }
+
+ template<class _UIntType,
+ size_t __w, size_t __n,
+ size_t __r, _UIntType... __consts>
+ _UIntType
+ philox_engine<_UIntType, __w, __n, __r, __consts...>::operator()()
+ {
+ _M_transition();
+ return _M_y[_M_i];
+ }
+
+#endif
template<typename _IntType, typename _CharT, typename _Traits>
std::basic_ostream<_CharT, _Traits>&
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index cf0672b4822..32eedb89bcf 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -2059,6 +2059,15 @@ ftms = {
};
};
+ftms = {
+ name = philox_engine;
+ values = {
+ v = 202406;
+ cxxmin = 26;
+ extra_cond = "__SIZEOF_INT128__";
+ };
+};
+
// Standard test specifications.
stds[97] = ">= 199711L";
stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index c01ddf14dd5..f90280b4dce 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2309,4 +2309,14 @@
#endif /* !defined(__cpp_lib_constexpr_exceptions) && defined(__glibcxx_want_constexpr_exceptions) */
#undef __glibcxx_want_constexpr_exceptions
+#if !defined(__cpp_lib_philox_engine)
+# if (__cplusplus > 202302L) && (__SIZEOF_INT128__)
+# define __glibcxx_philox_engine 202406L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_philox_engine)
+# define __cpp_lib_philox_engine 202406L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_philox_engine) && defined(__glibcxx_want_philox_engine) */
+#undef __glibcxx_want_philox_engine
+
#undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/std/random b/libstdc++-v3/include/std/random
index 0e058a04bd9..8a02ade4b75 100644
--- a/libstdc++-v3/include/std/random
+++ b/libstdc++-v3/include/std/random
@@ -39,6 +39,9 @@
# include <bits/c++0x_warning.h>
#else
+#define __glibcxx_want_philox_engine
+#include <bits/version.h>
+
#include <cmath>
#include <cstdint> // For uint_fast32_t, uint_fast64_t, uint_least32_t
#include <cstdlib>
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
new file mode 100644
index 00000000000..d5a8ca078ef
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
@@ -0,0 +1,23 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::philox4x32 a;
+ a.discard(9999);
+
+ VERIFY( a() == 1955073260 );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
new file mode 100644
index 00000000000..131f094cb28
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
@@ -0,0 +1,23 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::philox4x64 a;
+ a.discard(9999);
+
+ VERIFY( a() == 3409172418970261260 );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
new file mode 100644
index 00000000000..c3a5a0eb754
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
@@ -0,0 +1,39 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+#include <testsuite_hooks.h>
+
+int f(int x)
+{
+ std::seed_seq sq(&x, &x + 1);
+ auto rnd = std::philox4x32(sq);
+ return std::uniform_int_distribution<int>()(rnd);
+}
+
+int g(int x)
+{
+ std::seed_seq sq(&x, &x + 1);
+ auto rnd = std::philox4x32();
+ rnd.seed(sq);
+ return std::uniform_int_distribution<int>()(rnd);
+}
+
+void test01()
+{
+ const int f1 = f(0);
+ const int f2 = f(0);
+
+ const int g1 = g(0);
+ const int g2 = g(0);
+
+ VERIFY( f1 == f2 );
+ VERIFY( g1 == g2 );
+ VERIFY( f1 == g1 );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
new file mode 100644
index 00000000000..4f61928a157
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
@@ -0,0 +1,25 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+
+void
+test01()
+{
+
+ std::philox_engine<std::uint_fast32_t, 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53, 0xBB67AE85> e(1ul);
+
+ const auto f(e);
+ auto g(f);
+ g = g; // Suppress unused warning
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
new file mode 100644
index 00000000000..9f9ae94db0f
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> philox4x32nullkey(0);
+
+ VERIFY( philox4x32nullkey.min() == 0 );
+ VERIFY( philox4x32nullkey.max() == (1ul << 31 | (1ul << 31) - 1) );
+ VERIFY( philox4x32nullkey() == 0x6627e8d5ul );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
new file mode 100644
index 00000000000..5cb914f4b45
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
@@ -0,0 +1,20 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+
+void
+test01()
+{
+ unsigned long seed = 2;
+ std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> philox4x32seeded(seed);
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
new file mode 100644
index 00000000000..033667616f9
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
@@ -0,0 +1,22 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+void
+test01()
+{
+ std::seed_seq sseq{ 1, 2, 3, 4 };
+ std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> philox4x32sseq(sseq);
+}
+
+int
+main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
new file mode 100644
index 00000000000..4f62bfbbd88
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
@@ -0,0 +1,30 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> x, y;
+
+ VERIFY ( x == y);
+ x.discard(100);
+ y.discard(100);
+
+ VERIFY (x == y);
+}
+
+int
+main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
new file mode 100644
index 00000000000..86d757db904
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
@@ -0,0 +1,30 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> x, y;
+
+ VERIFY ( !(x != y) );
+ x.discard(100);
+ y.discard(100);
+
+ VERIFY ( !(x != y) );
+}
+
+int
+main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
new file mode 100644
index 00000000000..bec4b172512
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
@@ -0,0 +1,49 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <sstream>
+#include <random>
+#include <testsuite_hooks.h>
+#include <iostream>
+
+void
+test01()
+{
+ std::stringstream str;
+ std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> x, y;
+
+ x();
+ str << x;
+
+ VERIFY ( !(x == y) );
+ str >> y;
+ VERIFY ( x == y );
+ for (unsigned long i = 0; i < 100; ++i)
+ {
+ VERIFY (x() == y());
+ }
+ str.clear();
+ str << y;
+ x();
+ x();
+ x();
+ str >> x;
+ VERIFY ( x == y );
+ for (unsigned long i = 0; i < 1000; ++i)
+ {
+ VERIFY (x() == y());
+ }
+}
+
+int
+main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
new file mode 100644
index 00000000000..c242056e0a4
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
@@ -0,0 +1,26 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+
+void test01()
+{
+ std::philox4x32 philox;
+ const void* p = &philox.word_size;
+ p = &philox.word_count;
+ p = &philox.round_count;
+ p = &philox.multipliers;
+ p = &philox.round_consts;
+ p = &philox.default_seed;
+ p = p; // Suppress unused warning.
+}
+
+int
+main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
new file mode 100644
index 00000000000..5be0108c88c
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
@@ -0,0 +1,50 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+ struct constexpr_member_data
+ {
+ template<typename _Ttesttype>
+ void
+ operator()()
+ {
+ struct _Concept
+ {
+ void __constraint()
+ {
+ constexpr auto v1 __attribute__((unused))
+ = _Ttesttype::word_size;
+ constexpr auto v2 __attribute__((unused))
+ = _Ttesttype::word_count;
+ constexpr auto v3 __attribute__((unused))
+ = _Ttesttype::round_count;
+ constexpr auto v4 __attribute__((unused))
+ = _Ttesttype::multipliers;
+ constexpr auto v5 __attribute__((unused))
+ = _Ttesttype::round_consts;
+ constexpr auto v6 __attribute__((unused))
+ = _Ttesttype::default_seed;
+ }
+ };
+
+ _Concept c;
+ c.__constraint();
+ }
+ };
+};
+
+int
+main()
+{
+ __gnu_test::constexpr_member_data test;
+ typedef std::philox4x32 type;
+ test.operator()<type>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
new file mode 100644
index 00000000000..eb61d15568a
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
@@ -0,0 +1,41 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+ struct constexpr_member_functions
+ {
+ template<typename _Ttesttype>
+ void
+ operator()()
+ {
+ struct _Concept
+ {
+ void __constraint()
+ {
+ constexpr auto v1 __attribute__((unused))
+ = _Ttesttype::min();
+ constexpr auto v2 __attribute__((unused))
+ = _Ttesttype::max();
+ }
+ };
+ _Concept c;
+ c.__constraint();
+ }
+ };
+}
+
+int
+main()
+{
+ __gnu_test::constexpr_member_functions test;
+ typedef std::philox4x32 type;
+ test.operator()<type>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
new file mode 100644
index 00000000000..b368ee74106
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
@@ -0,0 +1,26 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+
+#include <random>
+
+void
+test01()
+{
+ typedef std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> testType;
+
+ typedef testType::result_type result_type;
+}
+
+int
+main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
index 0afba654152..f5d8492c16b 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
@@ -12,4 +12,4 @@ auto x = std::generate_canonical<std::size_t,
// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 270 }
-// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3357 }
+// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3543 }
--
2.49.0