-- e21e960918678629abf89ad1b694b7d4a456b434 by Greg Falcon <gfalcon@google.com>: Roll back invoke() change due to large increases in compiler memory usage. PiperOrigin-RevId: 315919455 -- f95872e1e1d7afdefbac94f42ea228d42d80eb6e by Greg Falcon <gfalcon@google.com>: Rollback of invoke() changes due to compiler memory usage growth PiperOrigin-RevId: 315911585 -- 6c6c6ba6892016a2ce4703042800254fb9b15727 by Laramie Leavitt <lar@google.com>: Move some of the common mocking code into MockHelpers. Use MockHelpers to do mock signature detection and improve the dispatch mechansim. PiperOrigin-RevId: 315825988 -- 5e9380367d280c7fa6dbd4d0f48c31ade7f1d419 by Greg Falcon <gfalcon@google.com>: Rename the internal implementation details Invoke and InvokeT to `invoke` and `invoke_result_t`, since these are re-implementations of C++17 library entites of the same names. PiperOrigin-RevId: 315790467 GitOrigin-RevId: e21e960918678629abf89ad1b694b7d4a456b434 Change-Id: Ia75011f94cb033c1c9a4cb64cf14d283b91426acpull/714/head
parent
e7ebf98037
commit
2c92bdc7c2
11 changed files with 212 additions and 184 deletions
@ -0,0 +1,127 @@ |
||||
//
|
||||
// Copyright 2019 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.
|
||||
|
||||
#ifndef ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ |
||||
#define ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ |
||||
|
||||
#include <tuple> |
||||
#include <type_traits> |
||||
|
||||
#include "absl/base/internal/fast_type_id.h" |
||||
#include "absl/types/optional.h" |
||||
|
||||
namespace absl { |
||||
ABSL_NAMESPACE_BEGIN |
||||
namespace random_internal { |
||||
|
||||
// MockHelpers works in conjunction with MockOverloadSet, MockingBitGen, and
|
||||
// BitGenRef to enable the mocking capability for absl distribution functions.
|
||||
//
|
||||
// MockingBitGen registers mocks based on the typeid of a mock signature, KeyT,
|
||||
// which is used to generate a unique id.
|
||||
//
|
||||
// KeyT is a signature of the form:
|
||||
// result_type(discriminator_type, std::tuple<args...>)
|
||||
// The mocked function signature will be composed from KeyT as:
|
||||
// result_type(args...)
|
||||
//
|
||||
class MockHelpers { |
||||
using IdType = ::absl::base_internal::FastTypeIdType; |
||||
|
||||
// Given a key signature type used to index the mock, extract the components.
|
||||
// KeyT is expected to have the form:
|
||||
// result_type(discriminator_type, arg_tuple_type)
|
||||
template <typename KeyT> |
||||
struct KeySignature; |
||||
|
||||
template <typename ResultT, typename DiscriminatorT, typename ArgTupleT> |
||||
struct KeySignature<ResultT(DiscriminatorT, ArgTupleT)> { |
||||
using result_type = ResultT; |
||||
using discriminator_type = DiscriminatorT; |
||||
using arg_tuple_type = ArgTupleT; |
||||
}; |
||||
|
||||
// Detector for InvokeMock.
|
||||
template <class T> |
||||
using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock( |
||||
std::declval<IdType>(), std::declval<void*>(), std::declval<void*>())); |
||||
|
||||
// Empty implementation of InvokeMock.
|
||||
template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, |
||||
typename... Args> |
||||
static absl::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) { |
||||
return absl::nullopt; |
||||
} |
||||
|
||||
// Non-empty implementation of InvokeMock.
|
||||
template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, |
||||
typename = invoke_mock_t<URBG>, typename... Args> |
||||
static absl::optional<ReturnT> InvokeMockImpl(int, URBG* urbg, |
||||
Args&&... args) { |
||||
ArgTupleT arg_tuple(std::forward<Args>(args)...); |
||||
ReturnT result; |
||||
if (urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple, |
||||
&result)) { |
||||
return result; |
||||
} |
||||
return absl::nullopt; |
||||
} |
||||
|
||||
public: |
||||
// Invoke a mock for the KeyT (may or may not be a signature).
|
||||
//
|
||||
// KeyT is used to generate a typeid-based lookup key for the mock.
|
||||
// KeyT is a signature of the form:
|
||||
// result_type(discriminator_type, std::tuple<args...>)
|
||||
// The mocked function signature will be composed from KeyT as:
|
||||
// result_type(args...)
|
||||
//
|
||||
// An instance of arg_tuple_type must be constructable from Args..., since
|
||||
// the underlying mechanism requires a pointer to an argument tuple.
|
||||
template <typename KeyT, typename URBG, typename... Args> |
||||
static auto MaybeInvokeMock(URBG* urbg, Args&&... args) |
||||
-> absl::optional<typename KeySignature<KeyT>::result_type> { |
||||
// Use function overloading to dispatch to the implemenation since
|
||||
// more modern patterns (e.g. require + constexpr) are not supported in all
|
||||
// compiler configurations.
|
||||
return InvokeMockImpl<KeyT, typename KeySignature<KeyT>::result_type, |
||||
typename KeySignature<KeyT>::arg_tuple_type, URBG>( |
||||
0, urbg, std::forward<Args>(args)...); |
||||
} |
||||
|
||||
// Acquire a mock for the KeyT (may or may not be a signature).
|
||||
//
|
||||
// KeyT is used to generate a typeid-based lookup for the mock.
|
||||
// KeyT is a signature of the form:
|
||||
// result_type(discriminator_type, std::tuple<args...>)
|
||||
// The mocked function signature will be composed from KeyT as:
|
||||
// result_type(args...)
|
||||
template <typename KeyT, typename MockURBG> |
||||
static auto MockFor(MockURBG& m) -> decltype( |
||||
std::declval<MockURBG>() |
||||
.template RegisterMock<typename KeySignature<KeyT>::result_type, |
||||
typename KeySignature<KeyT>::arg_tuple_type>( |
||||
std::declval<IdType>())) { |
||||
return m.template RegisterMock<typename KeySignature<KeyT>::result_type, |
||||
typename KeySignature<KeyT>::arg_tuple_type>( |
||||
::absl::base_internal::FastTypeId<KeyT>()); |
||||
} |
||||
}; |
||||
|
||||
} // namespace random_internal
|
||||
ABSL_NAMESPACE_END |
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_
|
Loading…
Reference in new issue