1*09467b48Spatrick //=== Registry.h - Linker-supported plugin registries -----------*- C++ -*-===//
2*09467b48Spatrick //
3*09467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*09467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*09467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*09467b48Spatrick //
7*09467b48Spatrick //===----------------------------------------------------------------------===//
8*09467b48Spatrick //
9*09467b48Spatrick // Defines a registry template for discovering pluggable modules.
10*09467b48Spatrick //
11*09467b48Spatrick //===----------------------------------------------------------------------===//
12*09467b48Spatrick 
13*09467b48Spatrick #ifndef LLVM_SUPPORT_REGISTRY_H
14*09467b48Spatrick #define LLVM_SUPPORT_REGISTRY_H
15*09467b48Spatrick 
16*09467b48Spatrick #include "llvm/ADT/STLExtras.h"
17*09467b48Spatrick #include "llvm/ADT/StringRef.h"
18*09467b48Spatrick #include "llvm/ADT/iterator_range.h"
19*09467b48Spatrick #include "llvm/Support/Compiler.h"
20*09467b48Spatrick #include "llvm/Support/DynamicLibrary.h"
21*09467b48Spatrick #include <memory>
22*09467b48Spatrick 
23*09467b48Spatrick namespace llvm {
24*09467b48Spatrick   /// A simple registry entry which provides only a name, description, and
25*09467b48Spatrick   /// no-argument constructor.
26*09467b48Spatrick   template <typename T>
27*09467b48Spatrick   class SimpleRegistryEntry {
28*09467b48Spatrick     StringRef Name, Desc;
29*09467b48Spatrick     std::unique_ptr<T> (*Ctor)();
30*09467b48Spatrick 
31*09467b48Spatrick   public:
SimpleRegistryEntry(StringRef N,StringRef D,std::unique_ptr<T> (* C)())32*09467b48Spatrick     SimpleRegistryEntry(StringRef N, StringRef D, std::unique_ptr<T> (*C)())
33*09467b48Spatrick         : Name(N), Desc(D), Ctor(C) {}
34*09467b48Spatrick 
getName()35*09467b48Spatrick     StringRef getName() const { return Name; }
getDesc()36*09467b48Spatrick     StringRef getDesc() const { return Desc; }
instantiate()37*09467b48Spatrick     std::unique_ptr<T> instantiate() const { return Ctor(); }
38*09467b48Spatrick   };
39*09467b48Spatrick 
40*09467b48Spatrick   /// A global registry used in conjunction with static constructors to make
41*09467b48Spatrick   /// pluggable components (like targets or garbage collectors) "just work" when
42*09467b48Spatrick   /// linked with an executable.
43*09467b48Spatrick   template <typename T>
44*09467b48Spatrick   class Registry {
45*09467b48Spatrick   public:
46*09467b48Spatrick     typedef T type;
47*09467b48Spatrick     typedef SimpleRegistryEntry<T> entry;
48*09467b48Spatrick 
49*09467b48Spatrick     class node;
50*09467b48Spatrick     class iterator;
51*09467b48Spatrick 
52*09467b48Spatrick   private:
53*09467b48Spatrick     Registry() = delete;
54*09467b48Spatrick 
55*09467b48Spatrick     friend class node;
56*09467b48Spatrick     static node *Head, *Tail;
57*09467b48Spatrick 
58*09467b48Spatrick   public:
59*09467b48Spatrick     /// Node in linked list of entries.
60*09467b48Spatrick     ///
61*09467b48Spatrick     class node {
62*09467b48Spatrick       friend class iterator;
63*09467b48Spatrick       friend Registry<T>;
64*09467b48Spatrick 
65*09467b48Spatrick       node *Next;
66*09467b48Spatrick       const entry& Val;
67*09467b48Spatrick 
68*09467b48Spatrick     public:
node(const entry & V)69*09467b48Spatrick       node(const entry &V) : Next(nullptr), Val(V) {}
70*09467b48Spatrick     };
71*09467b48Spatrick 
72*09467b48Spatrick     /// Add a node to the Registry: this is the interface between the plugin and
73*09467b48Spatrick     /// the executable.
74*09467b48Spatrick     ///
75*09467b48Spatrick     /// This function is exported by the executable and called by the plugin to
76*09467b48Spatrick     /// add a node to the executable's registry. Therefore it's not defined here
77*09467b48Spatrick     /// to avoid it being instantiated in the plugin and is instead defined in
78*09467b48Spatrick     /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
79*09467b48Spatrick     static void add_node(node *N);
80*09467b48Spatrick 
81*09467b48Spatrick     /// Iterators for registry entries.
82*09467b48Spatrick     ///
83*09467b48Spatrick     class iterator
84*09467b48Spatrick         : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
85*09467b48Spatrick                                             const entry> {
86*09467b48Spatrick       const node *Cur;
87*09467b48Spatrick 
88*09467b48Spatrick     public:
iterator(const node * N)89*09467b48Spatrick       explicit iterator(const node *N) : Cur(N) {}
90*09467b48Spatrick 
91*09467b48Spatrick       bool operator==(const iterator &That) const { return Cur == That.Cur; }
92*09467b48Spatrick       iterator &operator++() { Cur = Cur->Next; return *this; }
93*09467b48Spatrick       const entry &operator*() const { return Cur->Val; }
94*09467b48Spatrick     };
95*09467b48Spatrick 
96*09467b48Spatrick     // begin is not defined here in order to avoid usage of an undefined static
97*09467b48Spatrick     // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
98*09467b48Spatrick     static iterator begin();
end()99*09467b48Spatrick     static iterator end()   { return iterator(nullptr); }
100*09467b48Spatrick 
entries()101*09467b48Spatrick     static iterator_range<iterator> entries() {
102*09467b48Spatrick       return make_range(begin(), end());
103*09467b48Spatrick     }
104*09467b48Spatrick 
105*09467b48Spatrick     /// A static registration template. Use like such:
106*09467b48Spatrick     ///
107*09467b48Spatrick     ///   Registry<Collector>::Add<FancyGC>
108*09467b48Spatrick     ///   X("fancy-gc", "Newfangled garbage collector.");
109*09467b48Spatrick     ///
110*09467b48Spatrick     /// Use of this template requires that:
111*09467b48Spatrick     ///
112*09467b48Spatrick     ///  1. The registered subclass has a default constructor.
113*09467b48Spatrick     template <typename V>
114*09467b48Spatrick     class Add {
115*09467b48Spatrick       entry Entry;
116*09467b48Spatrick       node Node;
117*09467b48Spatrick 
CtorFn()118*09467b48Spatrick       static std::unique_ptr<T> CtorFn() { return std::make_unique<V>(); }
119*09467b48Spatrick 
120*09467b48Spatrick     public:
Add(StringRef Name,StringRef Desc)121*09467b48Spatrick       Add(StringRef Name, StringRef Desc)
122*09467b48Spatrick           : Entry(Name, Desc, CtorFn), Node(Entry) {
123*09467b48Spatrick         add_node(&Node);
124*09467b48Spatrick       }
125*09467b48Spatrick     };
126*09467b48Spatrick   };
127*09467b48Spatrick } // end namespace llvm
128*09467b48Spatrick 
129*09467b48Spatrick /// Instantiate a registry class.
130*09467b48Spatrick ///
131*09467b48Spatrick /// This provides template definitions of add_node, begin, and the Head and Tail
132*09467b48Spatrick /// pointers, then explicitly instantiates them. We could explicitly specialize
133*09467b48Spatrick /// them, instead of the two-step process of define then instantiate, but
134*09467b48Spatrick /// strictly speaking that's not allowed by the C++ standard (we would need to
135*09467b48Spatrick /// have explicit specialization declarations in all translation units where the
136*09467b48Spatrick /// specialization is used) so we don't.
137*09467b48Spatrick #define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
138*09467b48Spatrick   namespace llvm { \
139*09467b48Spatrick   template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
140*09467b48Spatrick   template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
141*09467b48Spatrick   template<typename T> \
142*09467b48Spatrick   void Registry<T>::add_node(typename Registry<T>::node *N) { \
143*09467b48Spatrick     if (Tail) \
144*09467b48Spatrick       Tail->Next = N; \
145*09467b48Spatrick     else \
146*09467b48Spatrick       Head = N; \
147*09467b48Spatrick     Tail = N; \
148*09467b48Spatrick   } \
149*09467b48Spatrick   template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
150*09467b48Spatrick     return iterator(Head); \
151*09467b48Spatrick   } \
152*09467b48Spatrick   template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
153*09467b48Spatrick   template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
154*09467b48Spatrick   template \
155*09467b48Spatrick   void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
156*09467b48Spatrick   template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
157*09467b48Spatrick   }
158*09467b48Spatrick 
159*09467b48Spatrick #endif // LLVM_SUPPORT_REGISTRY_H
160