1 //=== Registry.h - Linker-supported plugin registries -----------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Defines a registry template for discovering pluggable modules. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_SUPPORT_REGISTRY_H 15 #define LLVM_SUPPORT_REGISTRY_H 16 17 #include "llvm/ADT/iterator_range.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/Support/Compiler.h" 20 #include <memory> 21 22 namespace llvm { 23 /// A simple registry entry which provides only a name, description, and 24 /// no-argument constructor. 25 template <typename T> 26 class SimpleRegistryEntry { 27 const char *Name, *Desc; 28 std::unique_ptr<T> (*Ctor)(); 29 30 public: SimpleRegistryEntry(const char * N,const char * D,std::unique_ptr<T> (* C)())31 SimpleRegistryEntry(const char *N, const char *D, std::unique_ptr<T> (*C)()) 32 : Name(N), Desc(D), Ctor(C) 33 {} 34 getName()35 const char *getName() const { return Name; } getDesc()36 const char *getDesc() const { return Desc; } instantiate()37 std::unique_ptr<T> instantiate() const { return Ctor(); } 38 }; 39 40 /// Traits for registry entries. If using other than SimpleRegistryEntry, it 41 /// is necessary to define an alternate traits class. 42 template <typename T> 43 class RegistryTraits { 44 RegistryTraits() = delete; 45 46 public: 47 typedef SimpleRegistryEntry<T> entry; 48 49 /// nameof/descof - Accessors for name and description of entries. These are 50 // used to generate help for command-line options. nameof(const entry & Entry)51 static const char *nameof(const entry &Entry) { return Entry.getName(); } descof(const entry & Entry)52 static const char *descof(const entry &Entry) { return Entry.getDesc(); } 53 }; 54 55 /// A global registry used in conjunction with static constructors to make 56 /// pluggable components (like targets or garbage collectors) "just work" when 57 /// linked with an executable. 58 template <typename T, typename U = RegistryTraits<T> > 59 class Registry { 60 public: 61 typedef U traits; 62 typedef typename U::entry entry; 63 64 class node; 65 class listener; 66 class iterator; 67 68 private: 69 Registry() = delete; 70 Announce(const entry & E)71 static void Announce(const entry &E) { 72 for (listener *Cur = ListenerHead; Cur; Cur = Cur->Next) 73 Cur->registered(E); 74 } 75 76 friend class node; 77 static node *Head, *Tail; 78 79 friend class listener; 80 static listener *ListenerHead, *ListenerTail; 81 82 public: 83 /// Node in linked list of entries. 84 /// 85 class node { 86 friend class iterator; 87 88 node *Next; 89 const entry& Val; 90 91 public: node(const entry & V)92 node(const entry& V) : Next(nullptr), Val(V) { 93 if (Tail) 94 Tail->Next = this; 95 else 96 Head = this; 97 Tail = this; 98 99 Announce(V); 100 } 101 }; 102 103 /// Iterators for registry entries. 104 /// 105 class iterator { 106 const node *Cur; 107 108 public: iterator(const node * N)109 explicit iterator(const node *N) : Cur(N) {} 110 111 bool operator==(const iterator &That) const { return Cur == That.Cur; } 112 bool operator!=(const iterator &That) const { return Cur != That.Cur; } 113 iterator &operator++() { Cur = Cur->Next; return *this; } 114 const entry &operator*() const { return Cur->Val; } 115 const entry *operator->() const { return &Cur->Val; } 116 }; 117 begin()118 static iterator begin() { return iterator(Head); } end()119 static iterator end() { return iterator(nullptr); } 120 entries()121 static iterator_range<iterator> entries() { 122 return make_range(begin(), end()); 123 } 124 125 /// Abstract base class for registry listeners, which are informed when new 126 /// entries are added to the registry. Simply subclass and instantiate: 127 /// 128 /// \code 129 /// class CollectorPrinter : public Registry<Collector>::listener { 130 /// protected: 131 /// void registered(const Registry<Collector>::entry &e) { 132 /// cerr << "collector now available: " << e->getName() << "\n"; 133 /// } 134 /// 135 /// public: 136 /// CollectorPrinter() { init(); } // Print those already registered. 137 /// }; 138 /// 139 /// CollectorPrinter Printer; 140 /// \endcode 141 class listener { 142 listener *Prev, *Next; 143 144 friend void Registry::Announce(const entry &E); 145 146 protected: 147 /// Called when an entry is added to the registry. 148 /// 149 virtual void registered(const entry &) = 0; 150 151 /// Calls 'registered' for each pre-existing entry. 152 /// init()153 void init() { 154 for (iterator I = begin(), E = end(); I != E; ++I) 155 registered(*I); 156 } 157 158 public: listener()159 listener() : Prev(ListenerTail), Next(nullptr) { 160 if (Prev) 161 Prev->Next = this; 162 else 163 ListenerHead = this; 164 ListenerTail = this; 165 } 166 ~listener()167 virtual ~listener() { 168 if (Next) 169 Next->Prev = Prev; 170 else 171 ListenerTail = Prev; 172 if (Prev) 173 Prev->Next = Next; 174 else 175 ListenerHead = Next; 176 } 177 }; 178 179 /// A static registration template. Use like such: 180 /// 181 /// Registry<Collector>::Add<FancyGC> 182 /// X("fancy-gc", "Newfangled garbage collector."); 183 /// 184 /// Use of this template requires that: 185 /// 186 /// 1. The registered subclass has a default constructor. 187 // 188 /// 2. The registry entry type has a constructor compatible with this 189 /// signature: 190 /// 191 /// entry(const char *Name, const char *ShortDesc, T *(*Ctor)()); 192 /// 193 /// If you have more elaborate requirements, then copy and modify. 194 /// 195 template <typename V> 196 class Add { 197 entry Entry; 198 node Node; 199 CtorFn()200 static std::unique_ptr<T> CtorFn() { return make_unique<V>(); } 201 202 public: Add(const char * Name,const char * Desc)203 Add(const char *Name, const char *Desc) 204 : Entry(Name, Desc, CtorFn), Node(Entry) {} 205 }; 206 207 /// Registry::Parser now lives in llvm/Support/RegistryParser.h. 208 }; 209 210 // Since these are defined in a header file, plugins must be sure to export 211 // these symbols. 212 213 template <typename T, typename U> 214 typename Registry<T,U>::node *Registry<T,U>::Head; 215 216 template <typename T, typename U> 217 typename Registry<T,U>::node *Registry<T,U>::Tail; 218 219 template <typename T, typename U> 220 typename Registry<T,U>::listener *Registry<T,U>::ListenerHead; 221 222 template <typename T, typename U> 223 typename Registry<T,U>::listener *Registry<T,U>::ListenerTail; 224 225 } // end namespace llvm 226 227 #endif // LLVM_SUPPORT_REGISTRY_H 228