DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
test_Array.cpp
Go to the documentation of this file.
1/**
2 * @file test_Array.cpp
3 * @brief Doctest-based unit tests for DNDS::Array across all five data
4 * layouts (TABLE_StaticFixed, TABLE_Fixed, TABLE_StaticMax,
5 * TABLE_Max, CSR).
6 *
7 * This is a serial test (no MPI required). It also covers clone/copy
8 * semantics, edge cases, JSON serialization round-trips, array signature
9 * utilities, and hashing.
10 *
11 * @see @ref dnds_unit_tests for the full test-suite overview.
12 * @test Array layout correctness, resize, compress/decompress, clone, copy,
13 * swap, serialization round-trip, signature, hash.
14 */
15
16#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
17#include "doctest.h"
18
19#include "DNDS/Array.hpp"
20
21#include <cstdint>
22#include <cstdio>
23#include <filesystem>
24#include <string>
25
26using namespace DNDS;
27
28// ===================================================================
29// TABLE_StaticFixed: Array<real, 3> — compile-time fixed row size
30// ===================================================================
31TEST_CASE("Array TABLE_StaticFixed layout")
32{
34 a.Resize(10);
35
36 REQUIRE(a.Size() == 10);
37 REQUIRE(a.RowSize() == 3);
39
40 SUBCASE("write and read via operator()")
41 {
42 for (DNDS::index i = 0; i < a.Size(); i++)
43 for (DNDS::rowsize j = 0; j < a.RowSize(); j++)
44 a(i, j) = static_cast<DNDS::real>(i * 10 + j);
45
46 for (DNDS::index i = 0; i < a.Size(); i++)
47 for (DNDS::rowsize j = 0; j < a.RowSize(); j++)
48 CHECK(a(i, j) == static_cast<DNDS::real>(i * 10 + j));
49 }
50
51 SUBCASE("operator[] pointer access")
52 {
53 for (DNDS::index i = 0; i < a.Size(); i++)
54 for (DNDS::rowsize j = 0; j < a.RowSize(); j++)
55 a(i, j) = static_cast<DNDS::real>(i * 100 + j);
56
57 for (DNDS::index i = 0; i < a.Size(); i++)
58 {
59 DNDS::real *row = a[i];
60 REQUIRE(row != nullptr);
61 for (DNDS::rowsize j = 0; j < a.RowSize(); j++)
62 CHECK(row[j] == static_cast<DNDS::real>(i * 100 + j));
63 }
64 }
65
66 SUBCASE("DataSize and DataSizeBytes")
67 {
68 CHECK(a.DataSize() == 10 * 3);
69 CHECK(a.DataSizeBytes() == 10 * 3 * sizeof(DNDS::real));
70 }
71}
72
73// ===================================================================
74// TABLE_Fixed: Array<real, DynamicSize> — runtime-chosen fixed row size
75// ===================================================================
76TEST_CASE("Array TABLE_Fixed layout")
77{
79 b.Resize(8, 5);
80
81 REQUIRE(b.Size() == 8);
82 REQUIRE(b.RowSize() == 5);
83 CHECK(b.GetDataLayout() == TABLE_Fixed);
84
85 for (DNDS::index i = 0; i < b.Size(); i++)
86 for (DNDS::rowsize j = 0; j < b.RowSize(); j++)
87 b(i, j) = static_cast<DNDS::real>(i * 10 + j);
88
89 for (DNDS::index i = 0; i < b.Size(); i++)
90 for (DNDS::rowsize j = 0; j < b.RowSize(); j++)
91 CHECK(b(i, j) == static_cast<DNDS::real>(i * 10 + j));
92
93 CHECK(b.DataSize() == 8 * 5);
94 CHECK(b.DataSizeBytes() == 8 * 5 * sizeof(DNDS::real));
95}
96
97// ===================================================================
98// TABLE_StaticMax: Array<real, NonUniformSize, 4> — per-row size ≤ 4
99// ===================================================================
100TEST_CASE("Array TABLE_StaticMax layout")
101{
103 c.Resize(6);
104
105 REQUIRE(c.Size() == 6);
107 CHECK(c.RowSizeMax() == 4);
108
109 // Assign each row a different active size in [1, 4]
110 for (DNDS::index i = 0; i < c.Size(); i++)
111 c.ResizeRow(i, static_cast<DNDS::rowsize>(i % 4 + 1));
112
113 // Write values
114 for (DNDS::index i = 0; i < c.Size(); i++)
115 for (DNDS::rowsize j = 0; j < c.RowSize(i); j++)
116 c(i, j) = static_cast<DNDS::real>(i * 10 + j);
117
118 // Read back and verify
119 for (DNDS::index i = 0; i < c.Size(); i++)
120 {
121 CHECK(c.RowSize(i) == static_cast<DNDS::rowsize>(i % 4 + 1));
122 for (DNDS::rowsize j = 0; j < c.RowSize(i); j++)
123 CHECK(c(i, j) == static_cast<DNDS::real>(i * 10 + j));
124 }
125}
126
127// ===================================================================
128// TABLE_Max: Array<real, NonUniformSize, DynamicSize> — dynamic max
129// ===================================================================
130TEST_CASE("Array TABLE_Max layout")
131{
133 d.Resize(5, 6);
134
135 REQUIRE(d.Size() == 5);
137 CHECK(d.RowSizeMax() == 6);
138
139 for (DNDS::index i = 0; i < d.Size(); i++)
140 d.ResizeRow(i, static_cast<DNDS::rowsize>(i + 1)); // sizes 1..5
141
142 for (DNDS::index i = 0; i < d.Size(); i++)
143 for (DNDS::rowsize j = 0; j < d.RowSize(i); j++)
144 d(i, j) = static_cast<DNDS::real>(i * 100 + j);
145
146 for (DNDS::index i = 0; i < d.Size(); i++)
147 {
148 CHECK(d.RowSize(i) == static_cast<DNDS::rowsize>(i + 1));
149 for (DNDS::rowsize j = 0; j < d.RowSize(i); j++)
150 CHECK(d(i, j) == static_cast<DNDS::real>(i * 100 + j));
151 }
152}
153
154// ===================================================================
155// CSR: Array<real, NonUniformSize> — compressed sparse row
156// ===================================================================
157TEST_CASE("Array CSR layout")
158{
160 CHECK(e.GetDataLayout() == CSR);
161
162 SUBCASE("Resize with lambda and compress round-trip")
163 {
164 // Build compressed directly via lambda
165 e.Resize(10, [](DNDS::index i) -> DNDS::rowsize
166 { return static_cast<DNDS::rowsize>(i % 4 + 1); });
167
168 REQUIRE(e.Size() == 10);
169 CHECK(e.IfCompressed());
170
171 // Verify row sizes
172 for (DNDS::index i = 0; i < e.Size(); i++)
173 CHECK(e.RowSize(i) == static_cast<DNDS::rowsize>(i % 4 + 1));
174
175 // Write values (compressed)
176 for (DNDS::index i = 0; i < e.Size(); i++)
177 for (DNDS::rowsize j = 0; j < e.RowSize(i); j++)
178 e(i, j) = static_cast<DNDS::real>(i * 10 + j);
179
180 // Read back
181 for (DNDS::index i = 0; i < e.Size(); i++)
182 for (DNDS::rowsize j = 0; j < e.RowSize(i); j++)
183 CHECK(e(i, j) == static_cast<DNDS::real>(i * 10 + j));
184 }
185
186 SUBCASE("Decompress, modify, re-Compress")
187 {
188 e.Resize(6, [](DNDS::index i) -> DNDS::rowsize
189 { return static_cast<DNDS::rowsize>(i % 3 + 1); });
190
191 // Fill with known data
192 for (DNDS::index i = 0; i < e.Size(); i++)
193 for (DNDS::rowsize j = 0; j < e.RowSize(i); j++)
194 e(i, j) = static_cast<DNDS::real>(i + j * 0.1);
195
196 // Decompress
197 e.Decompress();
198 CHECK_FALSE(e.IfCompressed());
199
200 // Data should still be readable
201 for (DNDS::index i = 0; i < e.Size(); i++)
202 for (DNDS::rowsize j = 0; j < e.RowSize(i); j++)
203 CHECK(e(i, j) == doctest::Approx(static_cast<DNDS::real>(i + j * 0.1)));
204
205 // Resize some rows in decompressed mode
206 for (DNDS::index i = 0; i < e.Size(); i++)
207 e.ResizeRow(i, static_cast<DNDS::rowsize>(i % 2 + 2)); // sizes 2 or 3
208
209 // Write new data
210 for (DNDS::index i = 0; i < e.Size(); i++)
211 for (DNDS::rowsize j = 0; j < e.RowSize(i); j++)
212 e(i, j) = static_cast<DNDS::real>(i * 100 + j);
213
214 // Re-compress
215 e.Compress();
216 CHECK(e.IfCompressed());
217
218 // Verify sizes and data after round-trip
219 for (DNDS::index i = 0; i < e.Size(); i++)
220 {
221 CHECK(e.RowSize(i) == static_cast<DNDS::rowsize>(i % 2 + 2));
222 for (DNDS::rowsize j = 0; j < e.RowSize(i); j++)
223 CHECK(e(i, j) == static_cast<DNDS::real>(i * 100 + j));
224 }
225 }
226}
227
228// ===================================================================
229// Clone, copy, and swap
230// ===================================================================
231TEST_CASE("Array clone and copy")
232{
233 // Source: TABLE_Fixed with known data
235 src.Resize(5, 4);
236 for (DNDS::index i = 0; i < src.Size(); i++)
237 for (DNDS::rowsize j = 0; j < src.RowSize(); j++)
238 src(i, j) = static_cast<DNDS::real>(i * 10 + j);
239
240 SUBCASE("clone produces identical independent copy")
241 {
243 dst.clone(src);
244
245 REQUIRE(dst.Size() == src.Size());
246 REQUIRE(dst.RowSize() == src.RowSize());
247 for (DNDS::index i = 0; i < dst.Size(); i++)
248 for (DNDS::rowsize j = 0; j < dst.RowSize(); j++)
249 CHECK(dst(i, j) == src(i, j));
250
251 // Modifying source does not affect clone
252 src(0, 0) = -999.0;
253 CHECK(dst(0, 0) != -999.0);
254 }
255
256 SUBCASE("CopyData produces identical copy")
257 {
259 dst.CopyData(src);
260
261 REQUIRE(dst.Size() == src.Size());
262 for (DNDS::index i = 0; i < dst.Size(); i++)
263 for (DNDS::rowsize j = 0; j < dst.RowSize(); j++)
264 CHECK(dst(i, j) == src(i, j));
265 }
266
267 SUBCASE("copy constructor")
268 {
270
271 REQUIRE(cpy.Size() == src.Size());
272 REQUIRE(cpy.RowSize() == src.RowSize());
273 for (DNDS::index i = 0; i < cpy.Size(); i++)
274 for (DNDS::rowsize j = 0; j < cpy.RowSize(); j++)
275 CHECK(cpy(i, j) == src(i, j));
276 }
277
278 SUBCASE("SwapData exchanges contents")
279 {
281 other.Resize(5, 4);
282 for (DNDS::index i = 0; i < other.Size(); i++)
283 for (DNDS::rowsize j = 0; j < other.RowSize(); j++)
284 other(i, j) = static_cast<DNDS::real>(i * 10 + j + 1000);
285
286 DNDS::real src_0_0 = src(0, 0);
287 DNDS::real other_0_0 = other(0, 0);
288
289 src.SwapData(other);
290
291 CHECK(src(0, 0) == other_0_0);
292 CHECK(other(0, 0) == src_0_0);
293 }
294}
295
296// ===================================================================
297// Edge cases
298// ===================================================================
299TEST_CASE("Array edge cases")
300{
301 SUBCASE("zero-size TABLE_StaticFixed")
302 {
304 z.Resize(0);
305 CHECK(z.Size() == 0);
306 CHECK(z.DataSize() == 0);
307 CHECK(z.DataSizeBytes() == 0);
308 }
309
310 SUBCASE("single element TABLE_StaticFixed")
311 {
313 s.Resize(1);
314 REQUIRE(s.Size() == 1);
315 s(0, 0) = 42.0;
316 s(0, 1) = 43.0;
317 CHECK(s(0, 0) == 42.0);
318 CHECK(s(0, 1) == 43.0);
319 }
320
321 SUBCASE("CSR with lambda returning 0 for some rows")
322 {
324 csr.Resize(5, [](DNDS::index i) -> DNDS::rowsize
325 { return (i % 2 == 0) ? 0 : 3; });
326
327 REQUIRE(csr.Size() == 5);
328 for (DNDS::index i = 0; i < csr.Size(); i++)
329 {
330 DNDS::rowsize expected = (i % 2 == 0) ? 0 : 3;
331 CHECK(csr.RowSize(i) == expected);
332 }
333
334 // Write to non-zero rows only
335 for (DNDS::index i = 0; i < csr.Size(); i++)
336 for (DNDS::rowsize j = 0; j < csr.RowSize(i); j++)
337 csr(i, j) = static_cast<DNDS::real>(i * 10 + j);
338
339 // Read back
340 for (DNDS::index i = 0; i < csr.Size(); i++)
341 for (DNDS::rowsize j = 0; j < csr.RowSize(i); j++)
342 CHECK(csr(i, j) == static_cast<DNDS::real>(i * 10 + j));
343 }
344
345 SUBCASE("zero-size TABLE_Fixed")
346 {
348 z.Resize(0, 5);
349 CHECK(z.Size() == 0);
350 CHECK(z.DataSize() == 0);
351 }
352}
353
354// ===================================================================
355// Serialization round-trip (JSON)
356// ===================================================================
357TEST_CASE("Array serialization round-trip")
358{
359 namespace S = DNDS::Serializer;
360 const std::string tmpFile = "__test_array_ser_tmp.json";
361 auto cleanup = [&]()
362 {
363 std::filesystem::remove(tmpFile);
364 };
365
366 SUBCASE("TABLE_Fixed round-trip")
367 {
368 // Write
369 {
371 src.Resize(4, 3);
372 for (DNDS::index i = 0; i < src.Size(); i++)
373 for (DNDS::rowsize j = 0; j < src.RowSize(); j++)
374 src(i, j) = static_cast<DNDS::real>(i * 10 + j);
375
376 auto ser = std::make_shared<S::SerializerJSON>();
377 ser->OpenFile(tmpFile, false);
378 S::ArrayGlobalOffset offset = S::ArrayGlobalOffset_Unknown;
379 src.WriteSerializer(ser, "arr", offset);
380 ser->CloseFile();
381 }
382
383 // Read
384 {
386 auto ser = std::make_shared<S::SerializerJSON>();
387 ser->OpenFile(tmpFile, true);
388 S::ArrayGlobalOffset offset = S::ArrayGlobalOffset_Unknown;
389 dst.ReadSerializer(ser, "arr", offset);
390 ser->CloseFile();
391
392 REQUIRE(dst.Size() == 4);
393 REQUIRE(dst.RowSize() == 3);
394 for (DNDS::index i = 0; i < dst.Size(); i++)
395 for (DNDS::rowsize j = 0; j < dst.RowSize(); j++)
396 CHECK(dst(i, j) == static_cast<DNDS::real>(i * 10 + j));
397 }
398 cleanup();
399 }
400
401 SUBCASE("CSR round-trip")
402 {
403 // Write
404 {
406 src.Resize(6, [](DNDS::index i) -> DNDS::rowsize
407 { return static_cast<DNDS::rowsize>(i % 3 + 1); });
408
409 for (DNDS::index i = 0; i < src.Size(); i++)
410 for (DNDS::rowsize j = 0; j < src.RowSize(i); j++)
411 src(i, j) = static_cast<DNDS::real>(i * 100 + j);
412
413 auto ser = std::make_shared<S::SerializerJSON>();
414 ser->OpenFile(tmpFile, false);
415 S::ArrayGlobalOffset offset = S::ArrayGlobalOffset_Unknown;
416 src.WriteSerializer(ser, "csr", offset);
417 ser->CloseFile();
418 }
419
420 // Read
421 {
423 // Pre-create with any shape so ReadSerializer can populate it
424 dst.Resize(1, [](DNDS::index) -> DNDS::rowsize
425 { return 1; });
426
427 auto ser = std::make_shared<S::SerializerJSON>();
428 ser->OpenFile(tmpFile, true);
429 S::ArrayGlobalOffset offset = S::ArrayGlobalOffset_Unknown;
430 dst.ReadSerializer(ser, "csr", offset);
431 ser->CloseFile();
432
433 REQUIRE(dst.Size() == 6);
434 for (DNDS::index i = 0; i < dst.Size(); i++)
435 {
436 CHECK(dst.RowSize(i) == static_cast<DNDS::rowsize>(i % 3 + 1));
437 for (DNDS::rowsize j = 0; j < dst.RowSize(i); j++)
438 CHECK(dst(i, j) == static_cast<DNDS::real>(i * 100 + j));
439 }
440 }
441 cleanup();
442 }
443
444 SUBCASE("TABLE_StaticFixed round-trip")
445 {
446 // Write
447 {
449 src.Resize(5);
450 for (DNDS::index i = 0; i < src.Size(); i++)
451 for (DNDS::rowsize j = 0; j < src.RowSize(); j++)
452 src(i, j) = static_cast<DNDS::real>(i + j * 0.5);
453
454 auto ser = std::make_shared<S::SerializerJSON>();
455 ser->OpenFile(tmpFile, false);
456 S::ArrayGlobalOffset offset = S::ArrayGlobalOffset_Unknown;
457 src.WriteSerializer(ser, "sf", offset);
458 ser->CloseFile();
459 }
460
461 // Read
462 {
464 auto ser = std::make_shared<S::SerializerJSON>();
465 ser->OpenFile(tmpFile, true);
466 S::ArrayGlobalOffset offset = S::ArrayGlobalOffset_Unknown;
467 dst.ReadSerializer(ser, "sf", offset);
468 ser->CloseFile();
469
470 REQUIRE(dst.Size() == 5);
471 REQUIRE(dst.RowSize() == 3);
472 for (DNDS::index i = 0; i < dst.Size(); i++)
473 for (DNDS::rowsize j = 0; j < dst.RowSize(); j++)
474 CHECK(dst(i, j) == doctest::Approx(static_cast<DNDS::real>(i + j * 0.5)));
475 }
476 cleanup();
477 }
478}
479
480// ===================================================================
481// Signature helpers
482// ===================================================================
483TEST_CASE("Array signature")
484{
485 SUBCASE("GetArraySignature returns non-empty string")
486 {
488 CHECK_FALSE(sig.empty());
489 CHECK(sig.find("TABLE_StaticFixed") != std::string::npos);
490 }
491
492 SUBCASE("ParseArraySignatureTuple round-trips")
493 {
496
497 CHECK(sz == static_cast<int>(sizeof(DNDS::real)));
498 CHECK(rs == DynamicSize);
499 CHECK(rm == DynamicSize);
500 }
501
502 SUBCASE("ArraySignatureIsCompatible for matching type")
503 {
506 }
507
508 SUBCASE("ArraySignatureIsCompatible accepts DynamicSize reading static")
509 {
510 // A DynamicSize array should accept a static-row signature if
511 // the sizes are not contradictory.
514 }
515
516 SUBCASE("ArraySignatureIsCompatible rejects mismatched sizes")
517 {
518 // Array<real, 3> vs Array<real, 5> should not be compatible
521 }
522
523 SUBCASE("CSR signature")
524 {
526 CHECK(sig.find("CSR") != std::string::npos);
527 }
528}
529
530// ===================================================================
531// Hash
532// ===================================================================
533TEST_CASE("Array hash")
534{
535 SUBCASE("identical arrays have the same hash")
536 {
538 a.Resize(5);
539 b.Resize(5);
540 for (DNDS::index i = 0; i < 5; i++)
541 for (DNDS::rowsize j = 0; j < 3; j++)
542 {
543 a(i, j) = static_cast<DNDS::real>(i * 10 + j);
544 b(i, j) = static_cast<DNDS::real>(i * 10 + j);
545 }
546
547 CHECK(a.hash() == b.hash());
548 }
549
550 SUBCASE("modified array has different hash")
551 {
553 a.Resize(5);
554 b.Resize(5);
555 for (DNDS::index i = 0; i < 5; i++)
556 for (DNDS::rowsize j = 0; j < 3; j++)
557 {
558 a(i, j) = static_cast<DNDS::real>(i * 10 + j);
559 b(i, j) = static_cast<DNDS::real>(i * 10 + j);
560 }
561
562 b(2, 1) = -1.0;
563 CHECK(a.hash() != b.hash());
564 }
565}
566
567// ===================================================================
568// Parametric: Array resize-write-read across types and layouts
569// ===================================================================
570
573struct LayoutCSR {};
574
575template <class T, class Layout, DNDS::rowsize RS>
577{
578 using type = T;
579 using layout = Layout;
580 static constexpr DNDS::rowsize rs = RS;
581};
582
583// ---- TYPE_TO_STRING for every tag combination ----
584#define ARRAY_TAG_STR(T, L, RS) TYPE_TO_STRING(ArrayTag<T, L, RS>)
585
586// real
594// index
602// uint16_t
610// int32_t
618// uint8_t
626
627#undef ARRAY_TAG_STR
628
629// Full cross-product: 5 types x (2 fixed layouts x 3 RS + 1 CSR) = 35 cases
630#define ARRAY_ALL_TAGS \
631 /* real x StaticFixed */ \
632 ArrayTag<DNDS::real, LayoutStaticFixed, 1>, \
633 ArrayTag<DNDS::real, LayoutStaticFixed, 3>, \
634 ArrayTag<DNDS::real, LayoutStaticFixed, 7>, \
635 /* real x Dynamic */ \
636 ArrayTag<DNDS::real, LayoutDynamic, 1>, \
637 ArrayTag<DNDS::real, LayoutDynamic, 3>, \
638 ArrayTag<DNDS::real, LayoutDynamic, 7>, \
639 /* real x CSR */ \
640 ArrayTag<DNDS::real, LayoutCSR, 0>, \
641 /* index */ \
642 ArrayTag<DNDS::index, LayoutStaticFixed, 1>, \
643 ArrayTag<DNDS::index, LayoutStaticFixed, 3>, \
644 ArrayTag<DNDS::index, LayoutStaticFixed, 7>, \
645 ArrayTag<DNDS::index, LayoutDynamic, 1>, \
646 ArrayTag<DNDS::index, LayoutDynamic, 3>, \
647 ArrayTag<DNDS::index, LayoutDynamic, 7>, \
648 ArrayTag<DNDS::index, LayoutCSR, 0>, \
649 /* uint16_t */ \
650 ArrayTag<uint16_t, LayoutStaticFixed, 1>, \
651 ArrayTag<uint16_t, LayoutStaticFixed, 3>, \
652 ArrayTag<uint16_t, LayoutStaticFixed, 7>, \
653 ArrayTag<uint16_t, LayoutDynamic, 1>, \
654 ArrayTag<uint16_t, LayoutDynamic, 3>, \
655 ArrayTag<uint16_t, LayoutDynamic, 7>, \
656 ArrayTag<uint16_t, LayoutCSR, 0>, \
657 /* int32_t */ \
658 ArrayTag<int32_t, LayoutStaticFixed, 1>, \
659 ArrayTag<int32_t, LayoutStaticFixed, 3>, \
660 ArrayTag<int32_t, LayoutStaticFixed, 7>, \
661 ArrayTag<int32_t, LayoutDynamic, 1>, \
662 ArrayTag<int32_t, LayoutDynamic, 3>, \
663 ArrayTag<int32_t, LayoutDynamic, 7>, \
664 ArrayTag<int32_t, LayoutCSR, 0>, \
665 /* uint8_t */ \
666 ArrayTag<uint8_t, LayoutStaticFixed, 1>, \
667 ArrayTag<uint8_t, LayoutStaticFixed, 3>, \
668 ArrayTag<uint8_t, LayoutStaticFixed, 7>, \
669 ArrayTag<uint8_t, LayoutDynamic, 1>, \
670 ArrayTag<uint8_t, LayoutDynamic, 3>, \
671 ArrayTag<uint8_t, LayoutDynamic, 7>, \
672 ArrayTag<uint8_t, LayoutCSR, 0>
673
674TEST_CASE_TEMPLATE("Array resize-write-read", Tag, ARRAY_ALL_TAGS)
675{
676 using T = typename Tag::type;
677 using L = typename Tag::layout;
678 constexpr DNDS::rowsize RS = Tag::rs;
679
680 for (DNDS::index N : {1, 5, 20, 100, 500})
681 {
682 CAPTURE(N);
683
684 if constexpr (std::is_same_v<L, LayoutStaticFixed>)
685 {
686 Array<T, RS> a;
687 a.Resize(N);
688
689 REQUIRE(a.Size() == N);
690 REQUIRE(a.RowSize() == RS);
691
692 for (DNDS::index i = 0; i < a.Size(); i++)
693 for (DNDS::rowsize j = 0; j < a.RowSize(); j++)
694 a(i, j) = static_cast<T>(i * 100 + j * 3 + 7);
695
696 for (DNDS::index i = 0; i < a.Size(); i++)
697 for (DNDS::rowsize j = 0; j < a.RowSize(); j++)
698 CHECK(a(i, j) == static_cast<T>(i * 100 + j * 3 + 7));
699 }
700 else if constexpr (std::is_same_v<L, LayoutDynamic>)
701 {
703 a.Resize(N, RS);
704
705 REQUIRE(a.Size() == N);
706 REQUIRE(a.RowSize() == RS);
707
708 for (DNDS::index i = 0; i < a.Size(); i++)
709 for (DNDS::rowsize j = 0; j < a.RowSize(); j++)
710 a(i, j) = static_cast<T>(i * 100 + j * 3 + 7);
711
712 for (DNDS::index i = 0; i < a.Size(); i++)
713 for (DNDS::rowsize j = 0; j < a.RowSize(); j++)
714 CHECK(a(i, j) == static_cast<T>(i * 100 + j * 3 + 7));
715 }
716 else // LayoutCSR
717 {
719
721 { return static_cast<DNDS::rowsize>(i % 5 + 1); });
722
723 REQUIRE(a.Size() == N);
724 CHECK(a.IfCompressed());
725
726 // Verify row sizes
727 for (DNDS::index i = 0; i < a.Size(); i++)
728 CHECK(a.RowSize(i) == static_cast<DNDS::rowsize>(i % 5 + 1));
729
730 // Fill with data
731 for (DNDS::index i = 0; i < a.Size(); i++)
732 for (DNDS::rowsize j = 0; j < a.RowSize(i); j++)
733 a(i, j) = static_cast<T>(i * 100 + j * 3 + 7);
734
735 // Read back and verify
736 for (DNDS::index i = 0; i < a.Size(); i++)
737 {
738 CHECK(a.RowSize(i) == static_cast<DNDS::rowsize>(i % 5 + 1));
739 for (DNDS::rowsize j = 0; j < a.RowSize(i); j++)
740 CHECK(a(i, j) == static_cast<T>(i * 100 + j * 3 + 7));
741 }
742 }
743 } // for N
744}
Core 2D variable-length array container with five data layouts.
Core 2D variable-length array container, the storage foundation of DNDSR.
Definition Array.hpp:97
std::size_t hash()
Combined hash of size, structural arrays, and data.
Definition Array.hpp:748
void Resize(index nSize, rowsize nRow_size_dynamic)
Resize the array, setting a uniform or maximum row width.
Definition Array.hpp:395
void CopyData(const self_type &R)
Deep copy alias. Currently delegates to clone; kept for API compatibility and to allow a future true ...
Definition Array.hpp:805
void Decompress()
Layout-polymorphic decompress: no-op for non-CSR, calls CSRDecompress for CSR.
Definition Array.hpp:361
rowsize RowSize() const
Uniform row width for fixed layouts (no row index needed).
Definition Array.hpp:176
void WriteSerializer(Serializer::SerializerBaseSSP serializerP, const std::string &name, Serializer::ArrayGlobalOffset offset, Serializer::ArrayGlobalOffset dataOffset=Serializer::ArrayGlobalOffset_Unknown)
Serialize (write) array data to a serializer.
Definition Array.hpp:939
bool IfCompressed() const
(CSR only) Whether the array is in packed / flat form.
Definition Array.hpp:294
void SwapData(self_type &R)
Swap the storage of two arrays in-place.
Definition Array.hpp:831
size_t DataSizeBytes() const
Flat buffer size in bytes (= DataSize() * sizeof(T)).
Definition Array.hpp:698
void ResizeRow(index iRow, rowsize nRowSize)
Change the width of a single row.
Definition Array.hpp:504
size_t DataSize() const
Total number of T elements currently stored in the flat buffer.
Definition Array.hpp:688
void Compress()
Layout-polymorphic compress: no-op for non-CSR, calls CSRCompress for CSR.
Definition Array.hpp:355
rowsize RowSizeMax() const
Maximum allowed row width for TABLE_Max / TABLE_StaticMax.
Definition Array.hpp:245
index Size() const
Number of rows currently stored. O(1).
Definition Array.hpp:171
void clone(const self_type &R)
Shallow clone: copies all metadata and shares structural/data storage.
Definition Array.hpp:791
void ReadSerializer(Serializer::SerializerBaseSSP serializerP, const std::string &name, Serializer::ArrayGlobalOffset &offset)
Convenience overload that discards the dataOffset output.
Definition Array.hpp:992
constexpr DataLayout GetDataLayout()
Runtime accessor for the layout tag (constexpr-folded).
Definition Array.hpp:784
Describes one rank's window into a globally-distributed dataset.
the host side operators are provided as implemented
int32_t rowsize
Row-width / per-row element-count type (signed 32-bit).
Definition Defines.hpp:109
DNDS_CONSTANT const rowsize DynamicSize
Template parameter flag: "row width is set at runtime but uniform".
Definition Defines.hpp:277
@ 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).
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:107
double real
Canonical floating-point scalar used throughout DNDSR (double precision).
Definition Defines.hpp:105
Layout layout
static constexpr DNDS::rowsize rs
constexpr DNDS::index N
#define ARRAY_TAG_STR(T, L, RS)
#define ARRAY_ALL_TAGS
TEST_CASE_TEMPLATE("Array resize-write-read", Tag, ARRAY_ALL_TAGS)
tVec z(NCells)
tVec b(NCells)
CHECK(result.size()==3)
real expected
TEST_CASE("3D: VFV P2 HQM error < P1 on sinCos3D")