mirror of
https://github.com/mat007/turtle.git
synced 2026-06-22 12:13:43 +00:00
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:
parent
0c20ca1ce9
commit
b802c51c2d
5 changed files with 157 additions and 103 deletions
|
|
@ -11,17 +11,26 @@
|
||||||
|
|
||||||
#include "function.hpp"
|
#include "function.hpp"
|
||||||
#include "functor.hpp"
|
#include "functor.hpp"
|
||||||
#include "parameter.hpp"
|
|
||||||
#include "signature.hpp"
|
#include "signature.hpp"
|
||||||
|
#include "signature_traits.hpp"
|
||||||
#include "type_name.hpp"
|
#include "type_name.hpp"
|
||||||
#include <boost/preprocessor/repetition/repeat.hpp>
|
#include <boost/preprocessor/repetition/repeat.hpp>
|
||||||
#include <boost/preprocessor/stringize.hpp>
|
#include <boost/preprocessor/stringize.hpp>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace mock { namespace detail {
|
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>
|
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
|
}} // namespace mock::detail
|
||||||
|
|
||||||
#define MOCK_HELPER(t) t##_mock(mock::detail::root, BOOST_PP_STRINGIZE(t))
|
#define MOCK_HELPER(t) t##_mock(mock::detail::root, BOOST_PP_STRINGIZE(t))
|
||||||
|
|
@ -48,7 +57,7 @@ namespace mock { namespace detail {
|
||||||
#define MOCK_FORWARD_PARAM(z, n, d) BOOST_PP_COMMA_IF(n) d, n >> (p##n)
|
#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_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) \
|
#define MOCK_METHOD_AUX(M, n, S, t, c) \
|
||||||
static_assert(n == mock::detail::function_arity<S>::value, "Arity mismatch"); \
|
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)); }
|
MOCK_DECL(M, n, S, c) { return MOCK_ANONYMOUS_HELPER(t)(MOCK_FORWARD_PARAMS(n, S)); }
|
||||||
|
|
||||||
#define MOCK_METHOD_EXT(M, n, S, t) \
|
#define MOCK_METHOD_EXT(M, n, S, t) \
|
||||||
|
|
@ -75,11 +84,8 @@ namespace mock { namespace detail {
|
||||||
|
|
||||||
#define MOCK_FUNCTION_AUX(F, n, S, t, s) \
|
#define MOCK_FUNCTION_AUX(F, n, S, t, s) \
|
||||||
MOCK_FUNCTION_HELPER(S, t, s) \
|
MOCK_FUNCTION_HELPER(S, t, s) \
|
||||||
s MOCK_DECL(F, n, 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)); }
|
||||||
static_assert(n == mock::detail::function_arity<S>::value, "Arity mismatch"); \
|
|
||||||
return MOCK_HELPER(t)(MOCK_FORWARD_PARAMS(n, S)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MOCK_VARIADIC_ELEM_0(e0, ...) e0
|
#define MOCK_VARIADIC_ELEM_0(e0, ...) e0
|
||||||
#define MOCK_VARIADIC_ELEM_1(e0, e1, ...) e1
|
#define MOCK_VARIADIC_ELEM_1(e0, e1, ...) e1
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -54,19 +54,21 @@ namespace mock { namespace detail {
|
||||||
struct signature<Sig(C::*)> : signature<typename strip_function_qualifiers<Sig>::type>
|
struct signature<Sig(C::*)> : signature<typename strip_function_qualifiers<Sig>::type>
|
||||||
{};
|
{};
|
||||||
|
|
||||||
|
/// Return the (non-member) function signature out of (any) signature
|
||||||
template<typename M>
|
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>
|
template<typename T>
|
||||||
struct base
|
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:
|
// If an error is generated by the line below it means the method is ambiguous.
|
||||||
// specify its signature to disambiguate
|
// Specify its signature to disambiguate
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T& ambiguous_method_requires_to_specify_signature(const T&);
|
T ambiguous_method_requires_to_specify_signature(const T&);
|
||||||
}} // namespace mock::detail
|
}} // namespace mock::detail
|
||||||
|
|
||||||
#define MOCK_SIGNATURE(M) \
|
#define MOCK_SIGNATURE(M) \
|
||||||
|
|
|
||||||
62
include/turtle/detail/signature_traits.hpp
Normal file
62
include/turtle/detail/signature_traits.hpp
Normal 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
|
||||||
|
|
@ -6,21 +6,87 @@
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#include <turtle/detail/signature.hpp>
|
#include <turtle/mock.hpp>
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <map>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct base
|
struct base
|
||||||
{
|
{
|
||||||
void method_1();
|
void method_1();
|
||||||
float method_2(int) const;
|
float method_2(int);
|
||||||
|
// Using templates in result and argument types
|
||||||
|
std::map<int, float> method_3(std::map<int, int>, short);
|
||||||
|
|
||||||
|
// Qualified methods
|
||||||
|
float qual_1(int) &;
|
||||||
|
float qual_2(int) &&;
|
||||||
|
float qual_3(int) const;
|
||||||
|
float qual_4(int) const&;
|
||||||
|
float qual_5(int) const&&;
|
||||||
|
float qual_6(int) volatile;
|
||||||
|
float qual_7(int) volatile&;
|
||||||
|
float qual_8(int) volatile&&;
|
||||||
|
float qual_9(int) const volatile;
|
||||||
|
float qual_10(int) const volatile&;
|
||||||
|
float qual_11(int) const volatile&&;
|
||||||
};
|
};
|
||||||
typedef base base_type;
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(mock_signature_generates_signature)
|
BOOST_AUTO_TEST_CASE(signature_traits_return_correct_values)
|
||||||
{
|
{
|
||||||
|
using function1 = void();
|
||||||
|
static_assert(std::is_same<mock::detail::result_type_t<function1>, void>::value, "!");
|
||||||
|
static_assert(mock::detail::function_arity_t<function1>::value == 0, "!");
|
||||||
|
|
||||||
|
using function2 = float(int);
|
||||||
|
static_assert(std::is_same<mock::detail::result_type_t<function2>, float>::value, "!");
|
||||||
|
static_assert(mock::detail::function_arity_t<function2>::value == 1, "!");
|
||||||
|
static_assert(std::is_same<mock::detail::parameter_t<function2, 0>, int>::value, "!");
|
||||||
|
|
||||||
|
using function3 = unsigned(short&, int, const char*, float, double, char, unsigned char, std::map<int, char>);
|
||||||
|
static_assert(std::is_same<mock::detail::result_type_t<function3>, unsigned>::value, "!");
|
||||||
|
static_assert(mock::detail::function_arity_t<function3>::value == 8, "!");
|
||||||
|
static_assert(std::is_same<mock::detail::parameter_t<function3, 0>, short&>::value, "!");
|
||||||
|
static_assert(std::is_same<mock::detail::parameter_t<function3, 1>, int>::value, "!");
|
||||||
|
static_assert(std::is_same<mock::detail::parameter_t<function3, 2>, const char*>::value, "!");
|
||||||
|
static_assert(std::is_same<mock::detail::parameter_t<function3, 3>, float>::value, "!");
|
||||||
|
static_assert(std::is_same<mock::detail::parameter_t<function3, 4>, double>::value, "!");
|
||||||
|
static_assert(std::is_same<mock::detail::parameter_t<function3, 5>, char>::value, "!");
|
||||||
|
static_assert(std::is_same<mock::detail::parameter_t<function3, 6>, unsigned char>::value, "!");
|
||||||
|
static_assert(std::is_same<mock::detail::parameter_t<function3, 7>, std::map<int, char>>::value, "!");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(MOCK_SIGNATURE_generates_signature)
|
||||||
|
{
|
||||||
|
using base_type = base; // MOCK_SIGNATURE requires a visible base_type typedef in the current scope
|
||||||
static_assert(std::is_same<void(), MOCK_SIGNATURE(method_1)>::value, "!");
|
static_assert(std::is_same<void(), MOCK_SIGNATURE(method_1)>::value, "!");
|
||||||
static_assert(std::is_same<float(int), MOCK_SIGNATURE(method_2)>::value, "!");
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(method_2)>::value, "!");
|
||||||
|
static_assert(std::is_same<std::map<int, float>(std::map<int, int>, short), MOCK_SIGNATURE(method_3)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_1)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_2)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_3)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_4)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_5)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_6)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_7)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_8)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_9)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_10)>::value, "!");
|
||||||
|
static_assert(std::is_same<float(int), MOCK_SIGNATURE(qual_11)>::value, "!");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(MOCK_PROTECT_SIGNATURE_keeps_signature)
|
||||||
|
{
|
||||||
|
// MOCK_PROTECT_SIGNATURE is basically a no-op regarding its argument
|
||||||
|
// and only required to get it through a VAR_ARGS macro
|
||||||
|
// clang-format off
|
||||||
|
static_assert(std::is_same<void(), MOCK_PROTECT_SIGNATURE(
|
||||||
|
void())>::value, "!");
|
||||||
|
static_assert(std::is_same<float*(int*), MOCK_PROTECT_SIGNATURE(
|
||||||
|
float*(int*))>::value, "!");
|
||||||
|
static_assert(std::is_same<std::map<int, float>(std::map<int, int>, short), MOCK_PROTECT_SIGNATURE(
|
||||||
|
std::map<int, float>(std::map<int, int>, short))>::value, "!");
|
||||||
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue