-
Notifications
You must be signed in to change notification settings - Fork 0
/
Link.h
182 lines (149 loc) · 4.9 KB
/
Link.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
#pragma once
#include <cstddef>
#include <map>
#include <regex>
#include <typeinfo>
#include <map>
namespace tngl {
struct Node;
enum class Flags : int {
Optional = 0,
CreateIfNotExist = 1,
Required = 2,
CreateRequired = 3,
};
constexpr Flags operator|(Flags const& l, Flags const& r) {
return static_cast<Flags>(static_cast<int>(l) | static_cast<int>(r));
}
constexpr Flags operator&(Flags const& l, Flags const& r) {
return static_cast<Flags>(static_cast<int>(l) & static_cast<int>(r));
}
struct LinkBase {
LinkBase(Node* owner, Flags _flags=Flags::Optional, std::string const& _regex="");
virtual ~LinkBase();
Flags getFlags() const {
return flags;
}
virtual bool canSetOther(Node const* other) const = 0;
virtual void unset(Node const* other) = 0;
virtual void setOther(Node* other, std::string const& name) = 0;
virtual bool satisfied() const = 0;
virtual bool isConnectedTo(Node const*) const = 0;
bool matchesName(std::string const& name) const {
return std::regex_match(name, regex);
}
virtual std::type_info const& getType() const = 0;
std::string const& getRegex() const {
return regexStr;
}
protected:
LinkBase(LinkBase&&) noexcept;
LinkBase& operator=(LinkBase&&) noexcept;
private:
Flags flags {Flags::Optional};
std::regex regex;
std::string regexStr;
Node* owner {nullptr};
};
template<typename T=Node>
struct Link : LinkBase {
private:
T* node {nullptr};
std::string otherName;
public:
using LinkBase::LinkBase;
Link(Link&&) noexcept = default;
Link& operator=(Link&&) noexcept = default;
std::type_info const& getType() const override {
return typeid(T);
}
bool canSetOther(Node const* other) const override {
return dynamic_cast<T const*>(other);
}
void setOther(Node* other, std::string const& name) override {
T* otherCast = dynamic_cast<T*>(other);
if (otherCast) {
node = otherCast;
otherName = name;
}
}
void unset(Node const* other) override {
if (dynamic_cast<T const*>(other) == node) {
node = nullptr;
otherName = "";
}
}
bool satisfied() const override {
return node;
}
bool isConnectedTo(Node const* other) const override {
return other == dynamic_cast<Node const*>(node);
}
T * operator->() { return node; }
T const* operator->() const { return node; }
T & operator *() { return *node; }
T const& operator *() const { return *node; }
T * get() { return node; }
T const* get() const { return node; }
operator bool() const { return node != nullptr; }
auto getOtherName() const -> decltype(otherName) const& {
return otherName;
}
};
template<typename T=Node>
struct Links : LinkBase {
private:
std::multimap<std::string, T*> nodes;
public:
Links(Node* owner, std::string const& _regex=".*")
: LinkBase(owner, Flags::Optional, _regex)
{}
Links(Node* owner, Flags flags, std::string const& _regex=".*")
: LinkBase(owner, flags, _regex)
{}
Links(Links&&) noexcept = default;
Links& operator=(Links&&) noexcept = default;
std::type_info const& getType() const override {
return typeid(T);
}
bool canSetOther(Node const* other) const override {
return dynamic_cast<T const*>(other);
}
void setOther(Node* other, std::string const& name) override {
T* otherCast = dynamic_cast<T*>(other);
if (otherCast) {
// dont double insert a single instance
auto find = [=](auto const& p) { return p.second == otherCast; };
auto it = std::find_if(nodes.begin(), nodes.end(), find);
if (it == nodes.end()) {
nodes.emplace(name, otherCast);
}
}
}
void unset(Node const* other) override {
T const* otherCast = dynamic_cast<T const*>(other);
auto find = [=](auto const& p) { return p.second == otherCast; };
while (true) {
auto it = std::find_if(nodes.begin(), nodes.end(), find);
if (it == nodes.end()) {
break;
}
nodes.erase(it);
}
}
bool satisfied() const override {
return false;
}
bool isConnectedTo(Node const* other) const override {
auto it = std::find_if(nodes.begin(), nodes.end(), [&](auto o) { return other == dynamic_cast<Node const*>(o.second);});
return it != nodes.end();
}
auto getNodes() const -> decltype(nodes) const& {
return nodes;
}
auto begin() -> decltype(nodes.begin()) { return nodes.begin(); }
auto end() -> decltype(nodes.end()) { return nodes.end(); }
auto begin() const -> decltype(nodes.cbegin()) { return nodes.cbegin(); }
auto end() const -> decltype(nodes.cend()) { return nodes.cend(); }
};
}