80
80
* Thread-safe.
81
81
*/
82
82
void GetRandBytes (Span<unsigned char > bytes) noexcept ;
83
- /* * Generate a uniform random integer in the range [0..range). Precondition: range > 0 */
84
- uint64_t GetRandInternal (uint64_t nMax) noexcept ;
85
- /* * Generate a uniform random integer of type T in the range [0..nMax)
86
- * nMax defaults to std::numeric_limits<T>::max()
87
- * Precondition: nMax > 0, T is an integral type, no larger than uint64_t
88
- */
89
- template <typename T>
90
- T GetRand (T nMax=std::numeric_limits<T>::max()) noexcept {
91
- static_assert (std::is_integral<T>(), " T must be integral" );
92
- static_assert (std::numeric_limits<T>::max () <= std::numeric_limits<uint64_t >::max (), " GetRand only supports up to uint64_t" );
93
- return T (GetRandInternal (nMax));
94
- }
95
- /* * Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */
96
- template <typename D>
97
- D GetRandomDuration (typename std::common_type<D>::type max) noexcept
98
- // Having the compiler infer the template argument from the function argument
99
- // is dangerous, because the desired return value generally has a different
100
- // type than the function argument. So std::common_type is used to force the
101
- // call site to specify the type of the return value.
102
- {
103
- assert (max.count () > 0 );
104
- return D{GetRand (max.count ())};
105
- };
106
- constexpr auto GetRandMicros = GetRandomDuration<std::chrono::microseconds>;
107
- constexpr auto GetRandMillis = GetRandomDuration<std::chrono::milliseconds>;
108
83
109
84
/* *
110
85
* Return a timestamp in the future sampled from an exponential distribution
@@ -251,17 +226,17 @@ class RandomMixin
251
226
}
252
227
}
253
228
254
- /* * Generate a random integer in the range [0..range).
255
- * Precondition: range > 0.
256
- */
257
- uint64_t randrange (uint64_t range) noexcept
229
+ /* * Generate a random integer in the range [0..range), with range > 0. */
230
+ template <std::integral I>
231
+ I randrange (I range) noexcept
258
232
{
259
- assert (range);
260
- --range;
261
- int bits = std::bit_width (range);
233
+ static_assert (std::numeric_limits<I>::max () <= std::numeric_limits<uint64_t >::max ());
234
+ Assume (range > 0 );
235
+ uint64_t maxval = range - 1U ;
236
+ int bits = std::bit_width (maxval);
262
237
while (true ) {
263
238
uint64_t ret = Impl ().randbits (bits);
264
- if (ret <= range ) return ret;
239
+ if (ret <= maxval ) return ret;
265
240
}
266
241
}
267
242
@@ -284,6 +259,16 @@ class RandomMixin
284
259
}
285
260
}
286
261
262
+ /* * Generate a random integer in its entire (non-negative) range. */
263
+ template <std::integral I>
264
+ I rand () noexcept
265
+ {
266
+ static_assert (std::numeric_limits<I>::max () <= std::numeric_limits<uint64_t >::max ());
267
+ static constexpr auto BITS = std::bit_width (uint64_t (std::numeric_limits<I>::max ()));
268
+ static_assert (std::numeric_limits<I>::max () == std::numeric_limits<uint64_t >::max () >> (64 - BITS));
269
+ return I (Impl ().template randbits <BITS>());
270
+ }
271
+
287
272
/* * Generate random bytes. */
288
273
template <BasicByte B = unsigned char >
289
274
std::vector<B> randbytes (size_t len) noexcept
@@ -441,6 +426,33 @@ void Shuffle(I first, I last, R&& rng)
441
426
}
442
427
}
443
428
429
+ /* * Generate a uniform random integer of type T in the range [0..nMax)
430
+ * Precondition: nMax > 0, T is an integral type, no larger than uint64_t
431
+ */
432
+ template <typename T>
433
+ T GetRand (T nMax) noexcept {
434
+ return T (FastRandomContext ().randrange (nMax));
435
+ }
436
+
437
+ /* * Generate a uniform random integer of type T in its entire non-negative range. */
438
+ template <typename T>
439
+ T GetRand () noexcept {
440
+ return T (FastRandomContext ().rand <T>());
441
+ }
442
+
443
+ /* * Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */
444
+ template <typename D>
445
+ D GetRandomDuration (typename std::common_type<D>::type max) noexcept
446
+ // Having the compiler infer the template argument from the function argument
447
+ // is dangerous, because the desired return value generally has a different
448
+ // type than the function argument. So std::common_type is used to force the
449
+ // call site to specify the type of the return value.
450
+ {
451
+ return D{GetRand (max.count ())};
452
+ };
453
+ constexpr auto GetRandMicros = GetRandomDuration<std::chrono::microseconds>;
454
+ constexpr auto GetRandMillis = GetRandomDuration<std::chrono::milliseconds>;
455
+
444
456
/* Number of random bytes returned by GetOSRand.
445
457
* When changing this constant make sure to change all call sites, and make
446
458
* sure that the underlying OS APIs for all platforms support the number.
0 commit comments