xrpld
Loading...
Searching...
No Matches
include/xrpl/basics/random.h
1#pragma once
2
3#include <xrpl/beast/utility/instrumentation.h>
4#include <xrpl/beast/xor_shift_engine.h>
5
6#include <cstddef>
7#include <cstdint>
8#include <limits>
9#include <mutex>
10#include <random>
11#include <type_traits>
12
13namespace xrpl {
14
15#ifndef __INTELLISENSE__
16static_assert(
17 // NOLINTNEXTLINE(misc-redundant-expression)
20 "The XRPL default PRNG engine must return an unsigned integral type.");
21
22static_assert(
23 // NOLINTNEXTLINE(misc-redundant-expression)
26 "The XRPL default PRNG engine return must be at least 64 bits wide.");
27#endif
28
29namespace detail {
30
31// Determines if a type can be called like an Engine
32// NOLINTNEXTLINE(readability-redundant-typename): typename required by MSVC
33template <class Engine, class Result = typename Engine::result_type>
35} // namespace detail
36
49{
50 // This is used to seed the thread-specific PRNGs on demand
51 static beast::xor_shift_engine kSeeder = [] {
54 return beast::xor_shift_engine(distribution(rng));
55 }();
56
57 // This protects the seeder
58 static std::mutex kM;
59
60 // The thread-specific PRNGs:
61 thread_local beast::xor_shift_engine kEngine = [] {
62 std::uint64_t seed = 0;
63 {
64 std::scoped_lock const lk(kM);
66 seed = distribution(kSeeder);
67 }
68 return beast::xor_shift_engine{seed};
69 }();
70
71 return kEngine;
72}
73
94template <class Engine, class Integral>
95std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
96randInt(Engine& engine, Integral min, Integral max)
97{
98 XRPL_ASSERT(max > min, "xrpl::randInt : max over min inputs");
99
100 // This should have no state and constructing it should
101 // be very cheap. If that turns out not to be the case
102 // it could be hand-optimized.
103 return std::uniform_int_distribution<Integral>(min, max)(engine);
104}
105
106template <class Integral>
108randInt(Integral min, Integral max)
109{
110 return randInt(defaultPrng(), min, max);
111}
112
113template <class Engine, class Integral>
114std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
115randInt(Engine& engine, Integral max)
116{
117 return randInt(engine, Integral(0), max);
118}
119
120template <class Integral>
122randInt(Integral max)
123{
124 return randInt(defaultPrng(), max);
125}
126
127template <class Integral, class Engine>
128std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
129randInt(Engine& engine)
130{
132}
133
134template <class Integral = int>
140
141
144template <class Byte, class Engine>
147 detail::is_engine<Engine>::value,
148 Byte>
149randByte(Engine& engine)
150{
151 return static_cast<Byte>(randInt<Engine, std::uint32_t>(
153}
154
155template <class Byte = std::uint8_t>
158{
159 return randByte<Byte>(defaultPrng());
160}
161
162
165template <class Engine>
166inline bool
167randBool(Engine& engine)
168{
169 return randInt(engine, 1) == 1;
170}
171
172inline bool
174{
175 return randBool(defaultPrng());
176}
177
178
179} // namespace xrpl
T is_integral_v
T is_same_v
T is_unsigned_v
T max(T... args)
T min(T... args)
detail::XorShiftEngine<> xor_shift_engine
XOR-shift Generator.
std::is_invocable_r< Result, Engine > is_engine
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::enable_if_t<(std::is_same_v< Byte, unsigned char >||std::is_same_v< Byte, std::uint8_t >), Byte > randByte()
std::enable_if_t< std::is_integral_v< Integral >, Integral > randInt()
beast::xor_shift_engine & defaultPrng()
Return the default random engine.