[PATCH v6] libstdc++: Implement Philox Engine (PR119794)

Jonathan Wakely jwakely@redhat.com
Mon Sep 8 15:46:06 GMT 2025


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 <1nfocalypse@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
>>
>



More information about the Libstdc++ mailing list