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