Reduce number of template instantiations

Combine result_type, function_arity, parameter_types into 1 trait.
This reduces the amount of template classes instantiated by a factor of 3 which should improve compile times and memory consumption.

Also improve tests and documentation of touched classes/traits.
This commit is contained in:
Alexander Grund 2022-01-26 14:15:06 +01:00
parent 0c20ca1ce9
commit b802c51c2d
No known key found for this signature in database
GPG key ID: AA48A0760367A42B
5 changed files with 157 additions and 103 deletions

View file

@ -11,17 +11,26 @@
#include "function.hpp"
#include "functor.hpp"
#include "parameter.hpp"
#include "signature.hpp"
#include "signature_traits.hpp"
#include "type_name.hpp"
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <type_traits>
namespace mock { namespace detail {
/// Used in MOCK_PROTECT_SIGNATURE to unwrap the passed function signature
/// Simplified trait to extract the argument type of a function signature with 1 argument
template<typename T>
using unwrap_signature_t = std::remove_pointer_t<parameter_type_t<T>>;
struct arg_type;
template<typename T, typename U>
struct arg_type<T(U)>
{
using type = U;
};
/// Used in MOCK_PROTECT_SIGNATURE to unwrap the passed function signature
/// T is something like `void(std::map<int, float>)`
template<typename T>
using unwrap_signature_t = std::remove_pointer_t<typename arg_type<T>::type>;
}} // namespace mock::detail
#define MOCK_HELPER(t) t##_mock(mock::detail::root, BOOST_PP_STRINGIZE(t))
@ -47,8 +56,8 @@ namespace mock { namespace detail {
#define MOCK_FORWARD_PARAM(z, n, d) BOOST_PP_COMMA_IF(n) d, n >> (p##n)
#define MOCK_FORWARD_PARAMS(n, S) BOOST_PP_REPEAT(n, MOCK_FORWARD_PARAM, std::forward < MOCK_PARAM(S))
#define MOCK_METHOD_AUX(M, n, S, t, c) \
static_assert(n == mock::detail::function_arity<S>::value, "Arity mismatch"); \
#define MOCK_METHOD_AUX(M, n, S, t, c) \
static_assert(n == mock::detail::function_arity_t<S>::value, "Arity mismatch"); \
MOCK_DECL(M, n, S, c) { return MOCK_ANONYMOUS_HELPER(t)(MOCK_FORWARD_PARAMS(n, S)); }
#define MOCK_METHOD_EXT(M, n, S, t) \
@ -73,13 +82,10 @@ namespace mock { namespace detail {
T(MOCK_DECL_PARAMS(n, void A)) { MOCK_HELPER(t)(MOCK_FORWARD_PARAMS(n, void A)); } \
MOCK_FUNCTION_HELPER(void A, t, static)
#define MOCK_FUNCTION_AUX(F, n, S, t, s) \
MOCK_FUNCTION_HELPER(S, t, s) \
s MOCK_DECL(F, n, S, ) \
{ \
static_assert(n == mock::detail::function_arity<S>::value, "Arity mismatch"); \
return MOCK_HELPER(t)(MOCK_FORWARD_PARAMS(n, S)); \
}
#define MOCK_FUNCTION_AUX(F, n, S, t, s) \
MOCK_FUNCTION_HELPER(S, t, s) \
static_assert(n == mock::detail::function_arity_t<S>::value, "Arity mismatch"); \
s MOCK_DECL(F, n, S, ) { return MOCK_HELPER(t)(MOCK_FORWARD_PARAMS(n, S)); }
#define MOCK_VARIADIC_ELEM_0(e0, ...) e0
#define MOCK_VARIADIC_ELEM_1(e0, e1, ...) e1

View file

@ -1,82 +0,0 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_PARAMETER_HPP_INCLUDED
#define MOCK_PARAMETER_HPP_INCLUDED
#include "../config.hpp"
namespace mock { namespace detail {
template<class...>
struct tuple;
template<std::size_t I, class T>
struct tuple_element;
template<std::size_t I, class H, class... T>
struct tuple_element<I, tuple<H, T...>> : tuple_element<I - 1, tuple<T...>>
{};
template<class H, class... T>
struct tuple_element<0, tuple<H, T...>>
{
using type = H;
};
template<typename Signature>
struct result_type;
template<typename R, typename... Args>
struct result_type<R(Args...)>
{
using type = R;
};
template<typename Signature>
using result_type_t = typename result_type<Signature>::type;
template<typename Signature>
struct function_arity;
template<typename R, typename... Args>
struct function_arity<R(Args...)>
{
static constexpr size_t value = sizeof...(Args);
};
template<typename Signature>
struct parameter_types;
template<typename R, typename... Args>
struct parameter_types<R(Args...)>
{
using type = tuple<Args...>;
};
template<typename Signature, std::size_t n>
struct parameter
{
// This assertion is usually triggered when the arity passed to e.g. MOCK_METHOD exceeds the number of
// parameters of the mocked function or the passed function signature
static_assert(n < function_arity<Signature>::value, "Parameter index exceeds the number of parameters");
using type = typename tuple_element<n, typename parameter_types<Signature>::type>::type;
};
template<typename T, std::size_t n>
using parameter_t = typename parameter<T, n>::type;
template<typename T>
struct parameter_type;
template<typename T, typename U>
struct parameter_type<T(U)>
{
using type = U;
};
template<typename T>
using parameter_type_t = typename parameter_type<T>::type;
}} // namespace mock::detail
#endif // MOCK_PARAMETER_HPP_INCLUDED

View file

@ -54,19 +54,21 @@ namespace mock { namespace detail {
struct signature<Sig(C::*)> : signature<typename strip_function_qualifiers<Sig>::type>
{};
/// Return the (non-member) function signature out of (any) signature
template<typename M>
using signature_t = typename signature<std::remove_cv_t<std::remove_reference_t<M>>>::type;
using signature_t = typename signature<M>::type;
/// CRTP class to define the base_type typedef
template<typename T>
struct base
{
typedef T base_type;
using base_type = T;
};
// if an error is generated by the line below it means the method is ambiguous:
// specify its signature to disambiguate
// If an error is generated by the line below it means the method is ambiguous.
// Specify its signature to disambiguate
template<typename T>
T& ambiguous_method_requires_to_specify_signature(const T&);
T ambiguous_method_requires_to_specify_signature(const T&);
}} // namespace mock::detail
#define MOCK_SIGNATURE(M) \

View file

@ -0,0 +1,62 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_PARAMETER_HPP_INCLUDED
#define MOCK_PARAMETER_HPP_INCLUDED
#include "../config.hpp"
#include <cstddef>
namespace mock { namespace detail {
/// Helper class to store a tuple/list of types
template<class...>
struct tuple;
/// Get the type at the given index in the tuple
template<std::size_t index, class Tuple>
struct tuple_element;
template<std::size_t I, class H, class... T>
struct tuple_element<I, tuple<H, T...>> : tuple_element<I - 1, tuple<T...>>
{};
template<class H, class... T>
struct tuple_element<0, tuple<H, T...>>
{
using type = H;
};
/// Provides information about a given function signature
/// Member types: return_type, args
/// Member constant: arity
template<typename Signature>
struct signature_traits;
template<typename R, typename... Args>
struct signature_traits<R(Args...)>
{
using return_type = R;
static constexpr std::size_t arity = sizeof...(Args);
using args = tuple<Args...>;
};
/// Return the result type of the function signature
template<typename Signature>
using result_type_t = typename signature_traits<Signature>::return_type;
/// Return the arity of the function signature
template<typename Signature>
using function_arity_t = std::integral_constant<std::size_t, signature_traits<Signature>::arity>;
/// Return the type at the given index of the function signature
template<typename Signature, std::size_t idx>
using parameter_t = typename tuple_element<idx, typename signature_traits<Signature>::args>::type;
}} // namespace mock::detail
#endif // MOCK_PARAMETER_HPP_INCLUDED