Home | History | Annotate | Download | only in Support
      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:
     26     SimpleRegistryEntry(const char *N, const char *D, T *(*C)())
     27       : Name(N), Desc(D), Ctor(C)
     28     {}
     29 
     30     const char *getName() const { return Name; }
     31     const char *getDesc() const { return Desc; }
     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.
     47     static const char *nameof(const entry &Entry) { return Entry.getName(); }
     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 
     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:
     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:
    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 
    116     static iterator begin() { return iterator(Head); }
    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       ///
    147       void init() {
    148         for (iterator I = begin(), E = end(); I != E; ++I)
    149           registered(*I);
    150       }
    151 
    152     public:
    153       listener() : Prev(ListenerTail), Next(0) {
    154         if (Prev)
    155           Prev->Next = this;
    156         else
    157           ListenerHead = this;
    158         ListenerTail = this;
    159       }
    160 
    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 
    195       static T *CtorFn() { return new V(); }
    196 
    197     public:
    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