You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

bit_gen_ref.h 6.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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. #ifndef ABSL_RANDOM_BIT_GEN_REF_H_
  24. #define ABSL_RANDOM_BIT_GEN_REF_H_
  25. #include <limits>
  26. #include <type_traits>
  27. #include <utility>
  28. #include "absl/base/internal/fast_type_id.h"
  29. #include "absl/base/macros.h"
  30. #include "absl/meta/type_traits.h"
  31. #include "absl/random/internal/distribution_caller.h"
  32. #include "absl/random/internal/fast_uniform_bits.h"
  33. namespace absl {
  34. ABSL_NAMESPACE_BEGIN
  35. namespace random_internal {
  36. template <typename URBG, typename = void, typename = void, typename = void>
  37. struct is_urbg : std::false_type {};
  38. template <typename URBG>
  39. struct is_urbg<
  40. URBG,
  41. absl::enable_if_t<std::is_same<
  42. typename URBG::result_type,
  43. typename std::decay<decltype((URBG::min)())>::type>::value>,
  44. absl::enable_if_t<std::is_same<
  45. typename URBG::result_type,
  46. typename std::decay<decltype((URBG::max)())>::type>::value>,
  47. absl::enable_if_t<std::is_same<
  48. typename URBG::result_type,
  49. typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>
  50. : std::true_type {};
  51. template <typename>
  52. struct DistributionCaller;
  53. class MockHelpers;
  54. } // namespace random_internal
  55. // -----------------------------------------------------------------------------
  56. // absl::BitGenRef
  57. // -----------------------------------------------------------------------------
  58. //
  59. // `absl::BitGenRef` is a type-erasing class that provides a generator-agnostic
  60. // non-owning "reference" interface for use in place of any specific uniform
  61. // random bit generator (URBG). This class may be used for both Abseil
  62. // (e.g. `absl::BitGen`, `absl::InsecureBitGen`) and Standard library (e.g
  63. // `std::mt19937`, `std::minstd_rand`) bit generators.
  64. //
  65. // Like other reference classes, `absl::BitGenRef` does not own the
  66. // underlying bit generator, and the underlying instance must outlive the
  67. // `absl::BitGenRef`.
  68. //
  69. // `absl::BitGenRef` is particularly useful when used with an
  70. // `absl::MockingBitGen` to test specific paths in functions which use random
  71. // values.
  72. //
  73. // Example:
  74. // void TakesBitGenRef(absl::BitGenRef gen) {
  75. // int x = absl::Uniform<int>(gen, 0, 1000);
  76. // }
  77. //
  78. class BitGenRef {
  79. // SFINAE to detect whether the URBG type includes a member matching
  80. // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
  81. //
  82. // These live inside BitGenRef so that they have friend access
  83. // to MockingBitGen. (see similar methods in DistributionCaller).
  84. template <template <class...> class Trait, class AlwaysVoid, class... Args>
  85. struct detector : std::false_type {};
  86. template <template <class...> class Trait, class... Args>
  87. struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
  88. : std::true_type {};
  89. template <class T>
  90. using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
  91. std::declval<base_internal::FastTypeIdType>(), std::declval<void*>(),
  92. std::declval<void*>()));
  93. template <typename T>
  94. using HasInvokeMock = typename detector<invoke_mock_t, void, T>::type;
  95. public:
  96. BitGenRef(const BitGenRef&) = default;
  97. BitGenRef(BitGenRef&&) = default;
  98. BitGenRef& operator=(const BitGenRef&) = default;
  99. BitGenRef& operator=(BitGenRef&&) = default;
  100. template <typename URBG, typename absl::enable_if_t<
  101. (!std::is_same<URBG, BitGenRef>::value &&
  102. random_internal::is_urbg<URBG>::value &&
  103. !HasInvokeMock<URBG>::value)>* = nullptr>
  104. BitGenRef(URBG& gen) // NOLINT
  105. : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
  106. mock_call_(NotAMock),
  107. generate_impl_fn_(ImplFn<URBG>) {}
  108. template <typename URBG,
  109. typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
  110. random_internal::is_urbg<URBG>::value &&
  111. HasInvokeMock<URBG>::value)>* = nullptr>
  112. BitGenRef(URBG& gen) // NOLINT
  113. : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
  114. mock_call_(&MockCall<URBG>),
  115. generate_impl_fn_(ImplFn<URBG>) {}
  116. using result_type = uint64_t;
  117. static constexpr result_type(min)() {
  118. return (std::numeric_limits<result_type>::min)();
  119. }
  120. static constexpr result_type(max)() {
  121. return (std::numeric_limits<result_type>::max)();
  122. }
  123. result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); }
  124. private:
  125. using impl_fn = result_type (*)(uintptr_t);
  126. using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,
  127. void*);
  128. template <typename URBG>
  129. static result_type ImplFn(uintptr_t ptr) {
  130. // Ensure that the return values from operator() fill the entire
  131. // range promised by result_type, min() and max().
  132. absl::random_internal::FastUniformBits<result_type> fast_uniform_bits;
  133. return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));
  134. }
  135. // Get a type-erased InvokeMock pointer.
  136. template <typename URBG>
  137. static bool MockCall(uintptr_t gen_ptr, base_internal::FastTypeIdType type,
  138. void* result, void* arg_tuple) {
  139. return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(type, result,
  140. arg_tuple);
  141. }
  142. static bool NotAMock(uintptr_t, base_internal::FastTypeIdType, void*, void*) {
  143. return false;
  144. }
  145. inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
  146. void* result) {
  147. if (mock_call_ == NotAMock) return false; // avoids an indirect call.
  148. return mock_call_(t_erased_gen_ptr_, type, args_tuple, result);
  149. }
  150. uintptr_t t_erased_gen_ptr_;
  151. mock_call_fn mock_call_;
  152. impl_fn generate_impl_fn_;
  153. template <typename>
  154. friend struct ::absl::random_internal::DistributionCaller; // for InvokeMock
  155. friend class ::absl::random_internal::MockHelpers; // for InvokeMock
  156. };
  157. ABSL_NAMESPACE_END
  158. } // namespace absl
  159. #endif // ABSL_RANDOM_BIT_GEN_REF_H_