xref: /aosp_15_r20/external/abseil-cpp/absl/random/bit_gen_ref.h (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker //
2*9356374aSAndroid Build Coastguard Worker // Copyright 2018 The Abseil Authors.
3*9356374aSAndroid Build Coastguard Worker //
4*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*9356374aSAndroid Build Coastguard Worker //
8*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
9*9356374aSAndroid Build Coastguard Worker //
10*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*9356374aSAndroid Build Coastguard Worker // limitations under the License.
15*9356374aSAndroid Build Coastguard Worker //
16*9356374aSAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
17*9356374aSAndroid Build Coastguard Worker // File: bit_gen_ref.h
18*9356374aSAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
19*9356374aSAndroid Build Coastguard Worker //
20*9356374aSAndroid Build Coastguard Worker // This header defines a bit generator "reference" class, for use in interfaces
21*9356374aSAndroid Build Coastguard Worker // that take both Abseil (e.g. `absl::BitGen`) and standard library (e.g.
22*9356374aSAndroid Build Coastguard Worker // `std::mt19937`) bit generators.
23*9356374aSAndroid Build Coastguard Worker 
24*9356374aSAndroid Build Coastguard Worker #ifndef ABSL_RANDOM_BIT_GEN_REF_H_
25*9356374aSAndroid Build Coastguard Worker #define ABSL_RANDOM_BIT_GEN_REF_H_
26*9356374aSAndroid Build Coastguard Worker 
27*9356374aSAndroid Build Coastguard Worker #include <limits>
28*9356374aSAndroid Build Coastguard Worker #include <type_traits>
29*9356374aSAndroid Build Coastguard Worker #include <utility>
30*9356374aSAndroid Build Coastguard Worker 
31*9356374aSAndroid Build Coastguard Worker #include "absl/base/attributes.h"
32*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/fast_type_id.h"
33*9356374aSAndroid Build Coastguard Worker #include "absl/base/macros.h"
34*9356374aSAndroid Build Coastguard Worker #include "absl/meta/type_traits.h"
35*9356374aSAndroid Build Coastguard Worker #include "absl/random/internal/distribution_caller.h"
36*9356374aSAndroid Build Coastguard Worker #include "absl/random/internal/fast_uniform_bits.h"
37*9356374aSAndroid Build Coastguard Worker 
38*9356374aSAndroid Build Coastguard Worker namespace absl {
39*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
40*9356374aSAndroid Build Coastguard Worker namespace random_internal {
41*9356374aSAndroid Build Coastguard Worker 
42*9356374aSAndroid Build Coastguard Worker template <typename URBG, typename = void, typename = void, typename = void>
43*9356374aSAndroid Build Coastguard Worker struct is_urbg : std::false_type {};
44*9356374aSAndroid Build Coastguard Worker 
45*9356374aSAndroid Build Coastguard Worker template <typename URBG>
46*9356374aSAndroid Build Coastguard Worker struct is_urbg<
47*9356374aSAndroid Build Coastguard Worker     URBG,
48*9356374aSAndroid Build Coastguard Worker     absl::enable_if_t<std::is_same<
49*9356374aSAndroid Build Coastguard Worker         typename URBG::result_type,
50*9356374aSAndroid Build Coastguard Worker         typename std::decay<decltype((URBG::min)())>::type>::value>,
51*9356374aSAndroid Build Coastguard Worker     absl::enable_if_t<std::is_same<
52*9356374aSAndroid Build Coastguard Worker         typename URBG::result_type,
53*9356374aSAndroid Build Coastguard Worker         typename std::decay<decltype((URBG::max)())>::type>::value>,
54*9356374aSAndroid Build Coastguard Worker     absl::enable_if_t<std::is_same<
55*9356374aSAndroid Build Coastguard Worker         typename URBG::result_type,
56*9356374aSAndroid Build Coastguard Worker         typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>
57*9356374aSAndroid Build Coastguard Worker     : std::true_type {};
58*9356374aSAndroid Build Coastguard Worker 
59*9356374aSAndroid Build Coastguard Worker template <typename>
60*9356374aSAndroid Build Coastguard Worker struct DistributionCaller;
61*9356374aSAndroid Build Coastguard Worker class MockHelpers;
62*9356374aSAndroid Build Coastguard Worker 
63*9356374aSAndroid Build Coastguard Worker }  // namespace random_internal
64*9356374aSAndroid Build Coastguard Worker 
65*9356374aSAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
66*9356374aSAndroid Build Coastguard Worker // absl::BitGenRef
67*9356374aSAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
68*9356374aSAndroid Build Coastguard Worker //
69*9356374aSAndroid Build Coastguard Worker // `absl::BitGenRef` is a type-erasing class that provides a generator-agnostic
70*9356374aSAndroid Build Coastguard Worker // non-owning "reference" interface for use in place of any specific uniform
71*9356374aSAndroid Build Coastguard Worker // random bit generator (URBG). This class may be used for both Abseil
72*9356374aSAndroid Build Coastguard Worker // (e.g. `absl::BitGen`, `absl::InsecureBitGen`) and Standard library (e.g
73*9356374aSAndroid Build Coastguard Worker // `std::mt19937`, `std::minstd_rand`) bit generators.
74*9356374aSAndroid Build Coastguard Worker //
75*9356374aSAndroid Build Coastguard Worker // Like other reference classes, `absl::BitGenRef` does not own the
76*9356374aSAndroid Build Coastguard Worker // underlying bit generator, and the underlying instance must outlive the
77*9356374aSAndroid Build Coastguard Worker // `absl::BitGenRef`.
78*9356374aSAndroid Build Coastguard Worker //
79*9356374aSAndroid Build Coastguard Worker // `absl::BitGenRef` is particularly useful when used with an
80*9356374aSAndroid Build Coastguard Worker // `absl::MockingBitGen` to test specific paths in functions which use random
81*9356374aSAndroid Build Coastguard Worker // values.
82*9356374aSAndroid Build Coastguard Worker //
83*9356374aSAndroid Build Coastguard Worker // Example:
84*9356374aSAndroid Build Coastguard Worker //    void TakesBitGenRef(absl::BitGenRef gen) {
85*9356374aSAndroid Build Coastguard Worker //      int x = absl::Uniform<int>(gen, 0, 1000);
86*9356374aSAndroid Build Coastguard Worker //    }
87*9356374aSAndroid Build Coastguard Worker //
88*9356374aSAndroid Build Coastguard Worker class BitGenRef {
89*9356374aSAndroid Build Coastguard Worker   // SFINAE to detect whether the URBG type includes a member matching
90*9356374aSAndroid Build Coastguard Worker   // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
91*9356374aSAndroid Build Coastguard Worker   //
92*9356374aSAndroid Build Coastguard Worker   // These live inside BitGenRef so that they have friend access
93*9356374aSAndroid Build Coastguard Worker   // to MockingBitGen. (see similar methods in DistributionCaller).
94*9356374aSAndroid Build Coastguard Worker   template <template <class...> class Trait, class AlwaysVoid, class... Args>
95*9356374aSAndroid Build Coastguard Worker   struct detector : std::false_type {};
96*9356374aSAndroid Build Coastguard Worker   template <template <class...> class Trait, class... Args>
97*9356374aSAndroid Build Coastguard Worker   struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
98*9356374aSAndroid Build Coastguard Worker       : std::true_type {};
99*9356374aSAndroid Build Coastguard Worker 
100*9356374aSAndroid Build Coastguard Worker   template <class T>
101*9356374aSAndroid Build Coastguard Worker   using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
102*9356374aSAndroid Build Coastguard Worker       std::declval<base_internal::FastTypeIdType>(), std::declval<void*>(),
103*9356374aSAndroid Build Coastguard Worker       std::declval<void*>()));
104*9356374aSAndroid Build Coastguard Worker 
105*9356374aSAndroid Build Coastguard Worker   template <typename T>
106*9356374aSAndroid Build Coastguard Worker   using HasInvokeMock = typename detector<invoke_mock_t, void, T>::type;
107*9356374aSAndroid Build Coastguard Worker 
108*9356374aSAndroid Build Coastguard Worker  public:
109*9356374aSAndroid Build Coastguard Worker   BitGenRef(const BitGenRef&) = default;
110*9356374aSAndroid Build Coastguard Worker   BitGenRef(BitGenRef&&) = default;
111*9356374aSAndroid Build Coastguard Worker   BitGenRef& operator=(const BitGenRef&) = default;
112*9356374aSAndroid Build Coastguard Worker   BitGenRef& operator=(BitGenRef&&) = default;
113*9356374aSAndroid Build Coastguard Worker 
114*9356374aSAndroid Build Coastguard Worker   template <
115*9356374aSAndroid Build Coastguard Worker       typename URBGRef, typename URBG = absl::remove_cvref_t<URBGRef>,
116*9356374aSAndroid Build Coastguard Worker       typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
117*9356374aSAndroid Build Coastguard Worker                                   random_internal::is_urbg<URBG>::value &&
118*9356374aSAndroid Build Coastguard Worker                                   !HasInvokeMock<URBG>::value)>* = nullptr>
119*9356374aSAndroid Build Coastguard Worker   BitGenRef(URBGRef&& gen ABSL_ATTRIBUTE_LIFETIME_BOUND)  // NOLINT
120*9356374aSAndroid Build Coastguard Worker       : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
121*9356374aSAndroid Build Coastguard Worker         mock_call_(NotAMock),
122*9356374aSAndroid Build Coastguard Worker         generate_impl_fn_(ImplFn<URBG>) {}
123*9356374aSAndroid Build Coastguard Worker 
124*9356374aSAndroid Build Coastguard Worker   template <typename URBGRef, typename URBG = absl::remove_cvref_t<URBGRef>,
125*9356374aSAndroid Build Coastguard Worker             typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
126*9356374aSAndroid Build Coastguard Worker                                         random_internal::is_urbg<URBG>::value &&
127*9356374aSAndroid Build Coastguard Worker                                         HasInvokeMock<URBG>::value)>* = nullptr>
128*9356374aSAndroid Build Coastguard Worker   BitGenRef(URBGRef&& gen ABSL_ATTRIBUTE_LIFETIME_BOUND)  // NOLINT
129*9356374aSAndroid Build Coastguard Worker       : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
130*9356374aSAndroid Build Coastguard Worker         mock_call_(&MockCall<URBG>),
131*9356374aSAndroid Build Coastguard Worker         generate_impl_fn_(ImplFn<URBG>) {}
132*9356374aSAndroid Build Coastguard Worker 
133*9356374aSAndroid Build Coastguard Worker   using result_type = uint64_t;
134*9356374aSAndroid Build Coastguard Worker 
135*9356374aSAndroid Build Coastguard Worker   static constexpr result_type(min)() {
136*9356374aSAndroid Build Coastguard Worker     return (std::numeric_limits<result_type>::min)();
137*9356374aSAndroid Build Coastguard Worker   }
138*9356374aSAndroid Build Coastguard Worker 
139*9356374aSAndroid Build Coastguard Worker   static constexpr result_type(max)() {
140*9356374aSAndroid Build Coastguard Worker     return (std::numeric_limits<result_type>::max)();
141*9356374aSAndroid Build Coastguard Worker   }
142*9356374aSAndroid Build Coastguard Worker 
143*9356374aSAndroid Build Coastguard Worker   result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); }
144*9356374aSAndroid Build Coastguard Worker 
145*9356374aSAndroid Build Coastguard Worker  private:
146*9356374aSAndroid Build Coastguard Worker   using impl_fn = result_type (*)(uintptr_t);
147*9356374aSAndroid Build Coastguard Worker   using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,
148*9356374aSAndroid Build Coastguard Worker                                 void*);
149*9356374aSAndroid Build Coastguard Worker 
150*9356374aSAndroid Build Coastguard Worker   template <typename URBG>
151*9356374aSAndroid Build Coastguard Worker   static result_type ImplFn(uintptr_t ptr) {
152*9356374aSAndroid Build Coastguard Worker     // Ensure that the return values from operator() fill the entire
153*9356374aSAndroid Build Coastguard Worker     // range promised by result_type, min() and max().
154*9356374aSAndroid Build Coastguard Worker     absl::random_internal::FastUniformBits<result_type> fast_uniform_bits;
155*9356374aSAndroid Build Coastguard Worker     return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));
156*9356374aSAndroid Build Coastguard Worker   }
157*9356374aSAndroid Build Coastguard Worker 
158*9356374aSAndroid Build Coastguard Worker   // Get a type-erased InvokeMock pointer.
159*9356374aSAndroid Build Coastguard Worker   template <typename URBG>
160*9356374aSAndroid Build Coastguard Worker   static bool MockCall(uintptr_t gen_ptr, base_internal::FastTypeIdType type,
161*9356374aSAndroid Build Coastguard Worker                        void* result, void* arg_tuple) {
162*9356374aSAndroid Build Coastguard Worker     return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(type, result,
163*9356374aSAndroid Build Coastguard Worker                                                         arg_tuple);
164*9356374aSAndroid Build Coastguard Worker   }
165*9356374aSAndroid Build Coastguard Worker   static bool NotAMock(uintptr_t, base_internal::FastTypeIdType, void*, void*) {
166*9356374aSAndroid Build Coastguard Worker     return false;
167*9356374aSAndroid Build Coastguard Worker   }
168*9356374aSAndroid Build Coastguard Worker 
169*9356374aSAndroid Build Coastguard Worker   inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
170*9356374aSAndroid Build Coastguard Worker                          void* result) {
171*9356374aSAndroid Build Coastguard Worker     if (mock_call_ == NotAMock) return false;  // avoids an indirect call.
172*9356374aSAndroid Build Coastguard Worker     return mock_call_(t_erased_gen_ptr_, type, args_tuple, result);
173*9356374aSAndroid Build Coastguard Worker   }
174*9356374aSAndroid Build Coastguard Worker 
175*9356374aSAndroid Build Coastguard Worker   uintptr_t t_erased_gen_ptr_;
176*9356374aSAndroid Build Coastguard Worker   mock_call_fn mock_call_;
177*9356374aSAndroid Build Coastguard Worker   impl_fn generate_impl_fn_;
178*9356374aSAndroid Build Coastguard Worker 
179*9356374aSAndroid Build Coastguard Worker   template <typename>
180*9356374aSAndroid Build Coastguard Worker   friend struct ::absl::random_internal::DistributionCaller;  // for InvokeMock
181*9356374aSAndroid Build Coastguard Worker   friend class ::absl::random_internal::MockHelpers;          // for InvokeMock
182*9356374aSAndroid Build Coastguard Worker };
183*9356374aSAndroid Build Coastguard Worker 
184*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
185*9356374aSAndroid Build Coastguard Worker }  // namespace absl
186*9356374aSAndroid Build Coastguard Worker 
187*9356374aSAndroid Build Coastguard Worker #endif  // ABSL_RANDOM_BIT_GEN_REF_H_
188