tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

bit_gen_ref.h (7136B)


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