| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 | //// Copyright 2018 The Abseil Authors.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////      https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//// -----------------------------------------------------------------------------// File: bit_gen_ref.h// -----------------------------------------------------------------------------//// This header defines a bit generator "reference" class, for use in interfaces// that take both Abseil (e.g. `absl::BitGen`) and standard library (e.g.// `std::mt19937`) bit generators.#ifndef ABSL_RANDOM_BIT_GEN_REF_H_#define ABSL_RANDOM_BIT_GEN_REF_H_#include "absl/base/internal/fast_type_id.h"#include "absl/base/macros.h"#include "absl/meta/type_traits.h"#include "absl/random/internal/distribution_caller.h"#include "absl/random/internal/fast_uniform_bits.h"namespace absl {ABSL_NAMESPACE_BEGINnamespace random_internal {template <typename URBG, typename = void, typename = void, typename = void>struct is_urbg : std::false_type {};template <typename URBG>struct is_urbg<    URBG,    absl::enable_if_t<std::is_same<        typename URBG::result_type,        typename std::decay<decltype((URBG::min)())>::type>::value>,    absl::enable_if_t<std::is_same<        typename URBG::result_type,        typename std::decay<decltype((URBG::max)())>::type>::value>,    absl::enable_if_t<std::is_same<        typename URBG::result_type,        typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>    : std::true_type {};template <typename>struct DistributionCaller;}  // namespace random_internal// -----------------------------------------------------------------------------// absl::BitGenRef// -----------------------------------------------------------------------------//// `absl::BitGenRef` is a type-erasing class that provides a generator-agnostic// non-owning "reference" interface for use in place of any specific uniform// random bit generator (URBG). This class may be used for both Abseil// (e.g. `absl::BitGen`, `absl::InsecureBitGen`) and Standard library (e.g// `std::mt19937`, `std::minstd_rand`) bit generators.//// Like other reference classes, `absl::BitGenRef` does not own the// underlying bit generator, and the underlying instance must outlive the// `absl::BitGenRef`.//// `absl::BitGenRef` is particularly useful when used with an// `absl::MockingBitGen` to test specific paths in functions which use random// values.//// Example://    void TakesBitGenRef(absl::BitGenRef gen) {//      int x = absl::Uniform<int>(gen, 0, 1000);//    }//class BitGenRef {  // SFINAE to detect whether the URBG type includes a member matching  // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).  //  // These live inside BitGenRef so that they have friend access  // to MockingBitGen. (see similar methods in DistributionCaller).  template <template <class...> class Trait, class AlwaysVoid, class... Args>  struct detector : std::false_type {};  template <template <class...> class Trait, class... Args>  struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>      : std::true_type {};  template <class T>  using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(      std::declval<base_internal::FastTypeIdType>(), std::declval<void*>(),      std::declval<void*>()));  template <typename T>  using HasInvokeMock = typename detector<invoke_mock_t, void, T>::type; public:  BitGenRef(const BitGenRef&) = default;  BitGenRef(BitGenRef&&) = default;  BitGenRef& operator=(const BitGenRef&) = default;  BitGenRef& operator=(BitGenRef&&) = default;  template <typename URBG, typename absl::enable_if_t<                               (!std::is_same<URBG, BitGenRef>::value &&                                random_internal::is_urbg<URBG>::value &&                                !HasInvokeMock<URBG>::value)>* = nullptr>  BitGenRef(URBG& gen)  // NOLINT      : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),        mock_call_(NotAMock),        generate_impl_fn_(ImplFn<URBG>) {}  template <typename URBG,            typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&                                        random_internal::is_urbg<URBG>::value &&                                        HasInvokeMock<URBG>::value)>* = nullptr>  BitGenRef(URBG& gen)  // NOLINT      : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),        mock_call_(&MockCall<URBG>),        generate_impl_fn_(ImplFn<URBG>) {}  using result_type = uint64_t;  static constexpr result_type(min)() {    return (std::numeric_limits<result_type>::min)();  }  static constexpr result_type(max)() {    return (std::numeric_limits<result_type>::max)();  }  result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); } private:  using impl_fn = result_type (*)(uintptr_t);  using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,                                void*);  template <typename URBG>  static result_type ImplFn(uintptr_t ptr) {    // Ensure that the return values from operator() fill the entire    // range promised by result_type, min() and max().    absl::random_internal::FastUniformBits<result_type> fast_uniform_bits;    return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));  }  // Get a type-erased InvokeMock pointer.  template <typename URBG>  static bool MockCall(uintptr_t gen_ptr, base_internal::FastTypeIdType type,                       void* result, void* arg_tuple) {    return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(type, result,                                                        arg_tuple);  }  static bool NotAMock(uintptr_t, base_internal::FastTypeIdType, void*, void*) {    return false;  }  inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,                         void* result) {    if (mock_call_ == NotAMock) return false;  // avoids an indirect call.    return mock_call_(t_erased_gen_ptr_, type, args_tuple, result);  }  uintptr_t t_erased_gen_ptr_;  mock_call_fn mock_call_;  impl_fn generate_impl_fn_;  template <typename>  friend struct ::absl::random_internal::DistributionCaller;  // for InvokeMock};ABSL_NAMESPACE_END}  // namespace absl#endif  // ABSL_RANDOM_BIT_GEN_REF_H_
 |