1 #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 10 template <int I> 11 struct Int : public std::integral_constant<int, I> {}; 12 13 template <bool P> 14 struct Bool : public std::integral_constant<bool, P> {}; 15 16 struct Q_None { 17 template <class T> 18 struct apply { typedef T type; }; 19 }; 20 21 struct Q_Const { 22 template <class T> 23 struct apply { typedef T const type; }; 24 }; 25 26 struct Q_Volatile { 27 template <class T> 28 struct apply { typedef T volatile type; }; 29 }; 30 31 struct 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. 41 template <class QualTag, bool RValue = false> 42 struct 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 64 typedef Caster<Q_None> LValueCaster; 65 typedef Caster<Q_Const> ConstCaster; 66 typedef Caster<Q_Volatile> VolatileCaster; 67 typedef Caster<Q_CV> CVCaster; 68 typedef Caster<Q_None, true> MoveCaster; 69 typedef Caster<Q_Const, true> MoveConstCaster; 70 typedef Caster<Q_Volatile, true> MoveVolatileCaster; 71 typedef Caster<Q_CV, true> MoveCVCaster; 72 73 // A shorter name for 'static_cast' 74 template <class QualType, class Tp> 75 QualType 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. 80 struct ArgType { 81 int value; 82 explicit ArgType(int val = 0) : value(val) {} 83 private: 84 ArgType(ArgType const&); 85 ArgType& operator=(ArgType const&); 86 }; 87 88 //============================================================================== 89 // DerivedFromBase - A type that derives from it's template argument 'Base' 90 template <class Base> 91 struct 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. 101 template <class To> 102 struct 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. 117 template <class To> 118 struct 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. 151 template <class T> 152 struct 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 172 template <class T> int MethodID<T>::dummy = 0; 173 template <class T> void* MethodID<T>::id = (void*)&MethodID<T>::dummy; 174 template <class T> bool MethodID<T>::unchecked_call = false; 175 176 177 //============================================================================== 178 // FunctionPtrID - Like MethodID but for free function pointers. 179 template <class T, T*> 180 struct 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 198 template <class T, T* Ptr> int FunctionPtrID<T, Ptr>::dummy = 0; 199 template <class T, T* Ptr> void* FunctionPtrID<T, Ptr>::id = (void*)&FunctionPtrID<T, Ptr>::dummy; 200 template <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. 209 template <class ID, int Arity, class ObjectCaster = LValueCaster, 210 class ArgCaster = LValueCaster> 211 struct 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 224 private: 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 318