@@ -349,6 +349,57 @@ class FastRandomContext : public RandomMixin<FastRandomContext>
349349 void fillrand (Span<std::byte> output) noexcept ;
350350};
351351
352+ /* * xoroshiro128++ PRNG. Extremely fast, not appropriate for cryptographic purposes.
353+ *
354+ * Memory footprint is 128bit, period is 2^128 - 1.
355+ * This class is not thread-safe.
356+ *
357+ * Reference implementation available at https://prng.di.unimi.it/xoroshiro128plusplus.c
358+ * See https://prng.di.unimi.it/
359+ */
360+ class XoRoShiRo128PlusPlus
361+ {
362+ uint64_t m_s0;
363+ uint64_t m_s1;
364+
365+ [[nodiscard]] constexpr static uint64_t SplitMix64 (uint64_t & seedval) noexcept
366+ {
367+ uint64_t z = (seedval += 0x9e3779b97f4a7c15 );
368+ z = (z ^ (z >> 30 )) * 0xbf58476d1ce4e5b9 ;
369+ z = (z ^ (z >> 27 )) * 0x94d049bb133111eb ;
370+ return z ^ (z >> 31 );
371+ }
372+
373+ public:
374+ using result_type = uint64_t ;
375+
376+ constexpr explicit XoRoShiRo128PlusPlus (uint64_t seedval) noexcept
377+ : m_s0(SplitMix64(seedval)), m_s1(SplitMix64(seedval)) {}
378+
379+ // no copy - that is dangerous, we don't want accidentally copy the RNG and then have two streams
380+ // with exactly the same results.
381+ XoRoShiRo128PlusPlus (const XoRoShiRo128PlusPlus&) = delete ;
382+ XoRoShiRo128PlusPlus& operator =(const XoRoShiRo128PlusPlus&) = delete ;
383+
384+ // allow moves
385+ XoRoShiRo128PlusPlus (XoRoShiRo128PlusPlus&&) = default ;
386+ XoRoShiRo128PlusPlus& operator =(XoRoShiRo128PlusPlus&&) = default ;
387+
388+ constexpr result_type operator ()() noexcept
389+ {
390+ uint64_t s0 = m_s0, s1 = m_s1;
391+ const uint64_t result = std::rotl (s0 + s1, 17 ) + s0;
392+ s1 ^= s0;
393+ m_s0 = std::rotl (s0, 49 ) ^ s1 ^ (s1 << 21 );
394+ m_s1 = std::rotl (s1, 28 );
395+ return result;
396+ }
397+
398+ static constexpr result_type min () noexcept { return std::numeric_limits<result_type>::min (); }
399+ static constexpr result_type max () noexcept { return std::numeric_limits<result_type>::max (); }
400+ static constexpr double entropy () noexcept { return 0.0 ; }
401+ };
402+
352403/* * More efficient than using std::shuffle on a FastRandomContext.
353404 *
354405 * This is more efficient as std::shuffle will consume entropy in groups of
0 commit comments