Registry.h revision 84e66db653835cee524fc51185ed614f1d6ac628
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/Support/CommandLine.h" 18 19namespace llvm { 20 /// A simple registry entry which provides only a name, description, and 21 /// no-argument constructor. 22 template <typename T> 23 class SimpleRegistryEntry { 24 const char *Name, *Desc; 25 T *(*Ctor)(); 26 27 public: 28 SimpleRegistryEntry(const char *N, const char *D, T *(*C)()) 29 : Name(N), Desc(D), Ctor(C) 30 {} 31 32 const char *getName() const { return Name; } 33 const char *getDesc() const { return Desc; } 34 T *instantiate() const { return Ctor(); } 35 }; 36 37 38 /// Traits for registry entries. If using other than SimpleRegistryEntry, it 39 /// is necessary to define an alternate traits class. 40 template <typename T> 41 class RegistryTraits { 42 RegistryTraits(); // Do not implement. 43 44 public: 45 typedef SimpleRegistryEntry<T> entry; 46 47 /// Accessors for . 48 /// 49 static const char *nameof(const entry &Entry) { return Entry.getName(); } 50 static const char *descof(const entry &Entry) { return Entry.getDesc(); } 51 }; 52 53 54 /// A global registry used in conjunction with static constructors to make 55 /// pluggable components (like targets or garbage collectors) "just work" when 56 /// linked with an executable. 57 template <typename T, typename U = RegistryTraits<T> > 58 class Registry { 59 public: 60 typedef U traits; 61 typedef typename U::entry entry; 62 63 class node; 64 class listener; 65 class iterator; 66 67 private: 68 Registry(); // Do not implement. 69 70 static void Announce(const entry &E) { 71 for (listener *Cur = ListenerHead; Cur; Cur = Cur->Next) 72 Cur->registered(E); 73 } 74 75 friend class node; 76 static node *Head, *Tail; 77 78 friend class listener; 79 static listener *ListenerHead, *ListenerTail; 80 81 public: 82 class iterator; 83 84 85 /// Node in linked list of entries. 86 /// 87 class node { 88 friend class iterator; 89 90 node *Next; 91 const entry& Val; 92 93 public: 94 node(const entry& V) : Next(0), Val(V) { 95 if (Tail) 96 Tail->Next = this; 97 else 98 Head = this; 99 Tail = this; 100 101 Announce(V); 102 } 103 }; 104 105 106 /// Iterators for registry entries. 107 /// 108 class iterator { 109 const node *Cur; 110 111 public: 112 explicit iterator(const node *N) : Cur(N) {} 113 114 bool operator==(const iterator &That) const { return Cur == That.Cur; } 115 bool operator!=(const iterator &That) const { return Cur != That.Cur; } 116 iterator &operator++() { Cur = Cur->Next; return *this; } 117 const entry &operator*() const { return Cur->Val; } 118 const entry *operator->() const { return &Cur->Val; } 119 }; 120 121 static iterator begin() { return iterator(Head); } 122 static iterator end() { return iterator(0); } 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 /// class CollectorPrinter : public Registry<Collector>::listener { 129 /// protected: 130 /// void registered(const Registry<Collector>::entry &e) { 131 /// cerr << "collector now available: " << e->getName() << "\n"; 132 /// } 133 /// 134 /// public: 135 /// CollectorPrinter() { init(); } // Print those already registered. 136 /// }; 137 /// 138 /// CollectorPrinter Printer; 139 /// 140 class listener { 141 listener *Prev, *Next; 142 143 friend void Registry::Announce(const entry &E); 144 145 protected: 146 /// Called when an entry is added to the registry. 147 /// 148 virtual void registered(const entry &) = 0; 149 150 /// Calls 'registered' for each pre-existing entry. 151 /// 152 void init() { 153 for (iterator I = begin(), E = end(); I != E; ++I) 154 registered(*I); 155 } 156 157 public: 158 listener() : Prev(ListenerTail), Next(0) { 159 if (Prev) 160 Prev->Next = this; 161 else 162 ListenerHead = this; 163 ListenerTail = this; 164 } 165 166 virtual ~listener() { 167 if (Next) 168 Next->Prev = Prev; 169 else 170 ListenerTail = Prev; 171 if (Prev) 172 Prev->Next = Next; 173 else 174 ListenerHead = Next; 175 } 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 200 static T *CtorFn() { return new V(); } 201 202 public: 203 Add(const char *Name, const char *Desc) 204 : Entry(Name, Desc, CtorFn), Node(Entry) {} 205 }; 206 207 208 /// A command-line parser for a registry. Use like such: 209 /// 210 /// static cl::opt<Registry<Collector>::entry, false, 211 /// Registry<Collector>::Parser> 212 /// GCOpt("gc", cl::desc("Garbage collector to use."), 213 /// cl::value_desc()); 214 /// 215 /// To make use of the value: 216 /// 217 /// Collector *TheCollector = GCOpt->instantiate(); 218 /// 219 class Parser : public cl::parser<const typename U::entry*>, public listener{ 220 typedef U traits; 221 typedef typename U::entry entry; 222 223 protected: 224 void registered(const entry &E) { 225 addLiteralOption(traits::nameof(E), &E, traits::descof(E)); 226 } 227 228 public: 229 void initialize(cl::Option &O) { 230 listener::init(); 231 cl::parser<const typename U::entry*>::initialize(O); 232 } 233 }; 234 235 }; 236 237} 238 239#endif 240