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