Home | History | Annotate | Download | only in func.require
      1 #ifndef INVOKE_HELPERS_H
      2 #define INVOKE_HELPERS_H
      3 
      4 #include <type_traits>
      5 #include <cassert>
      6 #include <functional>
      7 
      8 #include "test_macros.h"
      9 
     10 template <int I>
     11 struct Int : public std::integral_constant<int, I> {};
     12 
     13 template <bool P>
     14 struct Bool : public std::integral_constant<bool, P> {};
     15 
     16 struct Q_None {
     17     template <class T>
     18     struct apply { typedef T type; };
     19 };
     20 
     21 struct Q_Const {
     22     template <class T>
     23     struct apply { typedef T const type; };
     24 };
     25 
     26 struct Q_Volatile {
     27     template <class T>
     28     struct apply { typedef T volatile type; };
     29 };
     30 
     31 struct Q_CV {
     32     template <class T>
     33     struct apply { typedef T const volatile type; };
     34 };
     35 
     36 // Caster - A functor object that performs cv-qualifier and value category
     37 //   conversions.
     38 //   QualTag - A metafunction type that applies cv-qualifiers to its argument.
     39 //   RValue - True if the resulting object should be an RValue reference.
     40 //            False otherwise.
     41 template <class QualTag, bool RValue = false>
     42 struct Caster {
     43     template <class T>
     44     struct apply {
     45         typedef typename std::remove_reference<T>::type RawType;
     46         typedef typename QualTag::template apply<RawType>::type CVType;
     47 #if TEST_STD_VER >= 11
     48         typedef typename std::conditional<RValue,
     49             CVType&&, CVType&
     50         >::type type;
     51 #else
     52         typedef CVType& type;
     53 #endif
     54     };
     55 
     56     template <class T>
     57     typename apply<T>::type
     58     operator()(T& obj) const {
     59         typedef typename apply<T>::type OutType;
     60         return static_cast<OutType>(obj);
     61     }
     62 };
     63 
     64 typedef Caster<Q_None>           LValueCaster;
     65 typedef Caster<Q_Const>          ConstCaster;
     66 typedef Caster<Q_Volatile>       VolatileCaster;
     67 typedef Caster<Q_CV>             CVCaster;
     68 typedef Caster<Q_None,     true> MoveCaster;
     69 typedef Caster<Q_Const,    true> MoveConstCaster;
     70 typedef Caster<Q_Volatile, true> MoveVolatileCaster;
     71 typedef Caster<Q_CV,       true> MoveCVCaster;
     72 
     73 // A shorter name for 'static_cast'
     74 template <class QualType, class Tp>
     75 QualType C_(Tp& v) { return static_cast<QualType>(v); };
     76 
     77 //==============================================================================
     78 // ArgType - A non-copyable type intended to be used as a dummy argument type
     79 //   to test functions.
     80 struct ArgType {
     81     int value;
     82     explicit ArgType(int val = 0) : value(val) {}
     83 private:
     84     ArgType(ArgType const&);
     85     ArgType& operator=(ArgType const&);
     86 };
     87 
     88 //==============================================================================
     89 // DerivedFromBase - A type that derives from it's template argument 'Base'
     90 template <class Base>
     91 struct DerivedFromType : public Base {
     92     DerivedFromType() : Base() {}
     93     template <class Tp>
     94     explicit DerivedFromType(Tp const& t) : Base(t) {}
     95 };
     96 
     97 //==============================================================================
     98 // DerefToType - A type that dereferences to it's template argument 'To'.
     99 //   The cv-ref qualifiers of the 'DerefToType' object do not propagate
    100 //   to the resulting 'To' object.
    101 template <class To>
    102 struct DerefToType {
    103     To object;
    104 
    105     DerefToType() {}
    106 
    107     template <class Up>
    108     explicit DerefToType(Up const& val) : object(val) {}
    109 
    110     To& operator*() const volatile { return const_cast<To&>(object); }
    111 };
    112 
    113 //==============================================================================
    114 // DerefPropToType - A type that dereferences to it's template argument 'To'.
    115 //   The cv-ref qualifiers of the 'DerefPropToType' object propagate
    116 //   to the resulting 'To' object.
    117 template <class To>
    118 struct DerefPropType {
    119     To object;
    120 
    121     DerefPropType() {}
    122 
    123     template <class Up>
    124     explicit DerefPropType(Up const& val) : object(val) {}
    125 
    126 #if TEST_STD_VER < 11
    127     To& operator*() { return object; }
    128     To const& operator*() const { return object; }
    129     To volatile& operator*() volatile  { return object; }
    130     To const volatile& operator*() const volatile { return object; }
    131 #else
    132     To& operator*() & { return object; }
    133     To const& operator*() const & { return object; }
    134     To volatile& operator*() volatile  & { return object; }
    135     To const volatile& operator*() const volatile & { return object; }
    136     To&& operator*() && { return static_cast<To &&>(object); }
    137     To const&& operator*() const && { return static_cast<To const&&>(object); }
    138     To volatile&& operator*() volatile  && { return static_cast<To volatile&&>(object); }
    139     To const volatile&& operator*() const volatile && { return static_cast<To const volatile&&>(object); }
    140 #endif
    141 };
    142 
    143 //==============================================================================
    144 // MethodID - A type that uniquely identifies a member function for a class.
    145 //   This type is used to communicate between the member functions being tested
    146 //   and the tests invoking them.
    147 // - Test methods should call 'setUncheckedCall()' whenever they are invoked.
    148 // - Tests consume the unchecked call using checkCall(<return-value>)` to assert
    149 //   that the method has been called and that the return value of `__invoke`
    150 //   matches what the method actually returned.
    151 template <class T>
    152 struct MethodID {
    153     typedef void* IDType;
    154 
    155     static int dummy; // A dummy memory location.
    156     static void* id; // The "ID" is the value of this pointer.
    157     static bool unchecked_call; // Has a call happened that has not been checked.
    158 
    159     static void*& setUncheckedCall() {
    160         assert(unchecked_call == false);
    161         unchecked_call = true;
    162         return id;
    163     }
    164 
    165     static bool checkCalled(void*& return_value) {
    166         bool old = unchecked_call;
    167         unchecked_call = false;
    168         return old && id == return_value && &id == &return_value;
    169     }
    170 };
    171 
    172 template <class T> int   MethodID<T>::dummy = 0;
    173 template <class T> void* MethodID<T>::id = (void*)&MethodID<T>::dummy;
    174 template <class T> bool  MethodID<T>::unchecked_call = false;
    175 
    176 
    177 //==============================================================================
    178 // FunctionPtrID - Like MethodID but for free function pointers.
    179 template <class T, T*>
    180 struct FunctionPtrID {
    181     static int dummy; // A dummy memory location.
    182     static void* id; // The "ID" is the value of this pointer.
    183     static bool unchecked_call; // Has a call happened that has not been checked.
    184 
    185     static void*& setUncheckedCall() {
    186         assert(unchecked_call == false);
    187         unchecked_call = true;
    188         return id;
    189     }
    190 
    191     static bool checkCalled(void*& return_value) {
    192         bool old = unchecked_call;
    193         unchecked_call = false;
    194         return old && id == return_value && &id == &return_value;
    195     }
    196 };
    197 
    198 template <class T, T* Ptr> int   FunctionPtrID<T, Ptr>::dummy = 0;
    199 template <class T, T* Ptr> void* FunctionPtrID<T, Ptr>::id = (void*)&FunctionPtrID<T, Ptr>::dummy;
    200 template <class T, T* Ptr> bool  FunctionPtrID<T, Ptr>::unchecked_call = false;
    201 
    202 //==============================================================================
    203 // BasicTest - The basic test structure for everything except
    204 // member object pointers.
    205 // ID - The "Function Identifier" type used either MethodID or FunctionPtrID.
    206 // Arity - The Arity of the call signature.
    207 // ObjectCaster - The object transformation functor type.
    208 // ArgCaster - The extra argument transformation functor type.
    209 template <class ID, int Arity, class ObjectCaster = LValueCaster,
    210                                class ArgCaster    = LValueCaster>
    211 struct BasicTest {
    212     template <class ObjectT>
    213     void runTest(ObjectT& object) {
    214         Int<Arity> A;
    215         runTestImp(A, object);
    216     }
    217 
    218     template <class MethodPtr, class ObjectT>
    219     void runTest(MethodPtr ptr, ObjectT& object) {
    220         Int<Arity> A;
    221         runTestImp(A, ptr, object);
    222     }
    223 
    224 private:
    225     typedef void*& CallRet;
    226     ObjectCaster object_cast;
    227     ArgCaster arg_cast;
    228     ArgType a0, a1, a2;
    229 
    230     //==========================================================================
    231     //                       BULLET 1 AND 2 TEST METHODS
    232     //==========================================================================
    233     template <class MethodPtr, class ObjectT>
    234     void runTestImp(Int<0>, MethodPtr ptr, ObjectT& object) {
    235         static_assert((std::is_same<
    236             decltype(std::__invoke(ptr, object_cast(object)))
    237           , CallRet>::value), "");
    238         assert(ID::unchecked_call == false);
    239         CallRet ret = std::__invoke(ptr, object_cast(object));
    240         assert(ID::checkCalled(ret));
    241     }
    242 
    243     template <class MethodPtr, class ObjectT>
    244     void runTestImp(Int<1>, MethodPtr ptr, ObjectT& object) {
    245         static_assert((std::is_same<
    246             decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0)))
    247           , CallRet>::value), "");
    248         assert(ID::unchecked_call == false);
    249         CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0));
    250         assert(ID::checkCalled(ret));
    251     }
    252 
    253     template <class MethodPtr, class ObjectT>
    254     void runTestImp(Int<2>, MethodPtr ptr, ObjectT& object) {
    255         static_assert((std::is_same<
    256             decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
    257           , CallRet>::value), "");
    258         assert(ID::unchecked_call == false);
    259         CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
    260         assert(ID::checkCalled(ret));
    261     }
    262 
    263     template <class MethodPtr, class ObjectT>
    264     void runTestImp(Int<3>, MethodPtr ptr, ObjectT& object) {
    265         static_assert((std::is_same<
    266             decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
    267           , CallRet>::value), "");
    268         assert(ID::unchecked_call == false);
    269         CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
    270         assert(ID::checkCalled(ret));
    271     }
    272 
    273     //==========================================================================
    274     //                       BULLET 5 TEST METHODS
    275     //==========================================================================
    276     template <class ObjectT>
    277     void runTestImp(Int<0>, ObjectT& object) {
    278         static_assert((std::is_same<
    279             decltype(std::__invoke(object_cast(object)))
    280           , CallRet>::value), "");
    281         assert(ID::unchecked_call == false);
    282         CallRet ret = std::__invoke(object_cast(object));
    283         assert(ID::checkCalled(ret));
    284     }
    285 
    286     template <class ObjectT>
    287     void runTestImp(Int<1>, ObjectT& object) {
    288         static_assert((std::is_same<
    289             decltype(std::__invoke(object_cast(object), arg_cast(a0)))
    290           , CallRet>::value), "");
    291         assert(ID::unchecked_call == false);
    292         CallRet ret = std::__invoke(object_cast(object), arg_cast(a0));
    293         assert(ID::checkCalled(ret));
    294     }
    295 
    296     template <class ObjectT>
    297     void runTestImp(Int<2>, ObjectT& object) {
    298         static_assert((std::is_same<
    299             decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)))
    300           , CallRet>::value), "");
    301         assert(ID::unchecked_call == false);
    302         CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1));
    303         assert(ID::checkCalled(ret));
    304     }
    305 
    306     template <class ObjectT>
    307     void runTestImp(Int<3>, ObjectT& object) {
    308         static_assert((std::is_same<
    309             decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
    310           , CallRet>::value), "");
    311         assert(ID::unchecked_call == false);
    312         CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
    313         assert(ID::checkCalled(ret));
    314     }
    315 };
    316 
    317 #endif // INVOKE_HELPERS_H
    318