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