PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
generic_matrix.hpp
Go to the documentation of this file.
1#pragma once
2#include <vector>
3#include <string>
4#include <type_traits>
5#include <algorithm>
6#include <stdexcept>
7#include <cstdint>
8#include <limits>
9#include <memory>
10#include <utility>
11
12namespace pineforge {
13
14namespace detail {
15
16// Storage-agnostic structural helpers parameterized on the underlying
17// row container type. Used by both GenericMatrix<T> (T != bool;
18// row = std::vector<T>) and GenericMatrix<bool> (row =
19// std::vector<char>) so both share a single implementation for every
20// method that doesn't care about the element type at the boundary.
21
22template <typename Row>
23inline void erase_row(std::vector<Row>& data, int idx) {
24 data.erase(data.begin() + idx);
25}
26
27template <typename Row>
28inline void erase_col(std::vector<Row>& data, int idx) {
29 // Strong guarantee: build a new buffer, swap on success.
30 std::vector<Row> next;
31 next.reserve(data.size());
32 for (const auto& r : data) {
33 Row row = r;
34 row.erase(row.begin() + idx);
35 next.push_back(std::move(row));
36 }
37 data.swap(next);
38}
39
40template <typename Row>
41inline void swap_rows_impl(std::vector<Row>& data, int i, int j) {
42 std::swap(data[i], data[j]);
43}
44
45template <typename Row>
46inline void swap_cols_impl(std::vector<Row>& data, int i, int j) {
47 // Strong guarantee: build a new buffer, swap on success.
48 std::vector<Row> next = data;
49 for (auto& r : next) std::swap(r[i], r[j]);
50 data.swap(next);
51}
52
53template <typename Row>
54inline std::vector<Row> copy_submatrix(const std::vector<Row>& data,
55 int from_row, int to_row,
56 int from_col, int to_col) {
57 std::vector<Row> out;
58 out.reserve(static_cast<size_t>(to_row - from_row));
59 for (int r = from_row; r < to_row; ++r) {
60 Row row(data[r].begin() + from_col, data[r].begin() + to_col);
61 out.push_back(std::move(row));
62 }
63 return out;
64}
65
66template <typename Row>
67inline std::vector<Row> transpose_impl(const std::vector<Row>& data,
68 int r, int c,
69 const typename Row::value_type& zero) {
70 std::vector<Row> out(static_cast<size_t>(c),
71 Row(static_cast<size_t>(r), zero));
72 for (int i = 0; i < r; ++i)
73 for (int j = 0; j < c; ++j)
74 out[j][i] = data[i][j];
75 return out;
76}
77
78template <typename Row>
79inline void concat_impl(std::vector<Row>& m, const std::vector<Row>& other,
80 bool horizontal) {
81 if (horizontal) {
82 for (size_t r = 0; r < m.size(); ++r)
83 m[r].insert(m[r].end(), other[r].begin(), other[r].end());
84 } else {
85 for (const auto& row : other) m.push_back(row);
86 }
87}
88
89template <typename Row>
90inline void reshape_impl(std::vector<Row>& data, int new_rows, int new_cols,
91 const typename Row::value_type& zero) {
92 if (new_rows < 0 || new_cols < 0)
93 throw std::runtime_error("GenericMatrix::reshape: negative dimension");
94 int64_t total = static_cast<int64_t>(new_rows) * static_cast<int64_t>(new_cols);
95 if (total > static_cast<int64_t>(std::numeric_limits<int>::max()))
96 throw std::runtime_error("matrix.reshape: dimension overflow");
97 std::vector<typename Row::value_type> flat;
98 flat.reserve(static_cast<size_t>(total));
99 for (const auto& r : data) for (const auto& v : r) flat.push_back(v);
100 flat.resize(static_cast<size_t>(total), zero);
101 std::vector<Row> next(static_cast<size_t>(new_rows),
102 Row(static_cast<size_t>(new_cols), zero));
103 size_t k = 0;
104 for (int r = 0; r < new_rows; ++r)
105 for (int c = 0; c < new_cols; ++c)
106 next[r][c] = flat[k++];
107 data.swap(next);
108}
109
110template <typename Row>
111inline int elements_count_impl(const std::vector<Row>& data) {
112 int64_t total = 0;
113 for (const auto& r : data) total += static_cast<int64_t>(r.size());
114 if (total > static_cast<int64_t>(std::numeric_limits<int>::max()))
115 throw std::overflow_error("matrix.elements_count: total exceeds int range");
116 return static_cast<int>(total);
117}
118
119template <typename Row>
120inline void sort_impl(std::vector<Row>& data, int column, bool ascending) {
121 std::sort(data.begin(), data.end(),
122 [column, ascending](const Row& a, const Row& b) {
123 return ascending ? (a[column] < b[column]) : (b[column] < a[column]);
124 });
125}
126
127} // namespace detail
128
129template <typename T>
130class GenericMatrix {
131 using Data = std::vector<std::vector<T>>;
132
133 struct Storage {
134 Data data;
135
136 Storage() = default;
137 explicit Storage(Data value) : data(std::move(value)) {}
138 };
139
140 static constexpr const char* kNaIdError =
141 "matrix operation on na ID";
142 static constexpr const char* kInvalidSnapshotError =
143 "matrix restore from invalid snapshot";
144
145 std::shared_ptr<Storage> storage_;
146
147 explicit GenericMatrix(Data data)
148 : storage_(std::make_shared<Storage>(std::move(data))) {}
149
150 Storage& require_storage() {
151 if (!storage_) throw std::runtime_error(kNaIdError);
152 return *storage_;
153 }
154
155 const Storage& require_storage() const {
156 if (!storage_) throw std::runtime_error(kNaIdError);
157 return *storage_;
158 }
159
160 Data& data() { return require_storage().data; }
161 const Data& data() const { return require_storage().data; }
162
163public:
164 // A GenericMatrix is a reference handle (a source language's matrix ID).
165 // Copies and assignments alias their backing store; copy() is the
166 // explicit operation that creates an independent handle.
167 GenericMatrix() noexcept = default;
168 GenericMatrix(const GenericMatrix&) noexcept = default;
169 GenericMatrix& operator=(const GenericMatrix&) noexcept = default;
170
171 // Preserve the source handle across C++ moves, matching handle assignment.
172 GenericMatrix(GenericMatrix&& other) noexcept
173 : storage_(other.storage_) {}
174 GenericMatrix& operator=(GenericMatrix&& other) noexcept {
175 if (this != &other) storage_ = other.storage_;
176 return *this;
177 }
178
179 // Snapshot copies the outer matrix state with ordinary T copy semantics.
180 // Primitive elements are detached values; UDT/collection handles remain
181 // shallow aliases so generated checkpoints can recurse through them.
182 class Snapshot {
183 std::shared_ptr<Storage> identity_;
184 Data state_;
185
186 Snapshot(std::shared_ptr<Storage> identity, const Data& state)
187 : identity_(std::move(identity)), state_(state) {}
188
189 friend class GenericMatrix;
190
191 public:
192 Snapshot(const Snapshot&) = default;
193 Snapshot& operator=(const Snapshot&) = default;
194 Snapshot(Snapshot&&) = default;
195 Snapshot& operator=(Snapshot&&) = default;
196 };
197
198 ~GenericMatrix() = default;
199
200 [[nodiscard]] static GenericMatrix new_(int rows, int cols, T init) {
201 if (rows < 0 || cols < 0)
202 throw std::invalid_argument("matrix.new: negative dimensions");
203 Data data(static_cast<size_t>(rows),
204 std::vector<T>(static_cast<size_t>(cols), init));
205 return GenericMatrix(std::move(data));
206 }
207
208 [[nodiscard]] static GenericMatrix new_(int rows, int cols) {
209 static_assert(std::is_default_constructible_v<T>,
210 "matrix.new: no-init overload requires default-constructible T");
211 if (rows < 0 || cols < 0)
212 throw std::invalid_argument("matrix.new: negative dimensions");
213 Data data(static_cast<size_t>(rows),
214 std::vector<T>(static_cast<size_t>(cols), T{}));
215 return GenericMatrix(std::move(data));
216 }
217
218 T get(int row, int col) const {
219 const Data& values = data();
220 if (row < 0 || row >= rows())
221 throw std::out_of_range("matrix.get: row index out of range");
223 throw std::out_of_range("matrix.get: column index out of range");
224 return values[static_cast<size_t>(row)][static_cast<size_t>(col)];
225 }
226
227 void set(int row, int col, T val) {
228 Data& values = data();
229 if (row < 0 || row >= rows())
230 throw std::out_of_range("matrix.set: row index out of range");
232 throw std::out_of_range("matrix.set: column index out of range");
233 values[static_cast<size_t>(row)][static_cast<size_t>(col)] = val;
234 }
235
236 void fill(T val) {
237 for (auto& r : data()) std::fill(r.begin(), r.end(), val);
238 }
239
240 int rows() const {
241 return static_cast<int>(data().size());
242 }
243 int columns() const {
244 const Data& values = data();
245 return values.empty() ? 0 : static_cast<int>(values[0].size());
246 }
247
248 std::vector<T> row(int idx) const {
249 const Data& values = data();
250 if (idx < 0 || idx >= rows())
251 throw std::out_of_range("matrix.row: row index out of range");
252 return values[static_cast<size_t>(idx)];
253 }
254
255 std::vector<T> col(int idx) const {
256 const Data& values = data();
257 if (idx < 0 || idx >= columns())
258 throw std::out_of_range("matrix.col: column index out of range");
259 std::vector<T> out;
260 out.reserve(values.size());
261 for (const auto& r : values) out.push_back(r[static_cast<size_t>(idx)]);
262 return out;
263 }
264
265 template <typename U = T,
266 typename = std::enable_if_t<!std::is_same_v<U, bool>>>
267 const std::vector<T>& row_ref(int idx) const {
268 const Data& values = data();
269 if (idx < 0 || idx >= rows())
270 throw std::out_of_range("matrix.row_ref: row index out of range");
271 return values[static_cast<size_t>(idx)];
272 }
273
274 void add_row(int idx, const std::vector<T>& values) {
275 Data& matrix_data = data();
276 if (idx < 0 || idx > rows())
277 throw std::out_of_range("matrix.add_row: row index out of range");
278 if (!matrix_data.empty() && values.size() != static_cast<size_t>(columns()))
279 throw std::runtime_error("matrix.add_row: values size must equal columns()");
280 matrix_data.reserve(matrix_data.size() + 1);
281 matrix_data.insert(matrix_data.begin() + idx, values);
282 }
283
284 void add_col(int idx, const std::vector<T>& values) {
285 Data& matrix_data = data();
286 if (matrix_data.empty())
287 throw std::logic_error("matrix.add_col on empty matrix: use add_row first");
288 if (idx < 0 || idx > columns())
289 throw std::out_of_range("matrix.add_col: column index out of range");
290 if (values.size() != matrix_data.size())
291 throw std::runtime_error("matrix.add_col: values size must equal rows()");
292 // Strong guarantee: build a new buffer, swap on success.
293 Data next;
294 next.reserve(matrix_data.size());
295 for (size_t r = 0; r < matrix_data.size(); ++r) {
296 std::vector<T> row = matrix_data[r];
297 row.insert(row.begin() + idx, values[r]);
298 next.push_back(std::move(row));
299 }
300 matrix_data.swap(next);
301 }
302
303 void remove_row(int idx) {
304 (void)data();
305 if (idx < 0 || idx >= rows())
306 throw std::out_of_range("matrix.remove_row: row index out of range");
307 detail::erase_row(data(), idx);
308 }
309
310 void remove_col(int idx) {
311 (void)data();
312 if (idx < 0 || idx >= columns())
313 throw std::out_of_range("matrix.remove_col: column index out of range");
314 detail::erase_col(data(), idx);
315 }
316
317 void swap_rows(int i, int j) {
318 (void)data();
319 if (i < 0 || i >= rows() || j < 0 || j >= rows())
320 throw std::out_of_range("matrix.swap_rows: row index out of range");
321 detail::swap_rows_impl(data(), i, j);
322 }
323
324 void swap_columns(int i, int j) {
325 (void)data();
326 if (i < 0 || i >= columns() || j < 0 || j >= columns())
327 throw std::out_of_range("matrix.swap_columns: column index out of range");
328 detail::swap_cols_impl(data(), i, j);
329 }
330
331 [[nodiscard]] GenericMatrix copy() const {
332 return GenericMatrix(data());
333 }
334
335 [[nodiscard]] GenericMatrix submatrix(int from_row, int to_row,
336 int from_col, int to_col) const {
337 (void)data();
338 if (from_row < 0 || to_row > rows())
339 throw std::out_of_range("matrix.submatrix: row index out of range");
340 if (from_col < 0 || to_col > columns())
341 throw std::out_of_range("matrix.submatrix: column index out of range");
342 if (from_row > to_row)
343 throw std::invalid_argument("matrix.submatrix: from_row must be <= to_row");
344 if (from_col > to_col)
345 throw std::invalid_argument("matrix.submatrix: from_col must be <= to_col");
346 return GenericMatrix(
347 detail::copy_submatrix(data(), from_row, to_row,
348 from_col, to_col));
349 }
350
351 [[nodiscard]] GenericMatrix transpose() const {
352 static_assert(std::is_default_constructible_v<T>,
353 "matrix.transpose: requires default-constructible element type");
354 return GenericMatrix(
355 detail::transpose_impl(data(), rows(), columns(), T{}));
356 }
357
358 [[nodiscard]] GenericMatrix concat(const GenericMatrix& other, bool horizontal) const {
359 (void)data();
360 (void)other.data();
361 if (horizontal) {
362 if (rows() != other.rows())
363 throw std::invalid_argument("matrix.concat: row count mismatch");
364 } else {
365 if (columns() != other.columns())
366 throw std::invalid_argument("matrix.concat: column count mismatch");
367 }
368 GenericMatrix m = copy();
369 detail::concat_impl(m.data(), other.data(), horizontal);
370 return m;
371 }
372
373 void reshape(int new_rows, int new_cols) {
374 static_assert(std::is_default_constructible_v<T>,
375 "matrix.reshape: requires default-constructible element type");
376 detail::reshape_impl(data(), new_rows, new_cols, T{});
377 }
378
379 void reverse() {
380 Data& values = data();
381 std::reverse(values.begin(), values.end());
382 }
383
384 void sort(int column, bool ascending = true) {
385 static_assert(std::is_same_v<T, int> ||
386 std::is_same_v<T, bool> ||
387 std::is_same_v<T, std::string>,
388 "matrix.sort: requires int, bool, or std::string element type");
389 detail::sort_impl(data(), column, ascending);
390 }
391
392 int elements_count() const {
393 return detail::elements_count_impl(data());
394 }
395
396 [[nodiscard]] bool is_na() const noexcept { return !storage_; }
397
398 [[nodiscard]] Snapshot snapshot() const {
399 const Storage& storage = require_storage();
400 return Snapshot(storage_, storage.data);
401 }
402
403 void restore(const Snapshot& snapshot) {
404 if (!snapshot.identity_) {
405 throw std::runtime_error(kInvalidSnapshotError);
406 }
407 Data replacement(snapshot.state_);
408 snapshot.identity_->data.swap(replacement);
409 storage_ = snapshot.identity_;
410 }
411};
412
413// GenericMatrix<bool> uses std::vector<char> as the row container because
414// std::vector<bool>'s proxy storage doesn't expose a stable element reference.
415// Only the boundary methods (get/set/fill/row/col/add_row/add_col) need
416// char<->bool conversion; every storage-agnostic structural method delegates
417// to the same detail:: helpers used by the primary template.
418template <>
419class GenericMatrix<bool> {
420 using Data = std::vector<std::vector<char>>;
421
422 struct Storage {
423 Data data;
424
425 Storage() = default;
426 explicit Storage(Data value) : data(std::move(value)) {}
427 };
428
429 static constexpr const char* kNaIdError =
430 "matrix operation on na ID";
431 static constexpr const char* kInvalidSnapshotError =
432 "matrix restore from invalid snapshot";
433
434 std::shared_ptr<Storage> storage_;
435
436 explicit GenericMatrix(Data data)
437 : storage_(std::make_shared<Storage>(std::move(data))) {}
438
439 Storage& require_storage() {
440 if (!storage_) throw std::runtime_error(kNaIdError);
441 return *storage_;
442 }
443
444 const Storage& require_storage() const {
445 if (!storage_) throw std::runtime_error(kNaIdError);
446 return *storage_;
447 }
448
449 Data& data() { return require_storage().data; }
450 const Data& data() const { return require_storage().data; }
451
452public:
453 GenericMatrix() noexcept = default;
454 GenericMatrix(const GenericMatrix&) noexcept = default;
455 GenericMatrix& operator=(const GenericMatrix&) noexcept = default;
456
457 GenericMatrix(GenericMatrix&& other) noexcept
458 : storage_(other.storage_) {}
459 GenericMatrix& operator=(GenericMatrix&& other) noexcept {
460 if (this != &other) storage_ = other.storage_;
461 return *this;
462 }
463
464 class Snapshot {
465 std::shared_ptr<Storage> identity_;
466 Data state_;
467
468 Snapshot(std::shared_ptr<Storage> identity, const Data& state)
469 : identity_(std::move(identity)), state_(state) {}
470
471 friend class GenericMatrix;
472
473 public:
474 Snapshot(const Snapshot&) = default;
475 Snapshot& operator=(const Snapshot&) = default;
476 Snapshot(Snapshot&&) = default;
477 Snapshot& operator=(Snapshot&&) = default;
478 };
479
480 [[nodiscard]] static GenericMatrix new_(int rows, int cols, bool init) {
481 if (rows < 0 || cols < 0)
482 throw std::invalid_argument("matrix.new: negative dimensions");
483 Data data(static_cast<size_t>(rows),
484 std::vector<char>(static_cast<size_t>(cols), init ? 1 : 0));
485 return GenericMatrix(std::move(data));
486 }
487
488 [[nodiscard]] static GenericMatrix new_(int rows, int cols) {
489 return new_(rows, cols, false);
490 }
491
492 bool get(int row, int col) const {
493 const Data& values = data();
494 if (row < 0 || row >= rows())
495 throw std::out_of_range("matrix.get: row index out of range");
497 throw std::out_of_range("matrix.get: column index out of range");
498 return values[static_cast<size_t>(row)][static_cast<size_t>(col)] != 0;
499 }
500
501 void set(int row, int col, bool val) {
502 Data& values = data();
503 if (row < 0 || row >= rows())
504 throw std::out_of_range("matrix.set: row index out of range");
506 throw std::out_of_range("matrix.set: column index out of range");
507 values[static_cast<size_t>(row)][static_cast<size_t>(col)] = val ? 1 : 0;
508 }
509
510 void fill(bool val) {
511 char c = val ? 1 : 0;
512 for (auto& r : data()) std::fill(r.begin(), r.end(), c);
513 }
514
515 int rows() const {
516 return static_cast<int>(data().size());
517 }
518 int columns() const {
519 const Data& values = data();
520 return values.empty() ? 0 : static_cast<int>(values[0].size());
521 }
522
523 std::vector<bool> row(int idx) const {
524 const Data& values = data();
525 if (idx < 0 || idx >= rows())
526 throw std::out_of_range("matrix.row: row index out of range");
527 std::vector<bool> out;
528 const auto& src = values[static_cast<size_t>(idx)];
529 out.reserve(src.size());
530 for (char c : src) out.push_back(c != 0);
531 return out;
532 }
533
534 std::vector<bool> col(int idx) const {
535 const Data& values = data();
536 if (idx < 0 || idx >= columns())
537 throw std::out_of_range("matrix.col: column index out of range");
538 std::vector<bool> out;
539 out.reserve(values.size());
540 for (const auto& r : values) out.push_back(r[static_cast<size_t>(idx)] != 0);
541 return out;
542 }
543
544 // row_ref intentionally NOT exposed for T=bool — proxy storage prevents
545 // returning const std::vector<bool>&.
546
547 void add_row(int idx, const std::vector<bool>& values) {
548 Data& matrix_data = data();
549 if (idx < 0 || idx > rows())
550 throw std::out_of_range("matrix.add_row: row index out of range");
551 if (!matrix_data.empty() && values.size() != static_cast<size_t>(columns()))
552 throw std::runtime_error("matrix.add_row: values size must equal columns()");
553 std::vector<char> row;
554 row.reserve(values.size());
555 for (bool v : values) row.push_back(v ? 1 : 0);
556 matrix_data.reserve(matrix_data.size() + 1);
557 matrix_data.insert(matrix_data.begin() + idx, std::move(row));
558 }
559
560 void add_col(int idx, const std::vector<bool>& values) {
561 Data& matrix_data = data();
562 if (matrix_data.empty())
563 throw std::logic_error("matrix.add_col on empty matrix: use add_row first");
564 if (idx < 0 || idx > columns())
565 throw std::out_of_range("matrix.add_col: column index out of range");
566 if (values.size() != matrix_data.size())
567 throw std::runtime_error("matrix.add_col: values size must equal rows()");
568 Data next;
569 next.reserve(matrix_data.size());
570 for (size_t r = 0; r < matrix_data.size(); ++r) {
571 std::vector<char> row = matrix_data[r];
572 row.insert(row.begin() + idx, values[r] ? 1 : 0);
573 next.push_back(std::move(row));
574 }
575 matrix_data.swap(next);
576 }
577
578 void remove_row(int idx) {
579 (void)data();
580 if (idx < 0 || idx >= rows())
581 throw std::out_of_range("matrix.remove_row: row index out of range");
582 detail::erase_row(data(), idx);
583 }
584
585 void remove_col(int idx) {
586 (void)data();
587 if (idx < 0 || idx >= columns())
588 throw std::out_of_range("matrix.remove_col: column index out of range");
589 detail::erase_col(data(), idx);
590 }
591
592 void swap_rows(int i, int j) {
593 (void)data();
594 if (i < 0 || i >= rows() || j < 0 || j >= rows())
595 throw std::out_of_range("matrix.swap_rows: row index out of range");
596 detail::swap_rows_impl(data(), i, j);
597 }
598
599 void swap_columns(int i, int j) {
600 (void)data();
601 if (i < 0 || i >= columns() || j < 0 || j >= columns())
602 throw std::out_of_range("matrix.swap_columns: column index out of range");
603 detail::swap_cols_impl(data(), i, j);
604 }
605
606 [[nodiscard]] GenericMatrix copy() const {
607 return GenericMatrix(data());
608 }
609
610 [[nodiscard]] GenericMatrix submatrix(int from_row, int to_row,
611 int from_col, int to_col) const {
612 (void)data();
613 if (from_row < 0 || to_row > rows())
614 throw std::out_of_range("matrix.submatrix: row index out of range");
615 if (from_col < 0 || to_col > columns())
616 throw std::out_of_range("matrix.submatrix: column index out of range");
617 if (from_row > to_row)
618 throw std::invalid_argument("matrix.submatrix: from_row must be <= to_row");
619 if (from_col > to_col)
620 throw std::invalid_argument("matrix.submatrix: from_col must be <= to_col");
621 return GenericMatrix(
622 detail::copy_submatrix(data(), from_row, to_row,
623 from_col, to_col));
624 }
625
626 void reshape(int new_rows, int new_cols) {
627 detail::reshape_impl(data(), new_rows, new_cols, static_cast<char>(0));
628 }
629
630 void reverse() {
631 Data& values = data();
632 std::reverse(values.begin(), values.end());
633 }
634
635 [[nodiscard]] GenericMatrix transpose() const {
636 return GenericMatrix(
638 static_cast<char>(0)));
639 }
640
641 [[nodiscard]] GenericMatrix concat(const GenericMatrix& other, bool horizontal) const {
642 (void)data();
643 (void)other.data();
644 if (horizontal) {
645 if (rows() != other.rows())
646 throw std::invalid_argument("matrix.concat: row count mismatch");
647 } else {
648 if (columns() != other.columns())
649 throw std::invalid_argument("matrix.concat: column count mismatch");
650 }
651 GenericMatrix m = copy();
652 detail::concat_impl(m.data(), other.data(), horizontal);
653 return m;
654 }
655
656 template <typename Dummy = void>
657 void sort(int /*column*/, bool /*ascending*/ = true) {
658 (void)data();
659 static_assert(!std::is_same_v<Dummy, void> && std::is_same_v<Dummy, void>,
660 "matrix.sort: not supported on bool element type");
661 }
662
663 int elements_count() const {
664 return detail::elements_count_impl(data());
665 }
666
667 [[nodiscard]] bool is_na() const noexcept { return !storage_; }
668
669 [[nodiscard]] Snapshot snapshot() const {
670 const Storage& storage = require_storage();
671 return Snapshot(storage_, storage.data);
672 }
673
674 void restore(const Snapshot& snapshot) {
675 if (!snapshot.identity_) {
676 throw std::runtime_error(kInvalidSnapshotError);
677 }
678 Data replacement(snapshot.state_);
679 snapshot.identity_->data.swap(replacement);
680 storage_ = snapshot.identity_;
681 }
682};
683
684template <typename T>
685inline bool is_na(const GenericMatrix<T>& matrix) noexcept {
686 return matrix.is_na();
687}
688
689// Deprecated spelling, kept as an exact alias template so generated code and
690// the source adapter compile unchanged (R5 lane N14, the same treatment
691// session_time.hpp / str_utils.hpp received in lane L11). New code names
692// GenericMatrix<T>.
693template <typename T>
695
696} // namespace pineforge
Snapshot & operator=(const Snapshot &)=default
Snapshot(const Snapshot &)=default
Snapshot & operator=(Snapshot &&)=default
Snapshot & operator=(const Snapshot &)=default
Snapshot & operator=(Snapshot &&)=default
void restore(const Snapshot &snapshot)
void set(int row, int col, bool val)
static GenericMatrix new_(int rows, int cols)
std::vector< bool > row(int idx) const
void add_col(int idx, const std::vector< bool > &values)
std::vector< bool > col(int idx) const
void add_row(int idx, const std::vector< bool > &values)
bool get(int row, int col) const
GenericMatrix() noexcept=default
void reshape(int new_rows, int new_cols)
GenericMatrix submatrix(int from_row, int to_row, int from_col, int to_col) const
GenericMatrix & operator=(GenericMatrix &&other) noexcept
static GenericMatrix new_(int rows, int cols, bool init)
GenericMatrix concat(const GenericMatrix &other, bool horizontal) const
bool is_na() const noexcept
GenericMatrix submatrix(int from_row, int to_row, int from_col, int to_col) const
GenericMatrix & operator=(GenericMatrix &&other) noexcept
void swap_rows(int i, int j)
void sort(int column, bool ascending=true)
void add_row(int idx, const std::vector< T > &values)
GenericMatrix() noexcept=default
GenericMatrix copy() const
std::vector< T > row(int idx) const
static GenericMatrix new_(int rows, int cols)
void restore(const Snapshot &snapshot)
GenericMatrix concat(const GenericMatrix &other, bool horizontal) const
void reshape(int new_rows, int new_cols)
void set(int row, int col, T val)
void add_col(int idx, const std::vector< T > &values)
static GenericMatrix new_(int rows, int cols, T init)
const std::vector< T > & row_ref(int idx) const
GenericMatrix transpose() const
T get(int row, int col) const
void swap_columns(int i, int j)
std::vector< T > col(int idx) const
void erase_col(std::vector< Row > &data, int idx)
void swap_cols_impl(std::vector< Row > &data, int i, int j)
int elements_count_impl(const std::vector< Row > &data)
void sort_impl(std::vector< Row > &data, int column, bool ascending)
void swap_rows_impl(std::vector< Row > &data, int i, int j)
void erase_row(std::vector< Row > &data, int idx)
void reshape_impl(std::vector< Row > &data, int new_rows, int new_cols, const typename Row::value_type &zero)
std::vector< Row > transpose_impl(const std::vector< Row > &data, int r, int c, const typename Row::value_type &zero)
void concat_impl(std::vector< Row > &m, const std::vector< Row > &other, bool horizontal)
std::vector< Row > copy_submatrix(const std::vector< Row > &data, int from_row, int to_row, int from_col, int to_col)
GenericMatrix< T > PineGenericMatrix
bool is_na(const Line &h)
Definition drawing.hpp:42