[gcc r16-4062] libstdc++: Implement Philox Engine (PR119794)

Jonathan Wakely redi@gcc.gnu.org
Tue Sep 23 15:38:54 GMT 2025


https://gcc.gnu.org/g:1c06243e65561726ae4fc1060b6164d0caec2ae6

commit r16-4062-g1c06243e65561726ae4fc1060b6164d0caec2ae6
Author: 1nfocalypse <1nfocalypse@protonmail.com>
Date:   Tue Aug 5 01:37:18 2025 +0000

    libstdc++: Implement Philox Engine (PR119794)
    
    Conforms with errata LWG4143, LWG4153 for Philox Engine.
    
            PR libstdc++/119794
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/random.h (philox_engine): Define.
            * include/bits/random.tcc (philox_engine): Define member
            functions.
            * include/bits/version.def (philox_engine): New macro.
            * include/bits/version.h: Regenerated.
            * include/std/random: Define __glibcxx_want_philox_engine and
            include <bits/version.h>.
            * testsuite/26_numerics/random/pr60037-neg.cc: Adjust dg-error
            line number.
            * testsuite/26_numerics/random/philox4x32.cc: New test.
            * testsuite/26_numerics/random/philox4x64.cc: New test.
            * testsuite/26_numerics/random/philox_engine/cons/119794.cc: New test.
            * testsuite/26_numerics/random/philox_engine/cons/copy.cc: New test.
            * testsuite/26_numerics/random/philox_engine/cons/default.cc: New test.
            * testsuite/26_numerics/random/philox_engine/cons/seed.cc: New test.
            * testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc: New test.
            * testsuite/26_numerics/random/philox_engine/operators/equal.cc: New test.
            * testsuite/26_numerics/random/philox_engine/operators/inequal.cc: New test.
            * testsuite/26_numerics/random/philox_engine/operators/serialize.cc: New test.
            * testsuite/26_numerics/random/philox_engine/requirements/constants.cc: New test.
            * testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc: New test.
            * testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc: New test.
            * testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc: New test.

Diff:
---
 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 +
 .../testsuite/26_numerics/random/philox4x32.cc     |  23 ++
 .../testsuite/26_numerics/random/philox4x64.cc     |  23 ++
 .../random/philox_engine/cons/119794.cc            |  39 +++
 .../26_numerics/random/philox_engine/cons/copy.cc  |  25 ++
 .../random/philox_engine/cons/default.cc           |  27 ++
 .../26_numerics/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 +++
 .../random/philox_engine/operators/serialize.cc    |  49 ++++
 .../random/philox_engine/requirements/constants.cc |  26 ++
 .../philox_engine/requirements/constexpr_data.cc   |  50 ++++
 .../requirements/constexpr_functions.cc            |  41 +++
 .../random/philox_engine/requirements/typedefs.cc  |  26 ++
 .../testsuite/26_numerics/random/pr60037-neg.cc    |   4 +-
 20 files changed, 931 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/bits/random.h b/libstdc++-v3/include/bits/random.h
index 1fdaf51934fd..e74b7bd75c03 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
+
+  /**
+   * @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)
+	      {
+		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)
+		  __os << __subkey << ' ';
+		for (auto &__ctr : __x._M_x)
+		  __os << __ctr << ' ';
+		__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)
+	      {
+		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;
+
+	/** @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
+	  */
+	static
+	_UIntType
+	_S_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
+	  */
+	static
+	_UIntType
+	_S_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 +2007,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 53ccacb2e38b..53f302da8007 100644
--- a/libstdc++-v3/include/bits/random.tcc
+++ b/libstdc++-v3/include/bits/random.tcc
@@ -907,6 +907,197 @@ _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...>::_S_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...>::_S_mullo(_UIntType __a, _UIntType __b)
+  {
+    return static_cast<_UIntType>((__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 constexpr (__n == 4)
+      {
+	__uint128_t __uh =
+	  (static_cast<__uint128_t>(_M_x[1]) << __w)
+		| (static_cast<__uint128_t>(_M_x[0]) + 1);
+	__uint128_t __lh =
+	  ((static_cast<__uint128_t>(_M_x[3]) << __w)
+		| (_M_x[2]));
+	__uint128_t __bigMask =
+	  (static_cast<__uint128_t>(1) << ((2 * __w) - 1))
+	        | ((static_cast<__uint128_t>(1) << ((2 * __w) - 1)) - 1);
+	if ((__uh & __bigMask) == 0)
+	{
+	  ++__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 =
+		(static_cast<__uint128_t>(_M_x[1]) << __w)
+		| (static_cast<__uint128_t>(_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 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)
+      {
+	__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];
+  }
+
+  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 721125df280f..3a26234f87ed 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -2137,6 +2137,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 7e8ad1007efa..46e4c1121e7a 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2397,4 +2397,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 0e058a04bd9a..8a02ade4b75e 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 000000000000..d5a8ca078eff
--- /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 000000000000..131f094cb287
--- /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 000000000000..c3a5a0eb7545
--- /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 000000000000..4f61928a1575
--- /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 000000000000..9f9ae94db0f3
--- /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 000000000000..5cb914f4b45c
--- /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 000000000000..7d9e3e6540d2
--- /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 000000000000..4f62bfbbd88e
--- /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 000000000000..86d757db9040
--- /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 000000000000..bec4b1725127
--- /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 000000000000..c242056e0a4b
--- /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 000000000000..5be0108c88cd
--- /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 000000000000..eb61d15568aa
--- /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 000000000000..b368ee741069
--- /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 0afba654152c..13a0b8947b05 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 }


More information about the Libstdc++-cvs mailing list