aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm16/include/llvm/Support/Registry.h
blob: 720f3528566c5ff48677c68ea5557934a2327af4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#pragma once

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

//=== Registry.h - Linker-supported plugin registries -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Defines a registry template for discovering pluggable modules.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_REGISTRY_H
#define LLVM_SUPPORT_REGISTRY_H

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DynamicLibrary.h"
#include <memory>

namespace llvm {
  /// A simple registry entry which provides only a name, description, and
  /// no-argument constructor.
  template <typename T>
  class SimpleRegistryEntry {
    StringRef Name, Desc;
    std::unique_ptr<T> (*Ctor)();

  public:
    SimpleRegistryEntry(StringRef N, StringRef D, std::unique_ptr<T> (*C)())
        : Name(N), Desc(D), Ctor(C) {}

    StringRef getName() const { return Name; }
    StringRef getDesc() const { return Desc; }
    std::unique_ptr<T> instantiate() const { return Ctor(); }
  };

  /// A global registry used in conjunction with static constructors to make
  /// pluggable components (like targets or garbage collectors) "just work" when
  /// linked with an executable.
  template <typename T>
  class Registry {
  public:
    typedef T type;
    typedef SimpleRegistryEntry<T> entry;

    class node;
    class iterator;

  private:
    Registry() = delete;

    friend class node;
    static node *Head, *Tail;

  public:
    /// Node in linked list of entries.
    ///
    class node {
      friend class iterator;
      friend Registry<T>;

      node *Next;
      const entry& Val;

    public:
      node(const entry &V) : Next(nullptr), Val(V) {}
    };

    /// Add a node to the Registry: this is the interface between the plugin and
    /// the executable.
    ///
    /// This function is exported by the executable and called by the plugin to
    /// add a node to the executable's registry. Therefore it's not defined here
    /// to avoid it being instantiated in the plugin and is instead defined in
    /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
    static void add_node(node *N);

    /// Iterators for registry entries.
    ///
    class iterator
        : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
                                            const entry> {
      const node *Cur;

    public:
      explicit iterator(const node *N) : Cur(N) {}

      bool operator==(const iterator &That) const { return Cur == That.Cur; }
      iterator &operator++() { Cur = Cur->Next; return *this; }
      const entry &operator*() const { return Cur->Val; }
    };

    // begin is not defined here in order to avoid usage of an undefined static
    // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
    static iterator begin();
    static iterator end()   { return iterator(nullptr); }

    static iterator_range<iterator> entries() {
      return make_range(begin(), end());
    }

    /// A static registration template. Use like such:
    ///
    ///   Registry<Collector>::Add<FancyGC>
    ///   X("fancy-gc", "Newfangled garbage collector.");
    ///
    /// Use of this template requires that:
    ///
    ///  1. The registered subclass has a default constructor.
    template <typename V>
    class Add {
      entry Entry;
      node Node;

      static std::unique_ptr<T> CtorFn() { return std::make_unique<V>(); }

    public:
      Add(StringRef Name, StringRef Desc)
          : Entry(Name, Desc, CtorFn), Node(Entry) {
        add_node(&Node);
      }
    };
  };
} // end namespace llvm

/// Instantiate a registry class.
///
/// This provides template definitions of add_node, begin, and the Head and Tail
/// pointers, then explicitly instantiates them. We could explicitly specialize
/// them, instead of the two-step process of define then instantiate, but
/// strictly speaking that's not allowed by the C++ standard (we would need to
/// have explicit specialization declarations in all translation units where the
/// specialization is used) so we don't.
#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
  namespace llvm { \
  template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
  template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
  template<typename T> \
  void Registry<T>::add_node(typename Registry<T>::node *N) { \
    if (Tail) \
      Tail->Next = N; \
    else \
      Head = N; \
    Tail = N; \
  } \
  template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
    return iterator(Head); \
  } \
  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
  template \
  void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
  template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
  }

#endif // LLVM_SUPPORT_REGISTRY_H

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif