1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef INVOKE_HELPERS_H
10 #define INVOKE_HELPERS_H
11
12 #include <type_traits>
13 #include <cassert>
14 #include <functional>
15
16 #include "test_macros.h"
17
18 template <int I>
19 struct Int : public std::integral_constant<int, I> {};
20
21 template <bool P>
22 struct Bool : public std::integral_constant<bool, P> {};
23
24 struct Q_None {
25 template <class T>
26 struct apply { typedef T type; };
27 };
28
29 struct Q_Const {
30 template <class T>
31 struct apply { typedef T const type; };
32 };
33
34 struct Q_Volatile {
35 template <class T>
36 struct apply { typedef T volatile type; };
37 };
38
39 struct Q_CV {
40 template <class T>
41 struct apply { typedef T const volatile type; };
42 };
43
44 // Caster - A functor object that performs cv-qualifier and value category
45 // conversions.
46 // QualTag - A metafunction type that applies cv-qualifiers to its argument.
47 // RValue - True if the resulting object should be an RValue reference.
48 // False otherwise.
49 template <class QualTag, bool RValue = false>
50 struct Caster {
51 template <class T>
52 struct apply {
53 typedef typename std::remove_reference<T>::type RawType;
54 typedef typename QualTag::template apply<RawType>::type CVType;
55 #if TEST_STD_VER >= 11
56 typedef typename std::conditional<RValue,
57 CVType&&, CVType&
58 >::type type;
59 #else
60 typedef CVType& type;
61 #endif
62 };
63
64 template <class T>
65 typename apply<T>::type
operatorCaster66 operator()(T& obj) const {
67 typedef typename apply<T>::type OutType;
68 return static_cast<OutType>(obj);
69 }
70 };
71
72 typedef Caster<Q_None> LValueCaster;
73 typedef Caster<Q_Const> ConstCaster;
74 typedef Caster<Q_Volatile> VolatileCaster;
75 typedef Caster<Q_CV> CVCaster;
76 typedef Caster<Q_None, true> MoveCaster;
77 typedef Caster<Q_Const, true> MoveConstCaster;
78 typedef Caster<Q_Volatile, true> MoveVolatileCaster;
79 typedef Caster<Q_CV, true> MoveCVCaster;
80
81
82 template <class Tp>
makeConst(Tp & ref)83 Tp const& makeConst(Tp& ref) { return ref; }
84
85 template <class Tp>
makeConst(Tp * ptr)86 Tp const* makeConst(Tp* ptr) { return ptr; }
87
88 template <class Tp>
makeConst(std::reference_wrapper<Tp> & ref)89 std::reference_wrapper<const Tp> makeConst(std::reference_wrapper<Tp>& ref) {
90 return std::reference_wrapper<const Tp>(ref.get());
91 }
92
93 template <class Tp>
makeVolatile(Tp & ref)94 Tp volatile& makeVolatile(Tp& ref) { return ref; }
95
96 template <class Tp>
makeVolatile(Tp * ptr)97 Tp volatile* makeVolatile(Tp* ptr) { return ptr; }
98
99 template <class Tp>
makeVolatile(std::reference_wrapper<Tp> & ref)100 std::reference_wrapper<volatile Tp> makeVolatile(std::reference_wrapper<Tp>& ref) {
101 return std::reference_wrapper<volatile Tp>(ref.get());
102 }
103
104 template <class Tp>
makeCV(Tp & ref)105 Tp const volatile& makeCV(Tp& ref) { return ref; }
106
107 template <class Tp>
makeCV(Tp * ptr)108 Tp const volatile* makeCV(Tp* ptr) { return ptr; }
109
110 template <class Tp>
makeCV(std::reference_wrapper<Tp> & ref)111 std::reference_wrapper<const volatile Tp> makeCV(std::reference_wrapper<Tp>& ref) {
112 return std::reference_wrapper<const volatile Tp>(ref.get());
113 }
114
115 // A shorter name for 'static_cast'
116 template <class QualType, class Tp>
C_(Tp & v)117 QualType C_(Tp& v) { return static_cast<QualType>(v); };
118
119 //==============================================================================
120 // ArgType - A non-copyable type intended to be used as a dummy argument type
121 // to test functions.
122 struct ArgType {
123 int value;
valueArgType124 explicit ArgType(int val = 0) : value(val) {}
125 private:
126 ArgType(ArgType const&);
127 ArgType& operator=(ArgType const&);
128 };
129
130 //==============================================================================
131 // DerivedFromBase - A type that derives from its template argument 'Base'
132 template <class Base>
133 struct DerivedFromType : public Base {
DerivedFromTypeDerivedFromType134 DerivedFromType() : Base() {}
135 template <class Tp>
DerivedFromTypeDerivedFromType136 explicit DerivedFromType(Tp const& t) : Base(t) {}
137 };
138
139 //==============================================================================
140 // DerefToType - A type that dereferences to its template argument 'To'.
141 // The cv-ref qualifiers of the 'DerefToType' object do not propagate
142 // to the resulting 'To' object.
143 template <class To>
144 struct DerefToType {
145 To object;
146
DerefToTypeDerefToType147 DerefToType() {}
148
149 template <class Up>
DerefToTypeDerefToType150 explicit DerefToType(Up const& val) : object(val) {}
151
152 To& operator*() const volatile { return const_cast<To&>(object); }
153 };
154
155 //==============================================================================
156 // DerefPropToType - A type that dereferences to its template argument 'To'.
157 // The cv-ref qualifiers of the 'DerefPropToType' object propagate
158 // to the resulting 'To' object.
159 template <class To>
160 struct DerefPropType {
161 To object;
162
DerefPropTypeDerefPropType163 DerefPropType() {}
164
165 template <class Up>
DerefPropTypeDerefPropType166 explicit DerefPropType(Up const& val) : object(val) {}
167
168 #if TEST_STD_VER < 11
169 To& operator*() { return object; }
170 To const& operator*() const { return object; }
171 To volatile& operator*() volatile { return object; }
172 To const volatile& operator*() const volatile { return object; }
173 #else
174 To& operator*() & { return object; }
175 To const& operator*() const & { return object; }
176 To volatile& operator*() volatile & { return object; }
177 To const volatile& operator*() const volatile & { return object; }
178 To&& operator*() && { return static_cast<To &&>(object); }
179 To const&& operator*() const && { return static_cast<To const&&>(object); }
180 To volatile&& operator*() volatile && { return static_cast<To volatile&&>(object); }
181 To const volatile&& operator*() const volatile && { return static_cast<To const volatile&&>(object); }
182 #endif
183 };
184
185 //==============================================================================
186 // MethodID - A type that uniquely identifies a member function for a class.
187 // This type is used to communicate between the member functions being tested
188 // and the tests invoking them.
189 // - Test methods should call 'setUncheckedCall()' whenever they are invoked.
190 // - Tests consume the unchecked call using checkCall(<return-value>)` to assert
191 // that the method has been called and that the return value of `__invoke`
192 // matches what the method actually returned.
193 template <class T>
194 struct MethodID {
195 typedef void* IDType;
196
197 static int dummy; // A dummy memory location.
198 static void* id; // The "ID" is the value of this pointer.
199 static bool unchecked_call; // Has a call happened that has not been checked.
200
setUncheckedCallMethodID201 static void*& setUncheckedCall() {
202 assert(unchecked_call == false);
203 unchecked_call = true;
204 return id;
205 }
206
checkCalledMethodID207 static bool checkCalled(void*& return_value) {
208 bool old = unchecked_call;
209 unchecked_call = false;
210 return old && id == return_value && &id == &return_value;
211 }
212 };
213
214 template <class T> int MethodID<T>::dummy = 0;
215 template <class T> void* MethodID<T>::id = (void*)&MethodID<T>::dummy;
216 template <class T> bool MethodID<T>::unchecked_call = false;
217
218
219 //==============================================================================
220 // FunctionPtrID - Like MethodID but for free function pointers.
221 template <class T, T*>
222 struct FunctionPtrID {
223 static int dummy; // A dummy memory location.
224 static void* id; // The "ID" is the value of this pointer.
225 static bool unchecked_call; // Has a call happened that has not been checked.
226
setUncheckedCallFunctionPtrID227 static void*& setUncheckedCall() {
228 assert(unchecked_call == false);
229 unchecked_call = true;
230 return id;
231 }
232
checkCalledFunctionPtrID233 static bool checkCalled(void*& return_value) {
234 bool old = unchecked_call;
235 unchecked_call = false;
236 return old && id == return_value && &id == &return_value;
237 }
238 };
239
240 template <class T, T* Ptr> int FunctionPtrID<T, Ptr>::dummy = 0;
241 template <class T, T* Ptr> void* FunctionPtrID<T, Ptr>::id = (void*)&FunctionPtrID<T, Ptr>::dummy;
242 template <class T, T* Ptr> bool FunctionPtrID<T, Ptr>::unchecked_call = false;
243
244 //==============================================================================
245 // BasicTest - The basic test structure for everything except
246 // member object pointers.
247 // ID - The "Function Identifier" type used either MethodID or FunctionPtrID.
248 // Arity - The Arity of the call signature.
249 // ObjectCaster - The object transformation functor type.
250 // ArgCaster - The extra argument transformation functor type.
251 template <class ID, int Arity, class ObjectCaster = LValueCaster,
252 class ArgCaster = LValueCaster>
253 struct BasicTest {
254 template <class ObjectT>
runTestBasicTest255 void runTest(ObjectT& object) {
256 Int<Arity> A;
257 runTestImp(A, object);
258 }
259
260 template <class MethodPtr, class ObjectT>
runTestBasicTest261 void runTest(MethodPtr ptr, ObjectT& object) {
262 Int<Arity> A;
263 runTestImp(A, ptr, object);
264 }
265
266 private:
267 typedef void*& CallRet;
268 ObjectCaster object_cast;
269 ArgCaster arg_cast;
270 ArgType a0, a1, a2;
271
272 //==========================================================================
273 // BULLET 1, 2 AND 3 TEST METHODS
274 //==========================================================================
275 template <class MethodPtr, class ObjectT>
runTestImpBasicTest276 void runTestImp(Int<0>, MethodPtr ptr, ObjectT& object) {
277 {
278 static_assert((std::is_same<
279 decltype(std::__invoke(ptr, object_cast(object)))
280 , CallRet>::value), "");
281 assert(ID::unchecked_call == false);
282 CallRet ret = std::__invoke(ptr, object_cast(object));
283 assert(ID::checkCalled(ret));
284 }
285 #if TEST_STD_VER >= 11
286 {
287 static_assert((std::is_same<
288 decltype(std::__invoke_constexpr(ptr, object_cast(object)))
289 , CallRet>::value), "");
290 assert(ID::unchecked_call == false);
291 CallRet ret = std::__invoke_constexpr(ptr, object_cast(object));
292 assert(ID::checkCalled(ret));
293 }
294 #endif
295 }
296
297 template <class MethodPtr, class ObjectT>
runTestImpBasicTest298 void runTestImp(Int<1>, MethodPtr ptr, ObjectT& object) {
299 {
300 static_assert((std::is_same<
301 decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0)))
302 , CallRet>::value), "");
303 assert(ID::unchecked_call == false);
304 CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0));
305 assert(ID::checkCalled(ret));
306 }
307 #if TEST_STD_VER >= 11
308 {
309 static_assert((std::is_same<
310 decltype(std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0)))
311 , CallRet>::value), "");
312 assert(ID::unchecked_call == false);
313 CallRet ret = std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0));
314 assert(ID::checkCalled(ret));
315 }
316 #endif
317 }
318
319 template <class MethodPtr, class ObjectT>
runTestImpBasicTest320 void runTestImp(Int<2>, MethodPtr ptr, ObjectT& object) {
321 {
322 static_assert((std::is_same<
323 decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
324 , CallRet>::value), "");
325 assert(ID::unchecked_call == false);
326 CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
327 assert(ID::checkCalled(ret));
328 }
329 #if TEST_STD_VER >= 11
330 {
331 static_assert((std::is_same<
332 decltype(std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
333 , CallRet>::value), "");
334 assert(ID::unchecked_call == false);
335 CallRet ret = std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
336 assert(ID::checkCalled(ret));
337 }
338 #endif
339 }
340
341 template <class MethodPtr, class ObjectT>
runTestImpBasicTest342 void runTestImp(Int<3>, MethodPtr ptr, ObjectT& object) {
343 {
344 static_assert((std::is_same<
345 decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
346 , CallRet>::value), "");
347 assert(ID::unchecked_call == false);
348 CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
349 assert(ID::checkCalled(ret));
350 }
351 #if TEST_STD_VER >= 11
352 {
353 static_assert((std::is_same<
354 decltype(std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
355 , CallRet>::value), "");
356 assert(ID::unchecked_call == false);
357 CallRet ret = std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
358 assert(ID::checkCalled(ret));
359 }
360 #endif
361 }
362
363 //==========================================================================
364 // BULLET 7 TEST METHODS
365 //==========================================================================
366 template <class ObjectT>
runTestImpBasicTest367 void runTestImp(Int<0>, ObjectT& object) {
368 {
369 static_assert((std::is_same<
370 decltype(std::__invoke(object_cast(object)))
371 , CallRet>::value), "");
372 assert(ID::unchecked_call == false);
373 CallRet ret = std::__invoke(object_cast(object));
374 assert(ID::checkCalled(ret));
375 }
376 #if TEST_STD_VER >= 11
377 {
378 static_assert((std::is_same<
379 decltype(std::__invoke_constexpr(object_cast(object)))
380 , CallRet>::value), "");
381 assert(ID::unchecked_call == false);
382 CallRet ret = std::__invoke_constexpr(object_cast(object));
383 assert(ID::checkCalled(ret));
384 }
385 #endif
386 }
387
388 template <class ObjectT>
runTestImpBasicTest389 void runTestImp(Int<1>, ObjectT& object) {
390 {
391 static_assert((std::is_same<
392 decltype(std::__invoke(object_cast(object), arg_cast(a0)))
393 , CallRet>::value), "");
394 assert(ID::unchecked_call == false);
395 CallRet ret = std::__invoke(object_cast(object), arg_cast(a0));
396 assert(ID::checkCalled(ret));
397 }
398 #if TEST_STD_VER >= 11
399 {
400 static_assert((std::is_same<
401 decltype(std::__invoke_constexpr(object_cast(object), arg_cast(a0)))
402 , CallRet>::value), "");
403 assert(ID::unchecked_call == false);
404 CallRet ret = std::__invoke_constexpr(object_cast(object), arg_cast(a0));
405 assert(ID::checkCalled(ret));
406 }
407 #endif
408 }
409
410 template <class ObjectT>
runTestImpBasicTest411 void runTestImp(Int<2>, ObjectT& object) {
412 {
413 static_assert((std::is_same<
414 decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)))
415 , CallRet>::value), "");
416 assert(ID::unchecked_call == false);
417 CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1));
418 assert(ID::checkCalled(ret));
419 }
420 #if TEST_STD_VER >= 11
421 {
422 static_assert((std::is_same<
423 decltype(std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1)))
424 , CallRet>::value), "");
425 assert(ID::unchecked_call == false);
426 CallRet ret = std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1));
427 assert(ID::checkCalled(ret));
428 }
429 #endif
430 }
431
432 template <class ObjectT>
runTestImpBasicTest433 void runTestImp(Int<3>, ObjectT& object) {
434 {
435 static_assert((std::is_same<
436 decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
437 , CallRet>::value), "");
438 assert(ID::unchecked_call == false);
439 CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
440 assert(ID::checkCalled(ret));
441 }
442 #if TEST_STD_VER >= 11
443 {
444 static_assert((std::is_same<
445 decltype(std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
446 , CallRet>::value), "");
447 assert(ID::unchecked_call == false);
448 CallRet ret = std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
449 assert(ID::checkCalled(ret));
450 }
451 #endif
452 }
453 };
454
455 #endif // INVOKE_HELPERS_H
456