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