Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:21

0001 //
0002 // Copyright 2018 The Abseil Authors.
0003 //
0004 // Licensed under the Apache License, Version 2.0 (the "License");
0005 // you may not use this file except in compliance with the License.
0006 // You may obtain a copy of the License at
0007 //
0008 //      https://www.apache.org/licenses/LICENSE-2.0
0009 //
0010 // Unless required by applicable law or agreed to in writing, software
0011 // distributed under the License is distributed on an "AS IS" BASIS,
0012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013 // See the License for the specific language governing permissions and
0014 // limitations under the License.
0015 //
0016 // -----------------------------------------------------------------------------
0017 // File: bit_gen_ref.h
0018 // -----------------------------------------------------------------------------
0019 //
0020 // This header defines a bit generator "reference" class, for use in interfaces
0021 // that take both Abseil (e.g. `absl::BitGen`) and standard library (e.g.
0022 // `std::mt19937`) bit generators.
0023 
0024 #ifndef ABSL_RANDOM_BIT_GEN_REF_H_
0025 #define ABSL_RANDOM_BIT_GEN_REF_H_
0026 
0027 #include <limits>
0028 #include <type_traits>
0029 #include <utility>
0030 
0031 #include "absl/base/attributes.h"
0032 #include "absl/base/internal/fast_type_id.h"
0033 #include "absl/base/macros.h"
0034 #include "absl/meta/type_traits.h"
0035 #include "absl/random/internal/distribution_caller.h"
0036 #include "absl/random/internal/fast_uniform_bits.h"
0037 
0038 namespace absl {
0039 ABSL_NAMESPACE_BEGIN
0040 namespace random_internal {
0041 
0042 template <typename URBG, typename = void, typename = void, typename = void>
0043 struct is_urbg : std::false_type {};
0044 
0045 template <typename URBG>
0046 struct is_urbg<
0047     URBG,
0048     absl::enable_if_t<std::is_same<
0049         typename URBG::result_type,
0050         typename std::decay<decltype((URBG::min)())>::type>::value>,
0051     absl::enable_if_t<std::is_same<
0052         typename URBG::result_type,
0053         typename std::decay<decltype((URBG::max)())>::type>::value>,
0054     absl::enable_if_t<std::is_same<
0055         typename URBG::result_type,
0056         typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>
0057     : std::true_type {};
0058 
0059 template <typename>
0060 struct DistributionCaller;
0061 class MockHelpers;
0062 
0063 }  // namespace random_internal
0064 
0065 // -----------------------------------------------------------------------------
0066 // absl::BitGenRef
0067 // -----------------------------------------------------------------------------
0068 //
0069 // `absl::BitGenRef` is a type-erasing class that provides a generator-agnostic
0070 // non-owning "reference" interface for use in place of any specific uniform
0071 // random bit generator (URBG). This class may be used for both Abseil
0072 // (e.g. `absl::BitGen`, `absl::InsecureBitGen`) and Standard library (e.g
0073 // `std::mt19937`, `std::minstd_rand`) bit generators.
0074 //
0075 // Like other reference classes, `absl::BitGenRef` does not own the
0076 // underlying bit generator, and the underlying instance must outlive the
0077 // `absl::BitGenRef`.
0078 //
0079 // `absl::BitGenRef` is particularly useful when used with an
0080 // `absl::MockingBitGen` to test specific paths in functions which use random
0081 // values.
0082 //
0083 // Example:
0084 //    void TakesBitGenRef(absl::BitGenRef gen) {
0085 //      int x = absl::Uniform<int>(gen, 0, 1000);
0086 //    }
0087 //
0088 class BitGenRef {
0089   // SFINAE to detect whether the URBG type includes a member matching
0090   // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
0091   //
0092   // These live inside BitGenRef so that they have friend access
0093   // to MockingBitGen. (see similar methods in DistributionCaller).
0094   template <template <class...> class Trait, class AlwaysVoid, class... Args>
0095   struct detector : std::false_type {};
0096   template <template <class...> class Trait, class... Args>
0097   struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
0098       : std::true_type {};
0099 
0100   template <class T>
0101   using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
0102       std::declval<base_internal::FastTypeIdType>(), std::declval<void*>(),
0103       std::declval<void*>()));
0104 
0105   template <typename T>
0106   using HasInvokeMock = typename detector<invoke_mock_t, void, T>::type;
0107 
0108  public:
0109   BitGenRef(const BitGenRef&) = default;
0110   BitGenRef(BitGenRef&&) = default;
0111   BitGenRef& operator=(const BitGenRef&) = default;
0112   BitGenRef& operator=(BitGenRef&&) = default;
0113 
0114   template <
0115       typename URBGRef, typename URBG = absl::remove_cvref_t<URBGRef>,
0116       typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
0117                                   random_internal::is_urbg<URBG>::value &&
0118                                   !HasInvokeMock<URBG>::value)>* = nullptr>
0119   BitGenRef(URBGRef&& gen ABSL_ATTRIBUTE_LIFETIME_BOUND)  // NOLINT
0120       : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
0121         mock_call_(NotAMock),
0122         generate_impl_fn_(ImplFn<URBG>) {}
0123 
0124   template <typename URBGRef, typename URBG = absl::remove_cvref_t<URBGRef>,
0125             typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
0126                                         random_internal::is_urbg<URBG>::value &&
0127                                         HasInvokeMock<URBG>::value)>* = nullptr>
0128   BitGenRef(URBGRef&& gen ABSL_ATTRIBUTE_LIFETIME_BOUND)  // NOLINT
0129       : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
0130         mock_call_(&MockCall<URBG>),
0131         generate_impl_fn_(ImplFn<URBG>) {}
0132 
0133   using result_type = uint64_t;
0134 
0135   static constexpr result_type(min)() {
0136     return (std::numeric_limits<result_type>::min)();
0137   }
0138 
0139   static constexpr result_type(max)() {
0140     return (std::numeric_limits<result_type>::max)();
0141   }
0142 
0143   result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); }
0144 
0145  private:
0146   using impl_fn = result_type (*)(uintptr_t);
0147   using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,
0148                                 void*);
0149 
0150   template <typename URBG>
0151   static result_type ImplFn(uintptr_t ptr) {
0152     // Ensure that the return values from operator() fill the entire
0153     // range promised by result_type, min() and max().
0154     absl::random_internal::FastUniformBits<result_type> fast_uniform_bits;
0155     return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));
0156   }
0157 
0158   // Get a type-erased InvokeMock pointer.
0159   template <typename URBG>
0160   static bool MockCall(uintptr_t gen_ptr, base_internal::FastTypeIdType type,
0161                        void* result, void* arg_tuple) {
0162     return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(type, result,
0163                                                         arg_tuple);
0164   }
0165   static bool NotAMock(uintptr_t, base_internal::FastTypeIdType, void*, void*) {
0166     return false;
0167   }
0168 
0169   inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
0170                          void* result) {
0171     if (mock_call_ == NotAMock) return false;  // avoids an indirect call.
0172     return mock_call_(t_erased_gen_ptr_, type, args_tuple, result);
0173   }
0174 
0175   uintptr_t t_erased_gen_ptr_;
0176   mock_call_fn mock_call_;
0177   impl_fn generate_impl_fn_;
0178 
0179   template <typename>
0180   friend struct ::absl::random_internal::DistributionCaller;  // for InvokeMock
0181   friend class ::absl::random_internal::MockHelpers;          // for InvokeMock
0182 };
0183 
0184 ABSL_NAMESPACE_END
0185 }  // namespace absl
0186 
0187 #endif  // ABSL_RANDOM_BIT_GEN_REF_H_