-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtree.hpp
More file actions
160 lines (146 loc) · 5.09 KB
/
tree.hpp
File metadata and controls
160 lines (146 loc) · 5.09 KB
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
#ifndef TREE_H
#define TREE_H
#define LOCK LockGuard<RMutex> _lock{_mutex};
template<typename T> requires std::same_as<T, ID> or std::same_as<T, PID>
struct Node
{
bool invalid() const noexcept
{ return id.invalid(); }
T id{};
T parent{};
std::set<T> children{};
};
template<typename T> requires std::same_as<T, ID> or std::same_as<T, PID>
struct Tree
{
private:
mutable RMutex _mutex{};
public:
std::unordered_map<T, Node<T>> nodes{};
Error add_node(Farg<T> inNodeID, Farg<T> inParentID = T{}) noexcept
{
LOCK
if(nodes.contains(inNodeID))
{ return ERR_ALREADY_EXISTS; }
else if(!inParentID.invalid())
{
if(!nodes.contains(inParentID))
{ return ERR_NOT_FOUND; }
nodes.at(inParentID).children.insert(inNodeID);
}
nodes.emplace(inNodeID, Node{inNodeID, inParentID});
return OK;
}
Error remove_node(Farg<T> inNodeID) noexcept
{
LOCK
if(auto found_it{nodes.find(inNodeID)}; found_it != nodes.end())
{
if(auto found_parent{nodes.find(found_it->second.parent)};
found_parent != nodes.end())
{ found_parent->second.children.erase(inNodeID); }
for(FAUTO child : found_it->second.children)
{
if(auto found_child{nodes.find(child)}; found_child != nodes.end())
{ found_child->second.parent = T{}; }
}
nodes.erase(found_it);
return OK;
}
return ERR_NOT_FOUND;
}
Error set_parent(Farg<T> inNodeID, Farg<T> inParentID) noexcept
{
LOCK
if(!nodes.contains(inNodeID)
or (!inParentID.invalid() and !nodes.contains(inParentID)))
{ return ERR_NOT_FOUND; }
auto& child{nodes.at(inNodeID)};
if(auto found_it{nodes.find(child.parent)}; found_it != nodes.end())
{ found_it->second.children.erase(inNodeID); }
if(!inParentID.invalid())
{ nodes.at(inParentID).children.insert(inNodeID); }
child.parent = inParentID;
return OK;
}
std::unordered_set<T> get_descendants(Farg<T> inNodeID) const noexcept
{
LOCK
// TODO: I should implement an actual root node instead of doing this
if(inNodeID.invalid())
{
auto keys{std::views::keys(nodes)};
return {keys.begin(), keys.end()};
}
else if(!nodes.contains(inNodeID))
{ return {}; }
std::unordered_set<T> output{};
auto iter{output.begin()};
FAUTO children{nodes.at(inNodeID).children};
for(FAUTO child : children)
{
iter = output.emplace_hint(iter, child);
std::unordered_set<T> sub_children{get_descendants(child)};
for(auto second_iter{sub_children.begin()}; second_iter != sub_children.end(); ++second_iter)
{ iter = output.emplace_hint(iter, *second_iter); }
}
return output;
}
std::unordered_set<T> get_ancestors(Farg<T> inNodeID) const noexcept
{
LOCK
if(!nodes.contains(inNodeID))
{ return {}; }
std::unordered_set<T> output{};
auto iter{output.begin()};
T parent{nodes.at(inNodeID).parent};
while(not parent.invalid())
{
if(nodes.contains(parent))
{
iter = output.emplace_hint(iter, parent);
parent = nodes.at(parent).parent;
continue;
}
parent = {};
}
return output;
}
std::vector<T> get_all_nodes() const noexcept
{
LOCK
auto keys{std::views::keys(nodes)};
return {keys.begin(), keys.end()};
}
Farg<Node<T>> get_node(Farg<T> inNodeID) const noexcept
{
LOCK
static Node<T> error_node{};
// TODO: I should implement an actual root node instead of doing this
static Node<T> root_node{};
if(inNodeID.invalid())
{
for(FAUTO [id, node] : nodes)
{
if(node.parent.invalid())
{ root_node.children.insert(id); }
}
return root_node;
}
else if(auto found_it{nodes.find(inNodeID)}; found_it != nodes.end())
{ return found_it->second; }
return error_node;
}
bool has_node(Farg<T> inNodeID) const noexcept
{
LOCK
return nodes.contains(inNodeID);
}
void clear() noexcept
{
LOCK
nodes.clear();
}
};
#undef LOCK
#endif // TREE_H