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