forked from scylladb/scylladb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclass_registrator.hh
205 lines (182 loc) · 7.04 KB
/
class_registrator.hh
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
* Copyright (C) 2015-present ScyllaDB
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
*/
#pragma once
#include <memory>
#include <seastar/core/shared_ptr.hh>
#include <seastar/core/sstring.hh>
#include "seastarx.hh"
class no_such_class : public std::runtime_error {
public:
using runtime_error::runtime_error;
};
inline bool is_class_name_qualified(std::string_view class_name) {
return class_name.find_last_of('.') != std::string_view::npos;
}
// BaseType is a base type of a type hierarchy that this registry will hold
// Args... are parameters for object's constructor
template<typename BaseType, typename... Args>
class nonstatic_class_registry {
template<typename T, typename ResultType = typename T::ptr_type>
requires requires (typename T::ptr_type ptr) {
{ ptr.get() } -> std::same_as<T*>;
}
struct result_for;
template<typename T>
struct result_for<T, std::unique_ptr<T>> {
typedef std::unique_ptr<T> type;
template<typename Impl>
static inline type make(Args&& ...args) {
return std::make_unique<Impl>(std::forward<Args>(args)...);
}
};
template<typename T>
struct result_for<T, seastar::shared_ptr<T>> {
typedef seastar::shared_ptr<T> type;
template<typename Impl>
static inline type make(Args&& ...args) {
return seastar::make_shared<Impl>(std::forward<Args>(args)...);
}
};
template<typename T>
struct result_for<T, seastar::lw_shared_ptr<T>> {
typedef seastar::lw_shared_ptr<T> type;
// lw_shared is not (yet?) polymorph, thus having automatic
// instantiation of it makes no sense. This way we get a nice
// compilation error if someone messes up.
};
template<typename T>
struct result_for<T, std::shared_ptr<T>> {
typedef std::shared_ptr<T> type;
template<typename Impl>
static inline type make(Args&& ...args) {
return std::make_shared<Impl>(std::forward<Args>(args)...);
}
};
template<typename T, typename D>
struct result_for<T, std::unique_ptr<T, D>> {
typedef std::unique_ptr<T, D> type;
template<typename Impl>
static inline type make(Args&& ...args) {
return std::make_unique<Impl, D>(std::forward<Args>(args)...);
}
};
public:
using result_type = typename BaseType::ptr_type;
using creator_type = std::function<result_type(Args...)>;
private:
std::unordered_map<sstring, creator_type> _classes;
public:
void register_class(sstring name, creator_type creator);
template<typename T>
void register_class(sstring name);
result_type create(const sstring& name, Args&&...);
std::unordered_map<sstring, creator_type>& classes() {
return _classes;
}
const std::unordered_map<sstring, creator_type>& classes() const {
return _classes;
}
sstring to_qualified_class_name(std::string_view class_name) const;
};
template<typename BaseType, typename... Args>
void nonstatic_class_registry<BaseType, Args...>::register_class(sstring name, typename nonstatic_class_registry<BaseType, Args...>::creator_type creator) {
classes().emplace(name, std::move(creator));
}
template<typename BaseType, typename... Args>
template<typename T>
void nonstatic_class_registry<BaseType, Args...>::register_class(sstring name) {
register_class(name, &result_for<BaseType>::template make<T>);
}
template<typename BaseType, typename... Args>
sstring nonstatic_class_registry<BaseType, Args...>::to_qualified_class_name(std::string_view class_name) const {
if (is_class_name_qualified(class_name)) {
return sstring(class_name);
} else {
const auto& classes{nonstatic_class_registry<BaseType, Args...>::classes()};
const auto it = std::ranges::find_if(classes, [class_name](const auto& registered_class) {
// the fully qualified name contains the short name
auto i = registered_class.first.find_last_of('.');
return i != sstring::npos && registered_class.first.compare(i + 1, sstring::npos, class_name) == 0;
});
if (it == classes.end()) {
return sstring(class_name);
}
return it->first;
}
}
// BaseType is a base type of a type hierarchy that this registry will hold
// Args... are parameters for object's constructor
template<typename BaseType, typename... Args>
class class_registry {
using base_registry = nonstatic_class_registry<BaseType, Args...>;
static base_registry& registry() {
static base_registry the_registry;
return the_registry;
}
public:
using result_type = typename base_registry::result_type;
using creator_type = std::function<result_type(Args...)>;
public:
static void register_class(sstring name, creator_type creator) {
registry().register_class(std::move(name), std::move(creator));
}
template<typename T>
static void register_class(sstring name) {
registry().template register_class<T>(std::move(name));
}
template <typename... U>
static result_type create(const sstring& name, U&&... a) {
return registry().create(name, std::forward<U>(a)...);
}
static std::unordered_map<sstring, creator_type>& classes() {
return registry().classes();
}
static sstring to_qualified_class_name(std::string_view class_name) {
return registry().to_qualified_class_name(class_name);
}
};
template<typename BaseType, typename T, typename... Args>
struct class_registrator {
class_registrator(const sstring& name) {
class_registry<BaseType, Args...>::template register_class<T>(name);
}
class_registrator(const sstring& name, typename class_registry<BaseType, Args...>::creator_type creator) {
class_registry<BaseType, Args...>::register_class(name, creator);
}
};
template<typename BaseType, typename... Args>
typename nonstatic_class_registry<BaseType, Args...>::result_type nonstatic_class_registry<BaseType, Args...>::create(const sstring& name, Args&&... args) {
auto it = classes().find(name);
if (it == classes().end()) {
throw no_such_class(sstring("unable to find class '") + name + sstring("'"));
}
return it->second(std::forward<Args>(args)...);
}
template<typename BaseType, typename... Args>
typename class_registry<BaseType, Args...>::result_type create_object(const sstring& name, Args&&... args) {
return class_registry<BaseType, Args...>::create(name, std::forward<Args>(args)...);
}
class qualified_name {
sstring _qname;
public:
qualified_name(std::string_view pkg_pfx, std::string_view name)
: _qname(is_class_name_qualified(name) ? name : make_sstring(pkg_pfx, name))
{}
operator const sstring&() const {
return _qname;
}
};
class unqualified_name {
sstring _qname;
public:
unqualified_name(std::string_view pkg_pfx, std::string_view name)
: _qname(name.compare(0, pkg_pfx.size(), pkg_pfx) == 0 ? name.substr(pkg_pfx.size()) : name)
{}
operator const sstring&() const {
return _qname;
}
};