]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/include/rocksdb/utilities/object_registry.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / rocksdb / include / rocksdb / utilities / object_registry.h
1 // Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5
6 #pragma once
7
8 #ifndef ROCKSDB_LITE
9
10 #include <functional>
11 #include <memory>
12 #include <regex>
13 #include <string>
14 #include <unordered_map>
15 #include <vector>
16 #include "rocksdb/status.h"
17
18 namespace ROCKSDB_NAMESPACE {
19 class Logger;
20 // Returns a new T when called with a string. Populates the std::unique_ptr
21 // argument if granting ownership to caller.
22 template <typename T>
23 using FactoryFunc =
24 std::function<T*(const std::string&, std::unique_ptr<T>*, std::string*)>;
25
26 class ObjectLibrary {
27 public:
28 // Base class for an Entry in the Registry.
29 class Entry {
30 public:
31 virtual ~Entry() {}
32 Entry(const std::string& name) : name_(std::move(name)) {}
33
34 // Checks to see if the target matches this entry
35 virtual bool matches(const std::string& target) const {
36 return name_ == target;
37 }
38 const std::string& Name() const { return name_; }
39
40 private:
41 const std::string name_; // The name of the Entry
42 }; // End class Entry
43
44 // An Entry containing a FactoryFunc for creating new Objects
45 template <typename T>
46 class FactoryEntry : public Entry {
47 public:
48 FactoryEntry(const std::string& name, FactoryFunc<T> f)
49 : Entry(name), pattern_(std::move(name)), factory_(std::move(f)) {}
50 ~FactoryEntry() override {}
51 bool matches(const std::string& target) const override {
52 return std::regex_match(target, pattern_);
53 }
54 // Creates a new T object.
55 T* NewFactoryObject(const std::string& target, std::unique_ptr<T>* guard,
56 std::string* msg) const {
57 return factory_(target, guard, msg);
58 }
59
60 private:
61 std::regex pattern_; // The pattern for this entry
62 FactoryFunc<T> factory_;
63 }; // End class FactoryEntry
64 public:
65 // Finds the entry matching the input name and type
66 const Entry* FindEntry(const std::string& type,
67 const std::string& name) const;
68 void Dump(Logger* logger) const;
69
70 // Registers the factory with the library for the pattern.
71 // If the pattern matches, the factory may be used to create a new object.
72 template <typename T>
73 const FactoryFunc<T>& Register(const std::string& pattern,
74 const FactoryFunc<T>& factory) {
75 std::unique_ptr<Entry> entry(new FactoryEntry<T>(pattern, factory));
76 AddEntry(T::Type(), entry);
77 return factory;
78 }
79 // Returns the default ObjectLibrary
80 static std::shared_ptr<ObjectLibrary>& Default();
81
82 private:
83 // Adds the input entry to the list for the given type
84 void AddEntry(const std::string& type, std::unique_ptr<Entry>& entry);
85
86 // ** FactoryFunctions for this loader, organized by type
87 std::unordered_map<std::string, std::vector<std::unique_ptr<Entry>>> entries_;
88 };
89
90 // The ObjectRegistry is used to register objects that can be created by a
91 // name/pattern at run-time where the specific implementation of the object may
92 // not be known in advance.
93 class ObjectRegistry {
94 public:
95 static std::shared_ptr<ObjectRegistry> NewInstance();
96
97 ObjectRegistry();
98
99 void AddLibrary(const std::shared_ptr<ObjectLibrary>& library) {
100 libraries_.emplace_back(library);
101 }
102
103 // Creates a new T using the factory function that was registered with a
104 // pattern that matches the provided "target" string according to
105 // std::regex_match.
106 //
107 // If no registered functions match, returns nullptr. If multiple functions
108 // match, the factory function used is unspecified.
109 //
110 // Populates res_guard with result pointer if caller is granted ownership.
111 template <typename T>
112 T* NewObject(const std::string& target, std::unique_ptr<T>* guard,
113 std::string* errmsg) {
114 guard->reset();
115 const auto* basic = FindEntry(T::Type(), target);
116 if (basic != nullptr) {
117 const auto* factory =
118 static_cast<const ObjectLibrary::FactoryEntry<T>*>(basic);
119 return factory->NewFactoryObject(target, guard, errmsg);
120 } else {
121 *errmsg = std::string("Could not load ") + T::Type();
122 return nullptr;
123 }
124 }
125
126 // Creates a new unique T using the input factory functions.
127 // Returns OK if a new unique T was successfully created
128 // Returns NotSupported if the type/target could not be created
129 // Returns InvalidArgument if the factory return an unguarded object
130 // (meaning it cannot be managed by a unique ptr)
131 template <typename T>
132 Status NewUniqueObject(const std::string& target,
133 std::unique_ptr<T>* result) {
134 std::string errmsg;
135 T* ptr = NewObject(target, result, &errmsg);
136 if (ptr == nullptr) {
137 return Status::NotSupported(errmsg, target);
138 } else if (*result) {
139 return Status::OK();
140 } else {
141 return Status::InvalidArgument(std::string("Cannot make a unique ") +
142 T::Type() + " from unguarded one ",
143 target);
144 }
145 }
146
147 // Creates a new shared T using the input factory functions.
148 // Returns OK if a new shared T was successfully created
149 // Returns NotSupported if the type/target could not be created
150 // Returns InvalidArgument if the factory return an unguarded object
151 // (meaning it cannot be managed by a shared ptr)
152 template <typename T>
153 Status NewSharedObject(const std::string& target,
154 std::shared_ptr<T>* result) {
155 std::string errmsg;
156 std::unique_ptr<T> guard;
157 T* ptr = NewObject(target, &guard, &errmsg);
158 if (ptr == nullptr) {
159 return Status::NotSupported(errmsg, target);
160 } else if (guard) {
161 result->reset(guard.release());
162 return Status::OK();
163 } else {
164 return Status::InvalidArgument(std::string("Cannot make a shared ") +
165 T::Type() + " from unguarded one ",
166 target);
167 }
168 }
169
170 // Creates a new static T using the input factory functions.
171 // Returns OK if a new static T was successfully created
172 // Returns NotSupported if the type/target could not be created
173 // Returns InvalidArgument if the factory return a guarded object
174 // (meaning it is managed by a unique ptr)
175 template <typename T>
176 Status NewStaticObject(const std::string& target, T** result) {
177 std::string errmsg;
178 std::unique_ptr<T> guard;
179 T* ptr = NewObject(target, &guard, &errmsg);
180 if (ptr == nullptr) {
181 return Status::NotSupported(errmsg, target);
182 } else if (guard.get()) {
183 return Status::InvalidArgument(std::string("Cannot make a static ") +
184 T::Type() + " from a guarded one ",
185 target);
186 } else {
187 *result = ptr;
188 return Status::OK();
189 }
190 }
191
192 // Dump the contents of the registry to the logger
193 void Dump(Logger* logger) const;
194
195 private:
196 const ObjectLibrary::Entry* FindEntry(const std::string& type,
197 const std::string& name) const;
198
199 // The set of libraries to search for factories for this registry.
200 // The libraries are searched in reverse order (back to front) when
201 // searching for entries.
202 std::vector<std::shared_ptr<ObjectLibrary>> libraries_;
203 };
204 } // namespace ROCKSDB_NAMESPACE
205 #endif // ROCKSDB_LITE