LLVM API Documentation
00001 //=== Registry.h - Linker-supported plugin registries -----------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // Defines a registry template for discovering pluggable modules. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #ifndef LLVM_SUPPORT_REGISTRY_H 00015 #define LLVM_SUPPORT_REGISTRY_H 00016 00017 #include "llvm/Support/CommandLine.h" 00018 00019 namespace llvm { 00020 /// A simple registry entry which provides only a name, description, and 00021 /// no-argument constructor. 00022 template <typename T> 00023 class SimpleRegistryEntry { 00024 const char *Name, *Desc; 00025 T *(*Ctor)(); 00026 00027 public: 00028 SimpleRegistryEntry(const char *N, const char *D, T *(*C)()) 00029 : Name(N), Desc(D), Ctor(C) 00030 {} 00031 00032 const char *getName() const { return Name; } 00033 const char *getDesc() const { return Desc; } 00034 T *instantiate() const { return Ctor(); } 00035 }; 00036 00037 00038 /// Traits for registry entries. If using other than SimpleRegistryEntry, it 00039 /// is necessary to define an alternate traits class. 00040 template <typename T> 00041 class RegistryTraits { 00042 RegistryTraits(); // Do not implement. 00043 00044 public: 00045 typedef SimpleRegistryEntry<T> entry; 00046 00047 /// nameof/descof - Accessors for name and description of entries. These are 00048 // used to generate help for command-line options. 00049 static const char *nameof(const entry &Entry) { return Entry.getName(); } 00050 static const char *descof(const entry &Entry) { return Entry.getDesc(); } 00051 }; 00052 00053 00054 /// A global registry used in conjunction with static constructors to make 00055 /// pluggable components (like targets or garbage collectors) "just work" when 00056 /// linked with an executable. 00057 template <typename T, typename U = RegistryTraits<T> > 00058 class Registry { 00059 public: 00060 typedef U traits; 00061 typedef typename U::entry entry; 00062 00063 class node; 00064 class listener; 00065 class iterator; 00066 00067 private: 00068 Registry(); // Do not implement. 00069 00070 static void Announce(const entry &E) { 00071 for (listener *Cur = ListenerHead; Cur; Cur = Cur->Next) 00072 Cur->registered(E); 00073 } 00074 00075 friend class node; 00076 static node *Head, *Tail; 00077 00078 friend class listener; 00079 static listener *ListenerHead, *ListenerTail; 00080 00081 public: 00082 class iterator; 00083 00084 00085 /// Node in linked list of entries. 00086 /// 00087 class node { 00088 friend class iterator; 00089 00090 node *Next; 00091 const entry& Val; 00092 00093 public: 00094 node(const entry& V) : Next(0), Val(V) { 00095 if (Tail) 00096 Tail->Next = this; 00097 else 00098 Head = this; 00099 Tail = this; 00100 00101 Announce(V); 00102 } 00103 }; 00104 00105 00106 /// Iterators for registry entries. 00107 /// 00108 class iterator { 00109 const node *Cur; 00110 00111 public: 00112 explicit iterator(const node *N) : Cur(N) {} 00113 00114 bool operator==(const iterator &That) const { return Cur == That.Cur; } 00115 bool operator!=(const iterator &That) const { return Cur != That.Cur; } 00116 iterator &operator++() { Cur = Cur->Next; return *this; } 00117 const entry &operator*() const { return Cur->Val; } 00118 const entry *operator->() const { return &Cur->Val; } 00119 }; 00120 00121 static iterator begin() { return iterator(Head); } 00122 static iterator end() { return iterator(0); } 00123 00124 00125 /// Abstract base class for registry listeners, which are informed when new 00126 /// entries are added to the registry. Simply subclass and instantiate: 00127 /// 00128 /// class CollectorPrinter : public Registry<Collector>::listener { 00129 /// protected: 00130 /// void registered(const Registry<Collector>::entry &e) { 00131 /// cerr << "collector now available: " << e->getName() << "\n"; 00132 /// } 00133 /// 00134 /// public: 00135 /// CollectorPrinter() { init(); } // Print those already registered. 00136 /// }; 00137 /// 00138 /// CollectorPrinter Printer; 00139 /// 00140 class listener { 00141 listener *Prev, *Next; 00142 00143 friend void Registry::Announce(const entry &E); 00144 00145 protected: 00146 /// Called when an entry is added to the registry. 00147 /// 00148 virtual void registered(const entry &) = 0; 00149 00150 /// Calls 'registered' for each pre-existing entry. 00151 /// 00152 void init() { 00153 for (iterator I = begin(), E = end(); I != E; ++I) 00154 registered(*I); 00155 } 00156 00157 public: 00158 listener() : Prev(ListenerTail), Next(0) { 00159 if (Prev) 00160 Prev->Next = this; 00161 else 00162 ListenerHead = this; 00163 ListenerTail = this; 00164 } 00165 00166 virtual ~listener() { 00167 if (Next) 00168 Next->Prev = Prev; 00169 else 00170 ListenerTail = Prev; 00171 if (Prev) 00172 Prev->Next = Next; 00173 else 00174 ListenerHead = Next; 00175 } 00176 }; 00177 00178 00179 /// A static registration template. Use like such: 00180 /// 00181 /// Registry<Collector>::Add<FancyGC> 00182 /// X("fancy-gc", "Newfangled garbage collector."); 00183 /// 00184 /// Use of this template requires that: 00185 /// 00186 /// 1. The registered subclass has a default constructor. 00187 // 00188 /// 2. The registry entry type has a constructor compatible with this 00189 /// signature: 00190 /// 00191 /// entry(const char *Name, const char *ShortDesc, T *(*Ctor)()); 00192 /// 00193 /// If you have more elaborate requirements, then copy and modify. 00194 /// 00195 template <typename V> 00196 class Add { 00197 entry Entry; 00198 node Node; 00199 00200 static T *CtorFn() { return new V(); } 00201 00202 public: 00203 Add(const char *Name, const char *Desc) 00204 : Entry(Name, Desc, CtorFn), Node(Entry) {} 00205 }; 00206 00207 00208 /// A command-line parser for a registry. Use like such: 00209 /// 00210 /// static cl::opt<Registry<Collector>::entry, false, 00211 /// Registry<Collector>::Parser> 00212 /// GCOpt("gc", cl::desc("Garbage collector to use."), 00213 /// cl::value_desc()); 00214 /// 00215 /// To make use of the value: 00216 /// 00217 /// Collector *TheCollector = GCOpt->instantiate(); 00218 /// 00219 class Parser : public cl::parser<const typename U::entry*>, public listener{ 00220 typedef U traits; 00221 typedef typename U::entry entry; 00222 00223 protected: 00224 void registered(const entry &E) { 00225 addLiteralOption(traits::nameof(E), &E, traits::descof(E)); 00226 } 00227 00228 public: 00229 void initialize(cl::Option &O) { 00230 listener::init(); 00231 cl::parser<const typename U::entry*>::initialize(O); 00232 } 00233 }; 00234 00235 }; 00236 00237 00238 template <typename T, typename U> 00239 typename Registry<T,U>::node *Registry<T,U>::Head; 00240 00241 template <typename T, typename U> 00242 typename Registry<T,U>::node *Registry<T,U>::Tail; 00243 00244 template <typename T, typename U> 00245 typename Registry<T,U>::listener *Registry<T,U>::ListenerHead; 00246 00247 template <typename T, typename U> 00248 typename Registry<T,U>::listener *Registry<T,U>::ListenerTail; 00249 00250 } 00251 00252 #endif
This web site is hosted by the Computer Science Department at the University of Illinois at Urbana-Champaign.