]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2016-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
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). | |
7c673cae FG |
5 | |
6 | #pragma once | |
7 | ||
8 | #ifndef ROCKSDB_LITE | |
9 | ||
10 | #include <functional> | |
11 | #include <memory> | |
12 | #include <regex> | |
13 | #include <string> | |
f67539c2 | 14 | #include <unordered_map> |
7c673cae | 15 | #include <vector> |
f67539c2 | 16 | #include "rocksdb/status.h" |
7c673cae | 17 | |
f67539c2 TL |
18 | namespace ROCKSDB_NAMESPACE { |
19 | class Logger; | |
494da23a TL |
20 | // Returns a new T when called with a string. Populates the std::unique_ptr |
21 | // argument if granting ownership to caller. | |
7c673cae | 22 | template <typename T> |
f67539c2 TL |
23 | using FactoryFunc = |
24 | std::function<T*(const std::string&, std::unique_ptr<T>*, std::string*)>; | |
25 | ||
26 | class ObjectLibrary { | |
7c673cae | 27 | public: |
f67539c2 TL |
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 | } | |
7c673cae | 59 | |
f67539c2 TL |
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(); | |
7c673cae | 81 | |
f67539c2 TL |
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); | |
7c673cae | 85 | |
f67539c2 TL |
86 | // ** FactoryFunctions for this loader, organized by type |
87 | std::unordered_map<std::string, std::vector<std::unique_ptr<Entry>>> entries_; | |
7c673cae FG |
88 | }; |
89 | ||
f67539c2 TL |
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); | |
7c673cae | 101 | } |
7c673cae | 102 | |
f67539c2 TL |
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 | |
20effc67 | 128 | // Returns NotSupported if the type/target could not be created |
f67539c2 TL |
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) { | |
20effc67 | 137 | return Status::NotSupported(errmsg, target); |
f67539c2 TL |
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 | } | |
7c673cae | 146 | |
f67539c2 TL |
147 | // Creates a new shared T using the input factory functions. |
148 | // Returns OK if a new shared T was successfully created | |
20effc67 | 149 | // Returns NotSupported if the type/target could not be created |
f67539c2 TL |
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) { | |
20effc67 | 159 | return Status::NotSupported(errmsg, target); |
f67539c2 TL |
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 | } | |
7c673cae | 169 | |
f67539c2 TL |
170 | // Creates a new static T using the input factory functions. |
171 | // Returns OK if a new static T was successfully created | |
20effc67 | 172 | // Returns NotSupported if the type/target could not be created |
f67539c2 TL |
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) { | |
20effc67 | 181 | return Status::NotSupported(errmsg, target); |
f67539c2 TL |
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(); | |
7c673cae FG |
189 | } |
190 | } | |
7c673cae | 191 | |
f67539c2 TL |
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; | |
7c673cae | 198 | |
f67539c2 TL |
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 | |
7c673cae | 205 | #endif // ROCKSDB_LITE |