xref: /aosp_15_r20/external/abseil-cpp/absl/random/internal/pool_urbg.h (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker // Copyright 2017 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker 
15*9356374aSAndroid Build Coastguard Worker #ifndef ABSL_RANDOM_INTERNAL_POOL_URBG_H_
16*9356374aSAndroid Build Coastguard Worker #define ABSL_RANDOM_INTERNAL_POOL_URBG_H_
17*9356374aSAndroid Build Coastguard Worker 
18*9356374aSAndroid Build Coastguard Worker #include <cinttypes>
19*9356374aSAndroid Build Coastguard Worker #include <limits>
20*9356374aSAndroid Build Coastguard Worker 
21*9356374aSAndroid Build Coastguard Worker #include "absl/random/internal/traits.h"
22*9356374aSAndroid Build Coastguard Worker #include "absl/types/span.h"
23*9356374aSAndroid Build Coastguard Worker 
24*9356374aSAndroid Build Coastguard Worker namespace absl {
25*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
26*9356374aSAndroid Build Coastguard Worker namespace random_internal {
27*9356374aSAndroid Build Coastguard Worker 
28*9356374aSAndroid Build Coastguard Worker // RandenPool is a thread-safe random number generator [random.req.urbg] that
29*9356374aSAndroid Build Coastguard Worker // uses an underlying pool of Randen generators to generate values.  Each thread
30*9356374aSAndroid Build Coastguard Worker // has affinity to one instance of the underlying pool generators.  Concurrent
31*9356374aSAndroid Build Coastguard Worker // access is guarded by a spin-lock.
32*9356374aSAndroid Build Coastguard Worker template <typename T>
33*9356374aSAndroid Build Coastguard Worker class RandenPool {
34*9356374aSAndroid Build Coastguard Worker  public:
35*9356374aSAndroid Build Coastguard Worker   using result_type = T;
36*9356374aSAndroid Build Coastguard Worker   static_assert(std::is_unsigned<result_type>::value,
37*9356374aSAndroid Build Coastguard Worker                 "RandenPool template argument must be a built-in unsigned "
38*9356374aSAndroid Build Coastguard Worker                 "integer type");
39*9356374aSAndroid Build Coastguard Worker 
result_type(min)40*9356374aSAndroid Build Coastguard Worker   static constexpr result_type(min)() {
41*9356374aSAndroid Build Coastguard Worker     return (std::numeric_limits<result_type>::min)();
42*9356374aSAndroid Build Coastguard Worker   }
43*9356374aSAndroid Build Coastguard Worker 
result_type(max)44*9356374aSAndroid Build Coastguard Worker   static constexpr result_type(max)() {
45*9356374aSAndroid Build Coastguard Worker     return (std::numeric_limits<result_type>::max)();
46*9356374aSAndroid Build Coastguard Worker   }
47*9356374aSAndroid Build Coastguard Worker 
RandenPool()48*9356374aSAndroid Build Coastguard Worker   RandenPool() {}
49*9356374aSAndroid Build Coastguard Worker 
50*9356374aSAndroid Build Coastguard Worker   // Returns a single value.
operator()51*9356374aSAndroid Build Coastguard Worker   inline result_type operator()() { return Generate(); }
52*9356374aSAndroid Build Coastguard Worker 
53*9356374aSAndroid Build Coastguard Worker   // Fill data with random values.
54*9356374aSAndroid Build Coastguard Worker   static void Fill(absl::Span<result_type> data);
55*9356374aSAndroid Build Coastguard Worker 
56*9356374aSAndroid Build Coastguard Worker  protected:
57*9356374aSAndroid Build Coastguard Worker   // Generate returns a single value.
58*9356374aSAndroid Build Coastguard Worker   static result_type Generate();
59*9356374aSAndroid Build Coastguard Worker };
60*9356374aSAndroid Build Coastguard Worker 
61*9356374aSAndroid Build Coastguard Worker extern template class RandenPool<uint8_t>;
62*9356374aSAndroid Build Coastguard Worker extern template class RandenPool<uint16_t>;
63*9356374aSAndroid Build Coastguard Worker extern template class RandenPool<uint32_t>;
64*9356374aSAndroid Build Coastguard Worker extern template class RandenPool<uint64_t>;
65*9356374aSAndroid Build Coastguard Worker 
66*9356374aSAndroid Build Coastguard Worker // PoolURBG uses an underlying pool of random generators to implement a
67*9356374aSAndroid Build Coastguard Worker // thread-compatible [random.req.urbg] interface with an internal cache of
68*9356374aSAndroid Build Coastguard Worker // values.
69*9356374aSAndroid Build Coastguard Worker template <typename T, size_t kBufferSize>
70*9356374aSAndroid Build Coastguard Worker class PoolURBG {
71*9356374aSAndroid Build Coastguard Worker   // Inheritance to access the protected static members of RandenPool.
72*9356374aSAndroid Build Coastguard Worker   using unsigned_type = typename make_unsigned_bits<T>::type;
73*9356374aSAndroid Build Coastguard Worker   using PoolType = RandenPool<unsigned_type>;
74*9356374aSAndroid Build Coastguard Worker   using SpanType = absl::Span<unsigned_type>;
75*9356374aSAndroid Build Coastguard Worker 
76*9356374aSAndroid Build Coastguard Worker   static constexpr size_t kInitialBuffer = kBufferSize + 1;
77*9356374aSAndroid Build Coastguard Worker   static constexpr size_t kHalfBuffer = kBufferSize / 2;
78*9356374aSAndroid Build Coastguard Worker 
79*9356374aSAndroid Build Coastguard Worker  public:
80*9356374aSAndroid Build Coastguard Worker   using result_type = T;
81*9356374aSAndroid Build Coastguard Worker 
82*9356374aSAndroid Build Coastguard Worker   static_assert(std::is_unsigned<result_type>::value,
83*9356374aSAndroid Build Coastguard Worker                 "PoolURBG must be parameterized by an unsigned integer type");
84*9356374aSAndroid Build Coastguard Worker 
85*9356374aSAndroid Build Coastguard Worker   static_assert(kBufferSize > 1,
86*9356374aSAndroid Build Coastguard Worker                 "PoolURBG must be parameterized by a buffer-size > 1");
87*9356374aSAndroid Build Coastguard Worker 
88*9356374aSAndroid Build Coastguard Worker   static_assert(kBufferSize <= 256,
89*9356374aSAndroid Build Coastguard Worker                 "PoolURBG must be parameterized by a buffer-size <= 256");
90*9356374aSAndroid Build Coastguard Worker 
result_type(min)91*9356374aSAndroid Build Coastguard Worker   static constexpr result_type(min)() {
92*9356374aSAndroid Build Coastguard Worker     return (std::numeric_limits<result_type>::min)();
93*9356374aSAndroid Build Coastguard Worker   }
94*9356374aSAndroid Build Coastguard Worker 
result_type(max)95*9356374aSAndroid Build Coastguard Worker   static constexpr result_type(max)() {
96*9356374aSAndroid Build Coastguard Worker     return (std::numeric_limits<result_type>::max)();
97*9356374aSAndroid Build Coastguard Worker   }
98*9356374aSAndroid Build Coastguard Worker 
PoolURBG()99*9356374aSAndroid Build Coastguard Worker   PoolURBG() : next_(kInitialBuffer) {}
100*9356374aSAndroid Build Coastguard Worker 
101*9356374aSAndroid Build Coastguard Worker   // copy-constructor does not copy cache.
PoolURBG(const PoolURBG &)102*9356374aSAndroid Build Coastguard Worker   PoolURBG(const PoolURBG&) : next_(kInitialBuffer) {}
103*9356374aSAndroid Build Coastguard Worker   const PoolURBG& operator=(const PoolURBG&) {
104*9356374aSAndroid Build Coastguard Worker     next_ = kInitialBuffer;
105*9356374aSAndroid Build Coastguard Worker     return *this;
106*9356374aSAndroid Build Coastguard Worker   }
107*9356374aSAndroid Build Coastguard Worker 
108*9356374aSAndroid Build Coastguard Worker   // move-constructor does move cache.
109*9356374aSAndroid Build Coastguard Worker   PoolURBG(PoolURBG&&) = default;
110*9356374aSAndroid Build Coastguard Worker   PoolURBG& operator=(PoolURBG&&) = default;
111*9356374aSAndroid Build Coastguard Worker 
operator()112*9356374aSAndroid Build Coastguard Worker   inline result_type operator()() {
113*9356374aSAndroid Build Coastguard Worker     if (next_ >= kBufferSize) {
114*9356374aSAndroid Build Coastguard Worker       next_ = (kBufferSize > 2 && next_ > kBufferSize) ? kHalfBuffer : 0;
115*9356374aSAndroid Build Coastguard Worker       PoolType::Fill(SpanType(reinterpret_cast<unsigned_type*>(state_ + next_),
116*9356374aSAndroid Build Coastguard Worker                               kBufferSize - next_));
117*9356374aSAndroid Build Coastguard Worker     }
118*9356374aSAndroid Build Coastguard Worker     return state_[next_++];
119*9356374aSAndroid Build Coastguard Worker   }
120*9356374aSAndroid Build Coastguard Worker 
121*9356374aSAndroid Build Coastguard Worker  private:
122*9356374aSAndroid Build Coastguard Worker   // Buffer size.
123*9356374aSAndroid Build Coastguard Worker   size_t next_;  // index within state_
124*9356374aSAndroid Build Coastguard Worker   result_type state_[kBufferSize];
125*9356374aSAndroid Build Coastguard Worker };
126*9356374aSAndroid Build Coastguard Worker 
127*9356374aSAndroid Build Coastguard Worker }  // namespace random_internal
128*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
129*9356374aSAndroid Build Coastguard Worker }  // namespace absl
130*9356374aSAndroid Build Coastguard Worker 
131*9356374aSAndroid Build Coastguard Worker #endif  // ABSL_RANDOM_INTERNAL_POOL_URBG_H_
132