Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 1 | //===-- llvm/Support/ExtensibleRTTI.h - ExtensibleRTTI support --*- C++ -*-===// | 
| 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 | // \file | ||
| 10 | // | ||
| 11 | // Defines an extensible RTTI mechanism designed to work with Casting.h. | ||
| 12 | // | ||
| 13 | // Extensible RTTI differs from LLVM's primary RTTI mechanism (see | ||
| 14 | // llvm.org/docs/HowToSetUpLLVMStyleRTTI.html) by supporting open type | ||
| 15 | // hierarchies, where new types can be added from outside libraries without | ||
| 16 | // needing to change existing code. LLVM's primary RTTI mechanism should be | ||
| 17 | // preferred where possible, but where open hierarchies are needed this system | ||
| 18 | // can be used. | ||
| 19 | // | ||
| 20 | // The RTTIRoot class defines methods for comparing type ids. Implementations | ||
| 21 | // of these methods can be injected into new classes using the RTTIExtends | ||
| 22 | // class template. | ||
| 23 | // | ||
| 24 | // E.g. | ||
| 25 | // | ||
| 26 | //   @code{.cpp} | ||
| 27 | //   class MyBaseClass : public RTTIExtends<MyBaseClass, RTTIRoot> { | ||
| 28 | //   public: | ||
| 29 | //     static char ID; | ||
| 30 | //     virtual void foo() = 0; | ||
| 31 | //   }; | ||
| 32 | // | ||
| 33 | //   class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> { | ||
| 34 | //   public: | ||
| 35 | //     static char ID; | ||
| 36 | //     void foo() override {} | ||
| 37 | //   }; | ||
| 38 | // | ||
| 39 | //   class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> { | ||
| 40 | //   public: | ||
| 41 | //     static char ID; | ||
| 42 | //     void foo() override {} | ||
| 43 | //   }; | ||
| 44 | // | ||
| 45 | //   char MyBaseClass::ID = 0; | ||
| 46 | //   char MyDerivedClass1::ID = 0; | ||
| 47 | //   char MyDerivedClass2:: ID = 0; | ||
| 48 | // | ||
| 49 | //   void fn() { | ||
| 50 | //     std::unique_ptr<MyBaseClass> B = llvm::make_unique<MyDerivedClass1>(); | ||
| 51 | //     llvm::outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1". | ||
| 52 | //     llvm::outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1". | ||
| 53 | //     llvm::outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'. | ||
| 54 | //   } | ||
| 55 | // | ||
| 56 | //   @endcode | ||
| 57 | // | ||
| 58 | //===----------------------------------------------------------------------===// | ||
| 59 | |||
| 60 | #ifndef LLVM_SUPPORT_EXTENSIBLERTTI_H | ||
| 61 | #define LLVM_SUPPORT_EXTENSIBLERTTI_H | ||
| 62 | |||
| 63 | namespace llvm { | ||
| 64 | |||
| 65 | /// Base class for the extensible RTTI hierarchy. | ||
| 66 | /// | ||
| 67 | /// This class defines virtual methods, dynamicClassID and isA, that enable | ||
| 68 | /// type comparisons. | ||
| 69 | class RTTIRoot { | ||
| 70 | public: | ||
| 71 | virtual ~RTTIRoot() = default; | ||
| 72 | |||
| 73 |   /// Returns the class ID for this type. | ||
| 74 | static const void *classID() { return &ID; } | ||
| 75 | |||
| 76 |   /// Returns the class ID for the dynamic type of this RTTIRoot instance. | ||
| 77 | virtual const void *dynamicClassID() const = 0; | ||
| 78 | |||
| 79 |   /// Returns true if this class's ID matches the given class ID. | ||
| 80 | virtual bool isA(const void *const ClassID) const { | ||
| 81 | return ClassID == classID(); | ||
| 82 |   } | ||
| 83 | |||
| 84 |   /// Check whether this instance is a subclass of QueryT. | ||
| 85 | template <typename QueryT> | ||
| 86 | bool isA() const { return isA(QueryT::classID()); } | ||
| 87 | |||
| 88 | private: | ||
| 89 | virtual void anchor(); | ||
| 90 | |||
| 91 | static char ID; | ||
| 92 | }; | ||
| 93 | |||
| 94 | /// Inheritance utility for extensible RTTI. | ||
| 95 | /// | ||
| 96 | /// Supports single inheritance only: A class can only have one | ||
| 97 | /// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work), | ||
| 98 | /// though it can have many non-ExtensibleRTTI parents. | ||
| 99 | /// | ||
| 100 | /// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the | ||
| 101 | /// newly introduced type, and the *second* argument is the parent class. | ||
| 102 | /// | ||
| 103 | /// class MyType : public RTTIExtends<MyType, RTTIRoot> { | ||
| 104 | /// public: | ||
| 105 | ///   static char ID; | ||
| 106 | /// }; | ||
| 107 | /// | ||
| 108 | /// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> { | ||
| 109 | /// public: | ||
| 110 | ///   static char ID; | ||
| 111 | /// }; | ||
| 112 | /// | ||
| 113 | template <typename ThisT, typename ParentT> | ||
| 114 | class RTTIExtends : public ParentT { | ||
| 115 | public: | ||
| 116 |   // Inherit constructors from ParentT. | ||
| 117 | using ParentT::ParentT; | ||
| 118 | |||
| 119 | static const void *classID() { return &ThisT::ID; } | ||
| 120 | |||
| 121 | const void *dynamicClassID() const override { return &ThisT::ID; } | ||
| 122 | |||
| 123 | bool isA(const void *const ClassID) const override { | ||
| 124 | return ClassID == classID() || ParentT::isA(ClassID); | ||
| 125 |   } | ||
| 126 | |||
| 127 | static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); } | ||
| 128 | }; | ||
| 129 | |||
| 130 | } // end namespace llvm | ||
| 131 | |||
| 132 | #endif // LLVM_SUPPORT_EXTENSIBLERTTI_H |