brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.4 KiB · a883112 Raw
242 lines · cpp
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// <functional>10 11// INVOKE (f, t1, t2, ..., tN)12 13//------------------------------------------------------------------------------14// TESTING INVOKE(f, t1, t2, ..., tN)15//   - Bullet 1 -- (t1.*f)(t2, ..., tN)16//   - Bullet 2 -- (t1.get().*f)(t2, ..., tN) // t1 is a reference_wrapper17//   - Bullet 3 -- ((*t1).*f)(t2, ..., tN)18//19// Overview:20//    Bullets 1, 2 and 3 handle the case where 'f' is a pointer to member function.21//    Bullet 1 only handles the cases where t1 is an object of type T or a22//    type derived from 'T'. Bullet 2 handles the case where 't1' is a reference23//    wrapper and bullet 3 handles all other cases.24//25// Concerns:26//   1) cv-qualified member function signatures are accepted.27//   2) reference qualified member function signatures are accepted.28//   3) member functions with varargs at the end are accepted.29//   4) The arguments are perfect forwarded to the member function call.30//   5) Classes that are publicly derived from 'T' are accepted as the call object31//   6) All types that dereference to T or a type derived from T can be used32//      as the call object.33//   7) Pointers to T or a type derived from T can be used as the call object.34//   8) Reference return types are properly deduced.35//   9) reference_wrappers are properly handled and unwrapped.36//37//38// Plan:39//   1) Create a class that contains a set, 'S', of non-static functions.40//     'S' should include functions that cover every single combination41//      of qualifiers and varargs for arities of 0, 1 and 2 (C-1,2,3).42//      The argument types used in the functions should be non-copyable (C-4).43//      The functions should return 'MethodID::setUncheckedCall()'.44//45//   2) Create a set of supported call object, 'Objs', of different types46//      and behaviors. (C-5,6,7)47//48//   3) Attempt to call each function, 'f', in 'S' with each call object, 'c',49//      in 'Objs'. After every attempted call to 'f' check that 'f' was50//      actually called using 'MethodID::checkCalled(<return-value>)'51//52//       3b) If 'f' is reference qualified call 'f' with the properly qualified53//       call object. Otherwise call 'f' with lvalue call objects.54//55//       3a) If 'f' is const, volatile, or cv qualified then call it with call56//       objects that are equally or less cv-qualified.57 58#include <functional>59#include <cassert>60#include <type_traits>61#include <utility>62 63#include "test_macros.h"64#include "invoke_helpers.h"65 66//==============================================================================67// MemFun03 - C++03 compatible set of test member functions.68struct MemFun03 {69    typedef void*& R;70#define F(...) \71    R f(__VA_ARGS__) { return MethodID<R(MemFun03::*)(__VA_ARGS__)>::setUncheckedCall(); } \72    R f(__VA_ARGS__) const { return MethodID<R(MemFun03::*)(__VA_ARGS__) const>::setUncheckedCall(); } \73    R f(__VA_ARGS__) volatile { return MethodID<R(MemFun03::*)(__VA_ARGS__) volatile>::setUncheckedCall(); } \74    R f(__VA_ARGS__) const volatile { return MethodID<R(MemFun03::*)(__VA_ARGS__) const volatile>::setUncheckedCall(); }75#76    F()77    F(...)78    F(ArgType&)79    F(ArgType&, ...)80    F(ArgType&, ArgType&)81    F(ArgType&, ArgType&, ...)82    F(ArgType&, ArgType&, ArgType&)83    F(ArgType&, ArgType&, ArgType&, ...)84#undef F85public:86    MemFun03() {}87private:88    MemFun03(MemFun03 const&);89    MemFun03& operator=(MemFun03 const&);90};91 92 93//==============================================================================94// TestCase - A test case for a single member function.95//   ClassType - The type of the class being tested.96//   CallSig   - The function signature of the method being tested.97//   Arity     - the arity of 'CallSig'98//   CV        - the cv qualifiers of 'CallSig' represented as a type tag.99//   RValue    - The method is RValue qualified.100//   ArgRValue - Call the method with RValue arguments.101template <class ClassType, class CallSig, int Arity, class CV,102          bool RValue = false, bool ArgRValue = false>103struct TestCaseImp {104public:105 106    static void run() { TestCaseImp().doTest(); }107 108private:109    //==========================================================================110    // TEST DISPATCH111    void doTest() {112         // (Plan-2) Create test call objects.113        typedef ClassType T;114        typedef DerivedFromType<T> D;115        T obj;116        T* obj_ptr = &obj;117        D der;118        D* der_ptr = &der;119        DerefToType<T>   dref;120        DerefPropType<T> dref2;121        std::reference_wrapper<T> rref(obj);122        std::reference_wrapper<D> drref(der);123 124         // (Plan-3) Dispatch based on the CV tags.125        CV tag;126        Bool<!RValue> NotRValue;127        runTestDispatch(tag,  obj);128        runTestDispatch(tag,  der);129        runTestDispatch(tag, dref2);130        runTestDispatchIf(NotRValue, tag, dref);131        runTestDispatchIf(NotRValue, tag, obj_ptr);132        runTestDispatchIf(NotRValue, tag, der_ptr);133    }134 135    template <class QT, class Tp>136    void runTestDispatchIf(Bool<true>, QT q, Tp& v) {137        runTestDispatch(q, v);138    }139 140    template <class QT, class Tp>141    void runTestDispatchIf(Bool<false>, QT, Tp&) {142    }143 144    template <class Tp>145    void runTestDispatch(Q_None, Tp& v) {146        runTest(v);147    }148 149    template <class Tp>150    void runTestDispatch(Q_Const, Tp& v) {151        runTest(v);152        runTest(makeConst(v));153    }154 155    template <class Tp>156    void runTestDispatch(Q_Volatile, Tp& v) {157        runTest(v);158        runTest(makeVolatile(v));159 160    }161 162    template <class Tp>163    void runTestDispatch(Q_CV, Tp& v) {164        runTest(v);165        runTest(makeConst(v));166        runTest(makeVolatile(v));167        runTest(makeCV(v));168    }169 170    template <class T>171    void runTest(const std::reference_wrapper<T>& obj) {172        typedef Caster<Q_None, RValue> SCast;173        typedef Caster<Q_None, ArgRValue> ACast;174        typedef CallSig (ClassType::*MemPtr);175        // Delegate test to logic in invoke_helpers.h176        BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b;177        b.runTest( (MemPtr)&ClassType::f, obj);178    }179 180    template <class T>181    void runTest(T* obj) {182        typedef Caster<Q_None, RValue> SCast;183        typedef Caster<Q_None, ArgRValue> ACast;184        typedef CallSig (ClassType::*MemPtr);185        // Delegate test to logic in invoke_helpers.h186        BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b;187        b.runTest( (MemPtr)&ClassType::f, obj);188    }189 190    template <class Obj>191    void runTest(Obj& obj) {192        typedef Caster<Q_None, RValue> SCast;193        typedef Caster<Q_None, ArgRValue> ACast;194        typedef CallSig (ClassType::*MemPtr);195        // Delegate test to logic in invoke_helpers.h196        BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b;197        b.runTest( (MemPtr)&ClassType::f, obj);198    }199};200 201template <class Sig, int Arity, class CV>202struct TestCase : public TestCaseImp<MemFun03, Sig, Arity, CV> {};203 204int main(int, char**) {205    typedef void*& R;206    typedef ArgType A;207    TestCase<R(),                                   0, Q_None>::run();208    TestCase<R() const,                             0, Q_Const>::run();209    TestCase<R() volatile,                          0, Q_Volatile>::run();210    TestCase<R() const volatile,                    0, Q_CV>::run();211    TestCase<R(...),                                0, Q_None>::run();212    TestCase<R(...) const,                          0, Q_Const>::run();213    TestCase<R(...) volatile,                       0, Q_Volatile>::run();214    TestCase<R(...) const volatile,                 0, Q_CV>::run();215    TestCase<R(A&),                                 1, Q_None>::run();216    TestCase<R(A&) const,                           1, Q_Const>::run();217    TestCase<R(A&) volatile,                        1, Q_Volatile>::run();218    TestCase<R(A&) const volatile,                  1, Q_CV>::run();219    TestCase<R(A&, ...),                            1, Q_None>::run();220    TestCase<R(A&, ...) const,                      1, Q_Const>::run();221    TestCase<R(A&, ...) volatile,                   1, Q_Volatile>::run();222    TestCase<R(A&, ...) const volatile,             1, Q_CV>::run();223    TestCase<R(A&, A&),                             2, Q_None>::run();224    TestCase<R(A&, A&) const,                       2, Q_Const>::run();225    TestCase<R(A&, A&) volatile,                    2, Q_Volatile>::run();226    TestCase<R(A&, A&) const volatile,              2, Q_CV>::run();227    TestCase<R(A&, A&, ...),                        2, Q_None>::run();228    TestCase<R(A&, A&, ...) const,                  2, Q_Const>::run();229    TestCase<R(A&, A&, ...) volatile,               2, Q_Volatile>::run();230    TestCase<R(A&, A&, ...) const volatile,         2, Q_CV>::run();231    TestCase<R(A&, A&, A&),                         3, Q_None>::run();232    TestCase<R(A&, A&, A&) const,                   3, Q_Const>::run();233    TestCase<R(A&, A&, A&) volatile,                3, Q_Volatile>::run();234    TestCase<R(A&, A&, A&) const volatile,          3, Q_CV>::run();235    TestCase<R(A&, A&, A&, ...),                    3, Q_None>::run();236    TestCase<R(A&, A&, A&, ...) const,              3, Q_Const>::run();237    TestCase<R(A&, A&, A&, ...) volatile,           3, Q_Volatile>::run();238    TestCase<R(A&, A&, A&, ...) const volatile,     3, Q_CV>::run();239 240  return 0;241}242