8080 * Thread-safe.
8181 */
8282void 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>;
10883
10984/* *
11085 * Return a timestamp in the future sampled from an exponential distribution
@@ -251,17 +226,17 @@ class RandomMixin
251226 }
252227 }
253228
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
258232 {
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);
262237 while (true ) {
263238 uint64_t ret = Impl ().randbits (bits);
264- if (ret <= range ) return ret;
239+ if (ret <= maxval ) return ret;
265240 }
266241 }
267242
@@ -284,6 +259,16 @@ class RandomMixin
284259 }
285260 }
286261
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+
287272 /* * Generate random bytes. */
288273 template <BasicByte B = unsigned char >
289274 std::vector<B> randbytes (size_t len) noexcept
@@ -441,6 +426,33 @@ void Shuffle(I first, I last, R&& rng)
441426 }
442427}
443428
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+
444456/* Number of random bytes returned by GetOSRand.
445457 * When changing this constant make sure to change all call sites, and make
446458 * sure that the underlying OS APIs for all platforms support the number.
0 commit comments