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 7.5 kB

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