I've pushed your philox implementation to trunk now, thanks very much for
adding it to GCC!

I also pushed some minor refactoring, and would still like to address the
(unnecessary?) uses of 64-bit types pointed out in the mail below. And we
need to make it use uint64_t for the calculations when the result type only
has 32-bits, and eventually emulate 128-bit arithmetic to support 64-bit
result types on targets without int128. But they can all be done later.


On Mon, 8 Sept 2025, 16:46 Jonathan Wakely, <jwak...@redhat.com> wrote:

> On Mon, 08 Sep 2025 at 15:55 +0100, Jonathan Wakely wrote:
> >On Tue, 05 Aug 2025 at 09:21 +0000, 1nfocalypse wrote:
> >>Implements Philox Engine (P2075R6) and associated tests.
> >>
> >>Implements additional feedback from v5 from Patrick Palka.
> >>Also cut some trailing whitespace from the limb propagation
> >>fix in v5.
> >>
> >>Apologies for the delay from v5 - I had to finish writing some
> >>CTF challenges for DEFCON this week. Thank you for the
> >>feedback, and please let me know if anything further needs
> >>to be changed.
> >>
> >>Built/tested on x86_64-pc-linux-gnu.
> >
> >>From 23ffd0ca595c27e8721d6d73ac746293aace7771 Mon Sep 17 00:00:00 2001
> >>From: 1nfocalypse <1nfocaly...@protonmail.com>
> >>Date: Tue, 5 Aug 2025 01:37:18 +0000
> >>Subject: [PATCH] [PATCH v6] libstdc++: Implement Philox Engine (PR119794)
> >>
> >>Implemented additional changes from Patrick Palka.
> >>Also removed some trailing whitespace in random.tcc.
> >>
> >>replaced alias of __ios_base with ios_base
> >>included <iomanip> in random.h
> >>altered line number in pr60037-neg.cc to be accurate
> >>Refactored iterator/index loops to be range-based for
> >>in istream/ostream operator overloads
> >>include <random> in philox_engine/cons/seed_seq.cc
> >>Conforms with errata LWG4143, LWG4153 for Philox Engine.
> >>
> >>      PR libstdc++/119794
> >>---
> >>libstdc++-v3/include/bits/random.h            | 283 ++++++++++++++++++
> >>libstdc++-v3/include/bits/random.tcc          | 191 ++++++++++++
> >>libstdc++-v3/include/bits/version.def         |   9 +
> >>libstdc++-v3/include/bits/version.h           |  10 +
> >>libstdc++-v3/include/std/random               |   3 +
> >>.../26_numerics/random/philox4x32.cc          |  23 ++
> >>.../26_numerics/random/philox4x64.cc          |  23 ++
> >>.../random/philox_engine/cons/119794.cc       |  39 +++
> >>.../random/philox_engine/cons/copy.cc         |  25 ++
> >>.../random/philox_engine/cons/default.cc      |  27 ++
> >>.../random/philox_engine/cons/seed.cc         |  20 ++
> >>.../random/philox_engine/cons/seed_seq.cc     |  24 ++
> >>.../random/philox_engine/operators/equal.cc   |  30 ++
> >>.../random/philox_engine/operators/inequal.cc |  30 ++
> >>.../philox_engine/operators/serialize.cc      |  49 +++
> >>.../philox_engine/requirements/constants.cc   |  26 ++
> >>.../requirements/constexpr_data.cc            |  50 ++++
> >>.../requirements/constexpr_functions.cc       |  41 +++
> >>.../philox_engine/requirements/typedefs.cc    |  26 ++
> >>.../26_numerics/random/pr60037-neg.cc         |   4 +-
> >>20 files changed, 931 insertions(+), 2 deletions(-)
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
> >>create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
> >>
> >>diff --git a/libstdc++-v3/include/bits/random.h
> b/libstdc++-v3/include/bits/random.h
> >>index 1fdaf51934f..e74b7bd75c0 100644
> >>--- a/libstdc++-v3/include/bits/random.h
> >>+++ b/libstdc++-v3/include/bits/random.h
> >>@@ -33,6 +33,7 @@
> >>
> >>#include <vector>
> >>#include <bits/uniform_int_dist.h>
> >>+#include <iomanip>
> >>
> >>namespace std _GLIBCXX_VISIBILITY(default)
> >>{
> >>@@ -1688,6 +1689,270 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >>    { return !(__lhs == __rhs); }
> >>#endif
> >>
> >>+#if __cpp_lib_philox_engine
> >
> >This should check __glibcxx_philox_engine (just in case this code is
> >moved to a separate header that ends up being included somewhere
> >withou all of <random>).
> >
> >>+  /**
> >>+   * @brief: A discrete pseudorandom number generator based off of
> weakened
> >>+   * cryptographic primitives.
> >
> >Can we say "based on" instead of "based off of" which is an informal
> >American English term that sounds wrong to me.
> >
> >I'm also not sure what this is telling me as a non-export user. Would
> >it be clearer to talk about it having weak cryptographic properties,
> >rather than being based on weakened cryptographic primitives?
> >
> >>+   *
> >>+   * This algorithm was intended to be used for highly parallel random
> number
> >
> >"was intended to be used" sounds like it refers to something in the
> >past that is no longer true. Maybe "was designed to be used" instead?
> >
> >>+   * generation, and is capable of immensely long periods.  It provides
> "Crush-
> >
> >I was going to ask whether immensely is a bit hyperbolic and could be
> >just "very long periods (e.g. ...)" but since we're talking at least
> >2^128 I think "immensely" is fine :-)
> >
> >>+   * resistance", denoting an ability to pass the TestU01 Suite's "Big
> Crush"
> >>+   * test, demonstrating significant apparent entropy.  It is not
> intended for
> >>+   * cryptographic use and should not be used for such, despite being
> based on
> >>+   * cryptographic primitives.
> >>+   *
> >>+   * The two four-word definitions are likely the best use for this
> algorithm,
> >>+   * and are given below as defaults.
> >
> >Can we refer to those as aliases or typedefs rather than definitions?
> >Or specializations?
> >
> >Maybe even say it like this:
> >
> >   * The typedefs `philox4x32` and `philox4x64` are provided as
> >   * suitable defaults for most use cases, providing high-quality
> >   * random numbers at reasonable performance.
> >
> >
> >>+   *
> >>+   * This algorithm was created by John Salmon, Mark Moraes, Ron Dror,
> and
> >>+   * David Shaw as a product of D.E. Shaw Research.
> >>+   *
> >>+   * @tparam __w     Word size
> >>+   * @tparam __n     Buffer size
> >>+   * @tparam __r     Rounds
> >>+   * @tparam __consts        Multiplication and round constant pack,
> ordered as
> >>+   *                         M_{0}, C_{0}, M_{1}, C_{1}, ... ,
> M_{N/2-1}, C_{N/2-1}
> >>+   *
> >>+   * @headerfile random
> >>+   * @since C++26
> >>+   */
> >>+  template<class _UIntType, size_t __w,
> >
> >Our convention in libstdc++ code is to type 'typename' for template
> >parameters instead of 'class'
> >
> >>+           size_t __n, size_t __r,
> >>+           _UIntType... __consts>
> >>+    class philox_engine
> >>+    {
> >>+      static_assert(__n == 2 || __n == 4,
> >>+           "template argument N must be either 2 or 4");
> >>+      static_assert(sizeof...(__consts) == __n,
> >>+           "length of consts array must match specified N");
> >>+      static_assert(0 < __r, "a number of rounds must be specified");
> >>+      static_assert((0 < __w && __w <=
> numeric_limits<_UIntType>::digits),
> >>+           "specified bitlength must match input type");
> >
> >The static assert messages all use the preferred "must" form, thanks!
> >
> >>+      template<typename _Sseq>
> >>+     using _If_seed_seq
> >>+       = __detail::_If_seed_seq_for<_Sseq, philox_engine, _UIntType>;
> >>+
> >>+      private:
> >
> >This access specifier is redundant because everything above it is
> >already private.
> >
> >>+     // the ordering here is essential to functionality.
> >
> >Does this refer to the ordering of the _S_popArray member in the
> >class, because it needs to be declared before it's used?
> >
> >If so, I think we can drop the comment. If somebody fails to notice
> >that when reading the class definition, they'd find out pretty quickly
> >if they tried to reorder it and got errors.
> >
> >The style recommendations to put private internal members last is not
> >a hard requirement, for cases like this where the order is significant
> >putting them first is obviously fine (since you have no choice! :-)
> >
> >>+     /** @brief an internal unpacking function for %philox_engine.  */
> >
> >We don't need a doxygen comment for private member functions, they
> >won't get included in the docs anyway.
> >
> >>+     template <size_t __ind0, size_t __ind1>
> >>+       static constexpr
> >>+       array<_UIntType, __n / 2>
> >>+       _S_popArray()
> >>+       {
> >>+         if constexpr (__n == 4)
> >>+           return {__consts...[__ind0], __consts...[__ind1]};
> >>+         else
> >>+           return {__consts...[__ind0]};
> >>+       }
> >>+
> >>+      public:
> >>+     /** Type of template param.  */
> >>+     using result_type = _UIntType;
> >>+     // public members
> >>+     static constexpr size_t word_size = __w;
> >>+     static constexpr size_t word_count = __n;
> >>+     static constexpr size_t round_count = __r;
> >>+     static constexpr array<result_type, __n / 2> multipliers =
> >>+        philox_engine::_S_popArray<0,2>();
> >>+     static constexpr array<result_type, __n / 2> round_consts =
> >>+        philox_engine::_S_popArray<1,3>();
> >>+
> >>+     /** @brief returns the minimum value possible.  */
> >>+     static constexpr result_type
> >>+     min()
> >>+     { return 0; }
> >>+
> >>+     /** @brief returns the maximum value possible.  */
> >>+     static constexpr result_type
> >>+     max()
> >>+     {
> >>+       return ((1ull << (__w - 1)) | ((1ull << (__w - 1)) - 1));
> >>+     }
> >>+     // default key value
> >>+     static constexpr result_type default_seed = 20111115u;
> >
> >I wonder if we have a defect in the C++26 draft here, because
> >20111115u won't fit in a 16-bit int. We fixed that for
> >std::subtract_with_carry_engine via:
> >https://cplusplus.github.io/LWG/issue3809
> >and then fixed what I broke via:
> >https://cplusplus.github.io/LWG/issue4014
> >
> >Since the value of default_seed is only used as the argument to the
> >default ctor (or the equivalent of calling seed() with no argument)
> >and the ctor reduces value by mod 2^w, I think we could define the
> >default seed as 20111115u & max().
> >
> >But let's leave it for now, I'll raise this with LWG.
> >
> >>+
> >>+     // constructors
> >>+     philox_engine()
> >>+     : philox_engine(default_seed)
> >>+     {}
> >>+
> >>+     explicit
> >>+     philox_engine(result_type __value);
> >>+
> >>+     /** @brief seed sequence constructor for %philox_engine
> >>+       *
> >>+       *  @params __q the seed sequence
> >>+       */
> >>+     template<typename _Sseq, typename = _If_seed_seq<_Sseq>>
> >>+       explicit
> >>+       philox_engine(_Sseq& __q)
> >>+       {
> >>+         seed(__q);
> >>+       }
> >>+
> >>+     void
> >>+     seed(result_type value = default_seed);
> >>+
> >>+     /** @brief seeds %philox_engine by seed sequence
> >>+       *
> >>+       * @params __q the seed sequence
> >>+       */
> >>+     template<typename _Sseq>
> >>+       _If_seed_seq<_Sseq>
> >>+       seed(_Sseq& __q);
> >>+
> >>+     /** @brief sets the internal counter "cleartext"
> >>+       *
> >>+       * @params __counter std::array of len N
> >>+       */
> >>+     void
> >>+     set_counter(const array<result_type, __n>& __counter);
> >>+
> >>+     /** @brief compares two %philox_engine objects
> >>+       *
> >>+       * @params __x A %philox_engine object
> >>+       * @params __y A %philox_engine object
> >>+       *
> >>+       * @returns true if the objects will produce an identical stream,
> false
> >>+       * otherwise
> >>+       */
> >>+     friend bool
> >>+     operator==(const philox_engine& __x, const philox_engine& __y)
> >>+     {
> >>+       return (std::equal(__x._M_x.begin(), __x._M_x.end(),
> >>+             __y._M_x.begin(), __y._M_x.end())
> >>+           && std::equal(__x._M_y.begin(), __x._M_y.end(),
> >>+             __y._M_y.begin(), __y._M_y.end())
> >>+           && std::equal(__x._M_k.begin(), __x._M_k.end(),
> >>+             __y._M_k.begin(), __y._M_k.end())
> >>+           && __x._M_i == __y._M_i);
> >>+     }
> >>+
> >>+     /** @brief outputs a single w-bit number and handles state
> advancement
> >>+       *
> >>+       * @returns return_type
> >>+       */
> >>+     _UIntType
> >>+     operator()();
> >>+
> >>+     /** @brief discards __z numbers
> >>+       *
> >>+       * @params __z number of iterations to discard
> >>+       */
> >>+     void
> >>+     discard(unsigned long long __z);
> >>+
> >>+     /** @brief outputs the state of the generator
> >>+      *
> >>+      * @param __os An output stream.
> >>+      * @param __x  A %philox_engine object reference
> >>+      *
> >>+      * @returns the state of the Philox Engine in __os
> >>+      */
> >>+     template<typename _CharT, typename _Traits>
> >>+       friend basic_ostream<_CharT, _Traits>&
> >>+         operator<<(basic_ostream<_CharT, _Traits>& __os,
> >>+           const philox_engine& __x)
> >>+           {
> >
> >The "operator<<" and "{" lines should be lined up with "friend"
> >
> >>+             const typename ios_base::fmtflags __flags = __os.flags();
> >>+             const _CharT __fill = __os.fill();
> >>+             __os.flags(ios_base::dec | ios_base::left);
> >>+             __os.fill(__os.widen(' '));
> >>+             for (auto &__subkey : __x._M_k)
> >
> >auto& rather than putting the space before the & please (and below as
> >well).
> >
> >>+               __os << __subkey << ' ';
> >>+             for (auto &__ctr : __x._M_x)
> >>+               __os << __ctr << ' ';
> >
> >Inserting ' ' will get widened if __os is a wide stream, but since
> >you've already called __os.widen(' ') above you could save the result
> >of that in a local variable and then insert that character instead of
> >' '. That will avoid calling widen again on every iteration of the
> >loop.
> >
> >>+             __os << __x._M_i;
> >>+             __os.flags(__flags);
> >
> >If writing to the stream throws an exception we won't restore the
> >flags and fill character, but I think that's consistent with all our
> >operator<< overloads in <random>.
> >
> >>+             __os.fill(__fill);
> >>+             return __os;
> >>+           }
> >>+
> >>+     /** @brief takes input to set the state of the %philox_engine
> object
> >>+       *
> >>+       * @param __is An input stream.
> >>+       * @param __x  A %philox_engine object reference
> >>+       *
> >>+       * @returns %philox_engine object is set with values from instream
> >>+       */
> >>+     template <typename _CharT, typename _Traits>
> >>+       friend basic_istream<_CharT, _Traits>&
> >>+         operator>>(basic_istream<_CharT, _Traits>& __is,
> >>+           philox_engine& __x)
> >>+           {
> >
> >Same comment about aligning to "friend".
> >
> >>+             const typename ios_base::fmtflags __flags = __is.flags();
> >>+             __is.flags(ios_base::dec | ios_base::skipws);
> >>+             for (auto &__subkey : __x._M_k)
> >>+               __is >> __subkey;
> >>+             for (auto &__ctr : __x._M_x)
> >>+               __is >> __ctr;
> >>+             array<_UIntType, __n> __tmpCtr = __x._M_x;
> >>+             unsigned char __setIndex = 0;
> >>+             for (size_t __j = 0; __j < __x._M_x.size(); ++__j)
> >>+             {
> >>+               if (__x._M_x[__j] > 0)
> >>+               {
> >>+                 __setIndex = __j;
> >>+                 break;
> >>+               }
> >>+             }
> >>+             for (size_t __j = 0; __j <= __setIndex; ++__j)
> >>+             {
> >>+               if (__j != __setIndex)
> >>+                 __x._M_x[__j] = max();
> >>+               else
> >>+                 --__x._M_x[__j];
> >>+             }
> >>+             __x._M_philox();
> >>+             __x._M_x = __tmpCtr;
> >>+             __is >> __x._M_i;
> >>+             __is.flags(__flags);
> >>+             return __is;
> >>+           }
> >>+      private:
> >>+     // private state variables
> >>+     array<_UIntType, __n> _M_x;
> >>+     array<_UIntType, __n / 2> _M_k;
> >>+     array<_UIntType, __n> _M_y;
> >>+     unsigned long long _M_i = 0;
>
> Why is this unsigned long long? The maximum value of i is 4, isn't it?
>
> >>+  template<class _UIntType,
> >>+     size_t __w, size_t __n,
> >>+     size_t __r, _UIntType... __consts>
> >>+  void
> >>+  philox_engine<_UIntType, __w, __n, __r, __consts...>::_M_philox()
> >>+  {
> >>+    array<_UIntType, __n> __outputSeq{};
> >>+    for (size_t __j = 0; __j < __n; ++__j)
> >>+      __outputSeq[__j] = _M_x[__j];
> >>+    for (unsigned long __j = 0; __j < __r; ++__j)
>
> Should __j be size_t?
>
> Otherwise on Windows it would be 32-bit, but __r is size_t which is
> 64-bit, and so __j < __r might never be true.
>
> >>+    {
> >>+      array<_UIntType, __n> __intermedSeq{};
> >>+      if constexpr (__n == 4)
> >>+      {
> >>+     __intermedSeq[0] = __outputSeq[2];
> >>+     __intermedSeq[1] = __outputSeq[1];
> >>+     __intermedSeq[2] = __outputSeq[0];
> >>+     __intermedSeq[3] = __outputSeq[3];
> >>+      } else
> >>+      {
> >>+     __intermedSeq[0] = __outputSeq[0];
> >>+     __intermedSeq[1] = __outputSeq[1];
> >>+      }
> >>+      for (unsigned long __k = 0; __k < (__n/2); ++__k)
>
> __k should be the same type as __n, although this loop never runs
> more than twice, right?
>
> >>+      {
> >>+     __outputSeq[2*__k]= _S_mulhi(__intermedSeq[2*__k],
> multipliers[__k])
> >>+       ^ (((_M_k[__k] + (__j * round_consts[__k])) & max()))
> >>+       ^ __intermedSeq[2*__k+1];
> >>+
> >>+     __outputSeq[(2*__k)+1]= _S_mullo(__intermedSeq[2*__k],
> >>+       multipliers[__k]);
> >>+      }
> >>+    }
> >>+    for (unsigned long __j = 0; __j < __n; ++__j)
> >>+      _M_y[__j] = __outputSeq[__j];
>
> __j should be the same type as __n, but can this be simply:
>
>      _M_y = __outputSeq;
>
> ?
>
> >>+  }
> >>+
> >>+  template<class _UIntType,
> >>+     size_t __w, size_t __n,
> >>+     size_t __r, _UIntType... __consts>
> >>+  philox_engine<_UIntType,
> >>+     __w, __n, __r, __consts...>::philox_engine(result_type __value)
> >>+  {
> >>+    std::fill(_M_x.begin(), _M_x.end(), 0);
> >>+    std::fill(_M_k.begin(), _M_k.end(), 0);
> >>+    std::fill(_M_y.begin(), _M_y.end(), 0);
> >
> >Can we just initialize these in a mem-initializer-list?
> >
> >    : _M_x{}, _M_k{}, _M_y{}
> >
> >The compiler is more likely to optimize that well.
> >
> >>+    _M_k[0] = __value & max();
> >>+    _M_i = __n - 1;
> >>+  }
> >>+
> >>+  template<class _UIntType,
> >>+     size_t __w, size_t __n,
> >>+     size_t __r, _UIntType... __consts>
> >>+  void
> >>+  philox_engine<_UIntType,
> >>+  __w, __n, __r, __consts...>::seed(result_type __value)
> >>+  {
> >>+    std::fill(_M_x.begin(), _M_x.end(), 0);
> >
> >This can use std::array::fill, i.e. _M_x.fill(0);
> >
> >Or would this whole function be simpler as:
> >
> >    *this = philox_engine(__value);
> >
> >?
> >
> >>+    std::fill(_M_k.begin(), _M_k.end(), 0);
> >>+    std::fill(_M_y.begin(), _M_y.end(), 0);
> >>+    _M_k[0] = __value & max();
> >>+    _M_i = __n - 1;
> >>+  }
> >>+
> >>+  template<class _UIntType,
> >>+     size_t __w, size_t __n,
> >>+     size_t __r, _UIntType... __consts>
> >>+  void
> >>+  philox_engine<_UIntType, __w,
> >>+  __n, __r, __consts...>::set_counter(const array<result_type, __n>&
> __counter)
> >>+  {
> >>+    for (unsigned long long __j = 0; __j < __n; ++__j)
>
> __j should be the same type as __n
>
> >>+      _M_x[__j] = __counter[__n - 1 - __j] & max();
> >>+    _M_i = __n - 1;
> >>+  }
> >>+
> >>+  template<class _UIntType,
> >>+     size_t __w, size_t __n,
> >>+     size_t __r, _UIntType... __consts>
> >>+  template<typename _Sseq>
> >>+  auto
> >>+  philox_engine<_UIntType, __w, __n, __r, __consts...>::seed(_Sseq& __q)
> >>+  -> _If_seed_seq<_Sseq>
> >>+  {
> >>+    std::fill(_M_k.begin(), _M_k.end(), 0);
> >>+    const unsigned long long __p = 1 + ((__w - 1)/ 32);
> >>+    uint_least32_t __tmpArr[(__n / 2) * __p];
> >>+    __q.generate(__tmpArr + 0, __tmpArr + ((__n / 2) *__p));
> >>+    for (unsigned long long __k = 0; __k < (__n/2); ++__k)
> >>+    {
> >>+      unsigned long long __precalc = 0;
> >>+      for (unsigned long long __j = 0; __j < __p; ++__j)
> >>+      {
> >>+     unsigned long long __multiplicand = (1ull << (32 * __j));
> >>+     __precalc += (__tmpArr[__k*__p + __j] * __multiplicand) & max();
> >>+      }
>
> Do any of the variables above need to be unsigned long long?
>
> >>+      _M_k[__k] = __precalc;
> >>+    }
> >>+    std::fill(_M_x.begin(), _M_x.end(), 0);
> >>+    std::fill(_M_y.begin(), _M_y.end(), 0);
> >>+    _M_i = __n - 1;
> >>+  }
> >>+
> >>+  template<class _UIntType,
> >>+     size_t __w, size_t __n,
> >>+     size_t __r, _UIntType... __consts>
> >>+  void
> >>+  philox_engine<_UIntType,
> >>+     __w, __n, __r, __consts...>::discard(unsigned long long __z)
> >>+  {
> >>+    for (unsigned long long __j = 0; __j < __z; ++__j)
> >>+      _M_transition();
> >>+  }
> >>+
> >>+  template<class _UIntType,
> >>+     size_t __w, size_t __n,
> >>+     size_t __r, _UIntType... __consts>
> >>+  _UIntType
> >>+  philox_engine<_UIntType, __w, __n, __r, __consts...>::operator()()
> >>+  {
> >>+    _M_transition();
> >>+    return _M_y[_M_i];
> >>+  }
> >>+
> >>+#endif
> >>
> >>  template<typename _IntType, typename _CharT, typename _Traits>
> >>    std::basic_ostream<_CharT, _Traits>&
> >>diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> >>index dbe2cb8f175..4c21fa187c8 100644
> >>--- a/libstdc++-v3/include/bits/version.def
> >>+++ b/libstdc++-v3/include/bits/version.def
> >>@@ -2069,6 +2069,15 @@ ftms = {
> >>  };
> >>};
> >>
> >>+ftms = {
> >>+  name = philox_engine;
> >>+  values = {
> >>+    v = 202406;
> >>+    cxxmin = 26;
> >>+    extra_cond = "__SIZEOF_INT128__";
> >>+  };
> >>+};
> >>+
> >>// Standard test specifications.
> >>stds[97] = ">= 199711L";
> >>stds[03] = ">= 199711L";
> >>diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> >>index 7bb6016df68..75a9946adce 100644
> >>--- a/libstdc++-v3/include/bits/version.h
> >>+++ b/libstdc++-v3/include/bits/version.h
> >>@@ -2318,4 +2318,14 @@
> >>#endif /* !defined(__cpp_lib_constexpr_exceptions) &&
> defined(__glibcxx_want_constexpr_exceptions) */
> >>#undef __glibcxx_want_constexpr_exceptions
> >>
> >>+#if !defined(__cpp_lib_philox_engine)
> >>+# if (__cplusplus >  202302L) && (__SIZEOF_INT128__)
> >>+#  define __glibcxx_philox_engine 202406L
> >>+#  if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_philox_engine)
> >>+#   define __cpp_lib_philox_engine 202406L
> >>+#  endif
> >>+# endif
> >>+#endif /* !defined(__cpp_lib_philox_engine) &&
> defined(__glibcxx_want_philox_engine) */
> >>+#undef __glibcxx_want_philox_engine
> >>+
> >>#undef __glibcxx_want_all
> >>diff --git a/libstdc++-v3/include/std/random
> b/libstdc++-v3/include/std/random
> >>index 0e058a04bd9..8a02ade4b75 100644
> >>--- a/libstdc++-v3/include/std/random
> >>+++ b/libstdc++-v3/include/std/random
> >>@@ -39,6 +39,9 @@
> >># include <bits/c++0x_warning.h>
> >>#else
> >>
> >>+#define __glibcxx_want_philox_engine
> >>+#include <bits/version.h>
> >>+
> >>#include <cmath>
> >>#include <cstdint> // For uint_fast32_t, uint_fast64_t, uint_least32_t
> >>#include <cstdlib>
> >>diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
> >>new file mode 100644
> >>index 00000000000..d5a8ca078ef
> >>--- /dev/null
> >>+++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
> >>@@ -0,0 +1,23 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >
> >Please identify the document where these references are from, because
> >29.5.4 might be a different subclause in C++29, i.e.
> >
> >>+// N5014 29.5.4 Random Number Engine Class Templates
> >>+// N5014 29.5.4.5 Class Template philox_engine
> >
> >(Ideally we'd say "C++26 29.5.4 ..." but we don't know if that
> >subclause number will be correct in the final standard.)
> >
> >>+
> >>+#include <random>
> >>+#include <testsuite_hooks.h>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+  std::philox4x32 a;
> >>+  a.discard(9999);
> >>+
> >>+  VERIFY( a() == 1955073260 );
> >>+}
> >>+
> >>+int main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
> >>new file mode 100644
> >>index 00000000000..131f094cb28
> >>--- /dev/null
> >>+++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
> >>@@ -0,0 +1,23 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <random>
> >>+#include <testsuite_hooks.h>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+  std::philox4x64 a;
> >>+  a.discard(9999);
> >>+
> >>+  VERIFY( a() == 3409172418970261260 );
> >>+}
> >>+
> >>+int main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
> >>new file mode 100644
> >>index 00000000000..c3a5a0eb754
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/119794.cc
> >>@@ -0,0 +1,39 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+#include <random>
> >>+#include <testsuite_hooks.h>
> >>+
> >>+int f(int x)
> >>+{
> >>+  std::seed_seq sq(&x, &x + 1);
> >>+  auto rnd = std::philox4x32(sq);
> >>+  return std::uniform_int_distribution<int>()(rnd);
> >>+}
> >>+
> >>+int g(int x)
> >>+{
> >>+  std::seed_seq sq(&x, &x + 1);
> >>+  auto rnd = std::philox4x32();
> >>+  rnd.seed(sq);
> >>+  return std::uniform_int_distribution<int>()(rnd);
> >>+}
> >>+
> >>+void test01()
> >>+{
> >>+  const int f1 = f(0);
> >>+  const int f2 = f(0);
> >>+
> >>+  const int g1 = g(0);
> >>+  const int g2 = g(0);
> >>+
> >>+  VERIFY( f1 == f2 );
> >>+  VERIFY( g1 == g2 );
> >>+  VERIFY( f1 == g1 );
> >>+}
> >>+
> >>+int main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
> >>new file mode 100644
> >>index 00000000000..4f61928a157
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
> >>@@ -0,0 +1,25 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <random>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+
> >>+  std::philox_engine<std::uint_fast32_t, 32, 4, 10, 0xCD9E8D57,
> >>+     0x9E3779B9, 0xD2511F53, 0xBB67AE85> e(1ul);
> >>+
> >>+  const auto f(e);
> >>+  auto g(f);
> >>+  g = g; // Suppress unused warning
> >>+}
> >>+
> >>+int main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
> >>new file mode 100644
> >>index 00000000000..9f9ae94db0f
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
> >>@@ -0,0 +1,27 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <random>
> >>+#include <testsuite_hooks.h>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+  std::philox_engine<std::uint_fast32_t,
> >>+                  32, 4, 10, 0xCD9E8D57,
> >>+                  0x9E3779B9, 0xD2511F53,
> >>+                  0xBB67AE85> philox4x32nullkey(0);
> >>+
> >>+  VERIFY( philox4x32nullkey.min() == 0 );
> >>+  VERIFY( philox4x32nullkey.max() == (1ul << 31 | (1ul << 31) - 1) );
> >>+  VERIFY( philox4x32nullkey() == 0x6627e8d5ul );
> >>+}
> >>+
> >>+int main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
> >>new file mode 100644
> >>index 00000000000..5cb914f4b45
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
> >>@@ -0,0 +1,20 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+#include <random>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+  unsigned long seed = 2;
> >>+  std::philox_engine<std::uint_fast32_t,
> >>+                  32, 4, 10, 0xCD9E8D57,
> >>+                  0x9E3779B9, 0xD2511F53,
> >>+                  0xBB67AE85> philox4x32seeded(seed);
> >>+}
> >>+
> >>+int main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
> >>new file mode 100644
> >>index 00000000000..7d9e3e6540d
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc
> >>@@ -0,0 +1,24 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <random>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+  std::seed_seq sseq{ 1, 2, 3, 4 };
> >>+  std::philox_engine<std::uint_fast32_t,
> >>+                  32, 4, 10, 0xCD9E8D57,
> >>+                  0x9E3779B9, 0xD2511F53,
> >>+                  0xBB67AE85> philox4x32sseq(sseq);
> >>+}
> >>+
> >>+int
> >>+main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
> >>new file mode 100644
> >>index 00000000000..4f62bfbbd88
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
> >>@@ -0,0 +1,30 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <random>
> >>+#include <testsuite_hooks.h>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+  std::philox_engine<std::uint_fast32_t,
> >>+                  32, 4, 10, 0xCD9E8D57,
> >>+                  0x9E3779B9, 0xD2511F53,
> >>+                  0xBB67AE85> x, y;
> >>+
> >>+  VERIFY ( x == y);
> >>+  x.discard(100);
> >>+  y.discard(100);
> >>+
> >>+  VERIFY (x == y);
> >>+}
> >>+
> >>+int
> >>+main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
> >>new file mode 100644
> >>index 00000000000..86d757db904
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/inequal.cc
> >>@@ -0,0 +1,30 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <random>
> >>+#include <testsuite_hooks.h>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+  std::philox_engine<std::uint_fast32_t,
> >>+                 32, 4, 10, 0xCD9E8D57,
> >>+                 0x9E3779B9, 0xD2511F53,
> >>+                 0xBB67AE85> x, y;
> >>+
> >>+  VERIFY ( !(x != y) );
> >>+  x.discard(100);
> >>+  y.discard(100);
> >>+
> >>+  VERIFY ( !(x != y) );
> >>+}
> >>+
> >>+int
> >>+main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
> >>new file mode 100644
> >>index 00000000000..bec4b172512
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
> >>@@ -0,0 +1,49 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <sstream>
> >>+#include <random>
> >>+#include <testsuite_hooks.h>
> >>+#include <iostream>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+  std::stringstream str;
> >>+  std::philox_engine<std::uint_fast32_t,
> >>+                  32, 4, 10, 0xCD9E8D57,
> >>+                  0x9E3779B9, 0xD2511F53,
> >>+                  0xBB67AE85> x, y;
> >>+
> >>+  x();
> >>+  str << x;
> >>+
> >>+  VERIFY ( !(x == y) );
> >>+  str >> y;
> >>+  VERIFY ( x == y );
> >>+  for (unsigned long i = 0; i < 100; ++i)
> >>+  {
> >>+    VERIFY (x() == y());
> >>+  }
> >>+  str.clear();
> >>+  str << y;
> >>+  x();
> >>+  x();
> >>+  x();
> >>+  str >> x;
> >>+  VERIFY ( x == y );
> >>+  for (unsigned long i = 0; i < 1000; ++i)
> >>+  {
> >>+    VERIFY (x() == y());
> >>+  }
> >>+}
> >>+
> >>+int
> >>+main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
> >>new file mode 100644
> >>index 00000000000..c242056e0a4
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
> >>@@ -0,0 +1,26 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <random>
> >>+
> >>+void test01()
> >>+{
> >>+  std::philox4x32 philox;
> >>+  const void* p = &philox.word_size;
> >>+  p = &philox.word_count;
> >>+  p = &philox.round_count;
> >>+  p = &philox.multipliers;
> >>+  p = &philox.round_consts;
> >>+  p = &philox.default_seed;
> >>+  p = p; // Suppress unused warning.
> >>+}
> >>+
> >>+int
> >>+main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
> >>new file mode 100644
> >>index 00000000000..5be0108c88c
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_data.cc
> >>@@ -0,0 +1,50 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <random>
> >>+#include <testsuite_common_types.h>
> >>+
> >>+namespace __gnu_test
> >>+{
> >>+  struct constexpr_member_data
> >>+  {
> >>+    template<typename _Ttesttype>
> >>+      void
> >>+      operator()()
> >>+      {
> >>+     struct _Concept
> >>+     {
> >>+       void __constraint()
> >>+       {
> >>+         constexpr auto v1 __attribute__((unused))
> >>+             = _Ttesttype::word_size;
> >>+         constexpr auto v2 __attribute__((unused))
> >>+             = _Ttesttype::word_count;
> >>+         constexpr auto v3 __attribute__((unused))
> >>+             = _Ttesttype::round_count;
> >>+         constexpr auto v4 __attribute__((unused))
> >>+             = _Ttesttype::multipliers;
> >>+         constexpr auto v5 __attribute__((unused))
> >>+             = _Ttesttype::round_consts;
> >>+         constexpr auto v6 __attribute__((unused))
> >>+             = _Ttesttype::default_seed;
> >>+       }
> >>+     };
> >>+
> >>+     _Concept c;
> >>+     c.__constraint();
> >>+      }
> >>+  };
> >>+};
> >>+
> >>+int
> >>+main()
> >>+{
> >>+  __gnu_test::constexpr_member_data test;
> >>+  typedef std::philox4x32 type;
> >>+  test.operator()<type>();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
> >>new file mode 100644
> >>index 00000000000..eb61d15568a
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constexpr_functions.cc
> >>@@ -0,0 +1,41 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+#include <random>
> >>+#include <testsuite_common_types.h>
> >>+
> >>+namespace __gnu_test
> >>+{
> >>+  struct constexpr_member_functions
> >>+  {
> >>+    template<typename _Ttesttype>
> >>+      void
> >>+      operator()()
> >>+      {
> >>+     struct _Concept
> >>+     {
> >>+       void __constraint()
> >>+       {
> >>+         constexpr auto v1 __attribute__((unused))
> >>+             = _Ttesttype::min();
> >>+         constexpr auto v2 __attribute__((unused))
> >>+             = _Ttesttype::max();
> >>+       }
> >>+     };
> >>+     _Concept c;
> >>+     c.__constraint();
> >>+      }
> >>+  };
> >>+}
> >>+
> >>+int
> >>+main()
> >>+{
> >>+  __gnu_test::constexpr_member_functions test;
> >>+  typedef std::philox4x32 type;
> >>+  test.operator()<type>();
> >>+  return 0;
> >>+}
> >>diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
> >>new file mode 100644
> >>index 00000000000..b368ee74106
> >>--- /dev/null
> >>+++
> b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
> >>@@ -0,0 +1,26 @@
> >>+// { dg-do run { target c++26 } }
> >>+// { dg-require-cstdint "" }
> >>+
> >>+// 29.5.4 Random Number Engine Class Templates
> >>+// 29.5.4.5 Class Template philox_engine
> >>+
> >>+
> >>+#include <random>
> >>+
> >>+void
> >>+test01()
> >>+{
> >>+  typedef std::philox_engine<std::uint_fast32_t,
> >>+                  32, 4, 10, 0xCD9E8D57,
> >>+                  0x9E3779B9, 0xD2511F53,
> >>+                  0xBB67AE85> testType;
> >>+
> >>+  typedef testType::result_type result_type;
> >>+}
> >>+
> >>+int
> >>+main()
> >>+{
> >>+  test01();
> >>+  return 0;
> >>+}
> >>diff --git a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
> b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
> >>index 0afba654152..13a0b8947b0 100644
> >>--- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
> >>+++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
> >>@@ -10,6 +10,6 @@ std::__detail::_Adaptor<std::mt19937, unsigned long>
> aurng(urng);
> >>auto x = std::generate_canonical<std::size_t,
> >>                      std::numeric_limits<std::size_t>::digits>(urng);
> >>
> >>-// { dg-error "static assertion failed: template argument must be a
> floating point type" "" { target *-*-* } 270 }
> >>+// { dg-error "static assertion failed: template argument must be a
> floating point type" "" { target *-*-* } 271 }
> >>
> >>-// { dg-error "static assertion failed: template argument must be a
> floating point type" "" { target *-*-* } 3357 }
> >>+// { dg-error "static assertion failed: template argument must be a
> floating point type" "" { target *-*-* } 3548 }
> >>--
> >>2.49.0
> >>
> >
>
>

Reply via email to