xref: /llvm-project/libcxx/test/libcxx/utilities/function.objects/func.require/invoke_helpers.h (revision 1b9c5f60aabdfd59096fb66b2bff55b7e71e1c5f)
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     }
286 
287     template <class MethodPtr, class ObjectT>
runTestImpBasicTest288     void runTestImp(Int<1>, MethodPtr ptr, ObjectT& object) {
289         {
290             static_assert((std::is_same<
291                 decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0)))
292               , CallRet>::value), "");
293             assert(ID::unchecked_call == false);
294             CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0));
295             assert(ID::checkCalled(ret));
296         }
297     }
298 
299     template <class MethodPtr, class ObjectT>
runTestImpBasicTest300     void runTestImp(Int<2>, MethodPtr ptr, ObjectT& object) {
301         {
302             static_assert((std::is_same<
303                 decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
304               , CallRet>::value), "");
305             assert(ID::unchecked_call == false);
306             CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
307             assert(ID::checkCalled(ret));
308         }
309     }
310 
311     template <class MethodPtr, class ObjectT>
runTestImpBasicTest312     void runTestImp(Int<3>, MethodPtr ptr, ObjectT& object) {
313         {
314             static_assert((std::is_same<
315                 decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
316               , CallRet>::value), "");
317             assert(ID::unchecked_call == false);
318             CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
319             assert(ID::checkCalled(ret));
320         }
321     }
322 
323     //==========================================================================
324     //                       BULLET 7 TEST METHODS
325     //==========================================================================
326     template <class ObjectT>
runTestImpBasicTest327     void runTestImp(Int<0>, ObjectT& object) {
328         {
329             static_assert((std::is_same<
330                 decltype(std::__invoke(object_cast(object)))
331               , CallRet>::value), "");
332             assert(ID::unchecked_call == false);
333             CallRet ret = std::__invoke(object_cast(object));
334             assert(ID::checkCalled(ret));
335         }
336     }
337 
338     template <class ObjectT>
runTestImpBasicTest339     void runTestImp(Int<1>, ObjectT& object) {
340         {
341             static_assert((std::is_same<
342                 decltype(std::__invoke(object_cast(object), arg_cast(a0)))
343               , CallRet>::value), "");
344             assert(ID::unchecked_call == false);
345             CallRet ret = std::__invoke(object_cast(object), arg_cast(a0));
346             assert(ID::checkCalled(ret));
347         }
348     }
349 
350     template <class ObjectT>
runTestImpBasicTest351     void runTestImp(Int<2>, ObjectT& object) {
352         {
353             static_assert((std::is_same<
354                 decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)))
355               , CallRet>::value), "");
356             assert(ID::unchecked_call == false);
357             CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1));
358             assert(ID::checkCalled(ret));
359         }
360     }
361 
362     template <class ObjectT>
runTestImpBasicTest363     void runTestImp(Int<3>, ObjectT& object) {
364         {
365             static_assert((std::is_same<
366                 decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
367               , CallRet>::value), "");
368             assert(ID::unchecked_call == false);
369             CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
370             assert(ID::checkCalled(ret));
371         }
372     }
373 };
374 
375 #endif // INVOKE_HELPERS_H
376