summaryrefslogtreecommitdiff
path: root/absl/random/bit_gen_ref.h
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2020-06-03 14:03:13 -0700
committerGravatar Gennadiy Rozental <rogeeff@google.com>2020-06-03 18:19:47 -0400
commit1d31b5c365e975d3c8a8f90492c3d9de35ef024f (patch)
treefbc8093e8aad757b8790fb2688c0e4694e082fa4 /absl/random/bit_gen_ref.h
parentda3a87690c56f965705b6a233d25ba5a3294067c (diff)
Export of internal Abseil changes
-- 9e8b4a286d70df9487bff080816bd07ae38af5f8 by Evan Brown <ezb@google.com>: Add btree_node::transfer_n/transfer_n_backward and replace usage of uninitialized_move_n and value_destroy_n. PiperOrigin-RevId: 314600027 -- 6c452aa1ee7e46ab941ba7d1fa636da8ea3d7370 by Laramie Leavitt <lar@google.com>: Remove the MockingBitGenBase base class in favor of type-erasure in BitGenRef. In Abseil random, mocking was split across two different classes, MockingBitGenBase and MockingBitGen. This split existed because Google Mock is a test-only library that we don't link into production, so MockingBitGenBase provided a low-overhead scaffold used to lookup mocks when in test code, but which is unused in production code. That has been replaced by type-erasure which looks for a method named CallImpl with the correct signature. Weaken the coupling between MockingBitGen, DistributionCaller, and MockOverloadSet. Rename CallImpl to InvokeMock() Previously, the implementation of DistributionCaller was also split across different files using explicit instantiation of the DistributionCaller struct and some details in the Mocking classes. Now Distribution caller uses the presence of the InvokeMock() method to choose whether to use the mockable call path or the default call path. PiperOrigin-RevId: 314584095 -- 07853c47dc98698d67d65a3b9b662a65ab9def0a by Abseil Team <absl-team@google.com>: Add PC / backtrace / symbolization support for Apple platforms. Full backtrace support requires iOS 9+ PiperOrigin-RevId: 314415072 -- 43889f17a132b31f6558c6482721cbbc776128fd by Gennadiy Rozental <rogeeff@google.com>: Consolidate all reflection interface in the new module 'reflection' and expose interface to locate reflection handle by name. PiperOrigin-RevId: 314390358 GitOrigin-RevId: 9e8b4a286d70df9487bff080816bd07ae38af5f8 Change-Id: I8e0910437740cf9ea9da5000adddfcef127e1158
Diffstat (limited to 'absl/random/bit_gen_ref.h')
-rw-r--r--absl/random/bit_gen_ref.h105
1 files changed, 66 insertions, 39 deletions
diff --git a/absl/random/bit_gen_ref.h b/absl/random/bit_gen_ref.h
index 59591a47..00e36248 100644
--- a/absl/random/bit_gen_ref.h
+++ b/absl/random/bit_gen_ref.h
@@ -24,11 +24,11 @@
#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"
-#include "absl/random/internal/mocking_bit_gen_base.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -51,6 +51,9 @@ struct is_urbg<
typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>
: std::true_type {};
+template <typename>
+struct DistributionCaller;
+
} // namespace random_internal
// -----------------------------------------------------------------------------
@@ -77,23 +80,50 @@ struct is_urbg<
// }
//
class BitGenRef {
- public:
- using result_type = uint64_t;
+ // 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;
- BitGenRef(const absl::BitGenRef&) = default;
- BitGenRef(absl::BitGenRef&&) = default;
- BitGenRef& operator=(const absl::BitGenRef&) = default;
- BitGenRef& operator=(absl::BitGenRef&&) = default;
+ 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)>* = nullptr>
+ 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
- : mocked_gen_ptr_(MakeMockPointer(&gen)),
- t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
- generate_impl_fn_(ImplFn<URBG>) {
- }
+ : 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)();
@@ -106,14 +136,9 @@ class BitGenRef {
result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); }
private:
- friend struct absl::random_internal::DistributionCaller<absl::BitGenRef>;
using impl_fn = result_type (*)(uintptr_t);
- using mocker_base_t = absl::random_internal::MockingBitGenBase;
-
- // Convert an arbitrary URBG pointer into either a valid mocker_base_t
- // pointer or a nullptr.
- static inline mocker_base_t* MakeMockPointer(mocker_base_t* t) { return t; }
- static inline mocker_base_t* MakeMockPointer(void*) { return nullptr; }
+ using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,
+ void*);
template <typename URBG>
static result_type ImplFn(uintptr_t ptr) {
@@ -123,29 +148,31 @@ class BitGenRef {
return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));
}
- mocker_base_t* mocked_gen_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_;
-};
-
-namespace random_internal {
-template <>
-struct DistributionCaller<absl::BitGenRef> {
- template <typename DistrT, typename... Args>
- static typename DistrT::result_type Call(absl::BitGenRef* gen_ref,
- Args&&... args) {
- auto* mock_ptr = gen_ref->mocked_gen_ptr_;
- if (mock_ptr == nullptr) {
- DistrT dist(std::forward<Args>(args)...);
- return dist(*gen_ref);
- } else {
- return mock_ptr->template Call<DistrT>(std::forward<Args>(args)...);
- }
- }
+ template <typename>
+ friend struct ::absl::random_internal::DistributionCaller; // for InvokeMock
};
-} // namespace random_internal
ABSL_NAMESPACE_END
} // namespace absl