My previous Registry.h header, as well as Collectors.h, which is the
[oota-llvm.git] / include / llvm / Support / Registry.h
1 //=== Registry.h - Linker-supported plugin registries -----------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Gordon Henriksen and is distributed under the
6 // University of Illinois Open Source 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
19 namespace 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(node *);
71     
72     friend class node;
73     static node *Head, *Tail;
74     
75     friend class listener;
76     static listener *ListenerHead, *ListenerTail;
77     
78   public:
79     class iterator;
80     
81     
82     /// Node in linked list of entries.
83     /// 
84     class node {
85       friend class iterator;
86       
87       node *Next;
88       const entry& Val;
89       
90     public:
91       node(const entry& V) : Next(0), Val(V) {
92         if (Tail)
93           Tail->Next = this;
94         else
95           Head = this;
96         Tail = this;
97         
98         Announce(V);
99       }
100     };
101     
102     
103     /// Iterators for registry entries.
104     /// 
105     class iterator {
106       const node *Cur;
107       
108     public:
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     
118     static iterator begin() { return iterator(Head); }
119     static iterator end()   { return iterator(0); }
120     
121     
122     /// Abstract base class for registry listeners, which are informed when new
123     /// entries are added to the registry. Simply subclass and instantiate:
124     /// 
125     ///   class CollectorPrinter : public Registry<Collector>::listener {
126     ///   protected:
127     ///     void registered(const Registry<Collector>::entry &e) {
128     ///       cerr << "collector now available: " << e->getName() << "\n";
129     ///     }
130     ///   
131     ///   public:
132     ///     CollectorPrinter() { init(); }  // Print those already registered.
133     ///   };
134     /// 
135     ///   CollectorPrinter Printer;
136     /// 
137     class listener {
138       listener *Prev, *Next;
139       
140       friend void Registry::Announce(const entry &E);
141       
142     protected:
143       /// Called when an entry is added to the registry.
144       /// 
145       virtual void registered(const entry &) = 0;
146       
147       /// Calls 'registered' for each pre-existing entry.
148       /// 
149       void init() {
150         for (iterator I = begin(), E = end(); I != E; ++I)
151           registered(*I);
152       }
153       
154     public:
155       listener() : Prev(ListenerTail), Next(0) {
156         if (Prev)
157           Prev->Next = this;
158         else
159           ListenerHead = this;
160         ListenerTail = this;
161       }
162       
163       virtual ~listener() {
164         if (Next)
165           Next->Prev = Prev;
166         else
167           ListenerTail = Prev;
168         if (Prev)
169           Prev->Next = Next;
170         else
171           ListenerHead = Next;
172       }
173     };
174     
175     
176     /// A static registration template. Use like such:
177     /// 
178     ///   Registry<Collector>::Add<FancyGC>
179     ///   X("fancy-gc", "Newfangled garbage collector.");
180     /// 
181     /// Use of this template requires that:
182     /// 
183     ///  1. The registered subclass has a default constructor.
184     // 
185     ///  2. The registry entry type has a constructor compatible with this
186     ///     signature:
187     /// 
188     ///       entry(const char *Name, const char *ShortDesc, T *(*Ctor)());
189     /// 
190     /// If you have more elaborate requirements, then copy and modify.
191     /// 
192     template <typename V>
193     class Add {
194       entry Entry;
195       node Node;
196       
197       static T *CtorFn() { return new V(); }
198       
199     public:
200       Add(const char *Name, const char *Desc)
201         : Entry(Name, Desc, CtorFn), Node(Entry) {}
202     };
203     
204     
205     /// A command-line parser for a registry. Use like such:
206     /// 
207     ///   static cl::opt<Registry<Collector>::entry, false,
208     ///                  Registry<Collector>::Parser>
209     ///   GCOpt("gc", cl::desc("Garbage collector to use."),
210     ///               cl::value_desc());
211     ///   
212     /// To make use of the value:
213     /// 
214     ///   Collector *TheCollector = GCOpt->instantiate();
215     /// 
216     class Parser : public cl::parser<const typename U::entry*>, public listener{
217       typedef U traits;
218       typedef typename U::entry entry;
219       
220     protected:
221       void registered(const entry &E) {
222         addLiteralOption(traits::nameof(E), &E, traits::descof(E));
223       }
224       
225     public:
226       void initialize(cl::Option &O) {
227         listener::init();
228         cl::parser<const typename U::entry*>::initialize(O);
229       }
230     };
231     
232     
233   private:
234     static void Announce(const entry &E) {
235       for (listener *Cur = ListenerHead; Cur; Cur = Cur->Next)
236         Cur->registered(E);
237     }
238     
239   };
240   
241 }
242
243 #endif