distribution_caller.h 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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. #ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_
  17. #define ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_
  18. #include <tuple>
  19. #include <type_traits>
  20. #include <utility>
  21. #include "absl/base/config.h"
  22. #include "absl/base/internal/fast_type_id.h"
  23. #include "absl/meta/type_traits.h"
  24. #include "absl/utility/utility.h"
  25. namespace absl {
  26. ABSL_NAMESPACE_BEGIN
  27. namespace random_internal {
  28. // DistributionCaller provides an opportunity to overload the general
  29. // mechanism for calling a distribution, allowing for mock-RNG classes
  30. // to intercept such calls.
  31. template <typename URBG>
  32. struct DistributionCaller {
  33. static_assert(!std::is_pointer<URBG>::value,
  34. "You must pass a reference, not a pointer.");
  35. // SFINAE to detect whether the URBG type includes a member matching
  36. // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
  37. //
  38. // These live inside BitGenRef so that they have friend access
  39. // to MockingBitGen. (see similar methods in DistributionCaller).
  40. template <template <class...> class Trait, class AlwaysVoid, class... Args>
  41. struct detector : std::false_type {};
  42. template <template <class...> class Trait, class... Args>
  43. struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
  44. : std::true_type {};
  45. template <class T>
  46. using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
  47. std::declval<::absl::base_internal::FastTypeIdType>(),
  48. std::declval<void*>(), std::declval<void*>()));
  49. using HasInvokeMock = typename detector<invoke_mock_t, void, URBG>::type;
  50. // Default implementation of distribution caller.
  51. template <typename DistrT, typename... Args>
  52. static typename DistrT::result_type Impl(std::false_type, URBG* urbg,
  53. Args&&... args) {
  54. DistrT dist(std::forward<Args>(args)...);
  55. return dist(*urbg);
  56. }
  57. // Mock implementation of distribution caller.
  58. // The underlying KeyT must match the KeyT constructed by MockOverloadSet.
  59. template <typename DistrT, typename... Args>
  60. static typename DistrT::result_type Impl(std::true_type, URBG* urbg,
  61. Args&&... args) {
  62. using ResultT = typename DistrT::result_type;
  63. using ArgTupleT = std::tuple<absl::decay_t<Args>...>;
  64. using KeyT = ResultT(DistrT, ArgTupleT);
  65. ArgTupleT arg_tuple(std::forward<Args>(args)...);
  66. ResultT result;
  67. if (!urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple,
  68. &result)) {
  69. auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
  70. result = dist(*urbg);
  71. }
  72. return result;
  73. }
  74. // Default implementation of distribution caller.
  75. template <typename DistrT, typename... Args>
  76. static typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
  77. return Impl<DistrT, Args...>(HasInvokeMock{}, urbg,
  78. std::forward<Args>(args)...);
  79. }
  80. };
  81. } // namespace random_internal
  82. ABSL_NAMESPACE_END
  83. } // namespace absl
  84. #endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_