359 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef INVOKE_HELPERS_H10#define INVOKE_HELPERS_H11 12#include <type_traits>13#include <cassert>14#include <functional>15 16#include "test_macros.h"17 18template <int I>19struct Int : public std::integral_constant<int, I> {};20 21template <bool P>22struct Bool : public std::integral_constant<bool, P> {};23 24struct Q_None {25 template <class T>26 struct apply { typedef T type; };27};28 29struct Q_Const {30 template <class T>31 struct apply { typedef T const type; };32};33 34struct Q_Volatile {35 template <class T>36 struct apply { typedef T volatile type; };37};38 39struct 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 category45// 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.49template <class QualTag, bool RValue = false>50struct 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 typedef CVType& type;56 };57 58 template <class T>59 typename apply<T>::type60 operator()(T& obj) const {61 typedef typename apply<T>::type OutType;62 return static_cast<OutType>(obj);63 }64};65 66typedef Caster<Q_None> LValueCaster;67typedef Caster<Q_Const> ConstCaster;68typedef Caster<Q_Volatile> VolatileCaster;69typedef Caster<Q_CV> CVCaster;70typedef Caster<Q_None, true> MoveCaster;71typedef Caster<Q_Const, true> MoveConstCaster;72typedef Caster<Q_Volatile, true> MoveVolatileCaster;73typedef Caster<Q_CV, true> MoveCVCaster;74 75 76template <class Tp>77Tp const& makeConst(Tp& ref) { return ref; }78 79template <class Tp>80Tp const* makeConst(Tp* ptr) { return ptr; }81 82template <class Tp>83std::reference_wrapper<const Tp> makeConst(std::reference_wrapper<Tp>& ref) {84 return std::reference_wrapper<const Tp>(ref.get());85}86 87template <class Tp>88Tp volatile& makeVolatile(Tp& ref) { return ref; }89 90template <class Tp>91Tp volatile* makeVolatile(Tp* ptr) { return ptr; }92 93template <class Tp>94std::reference_wrapper<volatile Tp> makeVolatile(std::reference_wrapper<Tp>& ref) {95 return std::reference_wrapper<volatile Tp>(ref.get());96}97 98template <class Tp>99Tp const volatile& makeCV(Tp& ref) { return ref; }100 101template <class Tp>102Tp const volatile* makeCV(Tp* ptr) { return ptr; }103 104template <class Tp>105std::reference_wrapper<const volatile Tp> makeCV(std::reference_wrapper<Tp>& ref) {106 return std::reference_wrapper<const volatile Tp>(ref.get());107}108 109// A shorter name for 'static_cast'110template <class QualType, class Tp>111QualType C_(Tp& v) { return static_cast<QualType>(v); };112 113//==============================================================================114// ArgType - A non-copyable type intended to be used as a dummy argument type115// to test functions.116struct ArgType {117 int value;118 explicit ArgType(int val = 0) : value(val) {}119private:120 ArgType(ArgType const&);121 ArgType& operator=(ArgType const&);122};123 124//==============================================================================125// DerivedFromBase - A type that derives from its template argument 'Base'126template <class Base>127struct DerivedFromType : public Base {128 DerivedFromType() : Base() {}129 template <class Tp>130 explicit DerivedFromType(Tp const& t) : Base(t) {}131};132 133//==============================================================================134// DerefToType - A type that dereferences to its template argument 'To'.135// The cv-ref qualifiers of the 'DerefToType' object do not propagate136// to the resulting 'To' object.137template <class To>138struct DerefToType {139 To object;140 141 DerefToType() {}142 143 template <class Up>144 explicit DerefToType(Up const& val) : object(val) {}145 146 To& operator*() const volatile { return const_cast<To&>(object); }147};148 149//==============================================================================150// DerefPropToType - A type that dereferences to its template argument 'To'.151// The cv-ref qualifiers of the 'DerefPropToType' object propagate152// to the resulting 'To' object.153template <class To>154struct DerefPropType {155 To object;156 157 DerefPropType() {}158 159 template <class Up>160 explicit DerefPropType(Up const& val) : object(val) {}161 162 To& operator*() { return object; }163 To const& operator*() const { return object; }164 To volatile& operator*() volatile { return object; }165 To const volatile& operator*() const volatile { return object; }166};167 168//==============================================================================169// MethodID - A type that uniquely identifies a member function for a class.170// This type is used to communicate between the member functions being tested171// and the tests invoking them.172// - Test methods should call 'setUncheckedCall()' whenever they are invoked.173// - Tests consume the unchecked call using checkCall(<return-value>)` to assert174// that the method has been called and that the return value of `__invoke`175// matches what the method actually returned.176template <class T>177struct MethodID {178 typedef void* IDType;179 180 static int dummy; // A dummy memory location.181 static void* id; // The "ID" is the value of this pointer.182 static bool unchecked_call; // Has a call happened that has not been checked.183 184 static void*& setUncheckedCall() {185 assert(unchecked_call == false);186 unchecked_call = true;187 return id;188 }189 190 static bool checkCalled(void*& return_value) {191 bool old = unchecked_call;192 unchecked_call = false;193 return old && id == return_value && &id == &return_value;194 }195};196 197template <class T> int MethodID<T>::dummy = 0;198template <class T> void* MethodID<T>::id = (void*)&MethodID<T>::dummy;199template <class T> bool MethodID<T>::unchecked_call = false;200 201 202//==============================================================================203// FunctionPtrID - Like MethodID but for free function pointers.204template <class T, T*>205struct FunctionPtrID {206 static int dummy; // A dummy memory location.207 static void* id; // The "ID" is the value of this pointer.208 static bool unchecked_call; // Has a call happened that has not been checked.209 210 static void*& setUncheckedCall() {211 assert(unchecked_call == false);212 unchecked_call = true;213 return id;214 }215 216 static bool checkCalled(void*& return_value) {217 bool old = unchecked_call;218 unchecked_call = false;219 return old && id == return_value && &id == &return_value;220 }221};222 223template <class T, T* Ptr> int FunctionPtrID<T, Ptr>::dummy = 0;224template <class T, T* Ptr> void* FunctionPtrID<T, Ptr>::id = (void*)&FunctionPtrID<T, Ptr>::dummy;225template <class T, T* Ptr> bool FunctionPtrID<T, Ptr>::unchecked_call = false;226 227//==============================================================================228// BasicTest - The basic test structure for everything except229// member object pointers.230// ID - The "Function Identifier" type used either MethodID or FunctionPtrID.231// Arity - The Arity of the call signature.232// ObjectCaster - The object transformation functor type.233// ArgCaster - The extra argument transformation functor type.234template <class ID, int Arity, class ObjectCaster = LValueCaster,235 class ArgCaster = LValueCaster>236struct BasicTest {237 template <class ObjectT>238 void runTest(ObjectT& object) {239 Int<Arity> A;240 runTestImp(A, object);241 }242 243 template <class MethodPtr, class ObjectT>244 void runTest(MethodPtr ptr, ObjectT& object) {245 Int<Arity> A;246 runTestImp(A, ptr, object);247 }248 249private:250 typedef void*& CallRet;251 ObjectCaster object_cast;252 ArgCaster arg_cast;253 ArgType a0, a1, a2;254 255 //==========================================================================256 // BULLET 1, 2 AND 3 TEST METHODS257 //==========================================================================258 template <class MethodPtr, class ObjectT>259 void runTestImp(Int<0>, MethodPtr ptr, ObjectT& object) {260 {261 static_assert((std::is_same<262 decltype(std::__invoke(ptr, object_cast(object)))263 , CallRet>::value), "");264 assert(ID::unchecked_call == false);265 CallRet ret = std::__invoke(ptr, object_cast(object));266 assert(ID::checkCalled(ret));267 }268 }269 270 template <class MethodPtr, class ObjectT>271 void runTestImp(Int<1>, MethodPtr ptr, ObjectT& object) {272 {273 static_assert((std::is_same<274 decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0)))275 , CallRet>::value), "");276 assert(ID::unchecked_call == false);277 CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0));278 assert(ID::checkCalled(ret));279 }280 }281 282 template <class MethodPtr, class ObjectT>283 void runTestImp(Int<2>, MethodPtr ptr, ObjectT& object) {284 {285 static_assert((std::is_same<286 decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))287 , CallRet>::value), "");288 assert(ID::unchecked_call == false);289 CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));290 assert(ID::checkCalled(ret));291 }292 }293 294 template <class MethodPtr, class ObjectT>295 void runTestImp(Int<3>, MethodPtr ptr, ObjectT& object) {296 {297 static_assert((std::is_same<298 decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))299 , CallRet>::value), "");300 assert(ID::unchecked_call == false);301 CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));302 assert(ID::checkCalled(ret));303 }304 }305 306 //==========================================================================307 // BULLET 7 TEST METHODS308 //==========================================================================309 template <class ObjectT>310 void runTestImp(Int<0>, ObjectT& object) {311 {312 static_assert((std::is_same<313 decltype(std::__invoke(object_cast(object)))314 , CallRet>::value), "");315 assert(ID::unchecked_call == false);316 CallRet ret = std::__invoke(object_cast(object));317 assert(ID::checkCalled(ret));318 }319 }320 321 template <class ObjectT>322 void runTestImp(Int<1>, ObjectT& object) {323 {324 static_assert((std::is_same<325 decltype(std::__invoke(object_cast(object), arg_cast(a0)))326 , CallRet>::value), "");327 assert(ID::unchecked_call == false);328 CallRet ret = std::__invoke(object_cast(object), arg_cast(a0));329 assert(ID::checkCalled(ret));330 }331 }332 333 template <class ObjectT>334 void runTestImp(Int<2>, ObjectT& object) {335 {336 static_assert((std::is_same<337 decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)))338 , CallRet>::value), "");339 assert(ID::unchecked_call == false);340 CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1));341 assert(ID::checkCalled(ret));342 }343 }344 345 template <class ObjectT>346 void runTestImp(Int<3>, ObjectT& object) {347 {348 static_assert((std::is_same<349 decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))350 , CallRet>::value), "");351 assert(ID::unchecked_call == false);352 CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));353 assert(ID::checkCalled(ret));354 }355 }356};357 358#endif // INVOKE_HELPERS_H359