bit_gen_ref.h 7.0 KB

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