Checking more __invoke tests.

Before I start trying to fix __invoke in C++03 it needs better test coverage.
This patch adds a large amount of tests for __invoke.


git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@243366 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier 2015-07-28 01:25:36 +00:00
parent 568bd0222f
commit 48aa2cf9f3
4 changed files with 1126 additions and 0 deletions

View File

@ -0,0 +1,318 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// <functional>
// INVOKE (f, t1, t2, ..., tN)
//------------------------------------------------------------------------------
// TESTING INVOKE(f, t1, t2, ..., tN)
// - Bullet 1 -- (t1.*f)(t2, ..., tN)
// - Bullet 2 -- ((*t1).*f)(t2, ..., tN)
//
// Overview:
// Bullets 1 and 2 handle the case where 'f' is a pointer to member function.
// Bullet 1 only handles the cases where t1 is an object of type T or a
// type derived from 'T'. Bullet 2 handles all other cases.
//
// Concerns:
// 1) cv-qualified member function signatures are accepted.
// 2) reference qualified member function signatures are accepted.
// 3) member functions with varargs at the end are accepted.
// 4) The arguments are perfect forwarded to the member function call.
// 5) Classes that are publicly derived from 'T' are accepted as the call object
// 6) All types that dereference to T or a type derived from T can be used
// as the call object.
// 7) Pointers to T or a type derived from T can be used as the call object.
// 8) Reference return types are properly deduced.
//
//
// Plan:
// 1) Create a class that contains a set, 'S', of non-static functions.
// 'S' should include functions that cover every single combination
// of qualifiers and varargs for arities of 0, 1 and 2 (C-1,2,3).
// The argument types used in the functions should be non-copyable (C-4).
// The functions should return 'MethodID::setUncheckedCall()'.
//
// 2) Create a set of supported call object, 'Objs', of different types
// and behaviors. (C-5,6,7)
//
// 3) Attempt to call each function, 'f', in 'S' with each call object, 'c',
// in 'Objs'. After every attempted call to 'f' check that 'f' was
// actually called using 'MethodID::checkCalled(<return-value>)'
//
// 3b) If 'f' is reference qualified call 'f' with the properly qualified
// call object. Otherwise call 'f' with lvalue call objects.
//
// 3a) If 'f' is const, volatile, or cv qualified then call it with call
// objects that are equally or less cv-qualified.
#include <functional>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "invoke_helpers.h"
//==============================================================================
// MemFun03 - C++03 compatible set of test member functions.
struct MemFun03 {
typedef void*& R;
#define F(...) \
R f(__VA_ARGS__) { return MethodID<R(MemFun03::*)(__VA_ARGS__)>::setUncheckedCall(); } \
R f(__VA_ARGS__) const { return MethodID<R(MemFun03::*)(__VA_ARGS__) const>::setUncheckedCall(); } \
R f(__VA_ARGS__) volatile { return MethodID<R(MemFun03::*)(__VA_ARGS__) volatile>::setUncheckedCall(); } \
R f(__VA_ARGS__) const volatile { return MethodID<R(MemFun03::*)(__VA_ARGS__) const volatile>::setUncheckedCall(); }
#
F()
F(...)
F(ArgType&)
F(ArgType&, ...)
F(ArgType&, ArgType&)
F(ArgType&, ArgType&, ...)
F(ArgType&, ArgType&, ArgType&)
F(ArgType&, ArgType&, ArgType&, ...)
#undef F
public:
MemFun03() {}
private:
MemFun03(MemFun03 const&);
MemFun03& operator=(MemFun03 const&);
};
#if TEST_STD_VER >= 11
//==============================================================================
// MemFun11 - C++11 reference qualified test member functions.
struct MemFun11 {
typedef void*& R;
typedef MemFun11 C;
#define F(...) \
R f(__VA_ARGS__) & { return MethodID<R(C::*)(__VA_ARGS__) &>::setUncheckedCall(); } \
R f(__VA_ARGS__) const & { return MethodID<R(C::*)(__VA_ARGS__) const &>::setUncheckedCall(); } \
R f(__VA_ARGS__) volatile & { return MethodID<R(C::*)(__VA_ARGS__) volatile &>::setUncheckedCall(); } \
R f(__VA_ARGS__) const volatile & { return MethodID<R(C::*)(__VA_ARGS__) const volatile &>::setUncheckedCall(); } \
R f(__VA_ARGS__) && { return MethodID<R(C::*)(__VA_ARGS__) &&>::setUncheckedCall(); } \
R f(__VA_ARGS__) const && { return MethodID<R(C::*)(__VA_ARGS__) const &&>::setUncheckedCall(); } \
R f(__VA_ARGS__) volatile && { return MethodID<R(C::*)(__VA_ARGS__) volatile &&>::setUncheckedCall(); } \
R f(__VA_ARGS__) const volatile && { return MethodID<R(C::*)(__VA_ARGS__) const volatile &&>::setUncheckedCall(); }
#
F()
F(...)
F(ArgType&&)
F(ArgType&&, ...)
F(ArgType&&, ArgType&&)
F(ArgType&&, ArgType&&, ...)
F(ArgType&&, ArgType&&, ArgType&&)
F(ArgType&&, ArgType&&, ArgType&&, ...)
#undef F
public:
MemFun11() {}
private:
MemFun11(MemFun11 const&);
MemFun11& operator=(MemFun11 const&);
};
#endif // TEST_STD_VER >= 11
//==============================================================================
// TestCase - A test case for a single member function.
// ClassType - The type of the class being tested.
// CallSig - The function signature of the method being tested.
// Arity - the arity of 'CallSig'
// CV - the cv qualifiers of 'CallSig' represented as a type tag.
// RValue - The method is RValue qualified.
// ArgRValue - Call the method with RValue arguments.
template <class ClassType, class CallSig, int Arity, class CV,
bool RValue = false, bool ArgRValue = false>
struct TestCaseImp {
public:
static void run() { TestCaseImp().doTest(); }
private:
//==========================================================================
// TEST DISPATCH
void doTest() {
// (Plan-2) Create test call objects.
typedef ClassType T;
typedef DerivedFromType<T> D;
T obj;
T* obj_ptr = &obj;
D der;
D* der_ptr = &der;
DerefToType<T> dref;
DerefPropType<T> dref2;
// (Plan-3) Dispatch based on the CV tags.
CV tag;
Bool<!RValue> NotRValue;
runTestDispatch(tag, obj);
runTestDispatch(tag, der);
runTestDispatch(tag, dref2);
runTestDispatchIf(NotRValue, tag, dref);
runTestDispatchIf(NotRValue, tag, obj_ptr);
runTestDispatchIf(NotRValue, tag, der_ptr);
}
template <class QT, class Tp>
void runTestDispatchIf(Bool<true>, QT q, Tp& v) {
runTestDispatch(q, v);
}
template <class QT, class Tp>
void runTestDispatchIf(Bool<false>, QT, Tp&) {
}
template <class Tp>
void runTestDispatch(Q_None, Tp& v) {
runTest(v);
}
template <class Tp>
void runTestDispatch(Q_Const, Tp& v) {
Tp const& cv = v;
runTest(v);
runTest(cv);
}
template <class Tp>
void runTestDispatch(Q_Volatile, Tp& v) {
Tp volatile& vv = v;
runTest(v);
runTest(vv);
}
template <class Tp>
void runTestDispatch(Q_CV, Tp& v) {
Tp const& cv = v;
Tp volatile& vv = v;
Tp const volatile& cvv = v;
runTest(v);
runTest(cv);
runTest(vv);
runTest(cvv);
}
template <class Obj>
void runTest(Obj& obj) {
typedef Caster<Q_None, RValue> SCast;
typedef Caster<Q_None, ArgRValue> ACast;
typedef CallSig (ClassType::*MemPtr);
// Delegate test to logic in invoke_helpers.h
BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b;
b.runTest( (MemPtr)&ClassType::f, obj);
}
};
template <class Sig, int Arity, class CV>
struct TestCase : public TestCaseImp<MemFun03, Sig, Arity, CV> {};
#if TEST_STD_VER >= 11
template <class Sig, int Arity, class CV, bool RValue = false>
struct TestCase11 : public TestCaseImp<MemFun11, Sig, Arity, CV, RValue, true> {};
#endif
int main() {
typedef void*& R;
typedef ArgType A;
TestCase<R(), 0, Q_None>::run();
TestCase<R() const, 0, Q_Const>::run();
TestCase<R() volatile, 0, Q_Volatile>::run();
TestCase<R() const volatile, 0, Q_CV>::run();
TestCase<R(...), 0, Q_None>::run();
TestCase<R(...) const, 0, Q_Const>::run();
TestCase<R(...) volatile, 0, Q_Volatile>::run();
TestCase<R(...) const volatile, 0, Q_CV>::run();
TestCase<R(A&), 1, Q_None>::run();
TestCase<R(A&) const, 1, Q_Const>::run();
TestCase<R(A&) volatile, 1, Q_Volatile>::run();
TestCase<R(A&) const volatile, 1, Q_CV>::run();
TestCase<R(A&, ...), 1, Q_None>::run();
TestCase<R(A&, ...) const, 1, Q_Const>::run();
TestCase<R(A&, ...) volatile, 1, Q_Volatile>::run();
TestCase<R(A&, ...) const volatile, 1, Q_CV>::run();
TestCase<R(A&, A&), 2, Q_None>::run();
TestCase<R(A&, A&) const, 2, Q_Const>::run();
TestCase<R(A&, A&) volatile, 2, Q_Volatile>::run();
TestCase<R(A&, A&) const volatile, 2, Q_CV>::run();
TestCase<R(A&, A&, ...), 2, Q_None>::run();
TestCase<R(A&, A&, ...) const, 2, Q_Const>::run();
TestCase<R(A&, A&, ...) volatile, 2, Q_Volatile>::run();
TestCase<R(A&, A&, ...) const volatile, 2, Q_CV>::run();
TestCase<R(A&, A&, A&), 3, Q_None>::run();
TestCase<R(A&, A&, A&) const, 3, Q_Const>::run();
TestCase<R(A&, A&, A&) volatile, 3, Q_Volatile>::run();
TestCase<R(A&, A&, A&) const volatile, 3, Q_CV>::run();
TestCase<R(A&, A&, A&, ...), 3, Q_None>::run();
TestCase<R(A&, A&, A&, ...) const, 3, Q_Const>::run();
TestCase<R(A&, A&, A&, ...) volatile, 3, Q_Volatile>::run();
TestCase<R(A&, A&, A&, ...) const volatile, 3, Q_CV>::run();
#if TEST_STD_VER >= 11
TestCase11<R() &, 0, Q_None>::run();
TestCase11<R() const &, 0, Q_Const>::run();
TestCase11<R() volatile &, 0, Q_Volatile>::run();
TestCase11<R() const volatile &, 0, Q_CV>::run();
TestCase11<R(...) &, 0, Q_None>::run();
TestCase11<R(...) const &, 0, Q_Const>::run();
TestCase11<R(...) volatile &, 0, Q_Volatile>::run();
TestCase11<R(...) const volatile &, 0, Q_CV>::run();
TestCase11<R(A&&) &, 1, Q_None>::run();
TestCase11<R(A&&) const &, 1, Q_Const>::run();
TestCase11<R(A&&) volatile &, 1, Q_Volatile>::run();
TestCase11<R(A&&) const volatile &, 1, Q_CV>::run();
TestCase11<R(A&&, ...) &, 1, Q_None>::run();
TestCase11<R(A&&, ...) const &, 1, Q_Const>::run();
TestCase11<R(A&&, ...) volatile &, 1, Q_Volatile>::run();
TestCase11<R(A&&, ...) const volatile &, 1, Q_CV>::run();
TestCase11<R(A&&, A&&) &, 2, Q_None>::run();
TestCase11<R(A&&, A&&) const &, 2, Q_Const>::run();
TestCase11<R(A&&, A&&) volatile &, 2, Q_Volatile>::run();
TestCase11<R(A&&, A&&) const volatile &, 2, Q_CV>::run();
TestCase11<R(A&&, A&&, ...) &, 2, Q_None>::run();
TestCase11<R(A&&, A&&, ...) const &, 2, Q_Const>::run();
TestCase11<R(A&&, A&&, ...) volatile &, 2, Q_Volatile>::run();
TestCase11<R(A&&, A&&, ...) const volatile &, 2, Q_CV>::run();
TestCase11<R() &&, 0, Q_None, /* RValue */ true>::run();
TestCase11<R() const &&, 0, Q_Const, /* RValue */ true>::run();
TestCase11<R() volatile &&, 0, Q_Volatile, /* RValue */ true>::run();
TestCase11<R() const volatile &&, 0, Q_CV, /* RValue */ true>::run();
TestCase11<R(...) &&, 0, Q_None, /* RValue */ true>::run();
TestCase11<R(...) const &&, 0, Q_Const, /* RValue */ true>::run();
TestCase11<R(...) volatile &&, 0, Q_Volatile, /* RValue */ true>::run();
TestCase11<R(...) const volatile &&, 0, Q_CV, /* RValue */ true>::run();
TestCase11<R(A&&) &&, 1, Q_None, /* RValue */ true>::run();
TestCase11<R(A&&) const &&, 1, Q_Const, /* RValue */ true>::run();
TestCase11<R(A&&) volatile &&, 1, Q_Volatile, /* RValue */ true>::run();
TestCase11<R(A&&) const volatile &&, 1, Q_CV, /* RValue */ true>::run();
TestCase11<R(A&&, ...) &&, 1, Q_None, /* RValue */ true>::run();
TestCase11<R(A&&, ...) const &&, 1, Q_Const, /* RValue */ true>::run();
TestCase11<R(A&&, ...) volatile &&, 1, Q_Volatile, /* RValue */ true>::run();
TestCase11<R(A&&, ...) const volatile &&, 1, Q_CV, /* RValue */ true>::run();
TestCase11<R(A&&, A&&) &&, 2, Q_None, /* RValue */ true>::run();
TestCase11<R(A&&, A&&) const &&, 2, Q_Const, /* RValue */ true>::run();
TestCase11<R(A&&, A&&) volatile &&, 2, Q_Volatile, /* RValue */ true>::run();
TestCase11<R(A&&, A&&) const volatile &&, 2, Q_CV, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, ...) &&, 2, Q_None, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, ...) const &&, 2, Q_Const, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, ...) volatile &&, 2, Q_Volatile, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, ...) const volatile &&, 2, Q_CV, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, A&&) &&, 3, Q_None, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, A&&) const &&, 3, Q_Const, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, A&&) volatile &&, 3, Q_Volatile, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, A&&) const volatile &&, 3, Q_CV, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, A&&, ...) &&, 3, Q_None, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, A&&, ...) const &&, 3, Q_Const, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, A&&, ...) volatile &&, 3, Q_Volatile, /* RValue */ true>::run();
TestCase11<R(A&&, A&&, A&&, ...) const volatile &&, 3, Q_CV, /* RValue */ true>::run();
#endif
}

View File

@ -0,0 +1,164 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// <functional>
// INVOKE (f, t1, t2, ..., tN)
//------------------------------------------------------------------------------
// TESTING INVOKE(f, t1, t2, ..., tN)
// - Bullet 3 -- t1.*f
// - Bullet 4 -- (*t1).*f
//
// Overview:
// Bullets 3 and 4 handle the case where 'f' is a pointer to member object.
// Bullet 3 only handles the cases where t1 is an object of type T or a
// type derived from 'T'. Bullet 4 handles all other cases.
//
// Concerns:
// 1) The return type is always an lvalue reference.
// 2) The return type is not less cv-qualified that the object that contains it.
// 3) The return type is not less cv-qualified than object type.
// 4) The call object is perfectly forwarded.
// 5) Classes that are publicly derived from 'T' are accepted as the call object
// 6) All types that dereference to T or a type derived from T can be used
// as the call object.
// 7) Pointers to T or a type derived from T can be used as the call object.
#include <functional>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "invoke_helpers.h"
template <class Tp>
struct TestMemberObject {
TestMemberObject() : object() {}
Tp object;
private:
TestMemberObject(TestMemberObject const&);
TestMemberObject& operator=(TestMemberObject const&);
};
template <class ObjectType>
struct TestCase {
public:
static void run() { TestCase().doTest(); }
private:
typedef TestMemberObject<ObjectType> TestType;
//==========================================================================
// TEST DISPATCH
void doTest() {
typedef DerivedFromType<TestType> Derived;
TestType obj;
TestType* obj_ptr = &obj;
Derived der;
Derived* der_ptr = &der;
DerefToType<TestType> dref;
DerefPropType<TestType> dref2;
{
typedef ObjectType (TestType::*MemPtr);
typedef ObjectType E;
MemPtr M = &TestType::object;
runTestDispatch<E>(M, obj, &obj.object);
runTestDispatch<E>(M, der, &der.object);
runTestDispatch<E>(M, dref2, &dref2.object.object);
runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object);
runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object);
runTestPointerDispatch<E>(M, dref, &dref.object.object);
}
{
typedef ObjectType const (TestType::*CMemPtr);
typedef ObjectType const E;
CMemPtr M = &TestType::object;
runTestDispatch<E>(M, obj, &obj.object);
runTestDispatch<E>(M, der, &der.object);
runTestDispatch<E>(M, dref2, &dref2.object.object);
runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object);
runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object);
runTestPointerDispatch<E>(M, dref, &dref.object.object);
}
{
typedef ObjectType volatile (TestType::*VMemPtr);
typedef ObjectType volatile E;
VMemPtr M = &TestType::object;
runTestDispatch<E>(M, obj, &obj.object);
runTestDispatch<E>(M, der, &der.object);
runTestDispatch<E>(M, dref2, &dref2.object.object);
runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object);
runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object);
runTestPointerDispatch<E>(M, dref, &dref.object.object);
}
{
typedef ObjectType const volatile (TestType::*CVMemPtr);
typedef ObjectType const volatile E;
CVMemPtr M = &TestType::object;
runTestDispatch<E>(M, obj, &obj.object);
runTestDispatch<E>(M, der, &der.object);
runTestDispatch<E>(M, dref2, &dref2.object.object);
runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object);
runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object);
runTestPointerDispatch<E>(M, dref, &dref.object.object);
}
}
template <class Expect, class Fn, class T>
void runTestDispatch(Fn M, T& obj, ObjectType* expect) {
runTest<Expect &> (M, C_<T&>(obj), expect);
runTest<Expect const&> (M, C_<T const&>(obj), expect);
runTest<Expect volatile&> (M, C_<T volatile&>(obj), expect);
runTest<Expect const volatile&>(M, C_<T const volatile&>(obj), expect);
#if TEST_STD_VER >= 11
runTest<Expect&&> (M, C_<T&&>(obj), expect);
runTest<Expect const&&> (M, C_<T const&&>(obj), expect);
runTest<Expect volatile&&> (M, C_<T volatile&&>(obj), expect);
runTest<Expect const volatile&&>(M, C_<T const volatile&&>(obj), expect);
#endif
}
template <class Expect, class Fn, class T>
void runTestPointerDispatch(Fn M, T& obj, ObjectType* expect) {
runTest<Expect&>(M, C_<T &>(obj), expect);
runTest<Expect&>(M, C_<T const&>(obj), expect);
runTest<Expect&>(M, C_<T volatile&>(obj), expect);
runTest<Expect&>(M, C_<T const volatile&>(obj), expect);
#if TEST_STD_VER >= 11
runTest<Expect&>(M, C_<T&&>(obj), expect);
runTest<Expect&>(M, C_<T const&&>(obj), expect);
runTest<Expect&>(M, C_<T volatile&&>(obj), expect);
runTest<Expect&>(M, C_<T const volatile&&>(obj), expect);
#endif
}
template <class Expect, class Fn, class T>
#if TEST_STD_VER >= 11
void runTest(Fn M, T&& obj, ObjectType* expect) {
#else
void runTest(Fn M, T& obj, ObjectType* expect ) {
#endif
static_assert((std::is_same<
decltype(std::__invoke(M, std::forward<T>(obj))), Expect
>::value), "");
Expect e = std::__invoke(M, std::forward<T>(obj));
assert(&e == expect);
}
};
int main() {
TestCase<ArgType>::run();
TestCase<ArgType const>::run();
TestCase<ArgType volatile>::run();
TestCase<ArgType const volatile>::run();
TestCase<ArgType*>::run();
}

View File

@ -0,0 +1,327 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// <functional>
// INVOKE (f, t1, t2, ..., tN)
//------------------------------------------------------------------------------
// TESTING INVOKE(f, t1, t2, ..., tN)
// - Bullet 5 -- f(t2, ..., tN)
//
// Overview:
// Bullet 5 handles the cases where the first argument is not a member
// function.
//
// Concerns:
// 1) Different types of callable objects are supported. Including
// 1a) Free Function pointers and references.
// 1b) Classes which provide a call operator
// 1c) lambdas
// 2) The callable objects are perfect forwarded.
// 3) The arguments are perfect forwarded.
// 4) Signatures which include varargs are supported.
// 5) In C++03 3 extra arguments should be allowed.
//
// Plan:
// 1) Define a set of free functions, 'SF', and class types with call
// operators, 'SC', that address concerns 4 and 5. The free functions should
// return 'FunctionID::setUncheckedCall()' and the call operators should
// return 'MethodID::setUncheckedCall()'.
//
// 2) For each function 'f' in 'SF' and 'SC' attempt to call 'f'
// using the correct number of arguments and cv-ref qualifiers. Check that
// 'f' has been called using 'FunctionID::checkCall()' if 'f' is a free
// function and 'MethodID::checkCall()' otherwise.
#include <functional>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "invoke_helpers.h"
//==============================================================================
// freeFunction03 - A C++03 free function.
void*& freeFunction03() {
return FunctionPtrID<void*&(), freeFunction03>::setUncheckedCall();
}
void*& freeFunction03(...) {
return FunctionPtrID<void*&(...), freeFunction03>::setUncheckedCall();
}
template <class A0>
void*& freeFunction03(A0&) {
return FunctionPtrID<void*&(A0&), freeFunction03>::setUncheckedCall();
}
template <class A0>
void*& freeFunction03(A0&, ...) {
return FunctionPtrID<void*&(A0&, ...), freeFunction03>::setUncheckedCall();
}
template <class A0, class A1>
void*& freeFunction03(A0&, A1&) {
return FunctionPtrID<void*&(A0&, A1&), freeFunction03>::setUncheckedCall();
}
template <class A0, class A1>
void*& freeFunction03(A0&, A1&, ...) {
return FunctionPtrID<void*&(A0&, A1&, ...), freeFunction03>::setUncheckedCall();
}
template <class A0, class A1, class A2>
void*& freeFunction03(A0&, A1&, A2&) {
return FunctionPtrID<void*&(A0&, A1&, A2&), freeFunction03>::setUncheckedCall();
}
template <class A0, class A1, class A2>
void*& freeFunction03(A0&, A1&, A2&, ...) {
return FunctionPtrID<void*&(A0&, A1&, A2&, ...), freeFunction03>::setUncheckedCall();
}
//==============================================================================
// Functor03 - C++03 compatible functor object
struct Functor03 {
typedef void*& R;
typedef Functor03 C;
#define F(Args, ...) \
__VA_ARGS__ R operator() Args { return MethodID<R(C::*) Args>::setUncheckedCall(); } \
__VA_ARGS__ R operator() Args const { return MethodID<R(C::*) Args const>::setUncheckedCall(); } \
__VA_ARGS__ R operator() Args volatile { return MethodID<R(C::*) Args volatile>::setUncheckedCall(); } \
__VA_ARGS__ R operator() Args const volatile { return MethodID<R(C::*) Args const volatile>::setUncheckedCall(); }
#
F(())
F((A0&), template <class A0>)
F((A0&, A1&), template <class A0, class A1>)
F((A0&, A1&, A2&), template <class A0, class A1, class A2>)
#undef F
public:
Functor03() {}
private:
Functor03(Functor03 const&);
Functor03& operator=(Functor03 const&);
};
#if TEST_STD_VER >= 11
//==============================================================================
// freeFunction11 - A C++11 free function.
template <class ...Args>
void*& freeFunction11(Args&&...) {
return FunctionPtrID<void*&(Args&&...), freeFunction11>::setUncheckedCall();
}
template <class ...Args>
void*& freeFunction11(Args&&...,...) {
return FunctionPtrID<void*&(Args&&...,...), freeFunction11>::setUncheckedCall();
}
//==============================================================================
// Functor11 - C++11 reference qualified test member functions.
struct Functor11 {
typedef void*& R;
typedef Functor11 C;
#define F(CV) \
template <class ...Args> \
R operator()(Args&&...) CV { return MethodID<R(C::*)(Args&&...) CV>::setUncheckedCall(); }
#
F(&)
F(const &)
F(volatile &)
F(const volatile &)
F(&&)
F(const &&)
F(volatile &&)
F(const volatile &&)
#undef F
public:
Functor11() {}
private:
Functor11(Functor11 const&);
Functor11& operator=(Functor11 const&);
};
#endif // TEST_STD_VER >= 11
//==============================================================================
// TestCaseFunctorImp - A test case for an operator() class method.
// ClassType - The type of the call object.
// CallSig - The function signature of the call operator being tested.
// Arity - the arity of 'CallSig'
// ObjCaster - Transformation function applied to call object.
// ArgCaster - Transformation function applied to the extra arguments.
template <class ClassType, class CallSig, int Arity,
class ObjCaster, class ArgCaster = LValueCaster>
struct TestCaseFunctorImp {
public:
static void run() {
typedef MethodID<CallSig ClassType::*> MID;
BasicTest<MID, Arity, ObjCaster, ArgCaster> t;
typedef ClassType T;
typedef DerivedFromType<T> D;
T obj;
D der;
t.runTest(obj);
t.runTest(der);
}
};
//==============================================================================
// TestCaseFreeFunction - A test case for a free function.
// CallSig - The function signature of the free function being tested.
// FnPtr - The function being tested.
// Arity - the arity of 'CallSig'
// ArgCaster - Transformation function to be applied to the extra arguments.
template <class CallSig, CallSig* FnPtr, int Arity, class ArgCaster>
struct TestCaseFreeFunction {
public:
static void run() {
typedef FunctionPtrID<CallSig, FnPtr> FID;
BasicTest<FID, Arity, LValueCaster, ArgCaster> t;
DerefToType<CallSig*> deref_to(FnPtr);
DerefToType<CallSig&> deref_to_ref(*FnPtr);
t.runTest(FnPtr);
t.runTest(*FnPtr);
t.runTest(deref_to);
t.runTest(deref_to_ref);
}
};
//==============================================================================
// runTest Helpers
//==============================================================================
#if TEST_STD_VER >= 11
template <class Sig, int Arity, class ArgCaster>
void runFunctionTestCase11() {
TestCaseFreeFunction<Sig, freeFunction11, Arity, ArgCaster>();
}
#endif
template <class Sig, int Arity, class ArgCaster>
void runFunctionTestCase() {
TestCaseFreeFunction<Sig, freeFunction03, Arity, ArgCaster>();
#if TEST_STD_VER >= 11
runFunctionTestCase11<Sig, Arity, ArgCaster>();
#endif
}
template <class Sig, int Arity, class ObjCaster, class ArgCaster>
void runFunctorTestCase() {
TestCaseFunctorImp<Functor03, Sig, Arity, ObjCaster, ArgCaster>::run();
}
template <class Sig, int Arity, class ObjCaster>
void runFunctorTestCase() {
TestCaseFunctorImp<Functor03, Sig, Arity, ObjCaster>::run();
}
#if TEST_STD_VER >= 11
// runTestCase - Run a test case for C++11 class functor types
template <class Sig, int Arity, class ObjCaster, class ArgCaster = LValueCaster>
void runFunctorTestCase11() {
TestCaseFunctorImp<Functor11, Sig, Arity, ObjCaster, ArgCaster>::run();
}
#endif
// runTestCase - Run a test case for both function and functor types.
template <class Sig, int Arity, class ArgCaster>
void runTestCase() {
runFunctionTestCase<Sig, Arity, ArgCaster>();
runFunctorTestCase <Sig, Arity, LValueCaster, ArgCaster>();
};
int main() {
typedef void*& R;
typedef ArgType A;
typedef A const CA;
runTestCase< R(), 0, LValueCaster >();
runTestCase< R(A&), 1, LValueCaster >();
runTestCase< R(A&, A&), 2, LValueCaster >();
runTestCase< R(A&, A&, A&), 3, LValueCaster >();
runTestCase< R(CA&), 1, ConstCaster >();
runTestCase< R(CA&, CA&), 2, ConstCaster >();
runTestCase< R(CA&, CA&, CA&), 3, ConstCaster >();
runFunctionTestCase<R(...), 0, LValueCaster >();
runFunctionTestCase<R(A&, ...), 1, LValueCaster >();
runFunctionTestCase<R(A&, A&, ...), 2, LValueCaster >();
runFunctionTestCase<R(A&, A&, A&, ...), 3, LValueCaster >();
#if TEST_STD_VER >= 11
runFunctionTestCase11<R(A&&), 1, MoveCaster >();
runFunctionTestCase11<R(A&&, ...), 1, MoveCaster >();
#endif
runFunctorTestCase<R(), 0, LValueCaster >();
runFunctorTestCase<R() const, 0, ConstCaster >();
runFunctorTestCase<R() volatile, 0, VolatileCaster >();
runFunctorTestCase<R() const volatile, 0, CVCaster >();
runFunctorTestCase<R(A&), 1, LValueCaster >();
runFunctorTestCase<R(A&) const, 1, ConstCaster >();
runFunctorTestCase<R(A&) volatile, 1, VolatileCaster >();
runFunctorTestCase<R(A&) const volatile, 1, CVCaster >();
runFunctorTestCase<R(A&, A&), 2, LValueCaster >();
runFunctorTestCase<R(A&, A&) const, 2, ConstCaster >();
runFunctorTestCase<R(A&, A&) volatile, 2, VolatileCaster >();
runFunctorTestCase<R(A&, A&) const volatile, 2, CVCaster >();
runFunctorTestCase<R(A&, A&, A&), 3, LValueCaster >();
runFunctorTestCase<R(A&, A&, A&) const, 3, ConstCaster >();
runFunctorTestCase<R(A&, A&, A&) volatile, 3, VolatileCaster >();
runFunctorTestCase<R(A&, A&, A&) const volatile, 3, CVCaster >();
{
typedef ConstCaster CC;
runFunctorTestCase<R(CA&), 1, LValueCaster, CC>();
runFunctorTestCase<R(CA&) const, 1, ConstCaster, CC>();
runFunctorTestCase<R(CA&) volatile, 1, VolatileCaster, CC>();
runFunctorTestCase<R(CA&) const volatile, 1, CVCaster, CC>();
runFunctorTestCase<R(CA&, CA&), 2, LValueCaster, CC>();
runFunctorTestCase<R(CA&, CA&) const, 2, ConstCaster, CC>();
runFunctorTestCase<R(CA&, CA&) volatile, 2, VolatileCaster, CC>();
runFunctorTestCase<R(CA&, CA&) const volatile, 2, CVCaster, CC>();
runFunctorTestCase<R(CA&, CA&, CA&), 3, LValueCaster, CC>();
runFunctorTestCase<R(CA&, CA&, CA&) const, 3, ConstCaster, CC>();
runFunctorTestCase<R(CA&, CA&, CA&) volatile, 3, VolatileCaster, CC>();
runFunctorTestCase<R(CA&, CA&, CA&) const volatile, 3, CVCaster, CC>();
}
#if TEST_STD_VER >= 11
runFunctorTestCase11<R() &, 0, LValueCaster >();
runFunctorTestCase11<R() const &, 0, ConstCaster >();
runFunctorTestCase11<R() volatile &, 0, VolatileCaster >();
runFunctorTestCase11<R() const volatile &, 0, CVCaster >();
runFunctorTestCase11<R() &&, 0, MoveCaster >();
runFunctorTestCase11<R() const &&, 0, MoveConstCaster >();
runFunctorTestCase11<R() volatile &&, 0, MoveVolatileCaster >();
runFunctorTestCase11<R() const volatile &&, 0, MoveCVCaster >();
{
typedef MoveCaster MC;
runFunctorTestCase11<R(A&&) &, 1, LValueCaster, MC>();
runFunctorTestCase11<R(A&&) const &, 1, ConstCaster, MC>();
runFunctorTestCase11<R(A&&) volatile &, 1, VolatileCaster, MC>();
runFunctorTestCase11<R(A&&) const volatile &, 1, CVCaster, MC>();
runFunctorTestCase11<R(A&&) &&, 1, MoveCaster, MC>();
runFunctorTestCase11<R(A&&) const &&, 1, MoveConstCaster, MC>();
runFunctorTestCase11<R(A&&) volatile &&, 1, MoveVolatileCaster, MC>();
runFunctorTestCase11<R(A&&) const volatile &&, 1, MoveCVCaster, MC>();
}
#endif
}

View File

@ -0,0 +1,317 @@
#ifndef INVOKE_HELPERS_H
#define INVOKE_HELPERS_H
#include <type_traits>
#include <cassert>
#include <functional>
#include "test_macros.h"
template <int I>
struct Int : public std::integral_constant<int, I> {};
template <bool P>
struct Bool : public std::integral_constant<bool, P> {};
struct Q_None {
template <class T>
struct apply { typedef T type; };
};
struct Q_Const {
template <class T>
struct apply { typedef T const type; };
};
struct Q_Volatile {
template <class T>
struct apply { typedef T volatile type; };
};
struct Q_CV {
template <class T>
struct apply { typedef T const volatile type; };
};
// Caster - A functor object that performs cv-qualifier and value category
// conversions.
// QualTag - A metafunction type that applies cv-qualifiers to its argument.
// RValue - True if the resulting object should be an RValue reference.
// False otherwise.
template <class QualTag, bool RValue = false>
struct Caster {
template <class T>
struct apply {
typedef typename std::remove_reference<T>::type RawType;
typedef typename QualTag::template apply<RawType>::type CVType;
#if TEST_STD_VER >= 11
typedef typename std::conditional<RValue,
CVType&&, CVType&
>::type type;
#else
typedef CVType& type;
#endif
};
template <class T>
typename apply<T>::type
operator()(T& obj) const {
typedef typename apply<T>::type OutType;
return static_cast<OutType>(obj);
}
};
typedef Caster<Q_None> LValueCaster;
typedef Caster<Q_Const> ConstCaster;
typedef Caster<Q_Volatile> VolatileCaster;
typedef Caster<Q_CV> CVCaster;
typedef Caster<Q_None, true> MoveCaster;
typedef Caster<Q_Const, true> MoveConstCaster;
typedef Caster<Q_Volatile, true> MoveVolatileCaster;
typedef Caster<Q_CV, true> MoveCVCaster;
// A shorter name for 'static_cast'
template <class QualType, class Tp>
QualType C_(Tp& v) { return static_cast<QualType>(v); };
//==============================================================================
// ArgType - A non-copyable type intended to be used as a dummy argument type
// to test functions.
struct ArgType {
int value;
explicit ArgType(int val = 0) : value(val) {}
private:
ArgType(ArgType const&);
ArgType& operator=(ArgType const&);
};
//==============================================================================
// DerivedFromBase - A type that derives from it's template argument 'Base'
template <class Base>
struct DerivedFromType : public Base {
DerivedFromType() : Base() {}
template <class Tp>
explicit DerivedFromType(Tp const& t) : Base(t) {}
};
//==============================================================================
// DerefToType - A type that dereferences to it's template argument 'To'.
// The cv-ref qualifiers of the 'DerefToType' object do not propagate
// to the resulting 'To' object.
template <class To>
struct DerefToType {
To object;
DerefToType() {}
template <class Up>
explicit DerefToType(Up const& val) : object(val) {}
To& operator*() const volatile { return const_cast<To&>(object); }
};
//==============================================================================
// DerefPropToType - A type that dereferences to it's template argument 'To'.
// The cv-ref qualifiers of the 'DerefPropToType' object propagate
// to the resulting 'To' object.
template <class To>
struct DerefPropType {
To object;
DerefPropType() {}
template <class Up>
explicit DerefPropType(Up const& val) : object(val) {}
#if TEST_STD_VER < 11
To& operator*() { return object; }
To const& operator*() const { return object; }
To volatile& operator*() volatile { return object; }
To const volatile& operator*() const volatile { return object; }
#else
To& operator*() & { return object; }
To const& operator*() const & { return object; }
To volatile& operator*() volatile & { return object; }
To const volatile& operator*() const volatile & { return object; }
To&& operator*() && { return static_cast<To &&>(object); }
To const&& operator*() const && { return static_cast<To const&&>(object); }
To volatile&& operator*() volatile && { return static_cast<To volatile&&>(object); }
To const volatile&& operator*() const volatile && { return static_cast<To const volatile&&>(object); }
#endif
};
//==============================================================================
// MethodID - A type that uniquely identifies a member function for a class.
// This type is used to communicate between the member functions being tested
// and the tests invoking them.
// - Test methods should call 'setUncheckedCall()' whenever they are invoked.
// - Tests consume the unchecked call using checkCall(<return-value>)` to assert
// that the method has been called and that the return value of `__invoke`
// matches what the method actually returned.
template <class T>
struct MethodID {
typedef void* IDType;
static int dummy; // A dummy memory location.
static void* id; // The "ID" is the value of this pointer.
static bool unchecked_call; // Has a call happened that has not been checked.
static void*& setUncheckedCall() {
assert(unchecked_call == false);
unchecked_call = true;
return id;
}
static bool checkCalled(void*& return_value) {
bool old = unchecked_call;
unchecked_call = false;
return old && id == return_value && &id == &return_value;
}
};
template <class T> int MethodID<T>::dummy = 0;
template <class T> void* MethodID<T>::id = (void*)&MethodID<T>::dummy;
template <class T> bool MethodID<T>::unchecked_call = false;
//==============================================================================
// FunctionPtrID - Like MethodID but for free function pointers.
template <class T, T*>
struct FunctionPtrID {
static int dummy; // A dummy memory location.
static void* id; // The "ID" is the value of this pointer.
static bool unchecked_call; // Has a call happened that has not been checked.
static void*& setUncheckedCall() {
assert(unchecked_call == false);
unchecked_call = true;
return id;
}
static bool checkCalled(void*& return_value) {
bool old = unchecked_call;
unchecked_call = false;
return old && id == return_value && &id == &return_value;
}
};
template <class T, T* Ptr> int FunctionPtrID<T, Ptr>::dummy = 0;
template <class T, T* Ptr> void* FunctionPtrID<T, Ptr>::id = (void*)&FunctionPtrID<T, Ptr>::dummy;
template <class T, T* Ptr> bool FunctionPtrID<T, Ptr>::unchecked_call = false;
//==============================================================================
// BasicTest - The basic test structure for everything except
// member object pointers.
// ID - The "Function Identifier" type used either MethodID or FunctionPtrID.
// Arity - The Arity of the call signature.
// ObjectCaster - The object transformation functor type.
// ArgCaster - The extra argument transformation functor type.
template <class ID, int Arity, class ObjectCaster = LValueCaster,
class ArgCaster = LValueCaster>
struct BasicTest {
template <class ObjectT>
void runTest(ObjectT& object) {
Int<Arity> A;
runTestImp(A, object);
}
template <class MethodPtr, class ObjectT>
void runTest(MethodPtr ptr, ObjectT& object) {
Int<Arity> A;
runTestImp(A, ptr, object);
}
private:
typedef void*& CallRet;
ObjectCaster object_cast;
ArgCaster arg_cast;
ArgType a0, a1, a2;
//==========================================================================
// BULLET 1 AND 2 TEST METHODS
//==========================================================================
template <class MethodPtr, class ObjectT>
void runTestImp(Int<0>, MethodPtr ptr, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object));
assert(ID::checkCalled(ret));
}
template <class MethodPtr, class ObjectT>
void runTestImp(Int<1>, MethodPtr ptr, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0));
assert(ID::checkCalled(ret));
}
template <class MethodPtr, class ObjectT>
void runTestImp(Int<2>, MethodPtr ptr, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
assert(ID::checkCalled(ret));
}
template <class MethodPtr, class ObjectT>
void runTestImp(Int<3>, MethodPtr ptr, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
assert(ID::checkCalled(ret));
}
//==========================================================================
// BULLET 5 TEST METHODS
//==========================================================================
template <class ObjectT>
void runTestImp(Int<0>, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object));
assert(ID::checkCalled(ret));
}
template <class ObjectT>
void runTestImp(Int<1>, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object), arg_cast(a0)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object), arg_cast(a0));
assert(ID::checkCalled(ret));
}
template <class ObjectT>
void runTestImp(Int<2>, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1));
assert(ID::checkCalled(ret));
}
template <class ObjectT>
void runTestImp(Int<3>, ObjectT& object) {
static_assert((std::is_same<
decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
, CallRet>::value), "");
assert(ID::unchecked_call == false);
CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
assert(ID::checkCalled(ret));
}
};
#endif // INVOKE_HELPERS_H