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
operatorCaster58     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>
C_(Tp & v)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;
valueArgType82     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 {
DerivedFromTypeDerivedFromType92     DerivedFromType() : Base() {}
93     template <class Tp>
DerivedFromTypeDerivedFromType94     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 
DerefToTypeDerefToType105     DerefToType() {}
106 
107     template <class Up>
DerefToTypeDerefToType108     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 
DerefPropTypeDerefPropType121     DerefPropType() {}
122 
123     template <class Up>
DerefPropTypeDerefPropType124     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 
setUncheckedCallMethodID159     static void*& setUncheckedCall() {
160         assert(unchecked_call == false);
161         unchecked_call = true;
162         return id;
163     }
164 
checkCalledMethodID165     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 
setUncheckedCallFunctionPtrID185     static void*& setUncheckedCall() {
186         assert(unchecked_call == false);
187         unchecked_call = true;
188         return id;
189     }
190 
checkCalledFunctionPtrID191     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>
runTestBasicTest213     void runTest(ObjectT& object) {
214         Int<Arity> A;
215         runTestImp(A, object);
216     }
217 
218     template <class MethodPtr, class ObjectT>
runTestBasicTest219     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>
runTestImpBasicTest234     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>
runTestImpBasicTest244     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>
runTestImpBasicTest254     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>
runTestImpBasicTest264     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>
runTestImpBasicTest277     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>
runTestImpBasicTest287     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>
runTestImpBasicTest297     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>
runTestImpBasicTest307     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