MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
container.h
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#ifndef CONTAINER_H_
8#define CONTAINER_H_
9
10#include <algorithm>
11#include <type_traits>
12#include <vector>
13#include "INCLUDE/maiamacro.h"
14#include "INCLUDE/maiatypes.h"
15#include "UTIL/functions.h"
16
17// The macro 'CONTAINER_SANITY_CHECKS' enables (potentially expensive) sanity checks for many
18// operations. It is enabled for build type "debug"
19#ifndef NDEBUG
20#define CONTAINER_SANITY_CHECKS
21#endif
22
23#define MAIA_CONTAINER_ENSURE(condition, message, at) \
24 if(!(condition)) { \
25 TERMM(1, std::string("\n\n") + (message) + "\n\n AT: " + at); \
26 } \
27 do { \
28 } while(false)
29
30#define MAIA_CONTAINER_ENSURE_VALID_ID(id) \
31 do { \
32 MAIA_CONTAINER_ENSURE(this->isValidId((id)), \
33 "id = " + std::to_string((id)) + " out-of-bounds [0, " + std::to_string(this->size()) \
34 + ") and is not the dummy cell at \"capacity() - 1\" = " \
35 + std::to_string(this->capacity() - 1), \
36 AT_); \
37 } while(false)
38
39
40// Sanity-checking macros for normal methods
41#ifdef CONTAINER_SANITY_CHECKS
42#define ENSURE_VALID_ID(id) \
43 do { \
44 MAIA_CONTAINER_ENSURE_VALID_ID(id); \
45 } while(false)
46#define ENSURE_CONDITION(condition, message) \
47 do { \
48 MAIA_CONTAINER_ENSURE(condition, message, AT_); \
49 } while(false)
50#else
51#define ENSURE_VALID_ID(id) \
52 do { \
53 } while(false)
54#define ENSURE_CONDITION(condition, message) \
55 do { \
56 } while(false)
57#endif
58
59
60namespace maia {
61namespace container {
62
68// void rawCopyGeneric(Functor&& c, const T& source, MInt begin, MInt end, MInt to)
76template <class Derived, template <class> class Invalid>
77class Container {
78 public:
79 // Constructors
81 constexpr Container() = default;
82
83 // Size/capacity handling
85 constexpr MInt capacity() const { return m_capacity; }
86 void reset(const MInt capacity);
87 void resize(const MInt capacity);
89 constexpr MInt size() const { return m_size; }
90 void size(const MInt size_);
91
92 // High-level operations to modify the container contents.
93 void append(const MInt count);
94 void append() { append(1); }
95 void shrink(const MInt count);
96 void shrink() { shrink(1); }
97 template <class T>
98 void copy(const T& source, const MInt begin, const MInt end, const MInt to);
99 template <class T>
100 void copy(const T& source, const MInt from, const MInt to) {
101 copy(source, from, from + 1, to);
102 }
103 void copy(const MInt begin, const MInt end, const MInt to) { copy(derived(), begin, end, to); }
104 void copy(const MInt from, const MInt to) { copy(from, from + 1, to); }
105 void move(const MInt begin, const MInt end, const MInt to);
106 void move(const MInt from, const MInt to) { move(from, from + 1, to); }
107 void swap(const MInt a, const MInt b);
108 void insert(const MInt begin, const MInt count);
109 void insert(const MInt id) { insert(id, 1); }
110 void erase(const MInt begin, const MInt end);
111 void erase(const MInt id) { erase(id, id + 1); }
112 void removeAndShift(const MInt begin, const MInt end);
113 void removeAndShift(const MInt id) { removeAndShift(id, id + 1); }
114 void removeAndFill(const MInt begin, const MInt end);
115 void removeAndFill(const MInt id) { removeAndFill(id, id + 1); }
116 void clear();
117
118 protected:
119 // Memory management
120 template <class T>
121 using Storage = std::vector<T>;
122 template <class T>
123 void resetStorage(const MInt n, Storage<T>& c);
124 template <class T>
125 void resizeStorage(const MInt n, Storage<T>& c);
126
127 virtual void resize() { TERMM(1, "not implemented"); };
128
129 // Fill data container with invalid values
130 template <typename Container_, typename T = typename Container_::value_type>
131 void fill_invalid(Container_& c, const MInt begin, const MInt end, const MInt solverSize = 1,
132 const T value = Invalid<T>::value()) {
133 std::fill(c.data() + begin * solverSize, c.data() + end * solverSize, value);
134 }
135
137 template <typename Container_, typename Functor>
138 void copyData(const Container_& source, Container_& target, Functor&& f, const MInt begin, const MInt end,
139 const MInt dest, const MInt solverSize = 1) {
140 f(source.data() + begin * solverSize, source.data() + end * solverSize, target.data() + dest * solverSize);
141 }
142
143 // private:
144 public:
145 // CRTP accessors
146 Derived& derived() { return static_cast<Derived&>(*this); }
147 const Derived& derived() const { return static_cast<const Derived&>(*this); }
148
149 // Types
150 template <MBool left>
151 struct Copy {
152 template <class It1, class It2, MBool l = left>
153 typename std::enable_if<l, It2>::type operator()(It1 first, It1 last, It2 dest) {
154 return std::copy(first, last, dest);
155 }
156 template <class It1, class It2, MBool l = left>
157 typename std::enable_if<!l, It2>::type operator()(It1 first, It1 last, It2 dest) {
158 return std::copy_backward(first, last, dest);
159 }
160 };
161
162 // Low-level modifications
163 template <class T>
164 void rawCopy(const T& source, const MInt begin, const MInt end, const MInt to);
165 template <class T>
166 void rawCopy(const T& source, const MInt from, const MInt to) {
167 rawCopy(source, from, from + 1, to);
168 }
169 void deleteConnectivity(const MInt NotUsed(begin), const MInt NotUsed(end)) {}
170 void moveConnectivity(const MInt NotUsed(begin), const MInt NotUsed(end), const MInt NotUsed(to)) {}
171 void moveConnectivity(const MInt from, const MInt to) { moveConnectivity(from, from + 1, to); }
172 constexpr MInt dummy() const { return m_capacity; }
173
174 protected:
175 // Sanity checking
176 MBool isValidId(const MInt id) const;
177
178 private:
179 // Capacity/size
182};
183
184
186template <class Derived, template <class> class Invalid>
188 ENSURE_CONDITION(capacity_ >= 0, "Capacity must be non-negative");
189
190 m_capacity = capacity_;
191 m_size = 0;
192
193 derived().reset();
194}
195
196
198template <class Derived, template <class> class Invalid>
200 ENSURE_CONDITION(capacity_ >= 0, "Capacity must be non-negative");
201 ENSURE_CONDITION(capacity_ >= m_capacity, "So far only resize to a larger size is tested.");
202
203 if(capacity_ == m_capacity) return;
204
205 m_capacity = capacity_;
206
207 derived().resize();
208}
209
210
212template <class Derived, template <class> class Invalid>
214 ENSURE_CONDITION(size_ >= 0, "Size must be non-negative");
215 ENSURE_CONDITION(size_ <= capacity(), "Size must not exceed capacity");
216
217 m_size = size_;
218}
219
220
222template <class Derived, template <class> class Invalid>
224 ENSURE_CONDITION(count >= 0, "Count must be non-negative");
225
226 if(size() + count > capacity()) {
227 std::cerr << "Container capacity exceeded: is:" + std::to_string(capacity())
228 + ", desired: " + std::to_string(size() + count)
229 << std::endl;
230 // Allow containers to grow if required -> for now resize with +10% capacity
231 const MInt newCapacity = 1.1 * (size() + count);
232 std::cerr << "New container capacity is: " << newCapacity << std::endl;
233 resize(size() + count);
234 }
235 derived().invalidate(size(), size() + count);
236 m_size += count;
237}
238
239
241template <class Derived, template <class> class Invalid>
243 ENSURE_CONDITION(count >= 0, "Count must be non-negative");
244 ENSURE_CONDITION(size() - count >= 0, "New size below zero");
245
246 removeAndShift(size() - count, size());
247}
248
249
251template <class Derived, template <class> class Invalid>
252template <class T>
253void Container<Derived, Invalid>::copy(const T& source, const MInt begin, const MInt end, const MInt to) {
254 ENSURE_CONDITION(begin >= 0 && begin < source.size(), "Begin position outside valid range");
255 ENSURE_CONDITION(end - 1 < source.size(), "End position outside valid range");
256 ENSURE_VALID_ID(to);
257 ENSURE_CONDITION(to + (end - begin) <= size(), "Target range outside valid size");
258
259 // Exit early if there is nothing to do
260 if(end <= begin || (&source == this && begin == to)) {
261 return;
262 }
263
264 rawCopy(source, begin, end, to);
265}
266
267
269template <class Derived, template <class> class Invalid>
270void Container<Derived, Invalid>::move(const MInt begin, const MInt end, const MInt to) {
271 ENSURE_VALID_ID(begin);
272 ENSURE_VALID_ID(end - 1);
273 ENSURE_VALID_ID(to);
274 ENSURE_CONDITION(to + (end - begin) - 1 < size(), "Target range outside valid size");
275
276 // Exit early if there is nothing to do
277 if(end <= begin || begin == to) {
278 return;
279 }
280
281 rawCopy(derived(), begin, end, to);
282 derived().moveConnectivity(begin, end, to);
283 derived().invalidate(begin, end);
284}
285
286
288template <class Derived, template <class> class Invalid>
290 ENSURE_VALID_ID(a);
291 ENSURE_VALID_ID(b);
292
293 // Exit early if a and b are the same node
294 if(a == b) {
295 return;
296 }
297
298 // Move a to dummy position
299 rawCopy(derived(), a, dummy());
300 derived().moveConnectivity(a, dummy());
301
302 // Move b to a
303 rawCopy(derived(), b, a);
304 derived().moveConnectivity(b, a);
305
306 // Move from dummy position to b
307 rawCopy(derived(), dummy(), b);
308 derived().moveConnectivity(dummy(), b);
309
310 // Invalidate dummy to be sure
311 derived().invalidate(dummy(), dummy() + 1);
312}
313
314
317template <class Derived, template <class> class Invalid>
318void Container<Derived, Invalid>::insert(const MInt id, const MInt count) {
319 ENSURE_CONDITION(isValidId(id) || id == size(), "Id must refer to a valid node or be equal to size()");
320 ENSURE_CONDITION(count >= 0, "Count must be non-negative");
321 ENSURE_CONDITION(count + size() <= capacity(), "New size exceeds capacity");
322
323 // Exit early if there is nothing to do
324 if(count == 0) {
325 return;
326 }
327
328 m_size += count;
329 move(id, size() - count, id + count);
330}
331
332
334template <class Derived, template <class> class Invalid>
335void Container<Derived, Invalid>::erase(const MInt begin, const MInt end) {
336 ENSURE_VALID_ID(begin);
337 ENSURE_VALID_ID(end - 1);
338
339 // Exit early if there is nothing to do
340 if(end <= begin) {
341 return;
342 }
343
344 derived().deleteConnectivity(begin, end);
345 derived().invalidate(begin, end);
346}
347
348
351template <class Derived, template <class> class Invalid>
353 ENSURE_VALID_ID(begin);
354 ENSURE_VALID_ID(end - 1);
355
356 // Exit early if there is nothing to do
357 if(end <= begin) {
358 return;
359 }
360
361 derived().deleteConnectivity(begin, end);
362 derived().invalidate(begin, end);
363 if(end < size()) {
364 move(end, size(), begin);
365 }
366 const MInt count = end - begin;
367 m_size -= count;
368}
369
370
373template <class Derived, template <class> class Invalid>
375 ENSURE_VALID_ID(begin);
376 ENSURE_VALID_ID(end - 1);
377
378 // Exit early if there is nothing to do
379 if(end <= begin) {
380 return;
381 }
382
383 derived().deleteConnectivity(begin, end);
384 derived().invalidate(begin, end);
385 const MInt count = end - begin;
386 if(end < size()) {
387 move(std::max(end, size() - count), size(), begin);
388 }
389 m_size -= count;
390}
391
392
394template <class Derived, template <class> class Invalid>
396 derived().invalidate(0, size());
397 m_size = 0;
398}
399
400
402template <class Derived, template <class> class Invalid>
403template <class T>
404void Container<Derived, Invalid>::rawCopy(const T& source, const MInt begin, const MInt end, const MInt to) {
405 // Use different methods for overlapping and non-overlapping ranges, depending on overlap type
406 if(to < begin || to >= end) {
407 // Non-overlapping ranges or overlap while copying left can be handled by std::copy
408 derived().rawCopyGeneric(Copy<true>{}, source, begin, end, to);
409 } else {
410 // Overlap while copying right can be handled by std::copy_backward
411 const MInt count = end - begin;
412 derived().rawCopyGeneric(Copy<false>{}, source, begin, end, to + count);
413 }
414}
415
416
418template <class Derived, template <class> class Invalid>
419template <class T>
421 // Note: Containers are always initialized with an invalid value as for, e.g., std::vector, all
422 // entries are default initialized anyways and not providing an invalid value would zero all int's
423 // and probably all float's as well.
424 Storage<T>(std::max((m_capacity + 1) * n, 1), Invalid<T>::value()).swap(c);
425 // TODO: This step is critical for OpenMP parallelization. In most numa
426 // architecture data is placed by a 'first touch'-policy.
427 // Storage(==std::vector) does a sequential initialization, i.e., it touches
428 // all memory from the core associated with the main thread. That might
429 // introduce memory access penalty in OpenMP usage.
430}
431
432
434template <class Derived, template <class> class Invalid>
435template <class T>
437 c.resize(std::max((m_capacity + 1) * n, 1), Invalid<T>::value());
438}
439
440
442template <class Derived, template <class> class Invalid>
444 // @memSplitGrid Note: allow second last position to be used as a dummy id (needed for FV solver to
445 // work atm, changing to the last position requires changing the allocation of solver variables to
446 // be of size maxNoCells+1)
447 if(!((id >= 0 && id < size()) || id == capacity() - 1)) {
448 std::cerr << "id = " << id << std::endl
449 << "size() = " << size() << std::endl
450 << "capacity() = " << capacity() << std::endl;
451 }
452 return ((id >= 0 && id < size()) || id == capacity() - 1);
453}
454
455} // namespace container
456} // namespace maia
457
458
459// Undefine macros that should not be used outside this file
460#undef CONTAINER_SANITY_CHECKS
461#undef ENSURE_VALID_ID
462#undef ENSURE_CONDITION
463
464#endif // ifndef CONTAINER_H_
void resize(const MInt capacity)
Resize the container capacity.
Definition: container.h:199
void move(const MInt begin, const MInt end, const MInt to)
Move nodes to another location and update parent/child/neighbor information accordingly.
Definition: container.h:270
void removeAndShift(const MInt id)
Definition: container.h:113
void moveConnectivity(const MInt NotUsed(begin), const MInt NotUsed(end), const MInt NotUsed(to))
Definition: container.h:170
void deleteConnectivity(const MInt NotUsed(begin), const MInt NotUsed(end))
Definition: container.h:169
void move(const MInt from, const MInt to)
Definition: container.h:106
void rawCopy(const T &source, const MInt begin, const MInt end, const MInt to)
Copy range of nodes [begin, end) to range starting at 'to'.
Definition: container.h:404
void removeAndFill(const MInt begin, const MInt end)
Definition: container.h:374
const Derived & derived() const
Definition: container.h:147
void insert(const MInt id)
Definition: container.h:109
void clear()
Clear tree by invalidating all nodes and setting size to zero.
Definition: container.h:395
void moveConnectivity(const MInt from, const MInt to)
Definition: container.h:171
MBool isValidId(const MInt id) const
Return whether given id refers to a valid node (auxiliary method).
Definition: container.h:443
std::vector< T > Storage
Definition: container.h:121
void copyData(const Container_ &source, Container_ &target, Functor &&f, const MInt begin, const MInt end, const MInt dest, const MInt solverSize=1)
Copy [begin, end) range with given solver size from source to dest position of target.
Definition: container.h:138
constexpr MInt dummy() const
Definition: container.h:172
void removeAndShift(const MInt begin, const MInt end)
Definition: container.h:352
void erase(const MInt begin, const MInt end)
Erase nodes in range [begin, end) and update parent/child/neighbor information.
Definition: container.h:335
constexpr MInt size() const
Return size (i.e., currently used number of nodes)
Definition: container.h:89
void copy(const MInt from, const MInt to)
Definition: container.h:104
virtual void resize()
Definition: container.h:127
void fill_invalid(Container_ &c, const MInt begin, const MInt end, const MInt solverSize=1, const T value=Invalid< T >::value())
Definition: container.h:131
void copy(const T &source, const MInt from, const MInt to)
Definition: container.h:100
void shrink(const MInt count)
Remove nodes from end of tree.
Definition: container.h:242
void resetStorage(const MInt n, Storage< T > &c)
Create new container with given size and replace original one.
Definition: container.h:420
constexpr MInt capacity() const
Return capacity (i.e., maximum number of nodes)
Definition: container.h:85
void resizeStorage(const MInt n, Storage< T > &c)
Resize container with given size.
Definition: container.h:436
void erase(const MInt id)
Definition: container.h:111
void reset(const MInt capacity)
Reset tree, re-create data structures with given capacity, and set size to zero.
Definition: container.h:187
void append(const MInt count)
Append nodes to end of tree.
Definition: container.h:223
void rawCopy(const T &source, const MInt from, const MInt to)
Definition: container.h:166
void removeAndFill(const MInt id)
Definition: container.h:115
void copy(const T &source, const MInt begin, const MInt end, const MInt to)
Copy nodes to another location without changing any parent/child/neighbor information.
Definition: container.h:253
constexpr Container()=default
Default c'tor does nothing.
void insert(const MInt begin, const MInt count)
Definition: container.h:318
void copy(const MInt begin, const MInt end, const MInt to)
Definition: container.h:103
void size(const MInt size_)
Resize tree WITHOUT CONSIDERING ANY NODE CONSISTENCY! Use at own risk and remove ASAP....
Definition: container.h:213
void swap(const MInt a, const MInt b)
Swap two nodes and update parent/child/neighbor information accordingly.
Definition: container.h:289
int32_t MInt
Definition: maiatypes.h:62
bool MBool
Definition: maiatypes.h:58
Namespace for auxiliary functions/classes.
Definition: contexttypes.h:19
std::enable_if<!l, It2 >::type operator()(It1 first, It1 last, It2 dest)
Definition: container.h:157
std::enable_if< l, It2 >::type operator()(It1 first, It1 last, It2 dest)
Definition: container.h:153