Don't require Registry specializations to define random static variables.
[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 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
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     /// nameof/descof - Accessors for name and description of entries. These are
48     //                  used to generate help for command-line options.
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   template <typename T, typename U>
239   typename Registry<T,U>::node *Registry<T,U>::Head;
240   
241   template <typename T, typename U>
242   typename Registry<T,U>::node *Registry<T,U>::Tail;
243   
244   template <typename T, typename U>
245   typename Registry<T,U>::listener *Registry<T,U>::ListenerHead;
246   
247   template <typename T, typename U>
248   typename Registry<T,U>::listener *Registry<T,U>::ListenerTail;
249   
250 }
251
252 #endif