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