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