Skip to content

Commit deed45f

Browse files
committed
flat_matrix alignment: span -> subrange
1 parent 602f7bc commit deed45f

3 files changed

Lines changed: 80 additions & 65 deletions

File tree

include/gl/types/flat_jagged_vector.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <stdexcept>
1414
#include <vector>
1515

16+
// TODO: use std::ranges::subrange instead of std::span
17+
1618
namespace gl {
1719

1820
/// @brief A flattened 2D vector (jagged array) providing efficient storage for variable-length segments.

include/gl/types/flat_matrix.hpp

Lines changed: 65 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,22 @@ class flat_matrix {
3535
using value_type = T;
3636
/// @brief Unsigned integral type used for sizes and indices
3737
using size_type = std::size_t;
38+
/// @brief The underlying contiguous storage container
39+
using container_type = std::vector<value_type>;
3840
/// @brief Reference to an element
39-
using reference = value_type&;
41+
using reference = typename container_type::reference;
4042
/// @brief Const reference to an element
41-
using const_reference = const value_type&;
42-
/// @brief Span type representing a non-owning uniform row of elements
43-
using row_type = std::span<value_type>;
44-
/// @brief Const span type representing a non-owning uniform const row of elements
45-
using const_row_type = std::span<const value_type>;
43+
using const_reference = typename container_type::const_reference;
44+
/// @brief Subrange type representing a non-owning uniform row of elements
45+
using row_type = std::ranges::subrange<typename container_type::iterator>;
46+
/// @brief Const subrange type representing a non-owning uniform const row of elements
47+
using const_row_type = std::ranges::subrange<typename container_type::const_iterator>;
4648

4749
// --- iterators ---
4850

4951
/// @brief Random access iterator over the rows of the `flat_matrix`.
5052
///
51-
/// This iterator dereferences to a `row_type` (span of elements representing a single matrix row),
53+
/// This iterator dereferences to a `row_type` (subrange of elements representing a single matrix row),
5254
/// allowing efficient iteration and random access. It calculates the memory offsets mathematically
5355
/// based on the column dimension.
5456
///
@@ -57,44 +59,48 @@ class flat_matrix {
5759
/// @warning Invalidated when the `flat_matrix` structural dimensions are modified or memory is reallocated.
5860
template <bool Const>
5961
class row_iterator {
60-
using data_ptr_type = std::conditional_t<Const, const T*, T*>;
62+
using data_iter_type = std::conditional_t<
63+
Const,
64+
typename container_type::const_iterator,
65+
typename container_type::iterator>;
6166

6267
public:
6368
/// @brief Satisfies random access iterator concept
6469
using iterator_concept = std::random_access_iterator_tag;
6570
/// @brief Legacy iterator category (random access)
6671
using iterator_category = std::random_access_iterator_tag;
67-
/// @brief Type of row this iterator dereferences to (span or const span)
72+
/// @brief Type of row this iterator dereferences to (subrange or const subrange)
6873
using value_type = std::conditional_t<Const, const_row_type, row_type>;
6974
/// @brief Signed integral difference type
7075
using difference_type = std::ptrdiff_t;
7176
/// @brief Pointer type (void because iterators dereference to spans)
7277
using pointer = void;
73-
/// @brief Reference type (span of elements)
78+
/// @brief Reference type (subrange of elements)
7479
using reference = value_type;
7580

7681
/// @brief Default constructor creates a null iterator
7782
row_iterator() = default;
7883

7984
/// @brief Constructs an iterator pointing to a specific row.
80-
/// @param data_ptr Pointer to the underlying flat element data
85+
/// @param data_iter Iterator to the underlying flat element data
8186
/// @param n_cols The number of columns in the matrix
8287
/// @param row_idx The index of the row this iterator currently points to
83-
row_iterator(data_ptr_type data_ptr, size_type n_cols, size_type row_idx) noexcept
84-
: _data_ptr(data_ptr), _row_size(n_cols), _row_idx(row_idx) {}
88+
row_iterator(data_iter_type data_iter, size_type n_cols, size_type row_idx) noexcept
89+
: _data_iter(data_iter), _row_size(n_cols), _row_idx(row_idx) {}
8590

8691
/// @brief Implicit conversion from mutable to const iterator
8792
/// @return A const iterator pointing to the same row
8893
operator row_iterator<true>() const noexcept
8994
requires(not Const)
9095
{
91-
return row_iterator<true>(this->_data_ptr, this->_row_size, this->_row_idx);
96+
return row_iterator<true>(this->_data_iter, this->_row_size, this->_row_idx);
9297
}
9398

9499
/// @brief Dereferences the iterator to the current row.
95-
/// @return A span representing the row at the current position
100+
/// @return A subrange representing the row at the current position
96101
[[nodiscard]] reference operator*() const noexcept {
97-
return reference(this->_data_ptr + this->_row_idx * this->_row_size, this->_row_size);
102+
const auto row_beg = this->_data_iter + this->_row_idx * this->_row_size;
103+
return reference(row_beg, row_beg + this->_row_size);
98104
}
99105

100106
/// @brief Random access to a row at an offset from the current position.
@@ -206,7 +212,7 @@ class flat_matrix {
206212
}
207213

208214
private:
209-
data_ptr_type _data_ptr{nullptr};
215+
data_iter_type _data_iter;
210216
size_type _row_size{0uz};
211217
size_type _row_idx{0uz};
212218
};
@@ -439,7 +445,7 @@ class flat_matrix {
439445
return;
440446
}
441447

442-
std::vector<value_type> new_data(new_rows * new_cols, value);
448+
container_type new_data(new_rows * new_cols, value);
443449
const auto min_rows = std::min(this->_n_rows, new_rows);
444450
const auto min_cols = std::min(this->_n_cols, new_cols);
445451

@@ -474,20 +480,22 @@ class flat_matrix {
474480

475481
/// @brief Returns the row at the given index without bounds checking.
476482
/// @param r The index of the row to access
477-
/// @return A span representing the row at index r
483+
/// @return A subrange representing the row at index r
478484
/// @pre `r < n_rows()`; otherwise Undefined Behavior
479485
/// @warning No bounds checking is performed for performance.
480486
[[nodiscard]] row_type operator[](size_type r) {
481-
return row_type(this->_data.data() + r * this->_n_cols, this->_n_cols);
487+
const auto row_beg = this->_data.begin() + r * this->_n_cols;
488+
return row_type(row_beg, row_beg + this->_n_cols);
482489
}
483490

484491
/// @brief Returns a const row at the given index without bounds checking.
485492
/// @param r The index of the row to access
486-
/// @return A const span representing the row at index r
493+
/// @return A const subrange representing the row at index r
487494
/// @pre `r < n_rows()`; otherwise Undefined Behavior
488495
/// @warning No bounds checking is performed.
489496
[[nodiscard]] const_row_type operator[](size_type r) const {
490-
return const_row_type(this->_data.data() + r * this->_n_cols, this->_n_cols);
497+
const auto row_beg = this->_data.begin() + r * this->_n_cols;
498+
return const_row_type(row_beg, row_beg + this->_n_cols);
491499
}
492500

493501
/// @brief Returns a reference to an element without bounds checking.
@@ -512,7 +520,7 @@ class flat_matrix {
512520

513521
/// @brief Returns the row at the given index with bounds checking.
514522
/// @param r The index of the row
515-
/// @return A span representing the row at index r
523+
/// @return A subrange representing the row at index r
516524
/// @exception std::out_of_range If `r >= n_rows()`
517525
[[nodiscard]] row_type at(size_type r) {
518526
this->_check_row(r);
@@ -521,7 +529,7 @@ class flat_matrix {
521529

522530
/// @brief Returns a const row at the given index with bounds checking.
523531
/// @param r The index of the row
524-
/// @return A const span representing the row at index r
532+
/// @return A const subrange representing the row at index r
525533
/// @exception std::out_of_range If `r >= n_rows()`
526534
[[nodiscard]] const_row_type at(size_type r) const {
527535
this->_check_row(r);
@@ -551,60 +559,60 @@ class flat_matrix {
551559
}
552560

553561
/// @brief Returns the first row without bounds checking.
554-
/// @return A span representing the first row
562+
/// @return A subrange representing the first row
555563
/// @pre Matrix must not be empty; otherwise Undefined Behavior
556564
/// @warning No bounds checking is performed.
557565
[[nodiscard]] row_type front() noexcept {
558566
return (*this)[0uz];
559567
}
560568

561569
/// @brief Returns a const reference to the first row without bounds checking.
562-
/// @return A const span representing the first row
570+
/// @return A const subrange representing the first row
563571
/// @pre Matrix must not be empty; otherwise Undefined Behavior
564572
/// @warning No bounds checking is performed.
565573
[[nodiscard]] const_row_type front() const noexcept {
566574
return (*this)[0uz];
567575
}
568576

569577
/// @brief Returns the last row without bounds checking.
570-
/// @return A span representing the last row
578+
/// @return A subrange representing the last row
571579
/// @pre Matrix must not be empty; otherwise Undefined Behavior
572580
/// @warning No bounds checking is performed.
573581
[[nodiscard]] row_type back() noexcept {
574582
return (*this)[this->_n_rows - 1uz];
575583
}
576584

577585
/// @brief Returns a const reference to the last row without bounds checking.
578-
/// @return A const span representing the last row
586+
/// @return A const subrange representing the last row
579587
/// @pre Matrix must not be empty; otherwise Undefined Behavior
580588
/// @warning No bounds checking is performed.
581589
[[nodiscard]] const_row_type back() const noexcept {
582590
return (*this)[this->_n_rows - 1uz];
583591
}
584592

585593
/// @brief Explicitly named alias for `front()` yielding the first row.
586-
/// @return A span representing the first row
594+
/// @return A subrange representing the first row
587595
/// @pre Matrix must not be empty; otherwise Undefined Behavior
588596
[[nodiscard]] row_type front_row() noexcept {
589597
return this->front();
590598
}
591599

592600
/// @brief Explicitly named alias for `front()` yielding the first const row.
593-
/// @return A const span representing the first row
601+
/// @return A const subrange representing the first row
594602
/// @pre Matrix must not be empty; otherwise Undefined Behavior
595603
[[nodiscard]] const_row_type front_row() const noexcept {
596604
return this->front();
597605
}
598606

599607
/// @brief Explicitly named alias for `back()` yielding the last row.
600-
/// @return A span representing the last row
608+
/// @return A subrange representing the last row
601609
/// @pre Matrix must not be empty; otherwise Undefined Behavior
602610
[[nodiscard]] row_type back_row() noexcept {
603611
return this->back();
604612
}
605613

606614
/// @brief Explicitly named alias for `back()` yielding the last const row.
607-
/// @return A const span representing the last row
615+
/// @return A const subrange representing the last row
608616
/// @pre Matrix must not be empty; otherwise Undefined Behavior
609617
[[nodiscard]] const_row_type back_row() const noexcept {
610618
return this->back();
@@ -644,15 +652,15 @@ class flat_matrix {
644652

645653
/// @brief Semantically symmetric alias for `at(r)` returning a bounds-checked row.
646654
/// @param r The row index
647-
/// @return A span representing the row
655+
/// @return A subrange representing the row
648656
/// @exception std::out_of_range If `r >= n_rows()`
649657
[[nodiscard]] row_type row(size_type r) {
650658
return this->at(r);
651659
}
652660

653661
/// @brief Semantically symmetric alias for `at(r)` returning a bounds-checked const row.
654662
/// @param r The row index
655-
/// @return A const span representing the row
663+
/// @return A const subrange representing the row
656664
/// @exception std::out_of_range If `r >= n_rows()`
657665
[[nodiscard]] const_row_type row(size_type r) const {
658666
return this->at(r);
@@ -712,41 +720,46 @@ class flat_matrix {
712720
return this->_data.size();
713721
}
714722

715-
/// @brief Returns a span over all element data in flattened 1D form.
716-
/// @return A span of all elements in the underlying `_data` array.
723+
/// @brief Returns a subrange of all element data in flattened 1D form.
724+
/// @return A subrange of all elements in the underlying `_data` array.
717725
[[nodiscard]] row_type data_view() noexcept {
718726
return row_type(this->_data);
719727
}
720728

721-
/// @brief Returns a const span over all element data in flattened 1D form.
722-
/// @return A const span of all elements in the underlying `_data` array.
729+
/// @brief Returns a const subrange of all element data in flattened 1D form.
730+
/// @return A const subrange of all elements in the underlying `_data` array.
723731
[[nodiscard]] const_row_type data_view() const noexcept {
724732
return const_row_type(this->_data);
725733
}
726734

727735
/// @brief Returns a reference to the underlying flat data container.
728736
/// @return A mutable reference to the underlying `_data` array.
729737
/// @warning Modifying this vector directly can fatally corrupt the matrix structure. Use for advanced operations only.
730-
[[nodiscard]] std::vector<value_type>& data_storage() noexcept {
738+
[[nodiscard]] container_type& data_storage() noexcept {
731739
return this->_data;
732740
}
733741

734742
/// @brief Returns a const reference to the underlying flat data container.
735743
/// @return A const reference to the underlying `_data` array.
736-
[[nodiscard]] const std::vector<value_type>& data_storage() const noexcept {
744+
[[nodiscard]] const container_type& data_storage() const noexcept {
737745
return this->_data;
738746
}
739747

740748
/// @brief Returns a raw pointer to the underlying flat data array.
741749
/// @return A raw pointer to the first element in the `_data` array.
742-
/// @warning No bounds checking is performed.
743-
[[nodiscard]] value_type* data_ptr() noexcept {
750+
/// @warning Not available for boolean matrices.
751+
[[nodiscard]] value_type* data_ptr() noexcept
752+
requires(not std::same_as<value_type, bool>)
753+
{
744754
return this->_data.data();
745755
}
746756

747757
/// @brief Returns a const raw pointer to the underlying flat data array.
748758
/// @return A const raw pointer to the first element in the `_data` array.
749-
[[nodiscard]] const value_type* data_ptr() const noexcept {
759+
/// @warning Not available for boolean matrices.
760+
[[nodiscard]] const value_type* data_ptr() const noexcept
761+
requires(not std::same_as<value_type, bool>)
762+
{
750763
return this->_data.data();
751764
}
752765

@@ -1009,7 +1022,7 @@ class flat_matrix {
10091022
this->_n_rows = col_size;
10101023

10111024
// pre-allocate new vector to guarantee O(RxC) structural shift, avoiding cubic complexity with multiple inserts
1012-
std::vector<value_type> new_data;
1025+
container_type new_data;
10131026
new_data.reserve(this->_n_rows * (this->_n_cols + 1uz));
10141027

10151028
auto r_it = std::ranges::begin(r);
@@ -1038,7 +1051,7 @@ class flat_matrix {
10381051
else {
10391052
// create a temporary sized range and recursively call the method to leverage the sized range logic,
10401053
// ensuring strong exception guarantee for unsized input
1041-
this->insert_col(pos, std::ranges::to<std::vector<value_type>>(std::forward<R>(r)));
1054+
this->insert_col(pos, std::ranges::to<container_type>(std::forward<R>(r)));
10421055
}
10431056
}
10441057

@@ -1074,7 +1087,7 @@ class flat_matrix {
10741087
));
10751088
}
10761089

1077-
std::vector<value_type> new_data;
1090+
container_type new_data;
10781091
new_data.reserve(this->_n_rows * (this->_n_cols + 1uz));
10791092

10801093
for (size_type r_idx = 0uz; r_idx < this->_n_rows; ++r_idx) {
@@ -1123,7 +1136,7 @@ class flat_matrix {
11231136
return;
11241137
}
11251138

1126-
std::vector<value_type> new_data;
1139+
container_type new_data;
11271140
new_data.reserve(this->_n_rows * (this->_n_cols - 1uz));
11281141

11291142
for (size_type r_idx = 0uz; r_idx < this->_n_rows; ++r_idx) {
@@ -1151,28 +1164,28 @@ class flat_matrix {
11511164
/// @return Iterator to the first row
11521165
/// @note Iterator invalidated by structural modifications
11531166
[[nodiscard]] iterator begin() noexcept {
1154-
return iterator(this->_data.data(), this->_n_cols, 0uz);
1167+
return iterator(this->_data.begin(), this->_n_cols, 0uz);
11551168
}
11561169

11571170
/// @brief Returns a mutable iterator past the last row (end sentinel).
11581171
/// @return Iterator one position past the last row
11591172
/// @note Iterator invalidated by structural modifications
11601173
[[nodiscard]] iterator end() noexcept {
1161-
return iterator(this->_data.data(), this->_n_cols, this->_n_rows);
1174+
return iterator(this->_data.begin(), this->_n_cols, this->_n_rows);
11621175
}
11631176

11641177
/// @brief Returns a const iterator to the first row.
11651178
/// @return Const iterator to the first row
11661179
/// @note Iterator invalidated by structural modifications
11671180
[[nodiscard]] const_iterator begin() const noexcept {
1168-
return const_iterator(this->_data.data(), this->_n_cols, 0uz);
1181+
return const_iterator(this->_data.begin(), this->_n_cols, 0uz);
11691182
}
11701183

11711184
/// @brief Returns a const iterator past the last row (end sentinel).
11721185
/// @return Const iterator one position past the last row
11731186
/// @note Iterator invalidated by structural modifications
11741187
[[nodiscard]] const_iterator end() const noexcept {
1175-
return const_iterator(this->_data.data(), this->_n_cols, this->_n_rows);
1188+
return const_iterator(this->_data.begin(), this->_n_cols, this->_n_rows);
11761189
}
11771190

11781191
/// @brief Returns a const iterator to the first row (explicit const form).
@@ -1289,7 +1302,7 @@ class flat_matrix {
12891302

12901303
size_type _n_rows{0uz};
12911304
size_type _n_cols{0uz};
1292-
std::vector<value_type> _data;
1305+
container_type _data;
12931306
};
12941307

12951308
} // namespace gl

0 commit comments

Comments
 (0)