blob: 0583b624da31499b2e807d3340e15e602c07d709 [file] [log] [blame]
Dan Albert1d4a1ed2016-05-25 22:36:09 -07001#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
10template <int I>
11struct Int : public std::integral_constant<int, I> {};
12
13template <bool P>
14struct Bool : public std::integral_constant<bool, P> {};
15
16struct Q_None {
17 template <class T>
18 struct apply { typedef T type; };
19};
20
21struct Q_Const {
22 template <class T>
23 struct apply { typedef T const type; };
24};
25
26struct Q_Volatile {
27 template <class T>
28 struct apply { typedef T volatile type; };
29};
30
31struct 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.
41template <class QualTag, bool RValue = false>
42struct 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
58 operator()(T& obj) const {
59 typedef typename apply<T>::type OutType;
60 return static_cast<OutType>(obj);
61 }
62};
63
64typedef Caster<Q_None> LValueCaster;
65typedef Caster<Q_Const> ConstCaster;
66typedef Caster<Q_Volatile> VolatileCaster;
67typedef Caster<Q_CV> CVCaster;
68typedef Caster<Q_None, true> MoveCaster;
69typedef Caster<Q_Const, true> MoveConstCaster;
70typedef Caster<Q_Volatile, true> MoveVolatileCaster;
71typedef Caster<Q_CV, true> MoveCVCaster;
72
73// A shorter name for 'static_cast'
74template <class QualType, class Tp>
75QualType 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.
80struct ArgType {
81 int value;
82 explicit ArgType(int val = 0) : value(val) {}
83private:
84 ArgType(ArgType const&);
85 ArgType& operator=(ArgType const&);
86};
87
88//==============================================================================
89// DerivedFromBase - A type that derives from it's template argument 'Base'
90template <class Base>
91struct DerivedFromType : public Base {
92 DerivedFromType() : Base() {}
93 template <class Tp>
94 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.
101template <class To>
102struct DerefToType {
103 To object;
104
105 DerefToType() {}
106
107 template <class Up>
108 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.
117template <class To>
118struct DerefPropType {
119 To object;
120
121 DerefPropType() {}
122
123 template <class Up>
124 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.
151template <class T>
152struct 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
159 static void*& setUncheckedCall() {
160 assert(unchecked_call == false);
161 unchecked_call = true;
162 return id;
163 }
164
165 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
172template <class T> int MethodID<T>::dummy = 0;
173template <class T> void* MethodID<T>::id = (void*)&MethodID<T>::dummy;
174template <class T> bool MethodID<T>::unchecked_call = false;
175
176
177//==============================================================================
178// FunctionPtrID - Like MethodID but for free function pointers.
179template <class T, T*>
180struct 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
185 static void*& setUncheckedCall() {
186 assert(unchecked_call == false);
187 unchecked_call = true;
188 return id;
189 }
190
191 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
198template <class T, T* Ptr> int FunctionPtrID<T, Ptr>::dummy = 0;
199template <class T, T* Ptr> void* FunctionPtrID<T, Ptr>::id = (void*)&FunctionPtrID<T, Ptr>::dummy;
200template <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.
209template <class ID, int Arity, class ObjectCaster = LValueCaster,
210 class ArgCaster = LValueCaster>
211struct BasicTest {
212 template <class ObjectT>
213 void runTest(ObjectT& object) {
214 Int<Arity> A;
215 runTestImp(A, object);
216 }
217
218 template <class MethodPtr, class ObjectT>
219 void runTest(MethodPtr ptr, ObjectT& object) {
220 Int<Arity> A;
221 runTestImp(A, ptr, object);
222 }
223
224private:
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>
234 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>
244 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>
254 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>
264 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>
277 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>
287 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>
297 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>
307 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