-
Notifications
You must be signed in to change notification settings - Fork 1
/
Relations.h
242 lines (204 loc) · 6.38 KB
/
Relations.h
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#pragma once
#include <string>
#include <regex>
#include <typeinfo>
namespace steamlein
{
namespace detail {
bool is_ancestor(std::type_info const& deriv, std::type_info const& base);
void const* manual_up_cast(void const* ptr, std::type_info const& deriv, std::type_info const& base);
}
struct Module;
struct Relation {
Relation(Module* owner);
virtual ~Relation() = default;
Relation(Relation const&) = delete;
Relation& operator=(Relation const&) = delete;
Relation(Relation&&) = delete;
Relation& operator=(Relation&&) = delete;
};
struct ProvideBase : Relation {
protected:
std::string name;
virtual ~ProvideBase() = default;
virtual void const* manualCast(std::type_info const& info) const = 0;
public:
ProvideBase(Module* owner, std::string const& _name) : Relation(owner), name(_name) {}
auto getName() const -> decltype(name) const& { return name; }
virtual std::type_info const& getType() const = 0;
template<typename T>
T const* as() const {
return static_cast<T const*>(manualCast(typeid(T)));
}
};
template<typename ...Args> struct Provide;
template<>
struct Provide<void> final : ProvideBase {
using ProvideBase::ProvideBase;
std::type_info const& getType() const override {
return typeid(void);
}
private:
void const* manualCast(std::type_info const&) const {
return nullptr;
}
};
template<typename T>
struct Provide<T> final : ProvideBase {
private:
T val;
void const* manualCast(std::type_info const& info) const {
if (detail::is_ancestor(getType(), info)) {
return detail::manual_up_cast(&val, getType(), info);
}
return nullptr;
}
public:
template<typename... Args>
Provide(Module* owner, std::string const& _name, Args &&... args)
: ProvideBase(owner, _name)
, val(std::forward<Args>(args)...) {}
T * operator->() { return &val; }
T const* operator->() const { return &val; }
T & operator* () { return val; }
T const& operator* () const { return val; }
T * get() { return &val; }
T const* get() const { return &val; }
std::type_info const& getType() const override {
return typeid(T);
}
};
// a view on a provide
struct ProvideView : Relation {
ProvideView(Module* owner, std::string const& _regex = ".+")
: Relation(owner)
, regex(_regex)
, selector(_regex)
{}
virtual bool setProvide(ProvideBase const* provide) = 0;
virtual std::type_info const& getType() const = 0;
std::string const& getSelector() const { return selector; }
protected:
std::regex regex;
std::string selector;
};
template<typename T>
struct TypedProvideView : ProvideView {
private:
T const* val {nullptr};
ProvideBase const* provide {nullptr};
public:
using ProvideView::ProvideView;
bool setProvide(ProvideBase const* _provide) override {
if (val) {
// only take the first successful assignment
return false;
}
if (std::regex_match(_provide->getName(), regex)) {
T const* castType = _provide->as<T>();
if (castType) {
val = castType;
provide = _provide;
}
return castType;
}
return false;
}
bool valid() const { return val; }
T const* operator->() const { return val; }
T const& operator*() const { return *val; }
T const* get() const { return val; }
ProvideBase const* getProvide() const { return provide; }
std::type_info const& getType() const override { return typeid(T); }
};
template<>
struct TypedProvideView<void> : ProvideView {
ProvideBase const* provide {nullptr};
public:
using ProvideView::ProvideView;
bool setProvide(ProvideBase const* _provide) override {
if (provide) {
// only take the first successful assignment
return false;
}
if (std::regex_match(_provide->getName(), regex)) {
provide = _provide;
return true;
}
return false;
}
bool valid() const { return provide; }
std::type_info const& getType() const override { return typeid(void); }
};
template<typename T>
struct TypedMultiProvideView : ProvideView {
using ContainerType = std::map<ProvideBase const*, T const*>;
private:
ContainerType vals;
public:
using ProvideView::ProvideView;
bool setProvide(ProvideBase const* provide) override {
if (std::regex_match(provide->getName(), regex)) {
T const* castType = provide->as<T>();
if (castType) {
vals.emplace(provide, castType);
}
return castType;
}
return false;
}
ContainerType const& get() const {
return vals;
}
std::type_info const& getType() const override {
return typeid(T);
}
};
template<>
struct TypedMultiProvideView<void> : ProvideView {
using ContainerType = std::vector<ProvideBase const*>;
private:
ContainerType vals;
public:
using ProvideView::ProvideView;
bool setProvide(ProvideBase const* provide) override {
if (std::regex_match(provide->getName(), regex)) {
vals.emplace_back(provide);
return true;
}
return false;
}
ContainerType const& get() const {
return vals;
}
std::type_info const& getType() const override {
return typeid(void);
}
};
struct AfterProvideBase {
virtual ~AfterProvideBase() = default;
};
struct BeforeProvideBase {
virtual ~BeforeProvideBase() = default;
};
template<typename T>
struct AfterProvide final : TypedProvideView<T>, AfterProvideBase {
using TypedProvideView<T>::TypedProvideView;
};
template<typename T>
struct BeforeProvide final : TypedProvideView<T>, BeforeProvideBase {
using TypedProvideView<T>::TypedProvideView;
};
template<typename T>
struct AfterProvides final : TypedMultiProvideView<T>, AfterProvideBase {
using TypedMultiProvideView<T>::TypedMultiProvideView;
};
template<typename T>
struct BeforeProvides final : TypedMultiProvideView<T>, BeforeProvideBase {
using TypedMultiProvideView<T>::TypedMultiProvideView;
};
template<typename T> using Require = AfterProvide<T>;
template<typename T> using Requires = AfterProvides<T>;
template<typename T> using Recycle = BeforeProvide<T>;
template<typename T> using Recycles = BeforeProvides<T>;
}