DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
ArrayBasic.hpp
Go to the documentation of this file.
1#pragma once
2/// @file ArrayBasic.hpp
3/// @brief Array layout descriptors, non-owning views, row views, and iterator base.
4
5#include "Defines.hpp"
6#include "Errors.hpp"
7
8namespace DNDS
9{
10
11 /**
12 * @brief Enumeration of the five concrete data layouts supported by @ref DNDS::Array "Array".
13 *
14 * @details The value is determined at compile time from `_row_size` and
15 * `_row_max` template parameters. See the layout table in Array.hpp.
16 */
18 {
19 ErrorLayout, ///< Invalid combination of template parameters.
20 TABLE_StaticFixed, ///< Fixed row width, known at compile time.
21 TABLE_Fixed, ///< Fixed row width, set at runtime (uniform across rows).
22 TABLE_Max, ///< Padded variable rows; max width set at runtime.
23 TABLE_StaticMax, ///< Padded variable rows; max width fixed at compile time.
24 CSR, ///< Compressed Sparse Row (flat buffer + row-start index).
25 };
26
27 /// @brief Whether the layout uses a TABLE (padded) representation (vs CSR).
28 constexpr bool isTABLE(DataLayout lo)
29 {
30 return lo == TABLE_StaticFixed || lo == TABLE_Fixed || lo == TABLE_Max || lo == TABLE_StaticMax;
31 }
32 /// @brief Whether the layout has a uniform row width (no per-row size needed).
33 constexpr bool isTABLE_Fixed(DataLayout lo)
34 {
35 return lo == TABLE_StaticFixed || lo == TABLE_Fixed;
36 }
37 /// @brief Whether the layout is a padded-max variant (uses `_pRowSizes`).
38 constexpr bool isTABLE_Max(DataLayout lo)
39 {
40 return lo == TABLE_Max || lo == TABLE_StaticMax;
41 }
42 /// @brief Whether the layout has a compile-time row-size constant.
43 constexpr bool isTABLE_Static(DataLayout lo)
44 {
45 return lo == TABLE_StaticFixed || lo == TABLE_StaticMax;
46 }
47 /// @brief Whether the layout carries a runtime row-size parameter.
48 constexpr bool isTABLE_Dynamic(DataLayout lo)
49 {
50 return lo == TABLE_Fixed || lo == TABLE_Max;
51 }
52
53 /// @brief Whether `T` is legal as an @ref DNDS::Array "Array" element type (trivially copyable
54 /// or a fixed-size real Eigen matrix). Controls CUDA/MPI copy paths.
55 template <class T>
56 constexpr bool array_comp_acceptable()
57 {
58 return std::is_trivially_copyable_v<T> || Meta::is_fixed_data_real_eigen_matrix_v<T>;
59 }
60
61 /**
62 * @brief Compile-time layout descriptor deducing the concrete @ref DataLayout
63 * from element type and row-size template arguments.
64 *
65 * @details Serves as a base class for @ref DNDS::Array "Array" / @ref DNDS::ArrayView "ArrayView" and as a static
66 * namespace of helpers (signature strings, compatibility checks). Carries
67 * no runtime state of its own.
68 *
69 * @tparam T Element type.
70 * @tparam _row_size Row size (>=0 / DynamicSize / NonUniformSize).
71 * @tparam _row_max Row max (>=0 / DynamicSize / NonUniformSize; only used
72 * when `_row_size == NonUniformSize`).
73 * @tparam _align Alignment hint (currently only @ref NoAlign implemented).
74 */
75 template <class T, rowsize _row_size = 1, rowsize _row_max = _row_size,
76 // rowsize _depth_size = 1,
77 rowsize _align = NoAlign>
79 {
80 public:
81 using value_type = T;
82 static const rowsize al = _align;
83 static const rowsize rs = _row_size;
84 static const rowsize rm = _row_max;
85 // static const rowsize ds = _depth_size;
86 static const size_t sizeof_T = sizeof(value_type);
87
88 static_assert(sizeof_T <= (1024ULL * 1024ULL * 1024ULL), "Row size larger than 1G");
89 static_assert(array_comp_acceptable<T>(), "Do not put in a non trivially copyable type ");
90 static_assert(rs >= 0 || rs == DynamicSize || rs == NonUniformSize);
91 static_assert(rm >= 0 || rm == DynamicSize || rm == NonUniformSize);
92 // static_assert(ds >= 1 || ds == DynamicSize);
93
94 static_assert(al == NoAlign || al >= 1, "Align bad");
95
96 static const rowsize s_T = al == NoAlign ? sizeof_T : (sizeof_T / al + 1) * al;
97 static_assert(s_T >= sizeof_T && s_T - sizeof_T < (al == NoAlign ? 1 : al), "I1");
98
99 /// @brief Deduce the @ref DataLayout tag from the template parameters.
100 static constexpr DataLayout _GetDataLayout()
101 {
102 if constexpr (rs != DynamicSize && rs != NonUniformSize && rs >= 0)
103 return TABLE_StaticFixed;
104 else if constexpr (rs == DynamicSize)
105 return TABLE_Fixed;
106 else if constexpr (rs == NonUniformSize)
107 {
108 if constexpr (rm == NonUniformSize)
109 return CSR;
110 else if constexpr (rm == DynamicSize)
111 return TABLE_Max;
112 else if constexpr (rm >= 0)
113 return TABLE_StaticMax;
114 else
115 return ErrorLayout;
116 }
117 else
118 return ErrorLayout;
119 }
121 static_assert(_dataLayout != ErrorLayout, "Layout Error");
122 static const bool isCSR = _dataLayout == CSR;
123
124 /// @brief Human-readable type identifier including element typeid, sizes, and alignment.
125 /// @details Format: `"<Layout>__<typeid>_<sizeof_T>_<rs>_<rm>_<al>"`.
126 /// Primarily for debugging / error messages. Not stable across compilers
127 /// (uses `typeid(T).name()`); use @ref GetArraySignature for persisted data.
128 static std::string GetArrayName()
129 {
130 std::string Layout;
131 if constexpr (_dataLayout == CSR)
132 Layout = "CSR";
133 if constexpr (_dataLayout == TABLE_StaticFixed)
134 Layout = "TABLE_StaticFixed";
135 if constexpr (_dataLayout == TABLE_Fixed)
136 Layout = "TABLE_Fixed";
137 if constexpr (_dataLayout == TABLE_StaticMax)
138 Layout = "TABLE_StaticMax";
139 if constexpr (_dataLayout == TABLE_Max)
140 Layout = "TABLE_Max";
141 return Layout + "__" +
142 typeid(T).name() + "_" + std::to_string(sizeof_T) + "_" + RowSize_To_PySnippet(_row_size) +
143 "_" + RowSize_To_PySnippet(_row_max) +
144 "_" + Align_To_PySnippet(_align);
145 }
146
147 /// @brief Compiler-independent identifier used by serializers to tag an array.
148 /// @details Format: `"<Layout>__<sizeof_T>_<rs>_<rm>_<al>"`, where template
149 /// parameters are encoded numerically (so `-1` = DynamicSize, `-2` = NonUniformSize).
150 /// Stable across compilers; used for compatibility checks during
151 /// serialized restart.
152 static std::string GetArraySignature()
153 {
154 std::string Layout;
155 if constexpr (_dataLayout == CSR)
156 Layout = "CSR";
157 if constexpr (_dataLayout == TABLE_StaticFixed)
158 Layout = "TABLE_StaticFixed";
159 if constexpr (_dataLayout == TABLE_Fixed)
160 Layout = "TABLE_Fixed";
161 if constexpr (_dataLayout == TABLE_StaticMax)
162 Layout = "TABLE_StaticMax";
163 if constexpr (_dataLayout == TABLE_Max)
164 Layout = "TABLE_Max";
165 return Layout + "__" + std::to_string(sizeof_T) +
166 "_" + std::to_string(_row_size) +
167 "_" + std::to_string(_row_max) +
168 "_" + std::to_string(_align);
169 }
170
171 /// @brief Signature with `_row_size` / `_row_max` replaced by DynamicSize.
172 /// @details Used when we want two arrays to match regardless of compile-time
173 /// row-size constants (e.g., compare a @ref DynamicSize reader against a
174 /// fixed-size writer file).
175 static std::string GetArraySignatureRelaxed()
176 {
177 std::string Layout;
178 if constexpr (_dataLayout == CSR)
179 Layout = "CSR";
180 if constexpr (_dataLayout == TABLE_StaticFixed)
181 Layout = "TABLE_StaticFixed";
182 if constexpr (_dataLayout == TABLE_Fixed)
183 Layout = "TABLE_Fixed";
184 if constexpr (_dataLayout == TABLE_StaticMax)
185 Layout = "TABLE_StaticMax";
186 if constexpr (_dataLayout == TABLE_Max)
187 Layout = "TABLE_Max";
188 return Layout + "__" + std::to_string(sizeof_T) +
189 "_" + std::to_string(DynamicSize) +
190 "_" + std::to_string(DynamicSize) +
191 // "_" + std::to_string(DynamicSize) +
192 "_" + std::to_string(_align);
193 }
194
195 /// @brief Parse a signature string into `(sizeof_T, row_size, row_max, align)`.
196 /// @details Accepts both @ref GetArrayName (6 components incl. typeid) and
197 /// @ref GetArraySignature (5 components) forms; returns the last 4 fields.
198 static std::tuple<int, int, int, int> ParseArraySignatureTuple(const std::string &v)
199 {
200 auto strings = splitSStringClean(v, '_');
201 DNDS_HD_assert(strings.size() == 5 || strings.size() == 6);
202 auto sz = strings.size();
203 return std::make_tuple(std::stoi(strings[sz - 4]), std::stoi(strings[sz - 3]), std::stoi(strings[sz - 2]), std::stoi(strings[sz - 1]));
204 }
205
206 /// @brief Whether a stored signature can be read into this array type.
207 /// @details Requires matching `sizeof(T)` and compatible row-size constants:
208 /// fixed row sizes must be equal when both sides declare them.
209 static bool ArraySignatureIsCompatible(const std::string &v)
210 {
211 auto [sz, rs, rm, align] = ParseArraySignatureTuple(v);
212 if (sz != sizeof_T)
213 return false;
214 if (rs >= 0 && _row_size >= 0 && rs != _row_size)
215 return false;
216 if (rm >= 0 && _row_max >= 0 && rm != _row_max)
217 return false;
218 return true;
219 }
220 };
221
222 /**
223 * @brief Non-owning, device-callable view onto an @ref DNDS::Array "Array".
224 *
225 * @details Captures pointers to the flat data buffer and the structural
226 * arrays (`_rowstart_or_rowsize`) plus the nested-vector pointer for CSR
227 * decompressed. It is the type responsible for actually implementing
228 * `operator[]` / `operator()` indexing across every layout, and is marked
229 * `__host__ __device__` to work inside CUDA kernels.
230 *
231 * Instances are typically produced by `Array::view()` and must not outlive
232 * the owning @ref DNDS::Array "Array".
233 */
234 template <class T, rowsize _row_size = 1, rowsize _row_max = _row_size,
235 // rowsize _depth_size = 1,
236 rowsize _align = NoAlign>
237 class ArrayView : public ArrayLayout<T, _row_size, _row_max,
238 // _depth_size,
239 _align>
240 {
241 protected:
242 using self_type = ArrayView<T, _row_size, _row_max,
243 // _depth_size,
244 _align>;
245 using t_Layout = ArrayLayout<T, _row_size, _row_max,
246 // _depth_size,
247 _align>;
248 using t_Layout::al,
261 using typename t_Layout::value_type;
262
264 T *_data = nullptr;
266 std::conditional_t<_dataLayout == CSR, const index *,
267 std::conditional_t<_dataLayout == TABLE_Max || _dataLayout == TABLE_StaticMax,
268 const rowsize *, EmptyNoDefault>>
270
271 bool _isCompressed = true;
272 std::conditional_t<_dataLayout == TABLE_Max || _dataLayout == TABLE_Fixed, rowsize, EmptyNoDefault>
274
275 using t_dataUncompressed = std::vector<std::vector<T>>;
276 std::conditional_t<_dataLayout == CSR, t_dataUncompressed *, EmptyNoDefault> _p_dataUncompressed = nullptr;
277
278 public:
280
281 /// @brief Construct a view from raw pointers. Intended for internal use by `Array::view()`.
282 DNDS_DEVICE_CALLABLE ArrayView(index n_size, T *n_data, index n_data_size,
283 const index *n_rowstart, index n_rowstart_size,
284 const rowsize *n_rowsizes, index n_rowsizes_size,
285 rowsize n_row_size_dynamic,
286 bool n_isCompressed, t_dataUncompressed *n_p_dataUncompressed)
287 : _size(n_size),
288 _data(n_data), _data_size(n_data_size),
289 _isCompressed(n_isCompressed),
290 _row_size_dynamic(n_row_size_dynamic),
291 _p_dataUncompressed(n_p_dataUncompressed)
292 {
293 if (_dataLayout != CSR || isCompressed())
294 DNDS_HD_assert(n_p_dataUncompressed == nullptr);
295
297 DNDS_HD_assert(n_row_size_dynamic == 0);
298 if constexpr (_dataLayout == CSR)
299 {
300 _rowstart_or_rowsize = n_rowstart;
301 DNDS_HD_assert(n_rowsizes == nullptr);
303 DNDS_HD_assert(n_rowstart_size == _size + 1);
304 }
305 if constexpr (_dataLayout == TABLE_Max || _dataLayout == TABLE_StaticMax)
306 {
307 _rowstart_or_rowsize = n_rowsizes;
308 DNDS_HD_assert(n_rowstart == nullptr);
309 DNDS_HD_assert(n_rowsizes_size == _size);
310 DNDS_HD_assert(n_rowsizes);
311 }
312 }
313
314 /// @brief Whether the underlying array is in the compressed (flat) form (always true for non-CSR).
315 DNDS_DEVICE_CALLABLE [[nodiscard]] bool isCompressed() const
316 {
317 if constexpr (_dataLayout == CSR)
318 return _isCompressed;
319 else
320 return true;
321 }
322
323 /// @brief Number of rows in the viewed array.
324 DNDS_DEVICE_CALLABLE [[nodiscard]] index Size() const { return _size; }
325
326 /// @brief Uniform row width for fixed layouts (asserts otherwise).
327 // to be device-callable
329 {
330 if constexpr (_dataLayout == TABLE_Fixed)
331 return _row_size_dynamic;
332 else if constexpr (_dataLayout == TABLE_StaticFixed)
333 return rs;
334 else
335 {
336 DNDS_HD_assert_infof(false, "invalid call");
337 return -1;
338 }
339 }
340
341 protected:
342 // to be device-callable
344 {
346 if constexpr (_dataLayout == TABLE_Fixed)
347 return _row_size_dynamic;
348 else if constexpr (_dataLayout == TABLE_StaticFixed)
349 return rs;
350 DNDS_HD_assert_infof(iRow < _size && iRow >= 0, "query position out of range");
351 if constexpr (_dataLayout == TABLE_Max || _dataLayout == TABLE_StaticMax) // TABLE with Max
352 {
353 DNDS_HD_assert_infof(_rowstart_or_rowsize, "_rowsizes invalid"); // TABLE with Max must have a RowSizes
354 DNDS_HD_assert_infof(iRow >= 0 && iRow < _size,
355 "iRow invalid: %lld / %lld", iRow, _size);
356 return _rowstart_or_rowsize[iRow]; //! unsafe
357 }
358 else if constexpr (_dataLayout == CSR)
359 {
360 DNDS_HD_assert_infof(_rowstart_or_rowsize, "_rowstart invalid");
361 DNDS_HD_assert_infof(iRow >= 0 && iRow + 1 < _size + 1,
362 "iRow invalid: %lld / %lld", iRow, _size);
363 index pDiff = _rowstart_or_rowsize[iRow + 1] - _rowstart_or_rowsize[iRow]; //! unsafe
364 DNDS_HD_assert(pDiff < INT32_MAX); // overflow
365 return static_cast<rowsize>(pDiff);
366 }
367 return UnInitRowsize;
368 }
369
370 public:
371 /// @brief Per-row width. Handles CSR compressed and decompressed modes.
372 // to be device-callable
373 DNDS_DEVICE_CALLABLE [[nodiscard]] rowsize RowSize(index iRow) const
374 {
375 if constexpr (_dataLayout == CSR)
376 {
377 if (isCompressed())
378 return this->RowSize_Compressed(iRow);
379 else
380 {
382 auto rs_cur = (*_p_dataUncompressed).at(iRow).size(); //! unsafe
383 return static_cast<rowsize>(rs_cur);
384 }
385 }
386 else
387 return this->RowSize_Compressed(iRow);
388 }
389
390 /// @brief Maximum row width (TABLE_*Max only).
391 // to be device-callable
393 {
394 if constexpr (_dataLayout == TABLE_Max || _dataLayout == TABLE_StaticMax)
396 else
397 DNDS_HD_assert_infof(false, "invalid call");
398 return UnInitRowsize;
399 }
400
401 /// @brief "Logical" row-field width used by derived Eigen arrays; see Array::RowSizeField.
402 // to be device-callable
404 {
405 if constexpr (_dataLayout == TABLE_Max || _dataLayout == TABLE_StaticMax)
406 return this->RowSizeMax();
407 else if constexpr (_dataLayout == TABLE_Fixed || _dataLayout == TABLE_StaticFixed)
408 return this->RowSize();
409 else
410 DNDS_HD_assert_infof(false, "invalid call");
411 return UnInitRowsize;
412 }
413
414 /// @brief Per-row "field" size for CSR (= actual row width).
415 // to be device-callable
417 {
418 if constexpr (_dataLayout == CSR)
419 return this->RowSize(iRow);
420 else
421 DNDS_HD_assert_infof(false, "invalid call");
422 return UnInitRowsize;
423 }
424
425 protected:
427 {
429 DNDS_HD_assert_infof(iRow < _size && iRow >= 0,
430 "query position i[%lld] out of range [0, %lld)",
431 iRow, _size);
432 DNDS_HD_assert_infof(iCol < RowSize(iRow) && iCol >= 0,
433 "query position j[%lld] out of range [0, %lld)",
434 iCol, RowSize(iRow));
435 index pos = -1;
436 if constexpr (_dataLayout == TABLE_StaticFixed)
437 pos = iRow * rs + iCol;
438 else if constexpr (_dataLayout == TABLE_StaticMax)
439 pos = iRow * rm + iCol;
440 else if constexpr (_dataLayout == TABLE_Fixed)
441 pos = iRow * _row_size_dynamic + iCol;
442 else if constexpr (_dataLayout == TABLE_Max)
443 pos = iRow * _row_size_dynamic + iCol;
444 else if constexpr (_dataLayout == CSR)
445 {
446 DNDS_HD_assert_infof(0 <= iRow && iRow + 1 < _size + 1,
447 "iRow invalid, %lld / %lld", iRow, _size);
448 pos = _rowstart_or_rowsize[iRow] + iCol; //! unsafe
449 }
450 else
451 DNDS_HD_assert_infof(false, "invalid call");
452 DNDS_HD_assert_infof(0 <= pos && pos < _data_size,
453 "pos in data not valid, %lld / %lld", pos, _data_size);
454 return _data[pos]; //! unsafe
455 }
456
457 public:
458 /// @brief Bounds-checked element read (not device-callable because CSR
459 /// decompressed uses `std::vector::at` which throws on the host).
460 // not device callable
461 const T &at(index iRow, rowsize iCol) const
462 {
463 if constexpr (_dataLayout == CSR)
464 {
465 if (isCompressed())
466 return this->at_compressed(iRow, iCol);
467 else
468 return (*_p_dataUncompressed).at(iRow).at(iCol); //! unsafe
469 }
470 else
471 return this->at_compressed(iRow, iCol);
472 }
473
474 /// @brief 2D indexed access (writable). See `at`.
475 T &operator()(index iRow, rowsize iCol = 0)
476 {
477 return const_cast<T &>(at(iRow, iCol));
478 }
479
480 /// @brief 2D indexed access (read-only).
481 const T &operator()(index iRow, rowsize iCol = 0) const
482 {
483 return at(iRow, iCol);
484 }
485
486 protected:
488 {
490 DNDS_HD_assert_infof(iRow <= _size && iRow >= 0, "query position i out of range");
491 if constexpr (_dataLayout == TABLE_StaticFixed)
492 return _data + iRow * rs;
493 else if constexpr (_dataLayout == TABLE_StaticMax)
494 return _data + iRow * rm;
495 else if constexpr (_dataLayout == TABLE_Fixed)
496 return _data + iRow * _row_size_dynamic;
497 else if constexpr (_dataLayout == TABLE_Max)
498 return _data + iRow * _row_size_dynamic;
499 else if constexpr (_dataLayout == CSR)
500 {
501 DNDS_HD_assert_infof(0 <= iRow && iRow < _size + 1,
502 "iRow invalid, %lld / %lld", iRow, _size);
503 return _data + _rowstart_or_rowsize[iRow]; //! unsafe
504 }
505 else
506 {
507 DNDS_assert_info(false, "invalid call");
508 return nullptr;
509 }
510 }
511
512 public:
513 /**
514 * @brief Raw row pointer. `iRow == Size()` is allowed for past-the-end
515 * queries (useful for computing buffer end in sweeps).
516 *
517 * @param iRow Row index.
518 * @return T*
519 */
521 {
522 if constexpr (_dataLayout == CSR)
523 {
524 if (isCompressed())
525 return this->get_rowstart_pointer_compressed(iRow);
526 else if (_size == 0)
527 {
528 static_assert(((T *)(NULL) - (T *)(NULL)) == 0);
529 return (T *)(NULL); // used for past-the-end inquiry of size 0 array
530 }
531 else
532 {
533 DNDS_HD_assert_infof(iRow < _size, "past-the-end query forbidden for CSR uncompressed");
534 return (*_p_dataUncompressed).at(iRow).data(); //! unsafe
535 }
536 }
537 else
538 return this->get_rowstart_pointer_compressed(iRow);
539 }
540
541 /// @brief Const row pointer; see the non-const overload.
542 const T *operator[](index iRow) const
543 {
544 return static_cast<const T *>(const_cast<self_type *>(this)->operator[](iRow));
545 }
546
547 /// @brief Raw pointer to the start of the flat data buffer.
548 /// @details For CSR, requires compressed form. Device-callable.
550 {
551 if constexpr (_dataLayout == CSR)
552 DNDS_HD_assert_infof(this->isCompressed(), "CSR must be compressed to get data pointer");
554 }
555
556 /// @brief Size of the flat data buffer in `T` elements.
558 {
559 if (this->Size() == 0)
560 return 0;
561 if constexpr (_dataLayout == CSR)
562 DNDS_HD_assert_infof(this->isCompressed(), "CSR must be compressed to get DataSize()");
563 return _data_size;
564 }
565
566 /// @brief Pointer equality (two views referring to the same buffer).
568 {
569 return R._data == _data;
570 }
571
572 /**
573 * @brief Non-owning view of a single row: `{pointer, size}`.
574 *
575 * @details Supports indexing, iteration (`begin`/`end`), copy-in / copy-out
576 * from `std::vector`, and an `assign_value` kernel-safe copy. Returned by
577 * iterators derived from @ref DNDS::ArrayIteratorBase "ArrayIteratorBase".
578 */
580 {
581 T *ptr = nullptr;
582 rowsize row_size = 0;
583
584 public:
585 // DNDS_DEVICE_TRIVIAL_COPY_DEFINE(AdjacencyRow, AdjacencyRow)
586
590 DNDS_DEVICE_CALLABLE RowView(T *n_ptr, rowsize siz) : ptr(n_ptr), row_size(siz) {} // default actually
591
593 {
594 DNDS_assert(j >= 0 && j < row_size);
595 return ptr[j];
596 }
597
599 {
600 DNDS_assert(j >= 0 && j < row_size);
601 return ptr[j];
602 }
603
604 operator std::vector<T>() const // copies to a new std::vector<index>
605 {
606 return {ptr, ptr + row_size};
607 }
608
609 void operator=(const std::vector<index> &r)
610 {
611 DNDS_assert(row_size == r.size());
612 std::copy(r.begin(), r.end(), ptr);
613 }
614
616 {
617 DNDS_assert(row_size == r.size());
618 std::copy(r.cbegin(), r.cend(), ptr);
619 }
620
621 DNDS_DEVICE_CALLABLE T *begin() { return ptr; }
622 DNDS_DEVICE_CALLABLE T *end() { return ptr + row_size; } // past-end
623 DNDS_DEVICE_CALLABLE T *cbegin() const { return ptr; }
624 DNDS_DEVICE_CALLABLE T *cend() const { return ptr + row_size; } // past-end
625 DNDS_DEVICE_CALLABLE [[nodiscard]] rowsize size() const { return row_size; }
626 };
627 };
628
629 /**
630 * @brief CRTP base for row-granularity iterators over an @ref DNDS::Array "Array" / @ref DNDS::ArrayView "ArrayView".
631 *
632 * @details Provides all comparison / arithmetic operators for a random-access
633 * iterator (the `difference_type` is `std::ptrdiff_t` on a row basis); the
634 * derived class supplies `getView()` and `operator*`. Used by
635 * `Array::iterator<B>` for both host and device traversal.
636 */
637 template <class Derived>
639 {
640 protected:
642
643 public:
644 using difference_type = std::ptrdiff_t;
645 using iterator_category = std::random_access_iterator_tag;
646 using reference = void;
647 using pointer = void;
648 using value = void;
649
651 {
652 auto dthis = static_cast<const Derived *>(this);
653 return dthis->getView();
654 }
656
658 {
659 // DNDS_HD_assert(iRow >= -1 && iRow <= getView().Size()); //! view in derived class is uninitialized here!
660 }
661
662 DNDS_DEVICE_CALLABLE index RowSize() const { return getView().RowSize(iRow); }
663
665 {
666 iRow = std::min(iRow + 1, getView().Size());
667 return *this;
668 }
669
671 {
672 auto tmp = *this;
673 ++(*this);
674 return tmp;
675 }
676
678 {
679 iRow = std::max(iRow - 1, index(-1));
680 return *this;
681 }
682
684 {
685 auto tmp = *this;
686 --(*this);
687 return tmp;
688 }
689
691 {
692 iRow = std::clamp(iRow + n, index(-1), getView().Size());
693 return *this;
694 }
695
697 {
698 iRow = std::clamp(iRow - n, index(-1), getView().Size());
699 return *this;
700 }
701
703 {
704 return Derived{getView(), std::clamp(iRow + n, index(-1), getView().Size())};
705 }
706
708 {
709 return Derived{getView(), std::clamp(iRow - n, index(-1), getView().Size())};
710 }
711
712 DNDS_DEVICE_CALLABLE difference_type operator-(const Derived &R) const { return iRow - R.iRow; }
713
714 DNDS_DEVICE_CALLABLE bool operator==(const Derived &R) const { return ((R.getView()) == (this->getView())) && (R.iRow == this->iRow); }
715 DNDS_DEVICE_CALLABLE bool operator!=(const Derived &R) const { return !((*this) == R); }
716 DNDS_DEVICE_CALLABLE bool operator<(const Derived &R) const { return ((R.getView()) == (this->getView())) && (this->iRow < R.iRow); }
717 DNDS_DEVICE_CALLABLE bool operator>=(const Derived &R) const { return ((R.getView()) == (this->getView())) && (this->iRow >= R.iRow); }
718 DNDS_DEVICE_CALLABLE bool operator>(const Derived &R) const { return ((R.getView()) == (this->getView())) && (this->iRow > R.iRow); }
719 DNDS_DEVICE_CALLABLE bool operator<=(const Derived &R) const { return ((R.getView()) == (this->getView())) && (this->iRow <= R.iRow); }
720
721 DNDS_DEVICE_CALLABLE auto operator[](difference_type n) { return (this->operator+(n)).operator*(); }
722 DNDS_DEVICE_CALLABLE auto operator[](difference_type n) const { return (this->operator+(n)).operator*(); }
723 };
724
725}
Core type aliases, constants, and metaprogramming utilities for the DNDS framework.
#define DNDS_DEVICE_TRIVIAL_COPY_DEFINE(T, T_Self)
Definition Defines.hpp:83
#define DNDS_DEVICE_CALLABLE
Definition Defines.hpp:76
#define DNDS_DEVICE_TRIVIAL_COPY_DEFINE_NO_EMPTY_CTOR(T, T_Self)
Definition Defines.hpp:91
Assertion / error-handling macros and supporting helper functions.
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
Definition Errors.hpp:113
#define DNDS_assert(expr)
Debug-only assertion (compiled out when DNDS_NDEBUG is defined). Prints the expression + file/line + ...
Definition Errors.hpp:108
#define DNDS_HD_assert(cond)
Host-only expansion of DNDS_HD_assert (equivalent to DNDS_assert).
Definition Errors.hpp:189
#define DNDS_HD_assert_infof(cond, info,...)
Host-only expansion of DNDS_HD_assert_infof.
Definition Errors.hpp:191
CRTP base for row-granularity iterators over an Array / ArrayView.
DNDS_DEVICE_CALLABLE auto operator[](difference_type n) const
DNDS_DEVICE_CALLABLE Derived operator+(difference_type n) const
std::random_access_iterator_tag iterator_category
std::ptrdiff_t difference_type
DNDS_DEVICE_CALLABLE auto operator[](difference_type n)
DNDS_DEVICE_CALLABLE difference_type operator-(const Derived &R) const
DNDS_DEVICE_CALLABLE auto getView() const
DNDS_DEVICE_CALLABLE bool operator!=(const Derived &R) const
DNDS_DEVICE_CALLABLE bool operator>=(const Derived &R) const
DNDS_DEVICE_CALLABLE bool operator>(const Derived &R) const
DNDS_DEVICE_CALLABLE bool operator<=(const Derived &R) const
DNDS_DEVICE_CALLABLE Derived & operator++()
DNDS_DEVICE_CALLABLE bool operator==(const Derived &R) const
DNDS_DEVICE_CALLABLE Derived operator-(difference_type n) const
DNDS_DEVICE_CALLABLE Derived operator--(int)
DNDS_DEVICE_CALLABLE index RowSize() const
DNDS_DEVICE_CALLABLE bool operator<(const Derived &R) const
DNDS_DEVICE_CALLABLE Derived & operator-=(difference_type n)
DNDS_DEVICE_CALLABLE Derived & operator+=(difference_type n)
DNDS_DEVICE_CALLABLE Derived operator++(int)
DNDS_DEVICE_CALLABLE Derived & operator--()
Compile-time layout descriptor deducing the concrete DataLayout from element type and row-size templa...
static bool ArraySignatureIsCompatible(const std::string &v)
Whether a stored signature can be read into this array type.
static const rowsize s_T
static const rowsize al
static std::tuple< int, int, int, int > ParseArraySignatureTuple(const std::string &v)
Parse a signature string into (sizeof_T, row_size, row_max, align).
static std::string GetArraySignatureRelaxed()
Signature with _row_size / _row_max replaced by DynamicSize.
static const DataLayout _dataLayout
static const bool isCSR
static constexpr DataLayout _GetDataLayout()
Deduce the DataLayout tag from the template parameters.
static const size_t sizeof_T
static std::string GetArrayName()
Human-readable type identifier including element typeid, sizes, and alignment.
static std::string GetArraySignature()
Compiler-independent identifier used by serializers to tag an array.
static const rowsize rs
static const rowsize rm
Non-owning view of a single row: {pointer, size}.
DNDS_DEVICE_CALLABLE T * cend() const
DNDS_DEVICE_CALLABLE T * begin()
DNDS_DEVICE_CALLABLE rowsize size() const
DNDS_DEVICE_CALLABLE RowView(T *n_ptr, rowsize siz)
DNDS_DEVICE_CALLABLE T * end()
DNDS_DEVICE_CALLABLE void assign_value(const RowView &r)
DNDS_DEVICE_CALLABLE RowView(const RowView &)=default
DNDS_DEVICE_CALLABLE T & operator[](rowsize j)
DNDS_DEVICE_CALLABLE ~RowView()=default
DNDS_DEVICE_CALLABLE RowView()=default
DNDS_DEVICE_CALLABLE T * cbegin() const
DNDS_DEVICE_CALLABLE T operator[](rowsize j) const
void operator=(const std::vector< index > &r)
Non-owning, device-callable view onto an Array.
const T & at(index iRow, rowsize iCol) const
Bounds-checked element read (not device-callable because CSR decompressed uses std::vector::at which ...
T * operator[](index iRow)
Raw row pointer. iRow == Size() is allowed for past-the-end queries (useful for computing buffer end ...
DNDS_DEVICE_CALLABLE T * get_rowstart_pointer_compressed(index iRow)
DNDS_DEVICE_CALLABLE bool operator==(const self_type &R) const
Pointer equality (two views referring to the same buffer).
std::conditional_t< _dataLayout==CSR, t_dataUncompressed *, EmptyNoDefault > _p_dataUncompressed
const T * operator[](index iRow) const
Const row pointer; see the non-const overload.
std::vector< std::vector< T > > t_dataUncompressed
DNDS_DEVICE_CALLABLE index Size() const
Number of rows in the viewed array.
const T & operator()(index iRow, rowsize iCol=0) const
2D indexed access (read-only).
DNDS_DEVICE_CALLABLE bool isCompressed() const
Whether the underlying array is in the compressed (flat) form (always true for non-CSR).
DNDS_DEVICE_CALLABLE T * data()
Raw pointer to the start of the flat data buffer.
DNDS_DEVICE_CALLABLE rowsize RowSize() const
Uniform row width for fixed layouts (asserts otherwise).
std::conditional_t< _dataLayout==TABLE_Max||_dataLayout==TABLE_Fixed, rowsize, EmptyNoDefault > _row_size_dynamic
DNDS_DEVICE_CALLABLE rowsize RowSize_Compressed(index iRow) const
std::conditional_t< _dataLayout==CSR, const index *, std::conditional_t< _dataLayout==TABLE_Max||_dataLayout==TABLE_StaticMax, const rowsize *, EmptyNoDefault > > _rowstart_or_rowsize
DNDS_DEVICE_CALLABLE rowsize RowSizeField(index iRow) const
Per-row "field" size for CSR (= actual row width).
DNDS_DEVICE_CALLABLE rowsize RowSize(index iRow) const
Per-row width. Handles CSR compressed and decompressed modes.
T & operator()(index iRow, rowsize iCol=0)
2D indexed access (writable). See at.
DNDS_DEVICE_CALLABLE rowsize RowSizeMax() const
Maximum row width (TABLE_*Max only).
DNDS_DEVICE_CALLABLE const T & at_compressed(index iRow, rowsize iCol) const
DNDS_DEVICE_CALLABLE rowsize RowSizeField() const
"Logical" row-field width used by derived Eigen arrays; see Array::RowSizeField.
DNDS_DEVICE_CALLABLE size_t DataSize() const
Size of the flat data buffer in T elements.
the host side operators are provided as implemented
constexpr bool isTABLE_Fixed(DataLayout lo)
Whether the layout has a uniform row width (no per-row size needed).
DNDS_CONSTANT const index UnInitIndex
Sentinel "not initialised" index value (= INT64_MIN).
Definition Defines.hpp:176
DNDS_CONSTANT const rowsize NoAlign
Alignment flag: no padding applied to rows (the only currently-supported value).
Definition Defines.hpp:282
constexpr bool isTABLE_Dynamic(DataLayout lo)
Whether the layout carries a runtime row-size parameter.
int32_t rowsize
Row-width / per-row element-count type (signed 32-bit).
Definition Defines.hpp:109
constexpr bool isTABLE(DataLayout lo)
Whether the layout uses a TABLE (padded) representation (vs CSR).
DNDS_CONSTANT const rowsize DynamicSize
Template parameter flag: "row width is set at runtime but uniform".
Definition Defines.hpp:277
DataLayout
Enumeration of the five concrete data layouts supported by Array.
@ ErrorLayout
Invalid combination of template parameters.
@ TABLE_StaticFixed
Fixed row width, known at compile time.
@ TABLE_Max
Padded variable rows; max width set at runtime.
@ CSR
Compressed Sparse Row (flat buffer + row-start index).
@ TABLE_StaticMax
Padded variable rows; max width fixed at compile time.
@ TABLE_Fixed
Fixed row width, set at runtime (uniform across rows).
DNDS_CONSTANT const rowsize NonUniformSize
Template parameter flag: "each row has an independent width".
Definition Defines.hpp:279
std::string RowSize_To_PySnippet(rowsize rs)
Encode a rowsize constant as a short Python-binding snippet: "<number>" for fixed,...
Definition Defines.hpp:294
constexpr bool isTABLE_Max(DataLayout lo)
Whether the layout is a padded-max variant (uses _pRowSizes).
constexpr bool array_comp_acceptable()
Whether T is legal as an Array element type (trivially copyable or a fixed-size real Eigen matrix)....
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:107
std::vector< std::string > splitSStringClean(const std::string &str, char delim)
Definition Defines.hpp:790
std::string Align_To_PySnippet(rowsize al)
Encode an alignment value as a Python-binding snippet: "N" for NoAlign, the number otherwise.
Definition Defines.hpp:310
DNDS_CONSTANT const rowsize UnInitRowsize
Sentinel "not initialised" rowsize value (= INT32_MIN).
Definition Defines.hpp:179
constexpr bool isTABLE_Static(DataLayout lo)
Whether the layout has a compile-time row-size constant.
Empty placeholder type without a default constructor; accepts any assignment.
Definition Defines.hpp:922
Eigen::Matrix< real, 5, 1 > v
tVec r(NCells)
Eigen::Vector3d n(1.0, 0.0, 0.0)