Peano
Loading...
Searching...
No Matches
spacetree.h
Go to the documentation of this file.
1#pragma once
2
3#include <memory>
4#include <cstring>
5
6#include <lang/assert.h>
7#include <lang/lambda.h>
8#include <lang/vec.h>
9
10#include <geometry/geometry.h>
11#include <grid/linked_grid.h>
13
14#include <lang/task.h>
15
16template<typename T, typename Spacetree>
17concept CtxUnawareStatelessOnNodeCallback = requires (T t, Spacetree *node) {
18 { t(node) } -> std::same_as<void>;
19};
20
21template<typename T, typename Spacetree>
22concept CtxAwareStatelessOnNodeCallback = requires (T t, Spacetree *node, TaskCtx &ctx) {
23 { t(node, ctx) } -> std::same_as<void>;
24};
25
26template<typename T, typename Spacetree>
28
29template<typename T, typename Spacetree, typename Val>
30concept CtxUnawareStatefulOnNodeCallback = requires (T t, Spacetree *node, Val &val) {
31 { t(node, val) } -> std::same_as<void>;
32};
33
34template<typename T, typename Spacetree, typename Val>
35concept CtxAwareStatefulOnNodeCallback = requires (T t, Spacetree *node, Val &val, TaskCtx &ctx) {
36 { t(node, val, ctx) } -> std::same_as<void>;
37};
38
39template<typename T, typename Spacetree, typename Val>
41
42// https://stackoverflow.com/questions/37486137/how-can-i-create-a-constexpr-function-that-returns-a-type-to-be-used-in-a-templ
43template<typename Spacetree, typename = void>
45
46template<typename Spacetree>
50
51template<typename _Geometry, typename _Item, int THRESHOLD = 64, int SPLIT_FACTOR = 2, typename _TaskBackend = ThreadPoolTaskBackend>
52struct Spacetree : public LinkedGrid<_Geometry, SPLIT_FACTOR, Spacetree<_Geometry, _Item, THRESHOLD, SPLIT_FACTOR, _TaskBackend>> {
54
55 using Geo = _Geometry;
56 using Item = _Item;
57 using TaskBackend = _TaskBackend;
58
59 static constexpr int CAPACITY = THRESHOLD;
60
62
67
68 template<int LEVEL = 4>
70
71 template<int LEVEL = 4>
73
75
77
78 Spacetree() = default;
79
81
82 Spacetree(Spacetree&& other) noexcept {
83 this->operator=(std::move(other));
84 }
85
86 Spacetree& operator=(Spacetree&& other) noexcept {
87 Base::operator=(std::move(other));
88 this->items = std::move(other.items);
89
90 return *this;
91 }
92
94 auto *node = this;
95
96 while (node->subtrees) {
97 auto subtreeIdx = node->range.splitIdx(SPLIT_FACTOR, p);
98 node = node->subtrees + subtreeIdx;
99 }
100
101 return node;
102 }
103
105 auto *node = this;
106
107 while (node->subtrees) {
108 auto subtreeIdx = node->range.splitIdx(SPLIT_FACTOR, region.low);
109 auto *nodeCandidate = node->subtrees + subtreeIdx;
110 if (nodeCandidate->range.containsEx(region.high)) node = nodeCandidate;
111 else break;
112 }
113
114 return node;
115 }
116
118 auto itemPos = item._x;
119
120 auto *inRangeNode = this;
121 while (!inRangeNode->range.contains(itemPos)) {
122 inRangeNode = inRangeNode->parent;
123 if (!inRangeNode) [[unlikely]] {
124 return nullptr;
125 }
126 }
127
128 auto *leafNode = inRangeNode->findLeaf(itemPos);
129
130 if (leafNode->items.size() == THRESHOLD) [[unlikely]] {
131 leafNode->splitIntoSubtrees();
132 leafNode = leafNode->findLeaf(itemPos);
133 }
134
135 leafNode->pushItem(item);
136
137 return leafNode;
138 }
139
140 void pushItem(Item p) {
141 assert(!this->subtrees)
142
143 this->items.push_back(p);
144 }
145
147 auto *fullTree = this;
148
149 do {
150 assert(fullTree->items.size() == THRESHOLD)
151
152 fullTree->split();
153
154 char idxs[THRESHOLD];
155
156 for (int i = 0; i < THRESHOLD; i++) {
157 auto pos = fullTree->items[i]._x;
158 auto quartIdx = fullTree->range.splitIdx(SPLIT_FACTOR, pos);
159 idxs[i] = quartIdx;
160 }
161
162 for (int i = 0; i < THRESHOLD; i++) {
163 auto *subtree = fullTree->subtrees + idxs[i];
164 subtree->items.push_back(fullTree->items[i]);
165 }
166 fullTree->items = Vector<Item>(); // free underlying memory
167
168 // check if all items went into the same subtree
169 // if that's the case, we need to split again
170 auto *subtrees = fullTree->subtrees;
171 fullTree = nullptr;
172 for (int i = 0; i < Spacetree::getMaxChildren(); i++) {
173 if (subtrees[i].items.size() < THRESHOLD) continue;
174 fullTree = subtrees + i;
175 break;
176 }
177 } while (fullTree && fullTree->level < 128);
178 }
179
180 Spacetree *getRegionParent(const Geo::Region &range, bool refined = false) {
181 auto *currSubtree = this;
182
183 if (refined && this->range.contains(range)) {
184 currSubtree = this->findChildNode(range);
185 return currSubtree;
186 }
187
188 while (!currSubtree->range.contains(range) & (currSubtree->parent != nullptr)) {
189 currSubtree = currSubtree->parent;
190 }
191
192 return currSubtree;
193 }
194
195 template<StatelessOnNodeCallback<Spacetree> Callback, typename Iter = LeafsIterator>
196 void onNode(Callback F, u32 numThreads = 0) {
197 auto iter = Iter(this);
198 this->onNode(F, iter, numThreads);
199 }
200
201 template<StatelessOnNodeCallback<Spacetree> Callback, typename Iter>
202 void onNode(Callback F, Iter iter, u32 numThreads = 0) {
203 auto taskGenerator = Lambda([](auto &iter, auto &callback) {
204 auto nodeOpt = iter.next();
206 auto task = Lambda([](auto *node, auto *callback, auto &ctx) {
207 (*callback)(node, ctx);
208 }, nodeOpt.value_or(nullptr), &callback);
209 return (nodeOpt) ? std::optional(task) : std::nullopt;
211 auto task = Lambda([](auto *node, auto *callback) {
212 (*callback)(node);
213 }, nodeOpt.value_or(nullptr), &callback);
214 return (nodeOpt) ? std::optional(task) : std::nullopt;
215 } else static_assert(false);
216 }, iter, F);
217
218 TaskBackend::runSerialGenerator(taskGenerator, numThreads);
219 }
220
221 template<typename StateInitF, StatefulOnNodeCallback<Spacetree, std::invoke_result_t<StateInitF>> Callback, typename Iter = LeafsIterator>
222 auto onNode(Callback F, StateInitF stateInitF, u32 numThreads = 0) {
223 auto iter = Iter(this);
224 return this->onNode(F, stateInitF, iter, numThreads);
225 }
226
227 template<typename StateInitF, StatefulOnNodeCallback<Spacetree, std::invoke_result_t<StateInitF>> Callback, typename Iter>
228 auto onNode(Callback F, StateInitF stateInitF, Iter iter, u32 numThreads = 0) {
229 using ValueType = std::invoke_result_t<StateInitF>;
230
231 auto taskGenerator = Lambda([](auto &iter, auto &callback) {
232 auto nodeOpt = iter.next();
234 auto task = Lambda([](auto *node, auto *callback, auto &acc, auto &ctx) {
235 (*callback)(node, acc, ctx);
236 }, nodeOpt.value_or(nullptr), &callback);
237 return (nodeOpt) ? std::optional(task) : std::nullopt;
239 auto task = Lambda([](auto *node, auto *callback, auto &acc) {
240 (*callback)(node, acc);
241 }, nodeOpt.value_or(nullptr), &callback);
242 return (nodeOpt) ? std::optional(task) : std::nullopt;
243 } else static_assert(false);
244 }, iter, F);
245
246 return TaskBackend::runSerialGenerator(taskGenerator, stateInitF, numThreads);
247 }
248
250 if (!this->subtrees) return;
251 for (int i = 0; i < Spacetree::getMaxChildren(); i++) this->subtrees[i].~Spacetree();
252 free(this->subtrees);
253 this->subtrees = nullptr;
254 }
255
256 void clear() {
257 if (!this->subtrees) {
258 this->items.clear();
259 return;
260 }
261
262 for (int i = 0; i < Spacetree::getMaxChildren(); i++) this->subtrees[i].clear();
263 }
264
265 static constexpr u32 getMaxChildren() {
266 return Geo::template PowerN<SPLIT_FACTOR>();
267 }
268
270 this->destroySubtrees();
271 }
272
273};
#define assert(...)
Definition LinuxAMD.h:28
Definition lambda.h:6
unsigned int level
Definition linked_grid.h:54
Geo::Region range
Definition linked_grid.h:51
LinkedGrid & operator=(LinkedGrid &&other) noexcept
Definition linked_grid.h:71
Geo::RowMajorIdx idx
Definition linked_grid.h:53
Derived * subtrees
Definition linked_grid.h:49
Derived * parent
Definition linked_grid.h:48
Definition vec.h:7
Region< dim, fp, topBoundaryInclusive > Region
Definition geometry.h:243
Point< dim, fp > Point
Definition geometry.h:242
void destroySubtrees()
Definition spacetree.h:249
Spacetree(Geo::Region range, Spacetree *parent, Geo::RowMajorIdx idx, int level)
Definition spacetree.h:80
void pushItem(Item p)
Definition spacetree.h:140
static constexpr u32 getMaxChildren()
Definition spacetree.h:265
void onNode(Callback F, u32 numThreads=0)
Definition spacetree.h:196
_Geometry Geo
Definition spacetree.h:55
Spacetree(Geo::Region range)
Definition spacetree.h:76
auto onNode(Callback F, StateInitF stateInitF, Iter iter, u32 numThreads=0)
Definition spacetree.h:228
static constexpr int CAPACITY
Definition spacetree.h:59
void clear()
Definition spacetree.h:256
auto onNode(Callback F, StateInitF stateInitF, u32 numThreads=0)
Definition spacetree.h:222
void onNode(Callback F, Iter iter, u32 numThreads=0)
Definition spacetree.h:202
_TaskBackend TaskBackend
Definition spacetree.h:57
Spacetree * findLeaf(const Geo::Point &p)
Definition spacetree.h:93
Vector< Item > items
Definition spacetree.h:74
Spacetree()=default
Spacetree * getRegionParent(const Geo::Region &range, bool refined=false)
Definition spacetree.h:180
Spacetree * insert(Item item)
Definition spacetree.h:117
IterationOrderSelector< Spacetree >::type IterOrder
Definition spacetree.h:61
Spacetree & operator=(Spacetree &&other) noexcept
Definition spacetree.h:86
Spacetree * findChildNode(const Geo::Region &region)
Definition spacetree.h:104
void splitIntoSubtrees()
Definition spacetree.h:146
Spacetree(Spacetree &&other) noexcept
Definition spacetree.h:82
Definition task.h:13
std::uint32_t u32
Definition type.h:11