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:
parent
568bd0222f
commit
48aa2cf9f3
@ -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
|
||||
}
|
@ -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();
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue
Block a user