diff mbox series

[v2] libstdc++: implement Philox Engine [PR119794]

Message ID 7NkKkN76x33TEnUnDOKCkDPJpnNXquauAjffq6z6fPOqI9RycQocz9mB3DfATUpezukNtty3llLowFAAE7_z7848YX_hyrANT9fGqv7o2ZE=@protonmail.com
State New
Headers show
Series [v2] libstdc++: implement Philox Engine [PR119794] | expand

Commit Message

1nfocalypse May 22, 2025, 12:07 a.m. UTC
Implements Philox Engine (P2075R6) and associated tests.

v2 corrects a multiline comment left in error in serialize.cc, and additionally corrects a bug hidden by said comment, where the stream was given the output of 'y()' instead of 'y', causing state to be incorrectly passed. Lastly, it fixes numerous whitespace issues found in the original patch. My apologies for not noticing prior to the submission of the original patch, which can now be disregarded.

To reiterate from the original email, the template unpacking functions are placed in a private classifier prior to the public one due to an ordering bug, where in order to function correctly, they must be placed prior to the bulk of the header. This is counter to the style recommendations, but I was unable to obtain functionality any other way. Additionally, while SIMD instructions are not utilized, and I do not think that they would integrate well with how the generator's state is currently handled, some structure choices could be made that may make them of interest.

Lastly, since word width can be specified, and thus atypical, maximum value is calculated via some bit manipulation rather than numeric_limits, since the specified width may differ from the width of the type used.

Built/tested on x86_64-linux-gnu.

- 1nfocalypse

Comments

Patrick Palka June 10, 2025, 1:16 a.m. UTC | #1
Hi,

On Thu, 22 May 2025, 1nfocalypse wrote:

> Implements Philox Engine (P2075R6) and associated tests.
> 
> v2 corrects a multiline comment left in error in serialize.cc, and additionally corrects a bug hidden by said comment, where the stream was given the output of 'y()' instead of 'y', causing state to be
> incorrectly passed. Lastly, it fixes numerous whitespace issues found in the original patch. My apologies for not noticing prior to the submission of the original patch, which can now be disregarded.
> 
> To reiterate from the original email, the template unpacking functions are placed in a private classifier prior to the public one due to an ordering bug, where in order to function correctly, they must be
> placed prior to the bulk of the header. This is counter to the style recommendations, but I was unable to obtain functionality any other way. Additionally, while SIMD instructions are not utilized, and I do
> not think that they would integrate well with how the generator's state is currently handled, some structure choices could be made that may make them of interest.
> 
> Lastly, since word width can be specified, and thus atypical, maximum value is calculated via some bit manipulation rather than numeric_limits, since the specified width may differ from the width of the type
> used.

Thanks for the nice patch!

Just to confirm, do you have a copyright assignment for
GCC in place (or are covered by a corporate assignment)?

If not, please complete that process, or contribute under the DCO
terms, see https://gcc.gnu.org/contribute.html#legal

Please don't put copyright and license headers on new tests at all,
unless they really are copyright FSF, and really do contain something
original and copyrightable (which I don't think applies here).
This is documented at
https://gcc.gnu.org/onlinedocs/libstdc++/manual/test.html#test.new_tests

If the patch is being contributed under the DCO, please resubmit it
with a Signed-off-by tag as per the first link :)

We hope to do a full review of the patch soon.

> 
> Built/tested on x86_64-linux-gnu.
> 
>  *  1nfocalypse
> 
>
Patrick Palka July 11, 2025, 4:29 p.m. UTC | #2
Hi,

On Thu, 22 May 2025, 1nfocalypse wrote:

> Implements Philox Engine (P2075R6) and associated tests.
> 
> v2 corrects a multiline comment left in error in serialize.cc, and additionally corrects a bug hidden by said comment, where the stream was given the output of 'y()' instead of 'y', causing state to be
> incorrectly passed. Lastly, it fixes numerous whitespace issues found in the original patch. My apologies for not noticing prior to the submission of the original patch, which can now be disregarded.
> 
> To reiterate from the original email, the template unpacking functions are placed in a private classifier prior to the public one due to an ordering bug, where in order to function correctly, they must be
> placed prior to the bulk of the header. This is counter to the style recommendations, but I was unable to obtain functionality any other way. Additionally, while SIMD instructions are not utilized, and I do
> not think that they would integrate well with how the generator's state is currently handled, some structure choices could be made that may make them of interest.
> 
> Lastly, since word width can be specified, and thus atypical, maximum value is calculated via some bit manipulation rather than numeric_limits, since the specified width may differ from the width of the type
> used.
> 
> Built/tested on x86_64-linux-gnu.

Sorry for the delay and thanks for your patience!  Some initial review
comments below.

> 
>  *  1nfocalypse

>  > 
>  > 
>  Subject: [PATCH] [PATCH v2] libstdc++: implement Philox Engine [PR119794]
>  
>  The template unpacking functions, while private, are placed prior
>  to the public access specifier due to issues where the template
>  pack could not be unpacked and used to populate the public member
>  arrays without being declared beforehand.
>  
>  Additionally, the tests implemented attempt to mirror the tests
>  for other engines, when they apply. Changes to random
>  provided cause for changing 'pr60037-neg.cc' because it suppresses
>  an error by explicit line number. It should still be correctly
>  suppressed in this patch. Lastly, v2 fixes an issue in
>  'serialize.cc' for Philox, where a portion of the test was
>  commented out, hiding a bug where 'y()' was passed to the
>  stream instead of 'y'. Both have been remedied in this patch.

This implements the changes to the original paper
https://wg21.link/lwg4134
https://wg21.link/lwg4153
right?  Maybe we could make a note of that in the commit message.

>  
>  Plus some whitespace fixes.
>  
>  	PR libstdc++/119794
>  
>  libstdc++-v3/ChangeLog:
>  
>  	* include/bits/random.h: Add Philox Engine components.
>  	* include/bits/random.tcc: Implement Philox Engine components.
>  	* testsuite/26_numerics/random/pr60037-neg.cc: Alter line #.
>  	* testsuite/26_numerics/random/inequal.cc: New test.
>  	* 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.
>  ---
>   libstdc++-v3/include/bits/random.h            | 340 ++++++++++++++++++
>   libstdc++-v3/include/bits/random.tcc          | 201 +++++++++++
>   .../testsuite/26_numerics/random/inequal.cc   |  49 +++
>   .../26_numerics/random/philox4x32.cc          |  42 +++
>   .../26_numerics/random/philox4x64.cc          |  42 +++
>   .../random/philox_engine/cons/119794.cc       |  57 +++
>   .../random/philox_engine/cons/copy.cc         |  44 +++
>   .../random/philox_engine/cons/default.cc      |  46 +++
>   .../random/philox_engine/cons/seed.cc         |  39 ++
>   .../random/philox_engine/cons/seed_seq.cc     |  41 +++
>   .../random/philox_engine/operators/equal.cc   |  49 +++
>   .../random/philox_engine/operators/inequal.cc |  49 +++
>   .../philox_engine/operators/serialize.cc      |  68 ++++
>   .../philox_engine/requirements/constants.cc   |  45 +++
>   .../requirements/constexpr_data.cc            |  69 ++++
>   .../requirements/constexpr_functions.cc       |  60 ++++
>   .../philox_engine/requirements/typedefs.cc    |  45 +++
>   .../26_numerics/random/pr60037-neg.cc         |   2 +-
>   18 files changed, 1287 insertions(+), 1 deletion(-)
>   create mode 100644 libstdc++-v3/testsuite/26_numerics/random/inequal.cc
>   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..5c675927515 100644
>  --- a/libstdc++-v3/include/bits/random.h
>  +++ b/libstdc++-v3/include/bits/random.h
>  @@ -1688,6 +1688,328 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       { return !(__lhs == __rhs); }
>   #endif
>   
>  +#if __cplusplus > 202302L

The implementation should more specifically be guarded by the
corresponding feature-test macro __cpp_lib_philox_engine
(defined to 202406L).

The way this is done nowadays in libstdc++ is to add philox_engine to
libstdc++-v3/include/bits/version.def and regenerate version.h via
'autogen version.def'.  This will define the internal feature-test macro
__glibcxx_philox_engine that we can check here.

In include/std/random, we need to do

#define __glibcxx_want_philox_engine
#include <bits/version.def>

so that the __cpp_lib_philox_engine is provided by that header.

>  +
>  +  /**
>  +   * @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)==1,

Can you remove the ==1?

>  +	      "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.  */
>  +	static constexpr
>  +	std::array<_UIntType, __n / 2>
>  +	__popMultArray()
>  +	{
>  +	  if constexpr (__n == 4)
>  +	  {

We typically elide the braces for single-statement if branches.

>  +	    return
>  +	      std::array<_UIntType, __n / 2> {__consts...[0], __consts...[2]};
>  +	  } else
>  +	  {
>  +	    return std::array<_UIntType, __n / 2> { __consts...[0] };
>  +	  }
>  +	}
>  +
>  +	/** @brief an internal unpacking function for %philox_engine.  */
>  +	static constexpr
>  +	std::array<_UIntType, __n / 2>
>  +	__popConstArray()
>  +	{
>  +	  if constexpr (__n == 4)
>  +	  {
>  +	    return
>  +	      std::array<_UIntType, __n / 2> {__consts...[1], __consts...[3]};
>  +	  } else
>  +	  {
>  +	    return std::array<_UIntType, __n / 2> {__consts...[1] };
>  +	  }
>  +	}
>  +
>  +      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 std::array<result_type, __n / 2> multipliers =
>  +	   philox_engine::__popMultArray();
>  +	static constexpr std::array<result_type, __n / 2> round_consts =
>  +	   philox_engine::__popConstArray();
>  +
>  +	/** @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 std::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
>  +	    {

Please use parens here instead.  It should be formatted as

  return (std::equal(...)
          && ...
          && __x._M_ == __y._M_i);

>  +	      std::equal(__x.__x.begin(), __x.__x.end(),
>  +			__y.__x.begin(), __y.__x.end()) &&
>  +	      std::equal(__x.__y.begin(), __x.__y.end(),
>  +			__y.__y.begin(), __y.__y.end()) &&
>  +	      std::equal(__x.__k.begin(), __x.__k.end(),
>  +			__y.__k.begin(), __y.__k.end()) &&
>  +	      __x.__i == __y.__i
>  +	    };
>  +	}
>  +
>  +
>  +	_UIntType
>  +	operator()();
>  +
>  +	/** @brief discards __z numbers
>  +	  *
>  +	  * @params __z number of iterations to discard
>  +	  */
>  +	void
>  +	discard(unsigned long long __z);
>  +
>  +	// Note: hidden friend seems best, suspect a better way of doing things
>  +	// but unable to find it
>  +	/** @brief outputs the state of the generator
>  +	 *
>  +	 * @param __os An output stream.
>  +	 * @param __x  A %philox_engine object reference
>  +	 *
>  +	 * @returns the state of the Philox Engine in __os
>  +	 */
>  +	template<typename _charT, typename _traits>
>  +	  friend basic_ostream<_charT, _traits>&
>  +	    operator<<(basic_ostream<_charT, _traits>& __os,
>  +	      const philox_engine& __x)
>  +	      {
>  +		using __ios_base =
>  +		  typename basic_ostream<_charT, _traits>::ios_base;
>  +		const typename __ios_base::fmtflags __flags = __os.flags();
>  +		const _charT __fill = __os.fill();
>  +		__os.flags(__ios_base::dec | __ios_base::left);
>  +		__os.fill(__os.widen(' '));
>  +		auto __it = __x.__k.begin();
>  +		while (__it != __x.__k.end())
>  +		{
>  +		  __os << *__it << ' ';
>  +		  ++__it;
>  +		}
>  +		auto __it2 = __x.__x.begin();
>  +		while (__it2 != __x.__x.end())
>  +		{
>  +		  __os << *__it2 << ' ';
>  +		  ++__it2;
>  +		}
>  +		__os << __x.__i;
>  +		__os.flags(__flags);
>  +		__os.fill(__fill);
>  +		return __os;
>  +	      }
>  +
>  +	/** @brief takes input to set the state of the %philox_engine object
>  +	  *
>  +	  * @param __is An input stream.
>  +	  * @param __x  A %philox_engine object reference
>  +	  *
>  +	  * @returns %philox_engine object is set with values from instream
>  +	  */
>  +	template <typename _charT, typename _traits>
>  +	  friend basic_istream<_charT, _traits>&
>  +	    operator>>(basic_istream<_charT, _traits>& __is,
>  +	      philox_engine& __x)
>  +	      {
>  +		using __ios_base =
>  +		  typename basic_istream<_charT, _traits>::ios_base;
>  +		const typename __ios_base::fmtflags __flags = __is.flags();
>  +		__is.flags(__ios_base::dec | __ios_base::skipws);
>  +		for (size_t __j = 0; __j < __x.__k.size(); ++__j)
>  +		{
>  +		  __is >> __x.__k[__j];
>  +		}
>  +		for (size_t __j = 0; __j < __x.__x.size(); ++__j)
>  +		{
>  +		  __is >> __x.__x[__j];
>  +		}
>  +		std::array<_UIntType, __n> __tmpCtr = __x.__x;
>  +		unsigned char __setIndex = 0;
>  +		for (size_t __j = 0; __j < __x.__x.size(); ++__j)
>  +		{
>  +		  if (__x.__x[__j] > 0)
>  +		  {
>  +		    __setIndex = __j;
>  +		    break;
>  +		  }
>  +		}
>  +		for (size_t __j = 0; __j <= __setIndex; ++__j)
>  +		{
>  +		  if (__j != __setIndex)
>  +		  {
>  +		    __x.__x[__j] = max();
>  +		  } else
>  +		  {
>  +		    --__x.__x[__j];
>  +		  }
>  +		}
>  +		__x.__philox();
>  +		__x.__x = __tmpCtr;
>  +		__is >> __x.__i;
>  +		__is.flags(__flags);
>  +		return __is;
>  +	      }
>  +      private:
>  +	// private state variables
>  +	std::array<_UIntType, __n> __x;
>  +	std::array<_UIntType, __n / 2> __k;
>  +	std::array<_UIntType, __n> __y;
>  +	unsigned long long __i = 0;

In libstdc++, internal non-static data members are conventionally
uglified as _M_foo.  Internal static members are uglified as _S_foo.

>  +
>  +	/** @brief Takes the high values of the product of __a, __b
>  +	  *
>  +	  * @params __a an unsigned integer
>  +	  * @params __b an unsigned integer
>  +	  *
>  +	  * @returns an unsigned integer of at most bitlength W
>  +	  */
>  +	_UIntType
>  +	__mulhi(_UIntType __a, _UIntType __b); // (A*B)/2^W
>  +
>  +	/** @brief Takes the low values of the product of __a, __b
>  +	  *
>  +	  * @params __a an unsigned integer
>  +	  * @params __b an unsigned integer
>  +	  *
>  +	  * @returns an unsigned integer of at most bitlength W
>  +	  */
>  +	_UIntType
>  +	__mullo(_UIntType __a, _UIntType __b); // (A*B)%2^W
>  +
>  +	/** @brief an R-round SP-net followed by a Feistel Network for
>  +	  * %philox_engine
>  +	  */
>  +	void
>  +	__philox();
>  +
>  +	/** @brief an internal transition function for the %philox_engine.  */
>  +	void
>  +	__transition();
>  +    };
>  +
>  +  /**
>  +   * Compares two %philox_engine random number generator objects
>  +   * of the same type for inequality.
>  +   *
>  +   * @param __lhs A %philox_engine random number generator object.
>  +   * @param __rhs Another %philox_engine random number generator
>  +   *		  object.
>  +   *
>  +   * @returns true if the streams would be different, false otherwise.
>  +   */
>  +  template<class _UIntType, size_t __w,
>  +	   size_t __n, size_t __r,
>  +	   _UIntType... __consts>
>  +  inline bool
>  +  operator!=(const std::philox_engine<_UIntType, __w,
>  +	     __n, __r, __consts...>& __lhs,
>  +	     const std::philox_engine<_UIntType, __w,
>  +	     __n, __r, __consts...>& __rhs)
>  +  { return !(__lhs == __rhs); }
>  +
>  +#endif
>  +
>     /**
>      * The classic Minimum Standard rand0 of Lewis, Goodman, and Miller.
>      */
>  @@ -1742,6 +2064,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>   
>     typedef minstd_rand0 default_random_engine;
>   
>  +#if __cplusplus > 202302L
>  +
>  +  typedef philox_engine<
>  +    uint_fast32_t,
>  +    32, 4, 10,
>  +    0xCD9E8D57, 0x9E3779B9,
>  +    0xD2511F53, 0xBB67AE85> philox4x32;
>  +
>  +  /**
>  +   * Alternative Philox instance (64 bit)
>  +   */
>  +  typedef philox_engine<
>  +    std::uint_fast64_t,
>  +    64, 4, 10,
>  +    0xCA5A826395121157, 0x9E3779B97F4A7C15,
>  +    0xD2E7470EE14C6C93, 0xBB67AE8584CAA73B> philox4x64;
>  +#endif
>  +
>     /**
>      * A standard interface to a platform-specific non-deterministic
>      * random number generator (if any are available).
>  diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc
>  index 53ccacb2e38..faba3b6d4b5 100644
>  --- a/libstdc++-v3/include/bits/random.tcc
>  +++ b/libstdc++-v3/include/bits/random.tcc
>  @@ -518,6 +518,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         return __is;
>       }
>   
>  +
>  +
>   #if ! __cpp_inline_variables
>     template<typename _UIntType, size_t __w, size_t __s, size_t __r>
>       constexpr size_t
>  @@ -907,6 +909,205 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         return __is;
>       }
>   
>  +#if __cplusplus > 202302L
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  _UIntType
>  +  std::philox_engine<_UIntType,

I believe std:: prefix here is unnecessary since we're already inside
the std namespace.  Why are some member functions defined inline and
some out-of-line?

>  +  __w, __n, __r, __consts...>::__mulhi(_UIntType __a, _UIntType __b)
>  +  {
>  +    const __uint128_t __num =

Since not all targets provide a 128-bit integer type, I think we need to
disable philox_engine on targets lacking it.  The easiest way would be
to add __SIZEOF_INT128__ to extra_conds in the corresponding version.def
entry.

>  +	static_cast<__uint128_t>(__a) * static_cast<__uint128_t>(__b);
>  +    const __uint128_t __div = (static_cast<__uint128_t>(1) << __w);
>  +    return static_cast<_UIntType>((__num / __div) & this->max());

Can we just right-shift by __w instead of dividing by 1 << __w?

>  +  }
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  _UIntType
>  +  std::philox_engine<_UIntType,
>  +  __w, __n, __r, __consts...>::__mullo(_UIntType __a, _UIntType __b)
>  +  {
>  +    return ((__a * __b) & max());
>  +  }
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  void
>  +  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::__transition()
>  +  {
>  +    ++__i;
>  +    if (__i == __n)
>  +    {
>  +      __philox();
>  +      if (__n == 4)
>  +      {
>  +	__uint128_t __uh =
>  +	{
>  +	  (static_cast<__uint128_t>(this->__x[1]) << __w)
>  +		| ((this->__x[0]) + 1)
>  +	};
>  +	__uint128_t __lh =
>  +	{
>  +	  ((static_cast<__uint128_t>(this->__x[3]) << __w)
>  +		| (this->__x[2]))
>  +	};
>  +	if (!(__uh & this->max()))
>  +	{
>  +	  ++__lh;
>  +	  __uh = 0;
>  +	}
>  +	this->__x[0] = __uh & this->max();
>  +	this->__x[1] = (__uh >> (__w)) & this->max();
>  +	this->__x[2] = __lh & this->max();
>  +	this->__x[3] = (__lh >> (__w)) & this->max();
>  +      } else
>  +      {
>  +	__uint128_t __num = ((this->__x[1] << __w)) | ((this->__x[0]) + 1);
>  +	this->__x[0] = __num & this->max();
>  +	this->__x[1] = (__num >> __w) & this->max();
>  +      }
>  +      __i = 0;
>  +    }
>  +  }
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  void
>  +  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::__philox()
>  +  {
>  +    std::array<_UIntType, __n> __outputSeq{};
>  +    for (size_t __j = 0; __j < __n; ++__j)
>  +    {
>  +      __outputSeq[__j] = __x[__j];
>  +    }
>  +    for (unsigned long __j = 0; __j < __r; ++__j)
>  +    {
>  +      std::array<_UIntType, __n> __intermedSeq{};
>  +      if (__n == 4)
>  +      {
>  +	__intermedSeq[0] = __outputSeq[2];
>  +	__intermedSeq[1] = __outputSeq[1];
>  +	__intermedSeq[2] = __outputSeq[0];
>  +	__intermedSeq[3] = __outputSeq[3];
>  +      } else
>  +      {
>  +	__intermedSeq[0] = __outputSeq[0];
>  +	__intermedSeq[1] = __outputSeq[1];
>  +      }
>  +      for (unsigned long __k = 0; __k < (__n/2); ++__k)
>  +      {
>  +	__outputSeq[2*__k]= __mulhi(__intermedSeq[2*__k], multipliers[__k])
>  +	  ^ (((this->__k[__k] + (__j * round_consts[__k])) & this->max()))
>  +	  ^ __intermedSeq[2*__k+1];
>  +
>  +	__outputSeq[(2*__k)+1]= __mullo(__intermedSeq[2*__k],
>  +	  multipliers[__k]);
>  +      }
>  +    }
>  +    for (unsigned long __j = 0; __j < __n; ++__j)
>  +    {
>  +      __y[__j] = __outputSeq[__j];
>  +    }
>  +  }
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  std::philox_engine<_UIntType,
>  +	__w, __n, __r, __consts...>::philox_engine(result_type __value)
>  +  {
>  +    std::fill(__x.begin(), __x.end(), 0);
>  +    std::fill(__k.begin(), __k.end(), 0);
>  +    std::fill(__y.begin(), __y.end(), 0);
>  +    __k[0] = __value & this->max();
>  +    __i = __n - 1;
>  +  }
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  void
>  +  std::philox_engine<_UIntType,
>  +  __w, __n, __r, __consts...>::seed(result_type __value)
>  +  {
>  +    std::fill(__x.begin(), __x.end(), 0);
>  +    std::fill(__k.begin(), __k.end(), 0);
>  +    std::fill(__y.begin(), __y.end(), 0);
>  +    __k[0] = __value & this->max();
>  +    __i = __n - 1;
>  +  }
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  void
>  +  std::philox_engine<_UIntType, __w,
>  +  __n, __r, __consts...>::set_counter(const array<result_type, __n>& __counter)
>  +  {
>  +    for (unsigned long long __j = 0; __j < __n; ++__j)
>  +    {
>  +      __x[__j] = __counter[__n - 1 - __j] & this->max();
>  +    }
>  +    __i = __n - 1;
>  +  }
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  template<typename _Sseq>
>  +  auto
>  +  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::seed(_Sseq& __q)
>  +  -> _If_seed_seq<_Sseq>
>  +  {
>  +    std::fill(__k.begin(), __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) - 1; ++__k)

this->__k has n/2 elements, but this loop is up to n/2 - 1?

>  +    {
>  +      unsigned long long __precalc = 0;
>  +      for (unsigned long long __j = 0; __j < __p; ++__j)
>  +      {
>  +	unsigned long long __multiplicand = (1ull << (32 * __j - 1));

I believe this left shift is UB when __j is zero (and so the shift
amount is huge).

>  +	__precalc += (__tmpArr[__k*__p + __j] * __multiplicand) & this->max();
>  +      }
>  +      this->__k[__k] = __precalc;
>  +    }
>  +    std::fill(__x.begin(), __x.end(), 0);
>  +    std::fill(__y.begin(), __y.begin(), 0);

__y.begin(), __y.end() rather?

>  +    __i = __n - 1;
>  +  }
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  void
>  +  std::philox_engine<_UIntType,
>  +	__w, __n, __r, __consts...>::discard(unsigned long long __z)
>  +  {
>  +    for (unsigned long long __j = 0; __j < __z; ++__j)
>  +    {
>  +      __transition();
>  +    }
>  +  }
>  +
>  +  template<class _UIntType,
>  +	size_t __w, size_t __n,
>  +	size_t __r, _UIntType... __consts>
>  +  _UIntType
>  +  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::operator()()
>  +  {
>  +    __transition();
>  +    return __y[__i];
>  +  }
>  +
>  +#endif
>   
>     template<typename _IntType, typename _CharT, typename _Traits>
>       std::basic_ostream<_CharT, _Traits>&
>  diff --git a/libstdc++-v3/testsuite/26_numerics/random/inequal.cc b/libstdc++-v3/testsuite/26_numerics/random/inequal.cc
>  new file mode 100644
>  index 00000000000..081c908a3eb
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/inequal.cc
>  @@ -0,0 +1,49 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>

Nowadays we don't add license headers to tests.

>  +
>  +// 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/philox4x32.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
>  new file mode 100644
>  index 00000000000..67fd8455f51
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
>  @@ -0,0 +1,42 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09	1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 29.5.4 Random Number Engine Class Templates
>  +// 29.5.4.5 Class Template philox_engine
>  +
>  +#include <random>
>  +#include <testsuite_hooks.h>
>  +
>  +void
>  +test01()
>  +{
>  +  std::philox4x32 a;
>  +  a.discard(9999);
>  +
>  +  VERIFY( a() == 1955073260 );
>  +}
>  +
>  +int main()
>  +{
>  +  test01();
>  +  return 0;
>  +}
>  diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
>  new file mode 100644
>  index 00000000000..9eb1722f2da
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
>  @@ -0,0 +1,42 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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..2884d6e3117
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
>  @@ -0,0 +1,57 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// Copyright (C) 2025 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library.  This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3.  If not see
>  +// <http://www.gnu.org/licenses/>.
>  +
>  +
>  +#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..64b96a91559
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
>  @@ -0,0 +1,44 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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..1bdee6e7911
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
>  @@ -0,0 +1,46 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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..91ef286e5e1
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
>  @@ -0,0 +1,39 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025  1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library.  This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3.  If not see
>  +// <http://www.gnu.org/licenses/>.
>  +
>  +#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..d35ce5fa05b
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
>  @@ -0,0 +1,41 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 29.5.4 Random Number Engine Class Templates
>  +// 29.5.4.5 Class Template philox_engine
>  +
>  +void
>  +test01()
>  +{
>  +  std::seed_seq sseq{ 1, 2, 3, 4 };
>  +  std::philox_engine<std::uint_fast32_t,
>  +		     32, 4, 10, 0xCD9E8D57,
>  +		     0x9E3779B9, 0xD2511F53,
>  +		     0xBB67AE85> philox4x32sseq(sseq);
>  +}
>  +
>  +int
>  +main()
>  +{
>  +  test01();
>  +  return 0;
>  +}
>  diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
>  new file mode 100644
>  index 00000000000..17cc2216791
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
>  @@ -0,0 +1,49 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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..c8255249ed8
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
>  @@ -0,0 +1,49 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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..f3672f956b9
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
>  @@ -0,0 +1,68 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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..80579f4cf91
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
>  @@ -0,0 +1,45 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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;

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..6832f17c833
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
>  @@ -0,0 +1,69 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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..6209573a211
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
>  @@ -0,0 +1,60 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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..ff4d357c5a2
>  --- /dev/null
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
>  @@ -0,0 +1,45 @@
>  +// { dg-do run { target c++26 } }
>  +// { dg-require-cstdint "" }
>  +//
>  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
>  +//
>  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
>  +//
>  +// This file is part of the GNU ISO C++ Library. This library is free
>  +// software; you can redistribute it and/or modify it under the
>  +// terms of the GNU General Public License as published by the
>  +// Free Software Foundation; either version 3, or (at your option)
>  +// any later version.
>  +//
>  +// This library is distributed in the hope that it will be useful,
>  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>  +// GNU General Public License for more details.
>  +//
>  +// You should have received a copy of the GNU General Public License along
>  +// with this library; see the file COPYING3. If not see
>  +// https://www.gnu.org/licenses>
>  +
>  +// 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..5bb3f31eddc 100644
>  --- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
>  +++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
>  @@ -12,4 +12,4 @@ auto x = std::generate_canonical<std::size_t,
>   
>   // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 270 }
>   
>  -// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3357 }
>  +// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3558 }
>  -- 
>  2.49.0
>
Jonathan Wakely July 11, 2025, 5:12 p.m. UTC | #3
On Fri, 11 Jul 2025 at 17:30, Patrick Palka <ppalka@redhat.com> wrote:
>
> Hi,
>
> On Thu, 22 May 2025, 1nfocalypse wrote:
>
> > Implements Philox Engine (P2075R6) and associated tests.
> >
> > v2 corrects a multiline comment left in error in serialize.cc, and additionally corrects a bug hidden by said comment, where the stream was given the output of 'y()' instead of 'y', causing state to be
> > incorrectly passed. Lastly, it fixes numerous whitespace issues found in the original patch. My apologies for not noticing prior to the submission of the original patch, which can now be disregarded.
> >
> > To reiterate from the original email, the template unpacking functions are placed in a private classifier prior to the public one due to an ordering bug, where in order to function correctly, they must be
> > placed prior to the bulk of the header. This is counter to the style recommendations, but I was unable to obtain functionality any other way. Additionally, while SIMD instructions are not utilized, and I do
> > not think that they would integrate well with how the generator's state is currently handled, some structure choices could be made that may make them of interest.
> >
> > Lastly, since word width can be specified, and thus atypical, maximum value is calculated via some bit manipulation rather than numeric_limits, since the specified width may differ from the width of the type
> > used.
> >
> > Built/tested on x86_64-linux-gnu.
>
> Sorry for the delay and thanks for your patience!  Some initial review
> comments below.
>
> >
> >  *  1nfocalypse
>
> >  >
> >  >
> >  Subject: [PATCH] [PATCH v2] libstdc++: implement Philox Engine [PR119794]
> >
> >  The template unpacking functions, while private, are placed prior
> >  to the public access specifier due to issues where the template
> >  pack could not be unpacked and used to populate the public member
> >  arrays without being declared beforehand.
> >
> >  Additionally, the tests implemented attempt to mirror the tests
> >  for other engines, when they apply. Changes to random
> >  provided cause for changing 'pr60037-neg.cc' because it suppresses
> >  an error by explicit line number. It should still be correctly
> >  suppressed in this patch. Lastly, v2 fixes an issue in
> >  'serialize.cc' for Philox, where a portion of the test was
> >  commented out, hiding a bug where 'y()' was passed to the
> >  stream instead of 'y'. Both have been remedied in this patch.
>
> This implements the changes to the original paper
> https://wg21.link/lwg4134
> https://wg21.link/lwg4153
> right?  Maybe we could make a note of that in the commit message.
>
> >
> >  Plus some whitespace fixes.
> >
> >       PR libstdc++/119794
> >
> >  libstdc++-v3/ChangeLog:
> >
> >       * include/bits/random.h: Add Philox Engine components.
> >       * include/bits/random.tcc: Implement Philox Engine components.
> >       * testsuite/26_numerics/random/pr60037-neg.cc: Alter line #.
> >       * testsuite/26_numerics/random/inequal.cc: New test.
> >       * 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.
> >  ---
> >   libstdc++-v3/include/bits/random.h            | 340 ++++++++++++++++++
> >   libstdc++-v3/include/bits/random.tcc          | 201 +++++++++++
> >   .../testsuite/26_numerics/random/inequal.cc   |  49 +++
> >   .../26_numerics/random/philox4x32.cc          |  42 +++
> >   .../26_numerics/random/philox4x64.cc          |  42 +++
> >   .../random/philox_engine/cons/119794.cc       |  57 +++
> >   .../random/philox_engine/cons/copy.cc         |  44 +++
> >   .../random/philox_engine/cons/default.cc      |  46 +++
> >   .../random/philox_engine/cons/seed.cc         |  39 ++
> >   .../random/philox_engine/cons/seed_seq.cc     |  41 +++
> >   .../random/philox_engine/operators/equal.cc   |  49 +++
> >   .../random/philox_engine/operators/inequal.cc |  49 +++
> >   .../philox_engine/operators/serialize.cc      |  68 ++++
> >   .../philox_engine/requirements/constants.cc   |  45 +++
> >   .../requirements/constexpr_data.cc            |  69 ++++
> >   .../requirements/constexpr_functions.cc       |  60 ++++
> >   .../philox_engine/requirements/typedefs.cc    |  45 +++
> >   .../26_numerics/random/pr60037-neg.cc         |   2 +-
> >   18 files changed, 1287 insertions(+), 1 deletion(-)
> >   create mode 100644 libstdc++-v3/testsuite/26_numerics/random/inequal.cc
> >   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..5c675927515 100644
> >  --- a/libstdc++-v3/include/bits/random.h
> >  +++ b/libstdc++-v3/include/bits/random.h
> >  @@ -1688,6 +1688,328 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >       { return !(__lhs == __rhs); }
> >   #endif
> >
> >  +#if __cplusplus > 202302L
>
> The implementation should more specifically be guarded by the
> corresponding feature-test macro __cpp_lib_philox_engine
> (defined to 202406L).
>
> The way this is done nowadays in libstdc++ is to add philox_engine to
> libstdc++-v3/include/bits/version.def and regenerate version.h via
> 'autogen version.def'.  This will define the internal feature-test macro
> __glibcxx_philox_engine that we can check here.
>
> In include/std/random, we need to do
>
> #define __glibcxx_want_philox_engine
> #include <bits/version.def>
>
> so that the __cpp_lib_philox_engine is provided by that header.
>
> >  +
> >  +  /**
> >  +   * @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)==1,
>
> Can you remove the ==1?
>
> >  +          "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.  */
> >  +    static constexpr
> >  +    std::array<_UIntType, __n / 2>
> >  +    __popMultArray()

In our naming convention this should be _S_pop_mult_array()

> >  +    {
> >  +      if constexpr (__n == 4)
> >  +      {
>
> We typically elide the braces for single-statement if branches.
>
> >  +        return
> >  +          std::array<_UIntType, __n / 2> {__consts...[0], __consts...[2]};

The "std::" on std::array is not needed. The surrounding code in
<random> is a bit inconsistent about this, but that's because it was
ported from <tr1/random> where everything was in namespace std::tr1
and so the std:: qualification made it clear where things came from.
For <random> which is all in std, we don't need that. Especially not
in new code.


> >  +      } else
> >  +      {
> >  +        return std::array<_UIntType, __n / 2> { __consts...[0] };
> >  +      }
> >  +    }
> >  +
> >  +    /** @brief an internal unpacking function for %philox_engine.  */
> >  +    static constexpr
> >  +    std::array<_UIntType, __n / 2>
> >  +    __popConstArray()

_S_pop_const_array()

> >  +    {
> >  +      if constexpr (__n == 4)
> >  +      {
> >  +        return
> >  +          std::array<_UIntType, __n / 2> {__consts...[1], __consts...[3]};
> >  +      } else
> >  +      {
> >  +        return std::array<_UIntType, __n / 2> {__consts...[1] };
> >  +      }
> >  +    }
> >  +
> >  +      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 std::array<result_type, __n / 2> multipliers =
> >  +       philox_engine::__popMultArray();
> >  +    static constexpr std::array<result_type, __n / 2> round_consts =
> >  +       philox_engine::__popConstArray();

Since you're creating static data members for these anyway, would it
make more sense for them to just be variable templates instead of
calling

Can we just use a single function for both of these?

template<size_t _Ind0, size_t _Ind1>
static constexpr array<result_type, __n/2>
_S_populate_array()
{
  if constexpr (__n == 4)
    return {__consts...[_Ind0], __consts[_Ind1]};
  else
    return {__consts...[_Ind0]};
}

then:

    static constexpr std::array<result_type, __n / 2> multipliers
       = _S_populate_array<0, 2>();
    static constexpr std::array<result_type, __n / 2> round_consts
       = _S_populate_array<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 std::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
> >  +        {
>
> Please use parens here instead.  It should be formatted as
>
>   return (std::equal(...)
>           && ...
>           && __x._M_ == __y._M_i);
>
> >  +          std::equal(__x.__x.begin(), __x.__x.end(),
> >  +                    __y.__x.begin(), __y.__x.end()) &&
> >  +          std::equal(__x.__y.begin(), __x.__y.end(),
> >  +                    __y.__y.begin(), __y.__y.end()) &&
> >  +          std::equal(__x.__k.begin(), __x.__k.end(),
> >  +                    __y.__k.begin(), __y.__k.end()) &&
> >  +          __x.__i == __y.__i
> >  +        };
> >  +    }
> >  +
> >  +
> >  +    _UIntType
> >  +    operator()();
> >  +
> >  +    /** @brief discards __z numbers
> >  +      *
> >  +      * @params __z number of iterations to discard
> >  +      */
> >  +    void
> >  +    discard(unsigned long long __z);
> >  +
> >  +    // Note: hidden friend seems best, suspect a better way of doing things
> >  +    // but unable to find it

Yes, a hidden friend is what we want here.

> >  +    /** @brief outputs the state of the generator
> >  +     *
> >  +     * @param __os An output stream.
> >  +     * @param __x  A %philox_engine object reference
> >  +     *
> >  +     * @returns the state of the Philox Engine in __os
> >  +     */
> >  +    template<typename _charT, typename _traits>
> >  +      friend basic_ostream<_charT, _traits>&
> >  +        operator<<(basic_ostream<_charT, _traits>& __os,
> >  +          const philox_engine& __x)
> >  +          {
> >  +            using __ios_base =
> >  +              typename basic_ostream<_charT, _traits>::ios_base;

Isn't that just ... std::ios_base? or simply ios_base?

> >  +            const typename __ios_base::fmtflags __flags = __os.flags();
> >  +            const _charT __fill = __os.fill();
> >  +            __os.flags(__ios_base::dec | __ios_base::left);
> >  +            __os.fill(__os.widen(' '));
> >  +            auto __it = __x.__k.begin();
> >  +            while (__it != __x.__k.end())
> >  +            {
> >  +              __os << *__it << ' ';
> >  +              ++__it;
> >  +            }
> >  +            auto __it2 = __x.__x.begin();
> >  +            while (__it2 != __x.__x.end())
> >  +            {
> >  +              __os << *__it2 << ' ';
> >  +              ++__it2;
> >  +            }
> >  +            __os << __x.__i;
> >  +            __os.flags(__flags);
> >  +            __os.fill(__fill);
> >  +            return __os;
> >  +          }
> >  +
> >  +    /** @brief takes input to set the state of the %philox_engine object
> >  +      *
> >  +      * @param __is An input stream.
> >  +      * @param __x  A %philox_engine object reference
> >  +      *
> >  +      * @returns %philox_engine object is set with values from instream
> >  +      */
> >  +    template <typename _charT, typename _traits>
> >  +      friend basic_istream<_charT, _traits>&
> >  +        operator>>(basic_istream<_charT, _traits>& __is,
> >  +          philox_engine& __x)
> >  +          {
> >  +            using __ios_base =
> >  +              typename basic_istream<_charT, _traits>::ios_base;
> >  +            const typename __ios_base::fmtflags __flags = __is.flags();
> >  +            __is.flags(__ios_base::dec | __ios_base::skipws);
> >  +            for (size_t __j = 0; __j < __x.__k.size(); ++__j)
> >  +            {
> >  +              __is >> __x.__k[__j];
> >  +            }
> >  +            for (size_t __j = 0; __j < __x.__x.size(); ++__j)
> >  +            {
> >  +              __is >> __x.__x[__j];
> >  +            }
> >  +            std::array<_UIntType, __n> __tmpCtr = __x.__x;
> >  +            unsigned char __setIndex = 0;
> >  +            for (size_t __j = 0; __j < __x.__x.size(); ++__j)
> >  +            {
> >  +              if (__x.__x[__j] > 0)
> >  +              {
> >  +                __setIndex = __j;
> >  +                break;
> >  +              }
> >  +            }
> >  +            for (size_t __j = 0; __j <= __setIndex; ++__j)
> >  +            {
> >  +              if (__j != __setIndex)
> >  +              {
> >  +                __x.__x[__j] = max();
> >  +              } else
> >  +              {
> >  +                --__x.__x[__j];
> >  +              }
> >  +            }
> >  +            __x.__philox();
> >  +            __x.__x = __tmpCtr;
> >  +            __is >> __x.__i;
> >  +            __is.flags(__flags);
> >  +            return __is;
> >  +          }
> >  +      private:
> >  +    // private state variables
> >  +    std::array<_UIntType, __n> __x;
> >  +    std::array<_UIntType, __n / 2> __k;
> >  +    std::array<_UIntType, __n> __y;
> >  +    unsigned long long __i = 0;
>
> In libstdc++, internal non-static data members are conventionally
> uglified as _M_foo.  Internal static members are uglified as _S_foo.

And private member functions use the same convention.

>
> >  +
> >  +    /** @brief Takes the high values of the product of __a, __b
> >  +      *
> >  +      * @params __a an unsigned integer
> >  +      * @params __b an unsigned integer
> >  +      *
> >  +      * @returns an unsigned integer of at most bitlength W
> >  +      */
> >  +    _UIntType
> >  +    __mulhi(_UIntType __a, _UIntType __b); // (A*B)/2^W
> >  +
> >  +    /** @brief Takes the low values of the product of __a, __b
> >  +      *
> >  +      * @params __a an unsigned integer
> >  +      * @params __b an unsigned integer
> >  +      *
> >  +      * @returns an unsigned integer of at most bitlength W
> >  +      */
> >  +    _UIntType
> >  +    __mullo(_UIntType __a, _UIntType __b); // (A*B)%2^W
> >  +
> >  +    /** @brief an R-round SP-net followed by a Feistel Network for
> >  +      * %philox_engine
> >  +      */
> >  +    void
> >  +    __philox();
> >  +
> >  +    /** @brief an internal transition function for the %philox_engine.  */
> >  +    void
> >  +    __transition();
> >  +    };
> >  +
> >  +  /**
> >  +   * Compares two %philox_engine random number generator objects
> >  +   * of the same type for inequality.
> >  +   *
> >  +   * @param __lhs A %philox_engine random number generator object.
> >  +   * @param __rhs Another %philox_engine random number generator
> >  +   *                  object.
> >  +   *
> >  +   * @returns true if the streams would be different, false otherwise.
> >  +   */
> >  +  template<class _UIntType, size_t __w,
> >  +       size_t __n, size_t __r,
> >  +       _UIntType... __consts>
> >  +  inline bool
> >  +  operator!=(const std::philox_engine<_UIntType, __w,
> >  +         __n, __r, __consts...>& __lhs,
> >  +         const std::philox_engine<_UIntType, __w,
> >  +         __n, __r, __consts...>& __rhs)
> >  +  { return !(__lhs == __rhs); }

Isn't this redundant in C++23? We only need operator==


> >  +
> >  +#endif
> >  +
> >     /**
> >      * The classic Minimum Standard rand0 of Lewis, Goodman, and Miller.
> >      */
> >  @@ -1742,6 +2064,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >
> >     typedef minstd_rand0 default_random_engine;
> >
> >  +#if __cplusplus > 202302L
> >  +
> >  +  typedef philox_engine<
> >  +    uint_fast32_t,
> >  +    32, 4, 10,
> >  +    0xCD9E8D57, 0x9E3779B9,
> >  +    0xD2511F53, 0xBB67AE85> philox4x32;
> >  +
> >  +  /**
> >  +   * Alternative Philox instance (64 bit)
> >  +   */
> >  +  typedef philox_engine<
> >  +    std::uint_fast64_t,
> >  +    64, 4, 10,
> >  +    0xCA5A826395121157, 0x9E3779B97F4A7C15,
> >  +    0xD2E7470EE14C6C93, 0xBB67AE8584CAA73B> philox4x64;
> >  +#endif
> >  +
> >     /**
> >      * A standard interface to a platform-specific non-deterministic
> >      * random number generator (if any are available).
> >  diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc
> >  index 53ccacb2e38..faba3b6d4b5 100644
> >  --- a/libstdc++-v3/include/bits/random.tcc
> >  +++ b/libstdc++-v3/include/bits/random.tcc
> >  @@ -518,6 +518,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >         return __is;
> >       }
> >
> >  +
> >  +
> >   #if ! __cpp_inline_variables
> >     template<typename _UIntType, size_t __w, size_t __s, size_t __r>
> >       constexpr size_t
> >  @@ -907,6 +909,205 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >         return __is;
> >       }
> >
> >  +#if __cplusplus > 202302L
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  _UIntType
> >  +  std::philox_engine<_UIntType,
>
> I believe std:: prefix here is unnecessary since we're already inside
> the std namespace.  Why are some member functions defined inline and
> some out-of-line?
>
> >  +  __w, __n, __r, __consts...>::__mulhi(_UIntType __a, _UIntType __b)
> >  +  {
> >  +    const __uint128_t __num =
>
> Since not all targets provide a 128-bit integer type, I think we need to
> disable philox_engine on targets lacking it.  The easiest way would be
> to add __SIZEOF_INT128__ to extra_conds in the corresponding version.def
> entry.
>
> >  +    static_cast<__uint128_t>(__a) * static_cast<__uint128_t>(__b);
> >  +    const __uint128_t __div = (static_cast<__uint128_t>(1) << __w);
> >  +    return static_cast<_UIntType>((__num / __div) & this->max());
>
> Can we just right-shift by __w instead of dividing by 1 << __w?
>
> >  +  }
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  _UIntType
> >  +  std::philox_engine<_UIntType,
> >  +  __w, __n, __r, __consts...>::__mullo(_UIntType __a, _UIntType __b)
> >  +  {
> >  +    return ((__a * __b) & max());
> >  +  }
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  void
> >  +  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::__transition()
> >  +  {
> >  +    ++__i;
> >  +    if (__i == __n)
> >  +    {
> >  +      __philox();
> >  +      if (__n == 4)
> >  +      {
> >  +    __uint128_t __uh =
> >  +    {
> >  +      (static_cast<__uint128_t>(this->__x[1]) << __w)
> >  +            | ((this->__x[0]) + 1)
> >  +    };
> >  +    __uint128_t __lh =
> >  +    {
> >  +      ((static_cast<__uint128_t>(this->__x[3]) << __w)
> >  +            | (this->__x[2]))
> >  +    };
> >  +    if (!(__uh & this->max()))
> >  +    {
> >  +      ++__lh;
> >  +      __uh = 0;
> >  +    }
> >  +    this->__x[0] = __uh & this->max();
> >  +    this->__x[1] = (__uh >> (__w)) & this->max();
> >  +    this->__x[2] = __lh & this->max();
> >  +    this->__x[3] = (__lh >> (__w)) & this->max();
> >  +      } else
> >  +      {
> >  +    __uint128_t __num = ((this->__x[1] << __w)) | ((this->__x[0]) + 1);
> >  +    this->__x[0] = __num & this->max();
> >  +    this->__x[1] = (__num >> __w) & this->max();
> >  +      }
> >  +      __i = 0;
> >  +    }
> >  +  }
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  void
> >  +  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::__philox()
> >  +  {
> >  +    std::array<_UIntType, __n> __outputSeq{};
> >  +    for (size_t __j = 0; __j < __n; ++__j)
> >  +    {
> >  +      __outputSeq[__j] = __x[__j];
> >  +    }
> >  +    for (unsigned long __j = 0; __j < __r; ++__j)
> >  +    {
> >  +      std::array<_UIntType, __n> __intermedSeq{};
> >  +      if (__n == 4)
> >  +      {
> >  +    __intermedSeq[0] = __outputSeq[2];
> >  +    __intermedSeq[1] = __outputSeq[1];
> >  +    __intermedSeq[2] = __outputSeq[0];
> >  +    __intermedSeq[3] = __outputSeq[3];
> >  +      } else
> >  +      {
> >  +    __intermedSeq[0] = __outputSeq[0];
> >  +    __intermedSeq[1] = __outputSeq[1];
> >  +      }
> >  +      for (unsigned long __k = 0; __k < (__n/2); ++__k)
> >  +      {
> >  +    __outputSeq[2*__k]= __mulhi(__intermedSeq[2*__k], multipliers[__k])
> >  +      ^ (((this->__k[__k] + (__j * round_consts[__k])) & this->max()))
> >  +      ^ __intermedSeq[2*__k+1];
> >  +
> >  +    __outputSeq[(2*__k)+1]= __mullo(__intermedSeq[2*__k],
> >  +      multipliers[__k]);
> >  +      }
> >  +    }
> >  +    for (unsigned long __j = 0; __j < __n; ++__j)
> >  +    {
> >  +      __y[__j] = __outputSeq[__j];
> >  +    }
> >  +  }
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  std::philox_engine<_UIntType,
> >  +    __w, __n, __r, __consts...>::philox_engine(result_type __value)
> >  +  {
> >  +    std::fill(__x.begin(), __x.end(), 0);
> >  +    std::fill(__k.begin(), __k.end(), 0);
> >  +    std::fill(__y.begin(), __y.end(), 0);
> >  +    __k[0] = __value & this->max();
> >  +    __i = __n - 1;
> >  +  }
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  void
> >  +  std::philox_engine<_UIntType,
> >  +  __w, __n, __r, __consts...>::seed(result_type __value)
> >  +  {
> >  +    std::fill(__x.begin(), __x.end(), 0);
> >  +    std::fill(__k.begin(), __k.end(), 0);
> >  +    std::fill(__y.begin(), __y.end(), 0);
> >  +    __k[0] = __value & this->max();
> >  +    __i = __n - 1;
> >  +  }
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  void
> >  +  std::philox_engine<_UIntType, __w,
> >  +  __n, __r, __consts...>::set_counter(const array<result_type, __n>& __counter)
> >  +  {
> >  +    for (unsigned long long __j = 0; __j < __n; ++__j)
> >  +    {
> >  +      __x[__j] = __counter[__n - 1 - __j] & this->max();
> >  +    }
> >  +    __i = __n - 1;
> >  +  }
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  template<typename _Sseq>
> >  +  auto
> >  +  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::seed(_Sseq& __q)
> >  +  -> _If_seed_seq<_Sseq>
> >  +  {
> >  +    std::fill(__k.begin(), __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) - 1; ++__k)
>
> this->__k has n/2 elements, but this loop is up to n/2 - 1?
>
> >  +    {
> >  +      unsigned long long __precalc = 0;
> >  +      for (unsigned long long __j = 0; __j < __p; ++__j)
> >  +      {
> >  +    unsigned long long __multiplicand = (1ull << (32 * __j - 1));
>
> I believe this left shift is UB when __j is zero (and so the shift
> amount is huge).
>
> >  +    __precalc += (__tmpArr[__k*__p + __j] * __multiplicand) & this->max();
> >  +      }
> >  +      this->__k[__k] = __precalc;
> >  +    }
> >  +    std::fill(__x.begin(), __x.end(), 0);
> >  +    std::fill(__y.begin(), __y.begin(), 0);
>
> __y.begin(), __y.end() rather?
>
> >  +    __i = __n - 1;
> >  +  }
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  void
> >  +  std::philox_engine<_UIntType,
> >  +    __w, __n, __r, __consts...>::discard(unsigned long long __z)
> >  +  {
> >  +    for (unsigned long long __j = 0; __j < __z; ++__j)
> >  +    {
> >  +      __transition();
> >  +    }
> >  +  }
> >  +
> >  +  template<class _UIntType,
> >  +    size_t __w, size_t __n,
> >  +    size_t __r, _UIntType... __consts>
> >  +  _UIntType
> >  +  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::operator()()
> >  +  {
> >  +    __transition();
> >  +    return __y[__i];
> >  +  }
> >  +
> >  +#endif
> >
> >     template<typename _IntType, typename _CharT, typename _Traits>
> >       std::basic_ostream<_CharT, _Traits>&
> >  diff --git a/libstdc++-v3/testsuite/26_numerics/random/inequal.cc b/libstdc++-v3/testsuite/26_numerics/random/inequal.cc
> >  new file mode 100644
> >  index 00000000000..081c908a3eb
> >  --- /dev/null
> >  +++ b/libstdc++-v3/testsuite/26_numerics/random/inequal.cc
> >  @@ -0,0 +1,49 @@
> >  +// { dg-do run { target c++26 } }
> >  +// { dg-require-cstdint "" }
> >  +//
> >  +// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
> >  +//
> >  +// Copyright (C) 2025-2034 Free Software Foundation, Inc.

2034? Huh?


> >  +//
> >  +// This file is part of the GNU ISO C++ Library. This library is free
> >  +// software; you can redistribute it and/or modify it under the
> >  +// terms of the GNU General Public License as published by the
> >  +// Free Software Foundation; either version 3, or (at your option)
> >  +// any later version.
> >  +//
> >  +// This library is distributed in the hope that it will be useful,
> >  +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> >  +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> >  +// GNU General Public License for more details.
> >  +//
> >  +// You should have received a copy of the GNU General Public License along
> >  +// with this library; see the file COPYING3. If not see
> >  +// https://www.gnu.org/licenses>
>
> Nowadays we don't add license headers to tests.

See https://gcc.gnu.org/onlinedocs/libstdc++/manual/test.html#test.new_tests
Jonathan Wakely July 11, 2025, 5:16 p.m. UTC | #4
On Fri, 11 Jul 2025 at 18:12, Jonathan Wakely <jwakely@redhat.com> wrote:
> > >  +    static constexpr std::array<result_type, __n / 2> multipliers =
> > >  +       philox_engine::__popMultArray();
> > >  +    static constexpr std::array<result_type, __n / 2> round_consts =
> > >  +       philox_engine::__popConstArray();
>
> Since you're creating static data members for these anyway, would it
> make more sense for them to just be variable templates instead of
> calling

Sorry, ignore this incomplete sentence, I changed my mind about
variable templates and wrote this instead ...

> Can we just use a single function for both of these?
>
> template<size_t _Ind0, size_t _Ind1>
> static constexpr array<result_type, __n/2>
> _S_populate_array()
> {
>   if constexpr (__n == 4)
>     return {__consts...[_Ind0], __consts[_Ind1]};
>   else
>     return {__consts...[_Ind0]};
> }
>
> then:
>
>     static constexpr std::array<result_type, __n / 2> multipliers
>        = _S_populate_array<0, 2>();
>     static constexpr std::array<result_type, __n / 2> round_consts
>        = _S_populate_array<1, 3>();
>

Or slightly simpler:

template<int _Offset>
static constexpr array<result_type, __n/2>
_S_populate_array()
{
  if constexpr (__n == 4)
    return {__consts...[_Offset], __consts...[_Offset+2]};
  else
    return {__consts...[_Offset]};
}

    static constexpr std::array<result_type, __n / 2> multipliers
       = _S_populate_array<0>();
    static constexpr std::array<result_type, __n / 2> round_consts
       = _S_populate_array<1>();
1nfocalypse July 12, 2025, 5:26 a.m. UTC | #5
Good evening!

Thank you both for the review, I'll get to work on cleaning it up and send out a v3 soon. Additionally, don't worry about the delay, and thank you for your patience. Have a good weekend!

Regards,
1nfocalypse

On Friday, July 11th, 2025 at 9:29 AM, Patrick Palka <ppalka@redhat.com> wrote:

> Hi,
> 
> On Thu, 22 May 2025, 1nfocalypse wrote:
> 
> > Implements Philox Engine (P2075R6) and associated tests.
> > 
> > v2 corrects a multiline comment left in error in serialize.cc, and additionally corrects a bug hidden by said comment, where the stream was given the output of 'y()' instead of 'y', causing state to be
> > incorrectly passed. Lastly, it fixes numerous whitespace issues found in the original patch. My apologies for not noticing prior to the submission of the original patch, which can now be disregarded.
> > 
> > To reiterate from the original email, the template unpacking functions are placed in a private classifier prior to the public one due to an ordering bug, where in order to function correctly, they must be
> > placed prior to the bulk of the header. This is counter to the style recommendations, but I was unable to obtain functionality any other way. Additionally, while SIMD instructions are not utilized, and I do
> > not think that they would integrate well with how the generator's state is currently handled, some structure choices could be made that may make them of interest.
> > 
> > Lastly, since word width can be specified, and thus atypical, maximum value is calculated via some bit manipulation rather than numeric_limits, since the specified width may differ from the width of the type
> > used.
> > 
> > Built/tested on x86_64-linux-gnu.
> 
> 
> Sorry for the delay and thanks for your patience! Some initial review
> comments below.
> 
> > * 1nfocalypse
> 
> > Subject: [PATCH] [PATCH v2] libstdc++: implement Philox Engine [PR119794]
> > 
> > The template unpacking functions, while private, are placed prior
> > to the public access specifier due to issues where the template
> > pack could not be unpacked and used to populate the public member
> > arrays without being declared beforehand.
> > 
> > Additionally, the tests implemented attempt to mirror the tests
> > for other engines, when they apply. Changes to random
> > provided cause for changing 'pr60037-neg.cc' because it suppresses
> > an error by explicit line number. It should still be correctly
> > suppressed in this patch. Lastly, v2 fixes an issue in
> > 'serialize.cc' for Philox, where a portion of the test was
> > commented out, hiding a bug where 'y()' was passed to the
> > stream instead of 'y'. Both have been remedied in this patch.
> 
> 
> This implements the changes to the original paper
> https://wg21.link/lwg4134
> https://wg21.link/lwg4153
> right? Maybe we could make a note of that in the commit message.
> 
> > Plus some whitespace fixes.
> > 
> > PR libstdc++/119794
> > 
> > libstdc++-v3/ChangeLog:
> > 
> > * include/bits/random.h: Add Philox Engine components.
> > * include/bits/random.tcc: Implement Philox Engine components.
> > * testsuite/26_numerics/random/pr60037-neg.cc: Alter line #.
> > * testsuite/26_numerics/random/inequal.cc: New test.
> > * 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.
> > ---
> > libstdc++-v3/include/bits/random.h | 340 ++++++++++++++++++
> > libstdc++-v3/include/bits/random.tcc | 201 +++++++++++
> > .../testsuite/26_numerics/random/inequal.cc | 49 +++
> > .../26_numerics/random/philox4x32.cc | 42 +++
> > .../26_numerics/random/philox4x64.cc | 42 +++
> > .../random/philox_engine/cons/119794.cc | 57 +++
> > .../random/philox_engine/cons/copy.cc | 44 +++
> > .../random/philox_engine/cons/default.cc | 46 +++
> > .../random/philox_engine/cons/seed.cc | 39 ++
> > .../random/philox_engine/cons/seed_seq.cc | 41 +++
> > .../random/philox_engine/operators/equal.cc | 49 +++
> > .../random/philox_engine/operators/inequal.cc | 49 +++
> > .../philox_engine/operators/serialize.cc | 68 ++++
> > .../philox_engine/requirements/constants.cc | 45 +++
> > .../requirements/constexpr_data.cc | 69 ++++
> > .../requirements/constexpr_functions.cc | 60 ++++
> > .../philox_engine/requirements/typedefs.cc | 45 +++
> > .../26_numerics/random/pr60037-neg.cc | 2 +-
> > 18 files changed, 1287 insertions(+), 1 deletion(-)
> > create mode 100644 libstdc++-v3/testsuite/26_numerics/random/inequal.cc
> > 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..5c675927515 100644
> > --- a/libstdc++-v3/include/bits/random.h
> > +++ b/libstdc++-v3/include/bits/random.h
> > @@ -1688,6 +1688,328 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > { return !(__lhs == __rhs); }
> > #endif
> > 
> > +#if __cplusplus > 202302L
> 
> 
> The implementation should more specifically be guarded by the
> corresponding feature-test macro __cpp_lib_philox_engine
> (defined to 202406L).
> 
> The way this is done nowadays in libstdc++ is to add philox_engine to
> libstdc++-v3/include/bits/version.def and regenerate version.h via
> 'autogen version.def'. This will define the internal feature-test macro
> __glibcxx_philox_engine that we can check here.
> 
> In include/std/random, we need to do
> 
> #define __glibcxx_want_philox_engine
> #include <bits/version.def>
> 
> 
> so that the __cpp_lib_philox_engine is provided by that header.
> 
> > +
> > + /**
> > + * @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)==1,
> 
> 
> Can you remove the ==1?
> 
> > + "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. */
> > + static constexpr
> > + std::array<_UIntType, __n / 2>
> > + __popMultArray()
> > + {
> > + if constexpr (__n == 4)
> > + {
> 
> 
> We typically elide the braces for single-statement if branches.
> 
> > + return
> > + std::array<_UIntType, __n / 2> {__consts...[0], __consts...[2]};
> > + } else
> > + {
> > + return std::array<_UIntType, __n / 2> { __consts...[0] };
> > + }
> > + }
> > +
> > + /** @brief an internal unpacking function for %philox_engine. /
> > + static constexpr
> > + std::array<_UIntType, __n / 2>
> > + __popConstArray()
> > + {
> > + if constexpr (__n == 4)
> > + {
> > + return
> > + std::array<_UIntType, __n / 2> {__consts...[1], __consts...[3]};
> > + } else
> > + {
> > + return std::array<_UIntType, __n / 2> {__consts...[1] };
> > + }
> > + }
> > +
> > + 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 std::array<result_type, __n / 2> multipliers =
> > + philox_engine::__popMultArray();
> > + static constexpr std::array<result_type, __n / 2> round_consts =
> > + philox_engine::__popConstArray();
> > +
> > + /* @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 std::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
> > + {
> 
> 
> Please use parens here instead. It should be formatted as
> 
> return (std::equal(...)
> && ...
> && __x.M == __y._M_i);
> 
> > + std::equal(__x.__x.begin(), __x.__x.end(),
> > + __y.__x.begin(), __y.__x.end()) &&
> > + std::equal(__x.__y.begin(), __x.__y.end(),
> > + __y.__y.begin(), __y.__y.end()) &&
> > + std::equal(__x.__k.begin(), __x.__k.end(),
> > + __y.__k.begin(), __y.__k.end()) &&
> > + __x.__i == __y.__i
> > + };
> > + }
> > +
> > +
> > + _UIntType
> > + operator()();
> > +
> > + /** @brief discards __z numbers
> > + *
> > + * @params __z number of iterations to discard
> > + /
> > + void
> > + discard(unsigned long long __z);
> > +
> > + // Note: hidden friend seems best, suspect a better way of doing things
> > + // but unable to find it
> > + /* @brief outputs the state of the generator
> > + *
> > + * @param __os An output stream.
> > + * @param __x A %philox_engine object reference
> > + *
> > + * @returns the state of the Philox Engine in __os
> > + */
> > + template<typename _charT, typename _traits>
> > + friend basic_ostream<_charT, _traits>&
> > + operator<<(basic_ostream<_charT, _traits>& __os,
> > + const philox_engine& __x)
> > + {
> > + using __ios_base =
> > + typename basic_ostream<_charT, _traits>::ios_base;
> > + const typename __ios_base::fmtflags __flags = __os.flags();
> > + const _charT __fill = __os.fill();
> > + __os.flags(__ios_base::dec | __ios_base::left);
> > + __os.fill(__os.widen(' '));
> > + auto __it = __x.__k.begin();
> > + while (__it != __x.__k.end())
> > + {
> > + __os << __it << ' ';
> > + ++__it;
> > + }
> > + auto __it2 = __x.__x.begin();
> > + while (__it2 != __x.__x.end())
> > + {
> > + __os << __it2 << ' ';
> > + ++__it2;
> > + }
> > + __os << __x.__i;
> > + __os.flags(__flags);
> > + __os.fill(__fill);
> > + return __os;
> > + }
> > +
> > + / @brief takes input to set the state of the %philox_engine object
> > + *
> > + * @param __is An input stream.
> > + * @param __x A %philox_engine object reference
> > + *
> > + * @returns %philox_engine object is set with values from instream
> > + */
> > + template <typename _charT, typename _traits>
> > + friend basic_istream<_charT, _traits>&
> > + operator>>(basic_istream<_charT, _traits>& __is,
> > + philox_engine& __x)
> > + {
> > + using __ios_base =
> > + typename basic_istream<_charT, _traits>::ios_base;
> > + const typename __ios_base::fmtflags __flags = __is.flags();
> > + __is.flags(__ios_base::dec | __ios_base::skipws);
> > + for (size_t __j = 0; __j < __x.__k.size(); ++__j)
> > + {
> > + __is >> __x.__k[__j];
> > + }
> > + for (size_t __j = 0; __j < __x.__x.size(); ++__j)
> > + {
> > + __is >> __x.__x[__j];
> > + }
> > + std::array<_UIntType, __n> __tmpCtr = __x.__x;
> > + unsigned char __setIndex = 0;
> > + for (size_t __j = 0; __j < __x.__x.size(); ++__j)
> > + {
> > + if (__x.__x[__j] > 0)
> > + {
> > + __setIndex = __j;
> > + break;
> > + }
> > + }
> > + for (size_t __j = 0; __j <= __setIndex; ++__j)
> > + {
> > + if (__j != __setIndex)
> > + {
> > + __x.__x[__j] = max();
> > + } else
> > + {
> > + --__x.__x[__j];
> > + }
> > + }
> > + __x.__philox();
> > + __x.__x = __tmpCtr;
> > + __is >> __x.__i;
> > + __is.flags(__flags);
> > + return __is;
> > + }
> > + private:
> > + // private state variables
> > + std::array<_UIntType, __n> __x;
> > + std::array<_UIntType, __n / 2> __k;
> > + std::array<_UIntType, __n> __y;
> > + unsigned long long __i = 0;
> 
> 
> In libstdc++, internal non-static data members are conventionally
> uglified as _M_foo. Internal static members are uglified as _S_foo.
> 
> > +
> > + /** @brief Takes the high values of the product of __a, __b
> > + *
> > + * @params __a an unsigned integer
> > + * @params __b an unsigned integer
> > + *
> > + * @returns an unsigned integer of at most bitlength W
> > + /
> > + _UIntType
> > + __mulhi(_UIntType __a, _UIntType __b); // (AB)/2^W
> > +
> > + /** @brief Takes the low values of the product of __a, __b
> > + *
> > + * @params __a an unsigned integer
> > + * @params __b an unsigned integer
> > + *
> > + * @returns an unsigned integer of at most bitlength W
> > + /
> > + _UIntType
> > + __mullo(_UIntType __a, _UIntType __b); // (AB)%2^W
> > +
> > + /** @brief an R-round SP-net followed by a Feistel Network for
> > + * %philox_engine
> > + /
> > + void
> > + __philox();
> > +
> > + /* @brief an internal transition function for the %philox_engine. /
> > + void
> > + __transition();
> > + };
> > +
> > + /*
> > + * Compares two %philox_engine random number generator objects
> > + * of the same type for inequality.
> > + *
> > + * @param __lhs A %philox_engine random number generator object.
> > + * @param __rhs Another %philox_engine random number generator
> > + * object.
> > + *
> > + * @returns true if the streams would be different, false otherwise.
> > + /
> > + template<class _UIntType, size_t __w,
> > + size_t __n, size_t __r,
> > + _UIntType... __consts>
> > + inline bool
> > + operator!=(const std::philox_engine<_UIntType, __w,
> > + __n, __r, __consts...>& __lhs,
> > + const std::philox_engine<_UIntType, __w,
> > + __n, __r, __consts...>& __rhs)
> > + { return !(__lhs == __rhs); }
> > +
> > +#endif
> > +
> > /*
> > * The classic Minimum Standard rand0 of Lewis, Goodman, and Miller.
> > */
> > @@ -1742,6 +2064,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > 
> > typedef minstd_rand0 default_random_engine;
> > 
> > +#if __cplusplus > 202302L
> > +
> > + typedef philox_engine<
> > + uint_fast32_t,
> > + 32, 4, 10,
> > + 0xCD9E8D57, 0x9E3779B9,
> > + 0xD2511F53, 0xBB67AE85> philox4x32;
> > +
> > + /**
> > + * Alternative Philox instance (64 bit)
> > + /
> > + typedef philox_engine<
> > + std::uint_fast64_t,
> > + 64, 4, 10,
> > + 0xCA5A826395121157, 0x9E3779B97F4A7C15,
> > + 0xD2E7470EE14C6C93, 0xBB67AE8584CAA73B> philox4x64;
> > +#endif
> > +
> > /*
> > * A standard interface to a platform-specific non-deterministic
> > * random number generator (if any are available).
> > diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc
> > index 53ccacb2e38..faba3b6d4b5 100644
> > --- a/libstdc++-v3/include/bits/random.tcc
> > +++ b/libstdc++-v3/include/bits/random.tcc
> > @@ -518,6 +518,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > return __is;
> > }
> > 
> > +
> > +
> > #if ! __cpp_inline_variables
> > template<typename _UIntType, size_t __w, size_t __s, size_t __r>
> > constexpr size_t
> > @@ -907,6 +909,205 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > return __is;
> > }
> > 
> > +#if __cplusplus > 202302L
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + _UIntType
> > + std::philox_engine<_UIntType,
> 
> 
> I believe std:: prefix here is unnecessary since we're already inside
> the std namespace. Why are some member functions defined inline and
> some out-of-line?
> 
> > + __w, __n, __r, __consts...>::__mulhi(_UIntType __a, _UIntType __b)
> > + {
> > + const __uint128_t __num =
> 
> 
> Since not all targets provide a 128-bit integer type, I think we need to
> disable philox_engine on targets lacking it. The easiest way would be
> to add SIZEOF_INT128 to extra_conds in the corresponding version.def
> entry.
> 
> > + static_cast<__uint128_t>(__a) * static_cast<__uint128_t>(__b);
> > + const __uint128_t __div = (static_cast<__uint128_t>(1) << __w);
> > + return static_cast<_UIntType>((__num / __div) & this->max());
> 
> 
> Can we just right-shift by __w instead of dividing by 1 << __w?
> 
> > + }
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + _UIntType
> > + std::philox_engine<_UIntType,
> > + __w, __n, __r, __consts...>::__mullo(_UIntType __a, _UIntType __b)
> > + {
> > + return ((__a * __b) & max());
> > + }
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + void
> > + std::philox_engine<_UIntType, __w, __n, __r, __consts...>::__transition()
> > + {
> > + ++__i;
> > + if (__i == __n)
> > + {
> > + __philox();
> > + if (__n == 4)
> > + {
> > + __uint128_t __uh =
> > + {
> > + (static_cast<__uint128_t>(this->__x[1]) << __w)
> > + | ((this->__x[0]) + 1)
> > + };
> > + __uint128_t __lh =
> > + {
> > + ((static_cast<__uint128_t>(this->__x[3]) << __w)
> > + | (this->__x[2]))
> > + };
> > + if (!(__uh & this->max()))
> > + {
> > + ++__lh;
> > + __uh = 0;
> > + }
> > + this->__x[0] = __uh & this->max();
> > + this->__x[1] = (__uh >> (__w)) & this->max();
> > + this->__x[2] = __lh & this->max();
> > + this->__x[3] = (__lh >> (__w)) & this->max();
> > + } else
> > + {
> > + __uint128_t __num = ((this->__x[1] << __w)) | ((this->__x[0]) + 1);
> > + this->__x[0] = __num & this->max();
> > + this->__x[1] = (__num >> __w) & this->max();
> > + }
> > + __i = 0;
> > + }
> > + }
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + void
> > + std::philox_engine<_UIntType, __w, __n, __r, __consts...>::__philox()
> > + {
> > + std::array<_UIntType, __n> __outputSeq{};
> > + for (size_t __j = 0; __j < __n; ++__j)
> > + {
> > + __outputSeq[__j] = __x[__j];
> > + }
> > + for (unsigned long __j = 0; __j < __r; ++__j)
> > + {
> > + std::array<_UIntType, __n> __intermedSeq{};
> > + if (__n == 4)
> > + {
> > + __intermedSeq[0] = __outputSeq[2];
> > + __intermedSeq[1] = __outputSeq[1];
> > + __intermedSeq[2] = __outputSeq[0];
> > + __intermedSeq[3] = __outputSeq[3];
> > + } else
> > + {
> > + __intermedSeq[0] = __outputSeq[0];
> > + __intermedSeq[1] = __outputSeq[1];
> > + }
> > + for (unsigned long __k = 0; __k < (__n/2); ++__k)
> > + {
> > + __outputSeq[2*__k]= __mulhi(__intermedSeq[2*__k], multipliers[__k])
> > + ^ (((this->__k[__k] + (__j * round_consts[__k])) & this->max()))
> > + ^ __intermedSeq[2*__k+1];
> > +
> > + __outputSeq[(2*__k)+1]= __mullo(__intermedSeq[2*__k],
> > + multipliers[__k]);
> > + }
> > + }
> > + for (unsigned long __j = 0; __j < __n; ++__j)
> > + {
> > + __y[__j] = __outputSeq[__j];
> > + }
> > + }
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + std::philox_engine<_UIntType,
> > + __w, __n, __r, __consts...>::philox_engine(result_type __value)
> > + {
> > + std::fill(__x.begin(), __x.end(), 0);
> > + std::fill(__k.begin(), __k.end(), 0);
> > + std::fill(__y.begin(), __y.end(), 0);
> > + __k[0] = __value & this->max();
> > + __i = __n - 1;
> > + }
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + void
> > + std::philox_engine<_UIntType,
> > + __w, __n, __r, __consts...>::seed(result_type __value)
> > + {
> > + std::fill(__x.begin(), __x.end(), 0);
> > + std::fill(__k.begin(), __k.end(), 0);
> > + std::fill(__y.begin(), __y.end(), 0);
> > + __k[0] = __value & this->max();
> > + __i = __n - 1;
> > + }
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + void
> > + std::philox_engine<_UIntType, __w,
> > + __n, __r, __consts...>::set_counter(const array<result_type, __n>& __counter)
> > + {
> > + for (unsigned long long __j = 0; __j < __n; ++__j)
> > + {
> > + __x[__j] = __counter[__n - 1 - __j] & this->max();
> > + }
> > + __i = __n - 1;
> > + }
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + template<typename _Sseq>
> > + auto
> > + std::philox_engine<_UIntType, __w, __n, __r, __consts...>::seed(_Sseq& __q)
> > + -> _If_seed_seq<_Sseq>
> > + {
> > + std::fill(__k.begin(), __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) - 1; ++__k)
> 
> 
> this->__k has n/2 elements, but this loop is up to n/2 - 1?
> 
> > + {
> > + unsigned long long __precalc = 0;
> > + for (unsigned long long __j = 0; __j < __p; ++__j)
> > + {
> > + unsigned long long __multiplicand = (1ull << (32 * __j - 1));
> 
> 
> I believe this left shift is UB when __j is zero (and so the shift
> amount is huge).
> 
> > + __precalc += (__tmpArr[__k*__p + __j] * __multiplicand) & this->max();
> > + }
> > + this->__k[__k] = __precalc;
> > + }
> > + std::fill(__x.begin(), __x.end(), 0);
> > + std::fill(__y.begin(), __y.begin(), 0);
> 
> 
> __y.begin(), __y.end() rather?
> 
> > + __i = __n - 1;
> > + }
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + void
> > + std::philox_engine<_UIntType,
> > + __w, __n, __r, __consts...>::discard(unsigned long long __z)
> > + {
> > + for (unsigned long long __j = 0; __j < __z; ++__j)
> > + {
> > + __transition();
> > + }
> > + }
> > +
> > + template<class _UIntType,
> > + size_t __w, size_t __n,
> > + size_t __r, _UIntType... __consts>
> > + _UIntType
> > + std::philox_engine<_UIntType, __w, __n, __r, __consts...>::operator()()
> > + {
> > + __transition();
> > + return __y[__i];
> > + }
> > +
> > +#endif
> > 
> > template<typename _IntType, typename _CharT, typename _Traits>
> > std::basic_ostream<_CharT, _Traits>&
> > diff --git a/libstdc++-v3/testsuite/26_numerics/random/inequal.cc b/libstdc++-v3/testsuite/26_numerics/random/inequal.cc
> > new file mode 100644
> > index 00000000000..081c908a3eb
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/inequal.cc
> > @@ -0,0 +1,49 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> 
> 
> Nowadays we don't add license headers to tests.
> 
> > +
> > +// 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/philox4x32.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
> > new file mode 100644
> > index 00000000000..67fd8455f51
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
> > @@ -0,0 +1,42 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 29.5.4 Random Number Engine Class Templates
> > +// 29.5.4.5 Class Template philox_engine
> > +
> > +#include <random>
> > +#include <testsuite_hooks.h>
> > +
> > +void
> > +test01()
> > +{
> > + std::philox4x32 a;
> > + a.discard(9999);
> > +
> > + VERIFY( a() == 1955073260 );
> > +}
> > +
> > +int main()
> > +{
> > + test01();
> > + return 0;
> > +}
> > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
> > new file mode 100644
> > index 00000000000..9eb1722f2da
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
> > @@ -0,0 +1,42 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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..2884d6e3117
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
> > @@ -0,0 +1,57 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// Copyright (C) 2025 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// http://www.gnu.org/licenses/.
> > +
> > +
> > +#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..64b96a91559
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
> > @@ -0,0 +1,44 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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..1bdee6e7911
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
> > @@ -0,0 +1,46 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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..91ef286e5e1
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
> > @@ -0,0 +1,39 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// http://www.gnu.org/licenses/.
> > +
> > +#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..d35ce5fa05b
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
> > @@ -0,0 +1,41 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 29.5.4 Random Number Engine Class Templates
> > +// 29.5.4.5 Class Template philox_engine
> > +
> > +void
> > +test01()
> > +{
> > + std::seed_seq sseq{ 1, 2, 3, 4 };
> > + std::philox_engine<std::uint_fast32_t,
> > + 32, 4, 10, 0xCD9E8D57,
> > + 0x9E3779B9, 0xD2511F53,
> > + 0xBB67AE85> philox4x32sseq(sseq);
> > +}
> > +
> > +int
> > +main()
> > +{
> > + test01();
> > + return 0;
> > +}
> > diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
> > new file mode 100644
> > index 00000000000..17cc2216791
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
> > @@ -0,0 +1,49 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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..c8255249ed8
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
> > @@ -0,0 +1,49 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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..f3672f956b9
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
> > @@ -0,0 +1,68 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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..80579f4cf91
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
> > @@ -0,0 +1,45 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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;
> 
> 
> 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..6832f17c833
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
> > @@ -0,0 +1,69 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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..6209573a211
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
> > @@ -0,0 +1,60 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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..ff4d357c5a2
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
> > @@ -0,0 +1,45 @@
> > +// { dg-do run { target c++26 } }
> > +// { dg-require-cstdint "" }
> > +//
> > +// 2025-04-09 1nfocalypse 1nfocalypse@protonmail.com
> > +//
> > +// Copyright (C) 2025-2034 Free Software Foundation, Inc.
> > +//
> > +// This file is part of the GNU ISO C++ Library. This library is free
> > +// software; you can redistribute it and/or modify it under the
> > +// terms of the GNU General Public License as published by the
> > +// Free Software Foundation; either version 3, or (at your option)
> > +// any later version.
> > +//
> > +// This library is distributed in the hope that it will be useful,
> > +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +// GNU General Public License for more details.
> > +//
> > +// You should have received a copy of the GNU General Public License along
> > +// with this library; see the file COPYING3. If not see
> > +// https://www.gnu.org/licenses>
> > +
> > +// 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..5bb3f31eddc 100644
> > --- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
> > +++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
> > @@ -12,4 +12,4 @@ auto x = std::generate_canonical<std::size_t,
> > 
> > // { dg-error "static assertion failed: template argument must be a floating point type" "" { target --* } 270 }
> > 
> > -// { dg-error "static assertion failed: template argument must be a floating point type" "" { target --* } 3357 }
> > +// { dg-error "static assertion failed: template argument must be a floating point type" "" { target --* } 3558 }
> > --
> > 2.49.0
diff mbox series

Patch

From 8fca3ac477c18fc988bd8148e1bc97fef0f3ff0c Mon Sep 17 00:00:00 2001
From: 1nfocalypse <1nfocalypse@protonmail.com>
Date: Wed, 21 May 2025 13:04:46 +0000
Subject: [PATCH] [PATCH v2] libstdc++: implement Philox Engine [PR119794]

The template unpacking functions, while private, are placed prior
to the public access specifier due to issues where the template
pack could not be unpacked and used to populate the public member
arrays without being declared beforehand.

Additionally, the tests implemented attempt to mirror the tests
for other engines, when they apply. Changes to random
provided cause for changing 'pr60037-neg.cc' because it suppresses
an error by explicit line number. It should still be correctly
suppressed in this patch. Lastly, v2 fixes an issue in
'serialize.cc' for Philox, where a portion of the test was
commented out, hiding a bug where 'y()' was passed to the
stream instead of 'y'. Both have been remedied in this patch.

Plus some whitespace fixes.

	PR libstdc++/119794

libstdc++-v3/ChangeLog:

	* include/bits/random.h: Add Philox Engine components.
	* include/bits/random.tcc: Implement Philox Engine components.
	* testsuite/26_numerics/random/pr60037-neg.cc: Alter line #.
	* testsuite/26_numerics/random/inequal.cc: New test.
	* 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.
---
 libstdc++-v3/include/bits/random.h            | 340 ++++++++++++++++++
 libstdc++-v3/include/bits/random.tcc          | 201 +++++++++++
 .../testsuite/26_numerics/random/inequal.cc   |  49 +++
 .../26_numerics/random/philox4x32.cc          |  42 +++
 .../26_numerics/random/philox4x64.cc          |  42 +++
 .../random/philox_engine/cons/119794.cc       |  57 +++
 .../random/philox_engine/cons/copy.cc         |  44 +++
 .../random/philox_engine/cons/default.cc      |  46 +++
 .../random/philox_engine/cons/seed.cc         |  39 ++
 .../random/philox_engine/cons/seed_seq.cc     |  41 +++
 .../random/philox_engine/operators/equal.cc   |  49 +++
 .../random/philox_engine/operators/inequal.cc |  49 +++
 .../philox_engine/operators/serialize.cc      |  68 ++++
 .../philox_engine/requirements/constants.cc   |  45 +++
 .../requirements/constexpr_data.cc            |  69 ++++
 .../requirements/constexpr_functions.cc       |  60 ++++
 .../philox_engine/requirements/typedefs.cc    |  45 +++
 .../26_numerics/random/pr60037-neg.cc         |   2 +-
 18 files changed, 1287 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/testsuite/26_numerics/random/inequal.cc
 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..5c675927515 100644
--- a/libstdc++-v3/include/bits/random.h
+++ b/libstdc++-v3/include/bits/random.h
@@ -1688,6 +1688,328 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return !(__lhs == __rhs); }
 #endif
 
+#if __cplusplus > 202302L
+
+  /**
+   * @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)==1,
+	      "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.  */
+	static constexpr
+	std::array<_UIntType, __n / 2>
+	__popMultArray()
+	{
+	  if constexpr (__n == 4)
+	  {
+	    return
+	      std::array<_UIntType, __n / 2> {__consts...[0], __consts...[2]};
+	  } else
+	  {
+	    return std::array<_UIntType, __n / 2> { __consts...[0] };
+	  }
+	}
+
+	/** @brief an internal unpacking function for %philox_engine.  */
+	static constexpr
+	std::array<_UIntType, __n / 2>
+	__popConstArray()
+	{
+	  if constexpr (__n == 4)
+	  {
+	    return
+	      std::array<_UIntType, __n / 2> {__consts...[1], __consts...[3]};
+	  } else
+	  {
+	    return std::array<_UIntType, __n / 2> {__consts...[1] };
+	  }
+	}
+
+      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 std::array<result_type, __n / 2> multipliers =
+	   philox_engine::__popMultArray();
+	static constexpr std::array<result_type, __n / 2> round_consts =
+	   philox_engine::__popConstArray();
+
+	/** @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 std::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.__x.begin(), __x.__x.end(),
+			__y.__x.begin(), __y.__x.end()) &&
+	      std::equal(__x.__y.begin(), __x.__y.end(),
+			__y.__y.begin(), __y.__y.end()) &&
+	      std::equal(__x.__k.begin(), __x.__k.end(),
+			__y.__k.begin(), __y.__k.end()) &&
+	      __x.__i == __y.__i
+	    };
+	}
+
+
+	_UIntType
+	operator()();
+
+	/** @brief discards __z numbers
+	  *
+	  * @params __z number of iterations to discard
+	  */
+	void
+	discard(unsigned long long __z);
+
+	// Note: hidden friend seems best, suspect a better way of doing things
+	// but unable to find it
+	/** @brief outputs the state of the generator
+	 *
+	 * @param __os An output stream.
+	 * @param __x  A %philox_engine object reference
+	 *
+	 * @returns the state of the Philox Engine in __os
+	 */
+	template<typename _charT, typename _traits>
+	  friend basic_ostream<_charT, _traits>&
+	    operator<<(basic_ostream<_charT, _traits>& __os,
+	      const philox_engine& __x)
+	      {
+		using __ios_base =
+		  typename basic_ostream<_charT, _traits>::ios_base;
+		const typename __ios_base::fmtflags __flags = __os.flags();
+		const _charT __fill = __os.fill();
+		__os.flags(__ios_base::dec | __ios_base::left);
+		__os.fill(__os.widen(' '));
+		auto __it = __x.__k.begin();
+		while (__it != __x.__k.end())
+		{
+		  __os << *__it << ' ';
+		  ++__it;
+		}
+		auto __it2 = __x.__x.begin();
+		while (__it2 != __x.__x.end())
+		{
+		  __os << *__it2 << ' ';
+		  ++__it2;
+		}
+		__os << __x.__i;
+		__os.flags(__flags);
+		__os.fill(__fill);
+		return __os;
+	      }
+
+	/** @brief takes input to set the state of the %philox_engine object
+	  *
+	  * @param __is An input stream.
+	  * @param __x  A %philox_engine object reference
+	  *
+	  * @returns %philox_engine object is set with values from instream
+	  */
+	template <typename _charT, typename _traits>
+	  friend basic_istream<_charT, _traits>&
+	    operator>>(basic_istream<_charT, _traits>& __is,
+	      philox_engine& __x)
+	      {
+		using __ios_base =
+		  typename basic_istream<_charT, _traits>::ios_base;
+		const typename __ios_base::fmtflags __flags = __is.flags();
+		__is.flags(__ios_base::dec | __ios_base::skipws);
+		for (size_t __j = 0; __j < __x.__k.size(); ++__j)
+		{
+		  __is >> __x.__k[__j];
+		}
+		for (size_t __j = 0; __j < __x.__x.size(); ++__j)
+		{
+		  __is >> __x.__x[__j];
+		}
+		std::array<_UIntType, __n> __tmpCtr = __x.__x;
+		unsigned char __setIndex = 0;
+		for (size_t __j = 0; __j < __x.__x.size(); ++__j)
+		{
+		  if (__x.__x[__j] > 0)
+		  {
+		    __setIndex = __j;
+		    break;
+		  }
+		}
+		for (size_t __j = 0; __j <= __setIndex; ++__j)
+		{
+		  if (__j != __setIndex)
+		  {
+		    __x.__x[__j] = max();
+		  } else
+		  {
+		    --__x.__x[__j];
+		  }
+		}
+		__x.__philox();
+		__x.__x = __tmpCtr;
+		__is >> __x.__i;
+		__is.flags(__flags);
+		return __is;
+	      }
+      private:
+	// private state variables
+	std::array<_UIntType, __n> __x;
+	std::array<_UIntType, __n / 2> __k;
+	std::array<_UIntType, __n> __y;
+	unsigned long long __i = 0;
+
+	/** @brief Takes the high values of the product of __a, __b
+	  *
+	  * @params __a an unsigned integer
+	  * @params __b an unsigned integer
+	  *
+	  * @returns an unsigned integer of at most bitlength W
+	  */
+	_UIntType
+	__mulhi(_UIntType __a, _UIntType __b); // (A*B)/2^W
+
+	/** @brief Takes the low values of the product of __a, __b
+	  *
+	  * @params __a an unsigned integer
+	  * @params __b an unsigned integer
+	  *
+	  * @returns an unsigned integer of at most bitlength W
+	  */
+	_UIntType
+	__mullo(_UIntType __a, _UIntType __b); // (A*B)%2^W
+
+	/** @brief an R-round SP-net followed by a Feistel Network for
+	  * %philox_engine
+	  */
+	void
+	__philox();
+
+	/** @brief an internal transition function for the %philox_engine.  */
+	void
+	__transition();
+    };
+
+  /**
+   * Compares two %philox_engine random number generator objects
+   * of the same type for inequality.
+   *
+   * @param __lhs A %philox_engine random number generator object.
+   * @param __rhs Another %philox_engine random number generator
+   *		  object.
+   *
+   * @returns true if the streams would be different, false otherwise.
+   */
+  template<class _UIntType, size_t __w,
+	   size_t __n, size_t __r,
+	   _UIntType... __consts>
+  inline bool
+  operator!=(const std::philox_engine<_UIntType, __w,
+	     __n, __r, __consts...>& __lhs,
+	     const std::philox_engine<_UIntType, __w,
+	     __n, __r, __consts...>& __rhs)
+  { return !(__lhs == __rhs); }
+
+#endif
+
   /**
    * The classic Minimum Standard rand0 of Lewis, Goodman, and Miller.
    */
@@ -1742,6 +2064,24 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   typedef minstd_rand0 default_random_engine;
 
+#if __cplusplus > 202302L
+
+  typedef philox_engine<
+    uint_fast32_t,
+    32, 4, 10,
+    0xCD9E8D57, 0x9E3779B9,
+    0xD2511F53, 0xBB67AE85> philox4x32;
+
+  /**
+   * Alternative Philox instance (64 bit)
+   */
+  typedef philox_engine<
+    std::uint_fast64_t,
+    64, 4, 10,
+    0xCA5A826395121157, 0x9E3779B97F4A7C15,
+    0xD2E7470EE14C6C93, 0xBB67AE8584CAA73B> philox4x64;
+#endif
+
   /**
    * A standard interface to a platform-specific non-deterministic
    * random number generator (if any are available).
diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc
index 53ccacb2e38..faba3b6d4b5 100644
--- a/libstdc++-v3/include/bits/random.tcc
+++ b/libstdc++-v3/include/bits/random.tcc
@@ -518,6 +518,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __is;
     }
 
+
+
 #if ! __cpp_inline_variables
   template<typename _UIntType, size_t __w, size_t __s, size_t __r>
     constexpr size_t
@@ -907,6 +909,205 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __is;
     }
 
+#if __cplusplus > 202302L
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  _UIntType
+  std::philox_engine<_UIntType,
+  __w, __n, __r, __consts...>::__mulhi(_UIntType __a, _UIntType __b)
+  {
+    const __uint128_t __num =
+	static_cast<__uint128_t>(__a) * static_cast<__uint128_t>(__b);
+    const __uint128_t __div = (static_cast<__uint128_t>(1) << __w);
+    return static_cast<_UIntType>((__num / __div) & this->max());
+  }
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  _UIntType
+  std::philox_engine<_UIntType,
+  __w, __n, __r, __consts...>::__mullo(_UIntType __a, _UIntType __b)
+  {
+    return ((__a * __b) & max());
+  }
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  void
+  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::__transition()
+  {
+    ++__i;
+    if (__i == __n)
+    {
+      __philox();
+      if (__n == 4)
+      {
+	__uint128_t __uh =
+	{
+	  (static_cast<__uint128_t>(this->__x[1]) << __w)
+		| ((this->__x[0]) + 1)
+	};
+	__uint128_t __lh =
+	{
+	  ((static_cast<__uint128_t>(this->__x[3]) << __w)
+		| (this->__x[2]))
+	};
+	if (!(__uh & this->max()))
+	{
+	  ++__lh;
+	  __uh = 0;
+	}
+	this->__x[0] = __uh & this->max();
+	this->__x[1] = (__uh >> (__w)) & this->max();
+	this->__x[2] = __lh & this->max();
+	this->__x[3] = (__lh >> (__w)) & this->max();
+      } else
+      {
+	__uint128_t __num = ((this->__x[1] << __w)) | ((this->__x[0]) + 1);
+	this->__x[0] = __num & this->max();
+	this->__x[1] = (__num >> __w) & this->max();
+      }
+      __i = 0;
+    }
+  }
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  void
+  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::__philox()
+  {
+    std::array<_UIntType, __n> __outputSeq{};
+    for (size_t __j = 0; __j < __n; ++__j)
+    {
+      __outputSeq[__j] = __x[__j];
+    }
+    for (unsigned long __j = 0; __j < __r; ++__j)
+    {
+      std::array<_UIntType, __n> __intermedSeq{};
+      if (__n == 4)
+      {
+	__intermedSeq[0] = __outputSeq[2];
+	__intermedSeq[1] = __outputSeq[1];
+	__intermedSeq[2] = __outputSeq[0];
+	__intermedSeq[3] = __outputSeq[3];
+      } else
+      {
+	__intermedSeq[0] = __outputSeq[0];
+	__intermedSeq[1] = __outputSeq[1];
+      }
+      for (unsigned long __k = 0; __k < (__n/2); ++__k)
+      {
+	__outputSeq[2*__k]= __mulhi(__intermedSeq[2*__k], multipliers[__k])
+	  ^ (((this->__k[__k] + (__j * round_consts[__k])) & this->max()))
+	  ^ __intermedSeq[2*__k+1];
+
+	__outputSeq[(2*__k)+1]= __mullo(__intermedSeq[2*__k],
+	  multipliers[__k]);
+      }
+    }
+    for (unsigned long __j = 0; __j < __n; ++__j)
+    {
+      __y[__j] = __outputSeq[__j];
+    }
+  }
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  std::philox_engine<_UIntType,
+	__w, __n, __r, __consts...>::philox_engine(result_type __value)
+  {
+    std::fill(__x.begin(), __x.end(), 0);
+    std::fill(__k.begin(), __k.end(), 0);
+    std::fill(__y.begin(), __y.end(), 0);
+    __k[0] = __value & this->max();
+    __i = __n - 1;
+  }
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  void
+  std::philox_engine<_UIntType,
+  __w, __n, __r, __consts...>::seed(result_type __value)
+  {
+    std::fill(__x.begin(), __x.end(), 0);
+    std::fill(__k.begin(), __k.end(), 0);
+    std::fill(__y.begin(), __y.end(), 0);
+    __k[0] = __value & this->max();
+    __i = __n - 1;
+  }
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  void
+  std::philox_engine<_UIntType, __w,
+  __n, __r, __consts...>::set_counter(const array<result_type, __n>& __counter)
+  {
+    for (unsigned long long __j = 0; __j < __n; ++__j)
+    {
+      __x[__j] = __counter[__n - 1 - __j] & this->max();
+    }
+    __i = __n - 1;
+  }
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  template<typename _Sseq>
+  auto
+  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::seed(_Sseq& __q)
+  -> _If_seed_seq<_Sseq>
+  {
+    std::fill(__k.begin(), __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) - 1; ++__k)
+    {
+      unsigned long long __precalc = 0;
+      for (unsigned long long __j = 0; __j < __p; ++__j)
+      {
+	unsigned long long __multiplicand = (1ull << (32 * __j - 1));
+	__precalc += (__tmpArr[__k*__p + __j] * __multiplicand) & this->max();
+      }
+      this->__k[__k] = __precalc;
+    }
+    std::fill(__x.begin(), __x.end(), 0);
+    std::fill(__y.begin(), __y.begin(), 0);
+    __i = __n - 1;
+  }
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  void
+  std::philox_engine<_UIntType,
+	__w, __n, __r, __consts...>::discard(unsigned long long __z)
+  {
+    for (unsigned long long __j = 0; __j < __z; ++__j)
+    {
+      __transition();
+    }
+  }
+
+  template<class _UIntType,
+	size_t __w, size_t __n,
+	size_t __r, _UIntType... __consts>
+  _UIntType
+  std::philox_engine<_UIntType, __w, __n, __r, __consts...>::operator()()
+  {
+    __transition();
+    return __y[__i];
+  }
+
+#endif
 
   template<typename _IntType, typename _CharT, typename _Traits>
     std::basic_ostream<_CharT, _Traits>&
diff --git a/libstdc++-v3/testsuite/26_numerics/random/inequal.cc b/libstdc++-v3/testsuite/26_numerics/random/inequal.cc
new file mode 100644
index 00000000000..081c908a3eb
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/inequal.cc
@@ -0,0 +1,49 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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/philox4x32.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
new file mode 100644
index 00000000000..67fd8455f51
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
@@ -0,0 +1,42 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09	1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::philox4x32 a;
+  a.discard(9999);
+
+  VERIFY( a() == 1955073260 );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
new file mode 100644
index 00000000000..9eb1722f2da
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
@@ -0,0 +1,42 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..2884d6e3117
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
@@ -0,0 +1,57 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// Copyright (C) 2025 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+
+#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..64b96a91559
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
@@ -0,0 +1,44 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..1bdee6e7911
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
@@ -0,0 +1,46 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..91ef286e5e1
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
@@ -0,0 +1,39 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025  1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#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..d35ce5fa05b
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
@@ -0,0 +1,41 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 29.5.4 Random Number Engine Class Templates
+// 29.5.4.5 Class Template philox_engine
+
+void
+test01()
+{
+  std::seed_seq sseq{ 1, 2, 3, 4 };
+  std::philox_engine<std::uint_fast32_t,
+		     32, 4, 10, 0xCD9E8D57,
+		     0x9E3779B9, 0xD2511F53,
+		     0xBB67AE85> philox4x32sseq(sseq);
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
new file mode 100644
index 00000000000..17cc2216791
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
@@ -0,0 +1,49 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..c8255249ed8
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
@@ -0,0 +1,49 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..f3672f956b9
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
@@ -0,0 +1,68 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..80579f4cf91
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
@@ -0,0 +1,45 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..6832f17c833
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
@@ -0,0 +1,69 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..6209573a211
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
@@ -0,0 +1,60 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..ff4d357c5a2
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
@@ -0,0 +1,45 @@ 
+// { dg-do run { target c++26 } }
+// { dg-require-cstdint "" }
+//
+// 2025-04-09   1nfocalypse <1nfocalypse@protonmail.com>
+//
+// Copyright (C) 2025-2034 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// https://www.gnu.org/licenses>
+
+// 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..5bb3f31eddc 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
@@ -12,4 +12,4 @@  auto x = std::generate_canonical<std::size_t,
 
 // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 270 }
 
-// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3357 }
+// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3558 }
-- 
2.49.0