123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- //
- // 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 <limits>
- #include <type_traits>
- #include <utility>
- #include "absl/base/attributes.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_BEGIN
- namespace 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;
- class MockHelpers;
- } // 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 URBGRef, typename URBG = absl::remove_cvref_t<URBGRef>,
- typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
- random_internal::is_urbg<URBG>::value &&
- !HasInvokeMock<URBG>::value)>* = nullptr>
- BitGenRef(URBGRef&& gen ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT
- : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
- mock_call_(NotAMock),
- generate_impl_fn_(ImplFn<URBG>) {}
- template <typename URBGRef, typename URBG = absl::remove_cvref_t<URBGRef>,
- typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
- random_internal::is_urbg<URBG>::value &&
- HasInvokeMock<URBG>::value)>* = nullptr>
- BitGenRef(URBGRef&& gen ABSL_ATTRIBUTE_LIFETIME_BOUND) // 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
- friend class ::absl::random_internal::MockHelpers; // for InvokeMock
- };
- ABSL_NAMESPACE_END
- } // namespace absl
- #endif // ABSL_RANDOM_BIT_GEN_REF_H_
|