Documentation 6b54b78464
Loading...
Searching...
No Matches
C2DContainer.hpp
Go to the documentation of this file.
1/*!
2 * \file C2DContainer.hpp
3 * \brief A templated vector/matrix object.
4 * \author P. Gomes
5 * \version 8.5.0 "Harrier"
6 *
7 * SU2 Project Website: https://su2code.github.io
8 *
9 * The SU2 Project is maintained by the SU2 Foundation
10 * (http://su2foundation.org)
11 *
12 * Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
13 *
14 * SU2 is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * SU2 is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28#pragma once
29
30#include "../toolboxes/allocation_toolbox.hpp"
31#include "../basic_types/datatype_structure.hpp"
32#include "../parallelization/vectorization.hpp"
33
34#include <utility>
35#include <type_traits>
36
37/// \addtogroup Containers
38/// @{
39
40/*!
41 * \enum StorageType
42 * \brief Supported ways to flatten a matrix into an array.
43 * Contiguous rows or contiguous columns respectively.
44 */
45enum class StorageType { RowMajor = 0, ColumnMajor = 1 };
46
47/*!
48 * \enum SizeType
49 * \brief Special value "DynamicSize" to indicate a dynamic size.
50 */
51enum SizeType : size_t { DynamicSize = 0 };
52
53/*--- Namespace to "hide" helper classes and
54 functions used by the container class. ---*/
56/*!
57 * \class AccessorImpl
58 * \brief Base accessor class and version of template for both sizes known at compile time.
59 *
60 * The actual container inherits from this class, this is to reduce the number of
61 * methods that need to be redefined with each size specialization.
62 */
63template <typename Index_t, class Scalar_t, StorageType Store, size_t AlignSize, size_t StaticRows, size_t StaticCols>
65 static_assert(StaticRows != 1 || Store != StorageType::ColumnMajor, "Row vector should have row-major storage.");
66 static_assert(StaticCols != 1 || Store != StorageType::RowMajor, "Column vector should have column-major storage.");
67
68 protected:
69 /*!
70 * For static specializations AlignSize will force the alignment
71 * specification of the entire class, not just the data.
72 */
73 alignas(AlignSize) Scalar_t m_data[StaticRows * StaticCols];
74
75 /*!
76 * Static size specializations use this do-nothing allocation macro.
77 */
78#define DUMMY_ALLOCATOR \
79 void m_allocate(size_t sz, Index_t rows, Index_t cols) noexcept {} \
80 void m_destroy() noexcept {}
81
82 /*!
83 * Dynamic size specializations use this one, EXTRA is used to set some
84 * runtime internal value that depend on the number of rows/columns.
85 * What values need setting depends on the specialization as not all have
86 * members for e.g. number of rows and cols (static size optimization).
87 * Because aligned allocation is used, "placement new" is used after to
88 * default construct the elements of non-trivial type. Such types also
89 * need to be destructed explicitly before freeing the memory.
90 */
91#define REAL_ALLOCATOR(EXTRA) \
92 static_assert(MemoryAllocation::is_power_of_two(AlignSize), "AlignSize is not a power of two."); \
93 \
94 void m_allocate(size_t sz, Index_t rows, Index_t cols) noexcept { \
95 EXTRA; \
96 m_data = MemoryAllocation::aligned_alloc<Scalar_t>(AlignSize, sz); \
97 if (!std::is_trivial<Scalar_t>::value) \
98 for (size_t i = 0; i < size(); ++i) new (m_data + i) Scalar_t(); \
99 } \
100 \
101 void m_destroy() noexcept { \
102 if (!std::is_trivial<Scalar_t>::value) \
103 for (size_t i = 0; i < size(); ++i) m_data[i].~Scalar_t(); \
104 MemoryAllocation::aligned_free<Scalar_t>(m_data); \
105 }
106
108
109 public:
110 /*!
111 * Dynamic types need to manage internal data as the derived class would
112 * not compile if it tried to set m_data to null on static specializations.
113 * Move construct/assign are enabled by transferring ownership of data
114 * pointer, the rvalue is left in the empty state.
115 * The default ctor needs to "INIT" some fields. The move ctor/assign need
116 * to "MOVE" those fields, i.e. copy and set "other" appropriately.
117 */
118#define CUSTOM_CTOR_AND_DTOR_BASE(INIT, MOVE) \
119 AccessorImpl() noexcept : m_data(nullptr) { INIT; } \
120 \
121 AccessorImpl(AccessorImpl&& other) noexcept { \
122 MOVE; \
123 m_data = other.m_data; \
124 other.m_data = nullptr; \
125 } \
126 \
127 AccessorImpl& operator=(AccessorImpl&& other) noexcept { \
128 m_destroy(); \
129 MOVE; \
130 m_data = other.m_data; \
131 other.m_data = nullptr; \
132 return *this; \
133 } \
134 \
135 ~AccessorImpl() noexcept { m_destroy(); }
136
137 /*!
138 * Shorthand for when specialization has only one more member than m_data.
139 */
140#define CUSTOM_CTOR_AND_DTOR(X) CUSTOM_CTOR_AND_DTOR_BASE(X = 0, X = other.X; other.X = 0)
141
142 /*!
143 * Universal accessors return a raw pointer to the data.
144 */
145#define UNIV_ACCESSORS \
146 bool empty() const noexcept { return size() == 0; } \
147 Scalar_t* data() noexcept { return m_data; } \
148 const Scalar_t* data() const noexcept { return m_data; } \
149 Scalar_t* begin() noexcept { return data(); } \
150 const Scalar_t* begin() const noexcept { return data(); } \
151 Scalar_t* end() noexcept { return data() + size(); } \
152 const Scalar_t* end() const noexcept { return data() + size(); }
153
154 /*!
155 * Operator (,) gives pointwise access, operator [] returns a pointer to the
156 * first element of the row/column of a row/column-major matrix respectively.
157 */
158#define MATRIX_ACCESSORS(M, N) \
159 UNIV_ACCESSORS \
160 Index_t rows() const noexcept { return M; } \
161 Index_t cols() const noexcept { return N; } \
162 size_t size() const noexcept { return M * N; } \
163 \
164 const Scalar_t& operator()(const Index_t i, const Index_t j) const noexcept { \
165 assert(i >= 0 && i < M && j >= 0 && j < N); \
166 if constexpr (Store == StorageType::RowMajor) { \
167 return m_data[i * N + j]; \
168 } else { \
169 return m_data[i + j * M]; \
170 } \
171 } \
172 \
173 Scalar_t& operator()(const Index_t i, const Index_t j) noexcept { \
174 const AccessorImpl& const_this = *this; \
175 return const_cast<Scalar_t&>(const_this(i, j)); \
176 } \
177 \
178 const Scalar_t* operator[](const Index_t k) const noexcept { \
179 if constexpr (Store == StorageType::RowMajor) { \
180 assert(k >= 0 && k < M); \
181 return &m_data[k * N]; \
182 } else { \
183 assert(k >= 0 && k < N); \
184 return &m_data[k * M]; \
185 } \
186 } \
187 \
188 Scalar_t* operator[](const Index_t k) noexcept { \
189 const AccessorImpl& const_this = *this; \
190 return const_cast<Scalar_t*>(const_this[k]); \
191 }
192
193 /*!
194 * Vectors provide both [] and () with the same behavior.
195 */
196#define VECTOR_ACCESSORS(M, ROWMAJOR) \
197 UNIV_ACCESSORS \
198 Index_t rows() const noexcept { return ROWMAJOR ? 1 : M; } \
199 Index_t cols() const noexcept { return ROWMAJOR ? M : 1; } \
200 size_t size() const noexcept { return M; } \
201 \
202 Scalar_t& operator()(const Index_t i) noexcept { \
203 assert(i >= 0 && i < M); \
204 return m_data[i]; \
205 } \
206 \
207 const Scalar_t& operator()(const Index_t i) const noexcept { \
208 assert(i >= 0 && i < M); \
209 return m_data[i]; \
210 } \
211 \
212 Scalar_t& operator[](const Index_t i) noexcept { \
213 assert(i >= 0 && i < M); \
214 return m_data[i]; \
215 } \
216 \
217 const Scalar_t& operator[](const Index_t i) const noexcept { \
218 assert(i >= 0 && i < M); \
219 return m_data[i]; \
220 }
221
222 MATRIX_ACCESSORS(StaticRows, StaticCols)
223};
224
225/*!
226 * Specialization for compile-time number of columns.
227 */
228template <typename Index_t, class Scalar_t, StorageType Store, size_t AlignSize, size_t StaticCols>
229class AccessorImpl<Index_t, Scalar_t, Store, AlignSize, DynamicSize, StaticCols> {
230 static_assert(StaticCols != 1 || Store != StorageType::RowMajor, "Column vector should have column-major storage.");
231
232 protected:
233 Index_t m_rows;
234 Scalar_t* m_data;
235
237
238 public:
240
241 MATRIX_ACCESSORS(m_rows, StaticCols)
242};
243
244/*!
245 * Specialization for compile-time number of columns.
246 */
247template <typename Index_t, class Scalar_t, StorageType Store, size_t AlignSize, size_t StaticRows>
248class AccessorImpl<Index_t, Scalar_t, Store, AlignSize, StaticRows, DynamicSize> {
249 static_assert(StaticRows != 1 || Store != StorageType::ColumnMajor, "Row vector should have row-major storage.");
250
251 protected:
252 Index_t m_cols;
253 Scalar_t* m_data;
254
256
257 public:
259
260 MATRIX_ACCESSORS(StaticRows, m_cols)
261};
262
263/*!
264 * Specialization for fully dynamic sizes (generic matrix).
265 */
266template <typename Index_t, class Scalar_t, StorageType Store, size_t AlignSize>
267class AccessorImpl<Index_t, Scalar_t, Store, AlignSize, DynamicSize, DynamicSize> {
268 protected:
269 Index_t m_rows, m_cols;
270 Scalar_t* m_data;
271
272 REAL_ALLOCATOR(m_rows = rows; m_cols = cols)
273
274 public:
275 CUSTOM_CTOR_AND_DTOR_BASE(m_rows = 0; m_cols = 0, m_rows = other.m_rows; other.m_rows = 0; m_cols = other.m_cols;
276 other.m_cols = 0)
277
278 MATRIX_ACCESSORS(m_rows, m_cols)
279};
280
281/*!
282 * Specialization for static column-vector.
283 */
284template <typename Index_t, class Scalar_t, size_t AlignSize, size_t StaticRows>
285class AccessorImpl<Index_t, Scalar_t, StorageType::ColumnMajor, AlignSize, StaticRows, 1> {
286 protected:
287 alignas(AlignSize) Scalar_t m_data[StaticRows];
288
290
291 public:
292 VECTOR_ACCESSORS(StaticRows, false)
293};
294
295/*!
296 * Specialization for dynamic column-vector.
297 */
298template <typename Index_t, class Scalar_t, size_t AlignSize>
299class AccessorImpl<Index_t, Scalar_t, StorageType::ColumnMajor, AlignSize, DynamicSize, 1> {
300 protected:
301 Index_t m_rows;
302 Scalar_t* m_data;
303
304 REAL_ALLOCATOR(m_rows = rows)
305
306 public:
308
309 VECTOR_ACCESSORS(m_rows, false)
310};
311
312/*!
313 * Specialization for static row-vector.
314 */
315template <typename Index_t, class Scalar_t, size_t AlignSize, size_t StaticCols>
316class AccessorImpl<Index_t, Scalar_t, StorageType::RowMajor, AlignSize, 1, StaticCols> {
317 protected:
318 alignas(AlignSize) Scalar_t m_data[StaticCols];
319
321
322 public:
323 VECTOR_ACCESSORS(StaticCols, true)
324};
325
326/*!
327 * Specialization for dynamic row-vector.
328 */
329template <typename Index_t, class Scalar_t, size_t AlignSize>
330class AccessorImpl<Index_t, Scalar_t, StorageType::RowMajor, AlignSize, 1, DynamicSize> {
331 protected:
332 Index_t m_cols;
333 Scalar_t* m_data;
334
335 REAL_ALLOCATOR(m_cols = cols)
336
337 public:
339
340 VECTOR_ACCESSORS(m_cols, true)
341};
342
343#undef CUSTOM_CTOR_AND_DTOR_BASE
344#undef CUSTOM_CTOR_AND_DTOR
345#undef DUMMY_ALLOCATOR
346#undef REAL_ALLOCATOR
347#undef MATRIX_ACCESSORS
348#undef VECTOR_ACCESSORS
349#undef UNIV_ACCESSORS
350} // namespace container_details
351
352/*!
353 * \class C2DContainer
354 * \brief A templated matrix/vector-like object.
355 *
356 * See notes about MATRIX_ACCESSORS and VECTOR_ACCESSORS for how to access data.
357 * For how to construct/resize/initialize see methods below.
358 *
359 * Template parameters:
360 *
361 * \param Index_t - The data type (built-in) for indices, signed and unsigned allowed.
362 * \param Scalar_t - The stored data type, anything that can be default constructed.
363 * \param Store - Mode to map 1D to 2D, row-major or column-major.
364 * \param AlignSize - Desired alignment for the data in bytes, 0 means default.
365 * \param StaticRows - Number of rows at compile time, for dynamic (sized at runtime) use "DynamicSize".
366 * \param StaticCols - As above for columns.
367 *
368 * \note All accesses to data are range checked via assertions, for
369 * release compile with -DNDEBUG to avoid the associated overhead.
370 *
371 */
372template <typename Index_t, class Scalar_t, StorageType Store, size_t AlignSize, size_t StaticRows, size_t StaticCols>
374 : public container_details::AccessorImpl<Index_t, Scalar_t, Store, AlignSize, StaticRows, StaticCols> {
375 static_assert(std::is_integral<Index_t>::value);
376
377 private:
379 using Base::m_allocate;
380 using Base::m_data;
381 using Base::m_destroy;
382
383 public:
384 using Base::cols;
385 using Base::rows;
386 using Base::size;
387 using Index = Index_t;
388 using Scalar = Scalar_t;
389 static constexpr StorageType Storage = Store;
390 static constexpr bool IsVector = (StaticRows == 1) || (StaticCols == 1);
391 static constexpr bool IsRowMajor = (Store == StorageType::RowMajor);
392 static constexpr bool IsColumnMajor = (Store == StorageType::ColumnMajor);
393 static constexpr size_t StaticSize = StaticRows * StaticCols;
394 static constexpr size_t StaticNRows = StaticRows;
395 static constexpr size_t StaticNCols = StaticCols;
396
397 /*!
398 * \brief Scalar iterator to the inner dimension of the container, read-only.
399 */
401 private:
402 const Index m_increment;
403 const Scalar* m_ptr;
404
405 public:
406 CInnerIter() = delete;
407
408 FORCEINLINE CInnerIter(const Scalar* ptr, Index increment) noexcept : m_increment(increment), m_ptr(ptr) {}
409
410 FORCEINLINE Scalar operator*() const noexcept { return *m_ptr; }
411
413 auto ret = *this;
414 m_ptr += m_increment;
415 return ret;
416 }
417 };
418
419 /*!
420 * \brief SIMD iterator to the inner dimension of the container,
421 * read-only, generic non-contiguous access.
422 */
423 template <class IndexSIMD_t>
425 private:
426 static_assert(std::is_integral<typename IndexSIMD_t::Scalar>::value);
427 enum { Size = IndexSIMD_t::Size };
428 IndexSIMD_t m_offsets;
429 const Index m_increment;
430 const Scalar* const m_data;
431
432 public:
434
435 FORCEINLINE CInnerIterGather(const Scalar* data, Index increment, IndexSIMD_t offsets) noexcept
436 : m_offsets(offsets), m_increment(increment), m_data(data) {}
437
439 return simd::Array<Scalar, Size>(m_data, m_offsets);
440 }
441
443 auto ret = *this;
444 m_offsets += m_increment;
445 return ret;
446 }
447 };
448
449 private:
450 /*!
451 * \brief Logic to resize data according to arguments, a non DynamicSize cannot be changed.
452 */
453 size_t m_resize(Index_t rows, Index_t cols) noexcept {
454 /*--- fully static, no allocation needed ---*/
455 if (StaticSize != DynamicSize) return StaticSize;
456
457 /*--- dynamic row vector, swap size specification ---*/
458 if (StaticRows == 1 && IsVector) {
459 cols = rows;
460 rows = 1;
461 }
462
463 /*--- assert a static size is not being asked to change ---*/
464 if (StaticRows != DynamicSize) assert(rows == StaticRows && "A static size was asked to change.");
465 if (StaticCols != DynamicSize) assert(cols == StaticCols && "A static size was asked to change.");
466
467 /*--- "rectify" sizes before continuing as asserts are usually dissabled ---*/
468 rows = (StaticRows != DynamicSize) ? StaticRows : rows;
469 cols = (StaticCols != DynamicSize) ? StaticCols : cols;
470
471 /*--- number of requested elements ---*/
472 size_t reqSize = rows * cols;
473
474 /*--- compare with current dimensions to determine if deallocation
475 is needed, also makes the container safe against self assignment
476 no need to check for 0 size as the allocators handle that ---*/
477 if (rows == this->rows() && cols == this->cols()) return reqSize;
478
479 m_destroy();
480
481 /*--- request actual allocation to base class as it needs specialization ---*/
482 size_t bytes = reqSize * sizeof(Scalar_t);
483 m_allocate(bytes, rows, cols);
484
485 return reqSize;
486 }
487
488 public:
489 /*!
490 * \brief Default ctor.
491 */
492 C2DContainer() noexcept : Base() {}
493
494 /*!
495 * \brief Sizing ctor (no initialization of data).
496 * For matrices size1 is rows and size2 columns, for vectors size1 is lenght and size2 is ignored.
497 */
498 C2DContainer(const Index_t size1, const Index_t size2 = 1) noexcept : Base() { m_resize(size1, size2); }
499
500 /*!
501 * \brief Copy ctor.
502 */
503 C2DContainer(const C2DContainer& other) noexcept : Base() {
504 size_t sz = m_resize(other.rows(), other.cols());
505 for (size_t i = 0; i < sz; ++i) m_data[i] = other.m_data[i];
506 }
507
508 /*!
509 * \brief Copy assignment operator, no re-allocation if sizes do not change.
510 */
511 C2DContainer& operator=(const C2DContainer& other) noexcept {
512 size_t sz = m_resize(other.rows(), other.cols());
513 for (size_t i = 0; i < sz; ++i) m_data[i] = other.m_data[i];
514 return *this;
515 }
516
517 /*!
518 * \brief Move ctor, implemented by base class (if fully static works as copy).
519 */
521
522 /*!
523 * \brief Move assign operator, implemented by base class (if fully static works as copy).
524 */
526
527 /*!
528 * \overload Set all entries to rhs value (syntax sugar, see "resize").
529 */
530 C2DContainer& operator=(const Scalar_t& value) noexcept {
531 setConstant(value);
532 return *this;
533 }
534
535 /*!
536 * \brief Request a change of size.
537 * \note Providing an interface that allowed resizing with value could cause
538 * overloading ambiguities when Scalar_t = Index_t, so we do not. But it
539 * is possible to assign a constant on top of resize: A.resize(m,n) = x;
540 */
541 C2DContainer& resize(const Index_t size1, const Index_t size2 = 1) noexcept {
542 m_resize(size1, size2);
543 return *this;
544 }
545
546 /*!
547 * \brief Set value of all entries to "value".
548 */
549 void setConstant(const Scalar_t& value) noexcept {
550 // GCC 13 has a false-positive about overflow of memcpy due to size being uint64_t, and its memcpy just int64_t.
551 SU2_IGNORE_WARNING("-Wstringop-overflow")
552 for (size_t i = 0; i < size(); ++i) m_data[i] = value;
554 }
555
556 /*!
557 * \brief Get a scalar iterator to the inner dimension of the container.
558 */
559 FORCEINLINE CInnerIter innerIter(Index_t row) const noexcept {
560 return CInnerIter(&m_data[IsRowMajor ? row * cols() : row], IsRowMajor ? 1 : rows());
561 }
562
563 /*!
564 * \brief Get a SIMD gather iterator to the inner dimension of the container.
565 */
566 template <class T, size_t N>
568 return CInnerIterGather<simd::Array<T, N> >(m_data, IsRowMajor ? 1 : rows(), IsRowMajor ? row * cols() : row);
569 }
570
571 /*!
572 * \brief Return copy of data in a static size container.
573 * \param[in] row - Row of the matrix.
574 * \param[in] start - Starting column to copy the data (amount determined by container size).
575 */
576 template <class StaticContainer>
577 FORCEINLINE StaticContainer get(Index_t row, Index_t start = 0) const noexcept {
578 constexpr size_t Size = StaticContainer::StaticSize;
579 static_assert(Size, "This method requires a static output type.");
580 assert(Size <= cols() - start);
581 StaticContainer ret;
583 for (size_t i = 0; i < Size; ++i)
584 ret.data()[i] = m_data[IsRowMajor ? row * cols() + i + start : row + (i + start) * rows()];
585 return ret;
586 }
587
588 /*!
589 * \brief Return copy of data in a static size container, SIMD version.
590 */
591 template <class StaticContainer, class T, size_t N>
592 FORCEINLINE StaticContainer get(simd::Array<T, N> row, Index_t start = 0) const noexcept {
593 constexpr size_t Size = StaticContainer::StaticSize;
594 static_assert(Size, "This method requires a static output type.");
595 assert(Size <= cols() - start);
596 StaticContainer ret;
597 for (size_t k = 0; k < N; ++k) {
599 for (size_t i = 0; i < Size; ++i)
600 ret.data()[i][k] = m_data[IsRowMajor ? row[k] * cols() + i + start : row[k] + (i + start) * rows()];
601 }
602 return ret;
603 }
604};
605
606/*!
607 * \brief Useful typedefs with default template parameters
608 */
609template <class T>
611template <class T>
613template <class T>
615
618
621
622/// @}
#define REAL_ALLOCATOR(EXTRA)
Definition C2DContainer.hpp:91
#define DUMMY_ALLOCATOR
Definition C2DContainer.hpp:78
#define CUSTOM_CTOR_AND_DTOR(X)
Definition C2DContainer.hpp:140
#define VECTOR_ACCESSORS(M, ROWMAJOR)
Definition C2DContainer.hpp:196
#define CUSTOM_CTOR_AND_DTOR_BASE(INIT, MOVE)
Definition C2DContainer.hpp:118
#define MATRIX_ACCESSORS(M, N)
Definition C2DContainer.hpp:158
SIMD iterator to the inner dimension of the container, read-only, generic non-contiguous access.
Definition C2DContainer.hpp:424
CInnerIterGather(const Scalar *data, Index increment, IndexSIMD_t offsets) noexcept
Definition C2DContainer.hpp:435
simd::Array< Scalar, Size > operator*() const noexcept
Definition C2DContainer.hpp:438
CInnerIterGather operator++(int) noexcept
Definition C2DContainer.hpp:442
Scalar iterator to the inner dimension of the container, read-only.
Definition C2DContainer.hpp:400
CInnerIter operator++(int) noexcept
Definition C2DContainer.hpp:412
CInnerIter(const Scalar *ptr, Index increment) noexcept
Definition C2DContainer.hpp:408
Scalar operator*() const noexcept
Definition C2DContainer.hpp:410
A templated matrix/vector-like object.
Definition C2DContainer.hpp:374
CInnerIterGather< simd::Array< T, N > > innerIter(simd::Array< T, N > row) const noexcept
Get a SIMD gather iterator to the inner dimension of the container.
Definition C2DContainer.hpp:567
C2DContainer(const C2DContainer &other) noexcept
Copy ctor.
Definition C2DContainer.hpp:503
C2DContainer & resize(const Index_t size1, const Index_t size2=1) noexcept
Request a change of size.
Definition C2DContainer.hpp:541
StaticContainer get(Index_t row, Index_t start=0) const noexcept
Return copy of data in a static size container.
Definition C2DContainer.hpp:577
CInnerIter innerIter(Index_t row) const noexcept
Get a scalar iterator to the inner dimension of the container.
Definition C2DContainer.hpp:559
Scalar_t Scalar
Definition C2DContainer.hpp:388
C2DContainer & operator=(const C2DContainer &other) noexcept
Copy assignment operator, no re-allocation if sizes do not change.
Definition C2DContainer.hpp:511
void setConstant(const Scalar_t &value) noexcept
Set value of all entries to "value".
Definition C2DContainer.hpp:549
C2DContainer(C2DContainer &&)=default
Move ctor, implemented by base class (if fully static works as copy).
C2DContainer & operator=(const Scalar_t &value) noexcept
Definition C2DContainer.hpp:530
C2DContainer() noexcept
Default ctor.
Definition C2DContainer.hpp:492
StaticContainer get(simd::Array< T, N > row, Index_t start=0) const noexcept
Return copy of data in a static size container, SIMD version.
Definition C2DContainer.hpp:592
C2DContainer(const Index_t size1, const Index_t size2=1) noexcept
Sizing ctor (no initialization of data). For matrices size1 is rows and size2 columns,...
Definition C2DContainer.hpp:498
Index_t Index
Definition C2DContainer.hpp:387
C2DContainer & operator=(C2DContainer &&)=default
Move assign operator, implemented by base class (if fully static works as copy).
Base accessor class and version of template for both sizes known at compile time.
Definition C2DContainer.hpp:64
Index_t cols() const noexcept
Definition C2DContainer.hpp:222
Scalar_t m_data[StaticRows *StaticCols]
Definition C2DContainer.hpp:73
Index_t rows() const noexcept
Definition C2DContainer.hpp:222
A simple SIMD type relying on implicit vectorization, i.e. done by the compiler, explicitly vectorize...
Definition vectorization.hpp:89
#define SU2_IGNORE_WARNING(WARNING)
Definition code_config.hpp:219
#define SU2_RESTORE_WARNING
Definition code_config.hpp:220
#define FORCEINLINE
Definition code_config.hpp:44
StorageType
Supported ways to flatten a matrix into an array. Contiguous rows or contiguous columns respectively.
Definition C2DContainer.hpp:45
SizeType
Special value "DynamicSize" to indicate a dynamic size.
Definition C2DContainer.hpp:51
@ DynamicSize
Definition C2DContainer.hpp:51
Definition C2DContainer.hpp:55
#define SU2_OMP_SIMD
Definition omp_structure.hpp:125
#define SU2_OMP_SIMD_IF_NOT_AD
Definition omp_structure.hpp:129