| //===----------------------------------------------------------------------===// |
| // |
| // 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. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #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 |