I've pushed your philox implementation to trunk now, thanks very much for adding it to GCC!
I also pushed some minor refactoring, and would still like to address the (unnecessary?) uses of 64-bit types pointed out in the mail below. And we need to make it use uint64_t for the calculations when the result type only has 32-bits, and eventually emulate 128-bit arithmetic to support 64-bit result types on targets without int128. But they can all be done later. On Mon, 8 Sept 2025, 16:46 Jonathan Wakely, <jwak...@redhat.com> wrote: > On Mon, 08 Sep 2025 at 15:55 +0100, Jonathan Wakely wrote: > >On Tue, 05 Aug 2025 at 09:21 +0000, 1nfocalypse wrote: > >>Implements Philox Engine (P2075R6) and associated tests. > >> > >>Implements additional feedback from v5 from Patrick Palka. > >>Also cut some trailing whitespace from the limb propagation > >>fix in v5. > >> > >>Apologies for the delay from v5 - I had to finish writing some > >>CTF challenges for DEFCON this week. Thank you for the > >>feedback, and please let me know if anything further needs > >>to be changed. > >> > >>Built/tested on x86_64-pc-linux-gnu. > > > >>From 23ffd0ca595c27e8721d6d73ac746293aace7771 Mon Sep 17 00:00:00 2001 > >>From: 1nfocalypse <1nfocaly...@protonmail.com> > >>Date: Tue, 5 Aug 2025 01:37:18 +0000 > >>Subject: [PATCH] [PATCH v6] libstdc++: Implement Philox Engine (PR119794) > >> > >>Implemented additional changes from Patrick Palka. > >>Also removed some trailing whitespace in random.tcc. > >> > >>replaced alias of __ios_base with ios_base > >>included <iomanip> in random.h > >>altered line number in pr60037-neg.cc to be accurate > >>Refactored iterator/index loops to be range-based for > >>in istream/ostream operator overloads > >>include <random> in philox_engine/cons/seed_seq.cc > >>Conforms with errata LWG4143, LWG4153 for Philox Engine. > >> > >> PR libstdc++/119794 > >>--- > >>libstdc++-v3/include/bits/random.h | 283 ++++++++++++++++++ > >>libstdc++-v3/include/bits/random.tcc | 191 ++++++++++++ > >>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 | 24 ++ > >>.../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 | 4 +- > >>20 files changed, 931 insertions(+), 2 deletions(-) > >>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..e74b7bd75c0 100644 > >>--- a/libstdc++-v3/include/bits/random.h > >>+++ b/libstdc++-v3/include/bits/random.h > >>@@ -33,6 +33,7 @@ > >> > >>#include <vector> > >>#include <bits/uniform_int_dist.h> > >>+#include <iomanip> > >> > >>namespace std _GLIBCXX_VISIBILITY(default) > >>{ > >>@@ -1688,6 +1689,270 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >> { return !(__lhs == __rhs); } > >>#endif > >> > >>+#if __cpp_lib_philox_engine > > > >This should check __glibcxx_philox_engine (just in case this code is > >moved to a separate header that ends up being included somewhere > >withou all of <random>). > > > >>+ /** > >>+ * @brief: A discrete pseudorandom number generator based off of > weakened > >>+ * cryptographic primitives. > > > >Can we say "based on" instead of "based off of" which is an informal > >American English term that sounds wrong to me. > > > >I'm also not sure what this is telling me as a non-export user. Would > >it be clearer to talk about it having weak cryptographic properties, > >rather than being based on weakened cryptographic primitives? > > > >>+ * > >>+ * This algorithm was intended to be used for highly parallel random > number > > > >"was intended to be used" sounds like it refers to something in the > >past that is no longer true. Maybe "was designed to be used" instead? > > > >>+ * generation, and is capable of immensely long periods. It provides > "Crush- > > > >I was going to ask whether immensely is a bit hyperbolic and could be > >just "very long periods (e.g. ...)" but since we're talking at least > >2^128 I think "immensely" is fine :-) > > > >>+ * 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. > > > >Can we refer to those as aliases or typedefs rather than definitions? > >Or specializations? > > > >Maybe even say it like this: > > > > * The typedefs `philox4x32` and `philox4x64` are provided as > > * suitable defaults for most use cases, providing high-quality > > * random numbers at reasonable performance. > > > > > >>+ * > >>+ * 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, > > > >Our convention in libstdc++ code is to type 'typename' for template > >parameters instead of 'class' > > > >>+ 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"); > > > >The static assert messages all use the preferred "must" form, thanks! > > > >>+ template<typename _Sseq> > >>+ using _If_seed_seq > >>+ = __detail::_If_seed_seq_for<_Sseq, philox_engine, _UIntType>; > >>+ > >>+ private: > > > >This access specifier is redundant because everything above it is > >already private. > > > >>+ // the ordering here is essential to functionality. > > > >Does this refer to the ordering of the _S_popArray member in the > >class, because it needs to be declared before it's used? > > > >If so, I think we can drop the comment. If somebody fails to notice > >that when reading the class definition, they'd find out pretty quickly > >if they tried to reorder it and got errors. > > > >The style recommendations to put private internal members last is not > >a hard requirement, for cases like this where the order is significant > >putting them first is obviously fine (since you have no choice! :-) > > > >>+ /** @brief an internal unpacking function for %philox_engine. */ > > > >We don't need a doxygen comment for private member functions, they > >won't get included in the docs anyway. > > > >>+ 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; > > > >I wonder if we have a defect in the C++26 draft here, because > >20111115u won't fit in a 16-bit int. We fixed that for > >std::subtract_with_carry_engine via: > >https://cplusplus.github.io/LWG/issue3809 > >and then fixed what I broke via: > >https://cplusplus.github.io/LWG/issue4014 > > > >Since the value of default_seed is only used as the argument to the > >default ctor (or the equivalent of calling seed() with no argument) > >and the ctor reduces value by mod 2^w, I think we could define the > >default seed as 20111115u & max(). > > > >But let's leave it for now, I'll raise this with LWG. > > > >>+ > >>+ // 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) > >>+ { > > > >The "operator<<" and "{" lines should be lined up with "friend" > > > >>+ 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(' ')); > >>+ for (auto &__subkey : __x._M_k) > > > >auto& rather than putting the space before the & please (and below as > >well). > > > >>+ __os << __subkey << ' '; > >>+ for (auto &__ctr : __x._M_x) > >>+ __os << __ctr << ' '; > > > >Inserting ' ' will get widened if __os is a wide stream, but since > >you've already called __os.widen(' ') above you could save the result > >of that in a local variable and then insert that character instead of > >' '. That will avoid calling widen again on every iteration of the > >loop. > > > >>+ __os << __x._M_i; > >>+ __os.flags(__flags); > > > >If writing to the stream throws an exception we won't restore the > >flags and fill character, but I think that's consistent with all our > >operator<< overloads in <random>. > > > >>+ __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) > >>+ { > > > >Same comment about aligning to "friend". > > > >>+ const typename ios_base::fmtflags __flags = __is.flags(); > >>+ __is.flags(ios_base::dec | ios_base::skipws); > >>+ for (auto &__subkey : __x._M_k) > >>+ __is >> __subkey; > >>+ for (auto &__ctr : __x._M_x) > >>+ __is >> __ctr; > >>+ 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; > > Why is this unsigned long long? The maximum value of i is 4, isn't it? > > >>+ 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) > > Should __j be size_t? > > Otherwise on Windows it would be 32-bit, but __r is size_t which is > 64-bit, and so __j < __r might never be true. > > >>+ { > >>+ array<_UIntType, __n> __intermedSeq{}; > >>+ if constexpr (__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) > > __k should be the same type as __n, although this loop never runs > more than twice, right? > > >>+ { > >>+ __outputSeq[2*__k]= _S_mulhi(__intermedSeq[2*__k], > multipliers[__k]) > >>+ ^ (((_M_k[__k] + (__j * round_consts[__k])) & max())) > >>+ ^ __intermedSeq[2*__k+1]; > >>+ > >>+ __outputSeq[(2*__k)+1]= _S_mullo(__intermedSeq[2*__k], > >>+ multipliers[__k]); > >>+ } > >>+ } > >>+ for (unsigned long __j = 0; __j < __n; ++__j) > >>+ _M_y[__j] = __outputSeq[__j]; > > __j should be the same type as __n, but can this be simply: > > _M_y = __outputSeq; > > ? > > >>+ } > >>+ > >>+ 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); > > > >Can we just initialize these in a mem-initializer-list? > > > > : _M_x{}, _M_k{}, _M_y{} > > > >The compiler is more likely to optimize that well. > > > >>+ _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); > > > >This can use std::array::fill, i.e. _M_x.fill(0); > > > >Or would this whole function be simpler as: > > > > *this = philox_engine(__value); > > > >? > > > >>+ 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) > > __j should be the same type as __n > > >>+ _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(); > >>+ } > > Do any of the variables above need to be unsigned long long? > > >>+ _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 dbe2cb8f175..4c21fa187c8 100644 > >>--- a/libstdc++-v3/include/bits/version.def > >>+++ b/libstdc++-v3/include/bits/version.def > >>@@ -2069,6 +2069,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 7bb6016df68..75a9946adce 100644 > >>--- a/libstdc++-v3/include/bits/version.h > >>+++ b/libstdc++-v3/include/bits/version.h > >>@@ -2318,4 +2318,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 > > > >Please identify the document where these references are from, because > >29.5.4 might be a different subclause in C++29, i.e. > > > >>+// N5014 29.5.4 Random Number Engine Class Templates > >>+// N5014 29.5.4.5 Class Template philox_engine > > > >(Ideally we'd say "C++26 29.5.4 ..." but we don't know if that > >subclause number will be correct in the final standard.) > > > >>+ > >>+#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..7d9e3e6540d > >>--- /dev/null > >>+++ > b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc > >>@@ -0,0 +1,24 @@ > >>+// { 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::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..13a0b8947b0 100644 > >>--- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc > >>+++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc > >>@@ -10,6 +10,6 @@ std::__detail::_Adaptor<std::mt19937, unsigned long> > aurng(urng); > >>auto x = std::generate_canonical<std::size_t, > >> std::numeric_limits<std::size_t>::digits>(urng); > >> > >>-// { 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 *-*-* } 271 } > >> > >>-// { 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 *-*-* } 3548 } > >>-- > >>2.49.0 > >> > > > >