userver: userver/utils/rand.hpp Source File
Loading...
Searching...
No Matches
rand.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/rand.hpp
4/// @brief Random number generators
5/// @ingroup userver_universal
6
7#include <algorithm>
8#include <cstdint>
9#include <limits>
10#include <random>
11#include <utility>
12
13#include <userver/compiler/thread_local.hpp>
14#include <userver/utils/assert.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace utils {
19
20/// @brief Virtualized standard UniformRandomBitGenerator concept, for use
21/// with random number distributions
23public:
24 using result_type = uint32_t;
25
26 virtual ~RandomBase() = default;
27
28 virtual result_type operator()() = 0;
29
30 static constexpr result_type min() { return std::mt19937::min(); }
31 static constexpr result_type max() { return std::mt19937::max(); }
32};
33
34namespace impl {
35
36std::seed_seq MakeSeedSeq();
37
38class RandomImpl final : public RandomBase {
39public:
40 RandomImpl();
41
42 result_type operator()() override { return gen_(); }
43
44private:
45 std::mt19937 gen_;
46};
47
48compiler::ThreadLocalScope<RandomImpl> UseLocalRandomImpl();
49
50} // namespace impl
51
52/// @brief Calls @a func with a thread-local UniformRandomBitGenerator
53/// (specifically of type utils::RandomBase).
54///
55/// @note The provided `RandomBase` instance is not cryptographically secure.
56///
57/// @a func should not contain any task context switches. That is, it should not
58/// use any userver synchronization primitives and should not access
59/// userver-based web or database clients.
60///
61/// @a func should not store the reference to the provided thread-local variable
62/// for use outside of the WithThreadLocal scope.
63///
64/// Prefer utils::RandRange if possible.
65///
66/// ## Usage example
67///
68/// Standard distributions can be passed to WithDefaultRandom directly:
69/// @snippet utils/rand_test.cpp WithDefaultRandom distribution
70///
71/// A lambda can be passed to perform a series of operations more efficiently:
72/// @snippet utils/rand_test.cpp WithDefaultRandom multiple
73///
74/// @param func functor that will be invoked with the RNG
75/// @returns The invocation result of @a func
76template <typename Func>
77decltype(auto) WithDefaultRandom(Func&& func) {
78 auto random = impl::UseLocalRandomImpl();
79 return std::forward<Func>(func)(static_cast<RandomBase&>(*random));
80}
81
82/// @brief Generates a random number in range [from, to)
83/// @note The used random generator is not cryptographically secure
84/// @note `from_inclusive` must be less than `to_exclusive`
85template <typename T>
86T RandRange(T from_inclusive, T to_exclusive) {
87 UINVARIANT(from_inclusive < to_exclusive, "attempt to get a random value in an incorrect range");
88 if constexpr (std::is_floating_point_v<T>) {
89 return utils::WithDefaultRandom(std::uniform_real_distribution<T>{from_inclusive, to_exclusive});
90 } else {
91 // 8-bit types are not allowed in uniform_int_distribution, so increase the
92 // T size.
93 return utils::WithDefaultRandom(std::uniform_int_distribution<std::common_type_t<T, unsigned short>>{
94 from_inclusive, to_exclusive - 1});
95 }
96}
97
98/// @brief Generates a random number in range [0, to)
99/// @note The used random generator is not cryptographically secure
100template <typename T>
101T RandRange(T to_exclusive) {
102 return RandRange(T{0}, to_exclusive);
103}
104
105/// @brief Shuffles the elements within the container
106/// @note The method used for determining a random permutation is not
107/// cryptographically secure
108template <typename Container>
109void Shuffle(Container& container) {
110 utils::WithDefaultRandom([&container](RandomBase& rng) {
111 std::shuffle(std::begin(container), std::end(container), rng);
112 });
113}
114
115/// @brief Generate a random number in the whole `uint32_t` range
116/// @note The used random generator is not cryptographically secure
117/// @warning Don't use `Rand() % N`, use `RandRange` instead
118std::uint32_t Rand();
119
120} // namespace utils
121
122USERVER_NAMESPACE_END