From patchwork Sat Jul 19 09:46:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: 1nfocalypse <1nfocalypse@protonmail.com> X-Patchwork-Id: 2113351 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=protonmail.com header.i=@protonmail.com header.a=rsa-sha256 header.s=protonmail3 header.b=ij++hoeo; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4bkhdJ6vnMz1xsw for ; Sat, 19 Jul 2025 19:46:44 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B37633858C50 for ; Sat, 19 Jul 2025 09:46:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B37633858C50 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=protonmail.com header.i=@protonmail.com header.a=rsa-sha256 header.s=protonmail3 header.b=ij++hoeo X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-43166.protonmail.ch (mail-43166.protonmail.ch [185.70.43.166]) by sourceware.org (Postfix) with ESMTPS id 2C2513858D35; Sat, 19 Jul 2025 09:46:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2C2513858D35 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=protonmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=protonmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2C2513858D35 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=185.70.43.166 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1752918371; cv=none; b=mfbLH9cElwXxOTzwfyqp2KRwkG9Wfy/nXUmE87Uun/NMUkqoudq3yvHCkWsHGL5U2b6qut3Y5xqBocX/gls/KGh1v/lcKhi8/R0CuVZfjERQihS7tg/BI7Iqxw8a6xDnRbJJLb3+hVg5ZGrkGs4sZ4/juA/fHUYvkYWQlKeBOCE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1752918371; c=relaxed/simple; bh=HReK0azZQKB3Ux9Kj2WocLTKx7c1bMYZyeYrGu/EH1s=; h=DKIM-Signature:Date:To:From:Subject:Message-ID:MIME-Version; b=pGVl6E9IRVcH4BYqepdpp2w1N5/Q+vHNwbF0C/xbeMB9YnFn0wUT8rrUXlwhrowQ2K81V6eD6KZaAsqGXOoJzPnn3F33xElZcmHE0yBYqe8G7lnidhlEa5+uxQlU7p8sdrhy1NCfLnhUjLeqVAmfOnerDGx2Vb7cstqjmUYKVVY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2C2513858D35 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail3; t=1752918369; x=1753177569; bh=HReK0azZQKB3Ux9Kj2WocLTKx7c1bMYZyeYrGu/EH1s=; h=Date:To:From:Subject:Message-ID:Feedback-ID:From:To:Cc:Date: Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=ij++hoeoYKhU5TT18r/yrym9K5Q1SqLhDQdH5aDa3UrV5aioYpqG33/ADw8Q4NfTP IAs4EkjCUjgLijdkB9jW/u3a+KpSKbu5wypqvst+OFW0JlQXCvT1bj6E20Qqlg5xjs oJ+E5Y6FMhVYb0z2KADx6AM2xQy88E3lW8Kg6PUUl/LGpe4s5FQYwpk2Vuf8vu5nnY FikGS09JNO2mkcTHGuaBS9UQLhd+/qEdUuRRHTIYiIjWYtjrc4Oi2abdqecldjSbsd rAIK5hQwu3kY9ekwfa8o2mok0xKpBgUq9YEoWpGVrHN1HcLVnaFPYzBXWyBxVx92I3 JRrVATeWe+iBA== Date: Sat, 19 Jul 2025 09:46:03 +0000 To: "gcc-patches@gcc.gnu.org" , "libstdc++@gcc.gnu.org" From: 1nfocalypse <1nfocalypse@protonmail.com> Subject: [PATCH v4] libstdc++: Implement Philox Engine [PR119794] Message-ID: Feedback-ID: 138844459:user:proton X-Pm-Message-ID: d1d9499b0694bd9ca2d5a9a5caf21eb90773f504 MIME-Version: 1.0 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Implements Philox Engine (P2075R6) and associated tests. Implements additional feedback from v3 from Patrick Palka. I went ahead and qualified the STL functions to avoid ADL ambiguity, as recommended. However, if this was erroneous, I'd be happy to go back and change it. Additionally, the suspicion expressed by Patrick was correct, and the issue with the extra paren was corrected. Thank you once again for the review, and if further changes are required, please let me know. Built and tested on x86_64-linux-gnu. From 08c131c76e75848f282389e21f61c3a47422be67 Mon Sep 17 00:00:00 2001 From: 1nfocalypse <1nfocalypse@protonmail.com> Date: Sat, 19 Jul 2025 02:08:07 +0000 Subject: [PATCH] [PATCH v4] libstdc++: Implement Philox Engine [PR119794] Implemented additional changes according to feedback from Patrick Palka. _charT, _traits -> _CharT, _Traits in stream operator templates Removed accidental whitespace in random.tcc Removed unnecessary this-> qualifiers Removed unnecessary {} wrappers in multiline variable definitions Removed {} in single-line for loops Qualified STL functions with std:: to avoid ADL ambiguity; Left data structures (i.e. std::array) unqualified per v2 feedback Bug in seed with sseq fixed - should now correctly compute integer ceil Removed accidental whitespace in include/std/random Removed duplicate test (covers removal of copyright header) Still implements LWG4143, LWG4153 errata for Philox Engine. Additionally altered pr60037-neg.cc to correctly suppress error. PR libstdc++/119794 --- libstdc++-v3/include/bits/random.h | 298 ++++++++++++++++++ libstdc++-v3/include/bits/random.tcc | 186 +++++++++++ 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 | 22 ++ .../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 | 2 +- 20 files changed, 938 insertions(+), 1 deletion(-) 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..0930008cd90 100644 --- a/libstdc++-v3/include/bits/random.h +++ b/libstdc++-v3/include/bits/random.h @@ -1688,6 +1688,286 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return !(__lhs == __rhs); } #endif +#if __cpp_lib_philox_engine + + /** + * @brief: A discrete pseudorandom number generator based off of weakened + * cryptographic primitives. + * + * This algorithm was intended to be used for highly parallel random number + * generation, and is capable of immensely long periods. It provides "Crush- + * resistance", denoting an ability to pass the TestU01 Suite's "Big Crush" + * test, demonstrating significant apparent entropy. It is not intended for + * cryptographic use and should not be used for such, despite being based on + * cryptographic primitives. + * + * The two four-word definitions are likely the best use for this algorithm, + * and are given below as defaults. + * + * This algorithm was created by John Salmon, Mark Moraes, Ron Dror, and + * David Shaw as a product of D.E. Shaw Research. + * + * @tparam __w Word size + * @tparam __n Buffer size + * @tparam __r Rounds + * @tparam __consts Multiplication and round constant pack, ordered as + * M_{0}, C_{0}, M_{1}, C_{1}, ... , M_{N/2-1}, C_{N/2-1} + * + * @headerfile random + * @since C++26 + */ + template + class philox_engine + { + static_assert(__n == 2 || __n == 4, + "template argument N must be either 2 or 4"); + static_assert(sizeof...(__consts) == __n, + "length of consts array must match specified N"); + static_assert(0 < __r, "a number of rounds must be specified"); + static_assert((0 < __w && __w <= numeric_limits<_UIntType>::digits), + "specified bitlength must match input type"); + template + using _If_seed_seq + = __detail::_If_seed_seq_for<_Sseq, philox_engine, _UIntType>; + + private: + // the ordering here is essential to functionality. + /** @brief an internal unpacking function for %philox_engine. */ + template + 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 multipliers = + philox_engine::_S_popArray<0,2>(); + static constexpr array round_consts = + philox_engine::_S_popArray<1,3>(); + + /** @brief returns the minimum value possible. */ + static constexpr result_type + min() + { return 0; } + + /** @brief returns the maximum value possible. */ + static constexpr result_type + max() + { + return ((1ull << (__w - 1)) | ((1ull << (__w - 1)) - 1)); + } + // default key value + static constexpr result_type default_seed = 20111115u; + + // constructors + philox_engine() + : philox_engine(default_seed) + {} + + explicit + philox_engine(result_type __value); + + /** @brief seed sequence constructor for %philox_engine + * + * @params __q the seed sequence + */ + template> + 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 + _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& __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 + friend basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, + const philox_engine& __x) + { + using __ios_base = 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._M_k.begin(); + while (__it != __x._M_k.end()) + { + __os << *__it << ' '; + ++__it; + } + auto __it2 = __x._M_x.begin(); + while (__it2 != __x._M_x.end()) + { + __os << *__it2 << ' '; + ++__it2; + } + __os << __x._M_i; + __os.flags(__flags); + __os.fill(__fill); + return __os; + } + + /** @brief takes input to set the state of the %philox_engine object + * + * @param __is An input stream. + * @param __x A %philox_engine object reference + * + * @returns %philox_engine object is set with values from instream + */ + template + friend basic_istream<_CharT, _Traits>& + operator>>(basic_istream<_CharT, _Traits>& __is, + philox_engine& __x) + { + using __ios_base = 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._M_k.size(); ++__j) + { + __is >> __x._M_k[__j]; + } + for (size_t __j = 0; __j < __x._M_x.size(); ++__j) + { + __is >> __x._M_x[__j]; + } + array<_UIntType, __n> __tmpCtr = __x._M_x; + unsigned char __setIndex = 0; + for (size_t __j = 0; __j < __x._M_x.size(); ++__j) + { + if (__x._M_x[__j] > 0) + { + __setIndex = __j; + break; + } + } + for (size_t __j = 0; __j <= __setIndex; ++__j) + { + if (__j != __setIndex) + { + __x._M_x[__j] = max(); + } else + { + --__x._M_x[__j]; + } + } + __x._M_philox(); + __x._M_x = __tmpCtr; + __is >> __x._M_i; + __is.flags(__flags); + return __is; + } + private: + // private state variables + array<_UIntType, __n> _M_x; + array<_UIntType, __n / 2> _M_k; + array<_UIntType, __n> _M_y; + unsigned long long _M_i = 0; + + /** @brief Takes the high values of the product of __a, __b + * + * @params __a an unsigned integer + * @params __b an unsigned integer + * + * @returns an unsigned integer of at most bitlength W + */ + _UIntType + _M_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 + _M_mullo(_UIntType __a, _UIntType __b); // (A*B)%2^W + + /** @brief an R-round substitution/Feistel Network hybrid for + * %philox_engine + */ + void + _M_philox(); + + /** @brief an internal transition function for the %philox_engine. */ + void + _M_transition(); + }; + +#endif + /** * The classic Minimum Standard rand0 of Lewis, Goodman, and Miller. */ @@ -1742,6 +2022,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef minstd_rand0 default_random_engine; +#if __cpp_lib_philox_engine + + typedef philox_engine< + uint_fast32_t, + 32, 4, 10, + 0xCD9E8D57, 0x9E3779B9, + 0xD2511F53, 0xBB67AE85> philox4x32; + + /** + * Alternative Philox instance (64 bit) + */ + typedef philox_engine< + uint_fast64_t, + 64, 4, 10, + 0xCA5A826395121157, 0x9E3779B97F4A7C15, + 0xD2E7470EE14C6C93, 0xBB67AE8584CAA73B> philox4x64; +#endif + /** * A standard interface to a platform-specific non-deterministic * random number generator (if any are available). diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc index 53ccacb2e38..de066cf3932 100644 --- a/libstdc++-v3/include/bits/random.tcc +++ b/libstdc++-v3/include/bits/random.tcc @@ -907,6 +907,192 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __is; } +#if __cpp_lib_philox_engine + + template + _UIntType + philox_engine<_UIntType, + __w, __n, __r, __consts...>::_M_mulhi(_UIntType __a, _UIntType __b) + { + const __uint128_t __num = + static_cast<__uint128_t>(__a) * static_cast<__uint128_t>(__b); + return static_cast<_UIntType>((__num >> __w) & max()); + } + + template + _UIntType + philox_engine<_UIntType, + __w, __n, __r, __consts...>::_M_mullo(_UIntType __a, _UIntType __b) + { + return ((__a * __b) & max()); + } + + template + void + philox_engine<_UIntType, __w, __n, __r, __consts...>::_M_transition() + { + ++_M_i; + if (_M_i == __n) + { + _M_philox(); + if (__n == 4) + { + __uint128_t __uh = + (static_cast<__uint128_t>(_M_x[1]) << __w) + | ((_M_x[0]) + 1); + __uint128_t __lh = + ((static_cast<__uint128_t>(_M_x[3]) << __w) + | (_M_x[2])); + if (!(__uh & max())) + { + ++__lh; + __uh = 0; + } + _M_x[0] = __uh & max(); + _M_x[1] = (__uh >> (__w)) & max(); + _M_x[2] = __lh & max(); + _M_x[3] = (__lh >> (__w)) & max(); + } else + { + __uint128_t __num = ((_M_x[1] << __w)) | ((_M_x[0]) + 1); + _M_x[0] = __num & max(); + _M_x[1] = (__num >> __w) & max(); + } + _M_i = 0; + } + } + + template + void + philox_engine<_UIntType, __w, __n, __r, __consts...>::_M_philox() + { + array<_UIntType, __n> __outputSeq{}; + for (size_t __j = 0; __j < __n; ++__j) + __outputSeq[__j] = _M_x[__j]; + for (unsigned long __j = 0; __j < __r; ++__j) + { + array<_UIntType, __n> __intermedSeq{}; + if (__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]= _M_mulhi(__intermedSeq[2*__k], multipliers[__k]) + ^ (((_M_k[__k] + (__j * round_consts[__k])) & max())) + ^ __intermedSeq[2*__k+1]; + + __outputSeq[(2*__k)+1]= _M_mullo(__intermedSeq[2*__k], + multipliers[__k]); + } + } + for (unsigned long __j = 0; __j < __n; ++__j) + _M_y[__j] = __outputSeq[__j]; + } + + template + philox_engine<_UIntType, + __w, __n, __r, __consts...>::philox_engine(result_type __value) + { + std::fill(_M_x.begin(), _M_x.end(), 0); + std::fill(_M_k.begin(), _M_k.end(), 0); + std::fill(_M_y.begin(), _M_y.end(), 0); + _M_k[0] = __value & max(); + _M_i = __n - 1; + } + + template + void + philox_engine<_UIntType, + __w, __n, __r, __consts...>::seed(result_type __value) + { + std::fill(_M_x.begin(), _M_x.end(), 0); + std::fill(_M_k.begin(), _M_k.end(), 0); + std::fill(_M_y.begin(), _M_y.end(), 0); + _M_k[0] = __value & max(); + _M_i = __n - 1; + } + + template + void + philox_engine<_UIntType, __w, + __n, __r, __consts...>::set_counter(const array& __counter) + { + for (unsigned long long __j = 0; __j < __n; ++__j) + _M_x[__j] = __counter[__n - 1 - __j] & max(); + _M_i = __n - 1; + } + + template + template + auto + philox_engine<_UIntType, __w, __n, __r, __consts...>::seed(_Sseq& __q) + -> _If_seed_seq<_Sseq> + { + std::fill(_M_k.begin(), _M_k.end(), 0); + const unsigned long long __p = 1 + ((__w - 1)/ 32); + uint_least32_t __tmpArr[(__n / 2) * __p]; + __q.generate(__tmpArr + 0, __tmpArr + ((__n / 2) *__p)); + for (unsigned long long __k = 0; __k < (__n/2); ++__k) + { + unsigned long long __precalc = 0; + for (unsigned long long __j = 0; __j < __p; ++__j) + { + unsigned long long __multiplicand = (1ull << (32 * __j)); + __precalc += (__tmpArr[__k*__p + __j] * __multiplicand) & max(); + } + _M_k[__k] = __precalc; + } + std::fill(_M_x.begin(), _M_x.end(), 0); + std::fill(_M_y.begin(), _M_y.end(), 0); + _M_i = __n - 1; + } + + template + 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 + _UIntType + philox_engine<_UIntType, __w, __n, __r, __consts...>::operator()() + { + _M_transition(); + return _M_y[_M_i]; + } + +#endif template std::basic_ostream<_CharT, _Traits>& diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index cf0672b4822..32eedb89bcf 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -2059,6 +2059,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 c01ddf14dd5..f90280b4dce 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -2309,4 +2309,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 #else +#define __glibcxx_want_philox_engine +#include + #include #include // For uint_fast32_t, uint_fast64_t, uint_least32_t #include 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 + +#include +#include + +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 +#include + +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 +#include + +int f(int x) +{ + std::seed_seq sq(&x, &x + 1); + auto rnd = std::philox4x32(sq); + return std::uniform_int_distribution()(rnd); +} + +int g(int x) +{ + std::seed_seq sq(&x, &x + 1); + auto rnd = std::philox4x32(); + rnd.seed(sq); + return std::uniform_int_distribution()(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 + +void +test01() +{ + + std::philox_engine 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 +#include + +void +test01() +{ + std::philox_engine 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 + +void +test01() +{ + unsigned long seed = 2; + std::philox_engine 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..033667616f9 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed_seq.cc @@ -0,0 +1,22 @@ +// { 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 + +void +test01() +{ + std::seed_seq sseq{ 1, 2, 3, 4 }; + std::philox_engine 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 +#include + +void +test01() +{ + std::philox_engine 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 +#include + +void +test01() +{ + std::philox_engine 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 +#include +#include +#include + +void +test01() +{ + std::stringstream str; + std::philox_engine 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 + +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 +#include + +namespace __gnu_test +{ + struct constexpr_member_data + { + template + 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()(); + 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 +#include + +namespace __gnu_test +{ + struct constexpr_member_functions + { + template + 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()(); + 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 + +void +test01() +{ + typedef std::philox_engine 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..f5d8492c16b 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