Skip to content

Commit 63c22d6

Browse files
committed
refactored concat_view
1 parent e393eee commit 63c22d6

4 files changed

Lines changed: 73 additions & 64 deletions

File tree

include/gl/util/ranges.hpp

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -39,50 +39,72 @@ template <std::ranges::forward_range R>
3939
return std::ranges::all_of(range, [&k](const auto& val) { return val == k; });
4040
}
4141

42-
// --- C++20 Concat View Utility ---
43-
44-
namespace detail {
42+
// TODO: add tests
4543

44+
/// @brief A generic view that concatenates two ranges/views.
45+
/// @todo Replace with `std::views::concat` (Requires C++26)
4646
template <std::ranges::view V1, std::ranges::view V2>
4747
class concat_view : public std::ranges::view_interface<concat_view<V1, V2>> {
4848
public:
4949
concat_view() = default;
5050

5151
constexpr concat_view(V1 v1, V2 v2) : _v1(std::move(v1)), _v2(std::move(v2)) {}
5252

53-
class sentinel {
54-
public:
55-
sentinel() = default;
53+
constexpr auto begin() {
54+
return iterator<false>(
55+
std::ranges::begin(_v1), std::ranges::end(_v1), std::ranges::begin(_v2)
56+
);
57+
}
5658

57-
constexpr explicit sentinel(std::ranges::sentinel_t<V2> end2) : _end2(std::move(end2)) {}
59+
constexpr auto begin() const
60+
requires std::ranges::range<const V1> && std::ranges::range<const V2>
61+
{
62+
return iterator<true>(
63+
std::ranges::begin(_v1), std::ranges::end(_v1), std::ranges::begin(_v2)
64+
);
65+
}
5866

59-
constexpr auto end2() const {
60-
return _end2;
61-
}
67+
constexpr auto end() {
68+
return sentinel<false>(std::ranges::end(_v2));
69+
}
6270

63-
private:
64-
std::ranges::sentinel_t<V2> _end2;
65-
friend class concat_view;
66-
};
71+
constexpr auto end() const
72+
requires std::ranges::range<const V1> && std::ranges::range<const V2>
73+
{
74+
return sentinel<true>(std::ranges::end(_v2));
75+
}
6776

77+
private:
78+
V1 _v1;
79+
V2 _v2;
80+
81+
template <bool Const>
82+
class sentinel; // forward declare
83+
84+
template <bool Const>
6885
class iterator {
86+
private:
87+
using BaseV1 = std::conditional_t<Const, const V1, V1>;
88+
using BaseV2 = std::conditional_t<Const, const V2, V2>;
89+
6990
public:
70-
using difference_type = std::
71-
common_type_t<std::ranges::range_difference_t<V1>, std::ranges::range_difference_t<V2>>;
72-
using value_type =
73-
std::common_type_t<std::ranges::range_value_t<V1>, std::ranges::range_value_t<V2>>;
91+
using difference_type = std::common_type_t<
92+
std::ranges::range_difference_t<BaseV1>,
93+
std::ranges::range_difference_t<BaseV2>>;
94+
using value_type = std::
95+
common_type_t<std::ranges::range_value_t<BaseV1>, std::ranges::range_value_t<BaseV2>>;
7496
using reference = std::common_reference_t<
75-
std::ranges::range_reference_t<V1>,
76-
std::ranges::range_reference_t<V2>>;
97+
std::ranges::range_reference_t<BaseV1>,
98+
std::ranges::range_reference_t<BaseV2>>;
7799
using iterator_category = std::forward_iterator_tag;
78100
using iterator_concept = std::forward_iterator_tag;
79101

80102
iterator() = default;
81103

82104
constexpr iterator(
83-
std::ranges::iterator_t<V1> it1,
84-
std::ranges::sentinel_t<V1> end1,
85-
std::ranges::iterator_t<V2> it2
105+
std::ranges::iterator_t<BaseV1> it1,
106+
std::ranges::sentinel_t<BaseV1> end1,
107+
std::ranges::iterator_t<BaseV2> it2
86108
)
87109
: _it1(std::move(it1)), _end1(std::move(end1)), _it2(std::move(it2)) {}
88110

@@ -112,41 +134,43 @@ class concat_view : public std::ranges::view_interface<concat_view<V1, V2>> {
112134
return _it1 == other._it1 && _it2 == other._it2;
113135
}
114136

115-
constexpr bool operator==(const sentinel& s) const {
137+
constexpr bool operator==(const sentinel<Const>& s) const {
116138
return _it1 == _end1 && _it2 == s.end2();
117139
}
118140

119141
private:
120-
std::ranges::iterator_t<V1> _it1;
121-
std::ranges::sentinel_t<V1> _end1;
122-
std::ranges::iterator_t<V2> _it2;
142+
std::ranges::iterator_t<BaseV1> _it1{};
143+
std::ranges::sentinel_t<BaseV1> _end1{};
144+
std::ranges::iterator_t<BaseV2> _it2{};
145+
146+
friend class concat_view;
123147
};
124148

125-
constexpr iterator begin() {
126-
return iterator(std::ranges::begin(_v1), std::ranges::end(_v1), std::ranges::begin(_v2));
127-
}
149+
template <bool Const>
150+
class sentinel {
151+
private:
152+
using BaseV2 = std::conditional_t<Const, const V2, V2>;
128153

129-
constexpr iterator begin() const
130-
requires std::ranges::range<const V1> && std::ranges::range<const V2>
131-
{
132-
return iterator(std::ranges::begin(_v1), std::ranges::end(_v1), std::ranges::begin(_v2));
133-
}
154+
public:
155+
sentinel() = default;
134156

135-
constexpr sentinel end() {
136-
return sentinel(std::ranges::end(_v2));
137-
}
157+
constexpr explicit sentinel(std::ranges::sentinel_t<BaseV2> end2)
158+
: _end2(std::move(end2)) {}
138159

139-
constexpr sentinel end() const
140-
requires std::ranges::range<const V1> && std::ranges::range<const V2>
141-
{
142-
return sentinel(std::ranges::end(_v2));
143-
}
160+
constexpr auto end2() const {
161+
return _end2;
162+
}
144163

145-
private:
146-
V1 _v1;
147-
V2 _v2;
164+
private:
165+
std::ranges::sentinel_t<BaseV2> _end2{};
166+
167+
friend class concat_view;
168+
friend class iterator<Const>;
169+
};
148170
};
149171

172+
namespace detail {
173+
150174
struct concat_fn {
151175
template <std::ranges::viewable_range R1, std::ranges::viewable_range R2>
152176
constexpr auto operator()(R1&& r1, R2&& r2) const {

include/hgl/impl/flat_incidence_list.hpp

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -495,18 +495,10 @@ class flat_incidence_list<hgl::bf_directed_t, ImplTag> final {
495495
const id_type id, const Projection storage_proj
496496
) const noexcept {
497497
const auto idx = to_idx(id);
498-
if constexpr (std::same_as<Projection, std::identity>) {
499-
// TODO: use std::views::concat (C++26)
500-
// NOTE: This is safe because the range operator | creates an owning view over the array
501-
// return std::array<storage_const_segment_type, 2uz>{
502-
// this->_tail_storage[idx], this->_head_storage[idx]
503-
// }
504-
// | std::views::join;
498+
if constexpr (std::same_as<Projection, std::identity>)
505499
return util::concat(this->_tail_storage[idx], this->_head_storage[idx]);
506-
}
507-
else {
500+
else
508501
return std::invoke(storage_proj, this)[idx];
509-
}
510502
}
511503

512504
template <element_type Element>
@@ -546,10 +538,6 @@ class flat_incidence_list<hgl::bf_directed_t, ImplTag> final {
546538
[[nodiscard]] gl_attr_force_inline auto _get(const id_type id) const noexcept {
547539
if constexpr (Element == layout_tag::major_element) { // get major
548540
const auto idx = to_idx(id);
549-
// return std::array<storage_const_segment_type, 2uz>{
550-
// this->_tail_storage[idx], this->_head_storage[idx]
551-
// }
552-
// | std::views::join;
553541
return util::concat(this->_tail_storage[idx], this->_head_storage[idx]);
554542
}
555543
else { // get minor

include/hgl/impl/incidence_list.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,10 +482,6 @@ class incidence_list<hgl::bf_directed_t, ImplTag> final {
482482
[[nodiscard]] gl_attr_force_inline auto _get(const id_type id) const noexcept {
483483
if constexpr (Element == layout_tag::major_element) { // get major
484484
const auto idx = to_idx(id);
485-
// return std::array<std::span<const minor_element_type>, 2>{
486-
// this->_tail_storage[idx], this->_head_storage[idx]
487-
// }
488-
// | std::views::join;
489485
return util::concat(this->_tail_storage[idx], this->_head_storage[idx]);
490486
}
491487
else { // get minor

include/hgl/util.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace hgl::util {
1010

1111
using gl::util::all_equal;
1212
using gl::util::concat;
13+
using gl::util::concat_view;
1314
using gl::util::deref_view;
1415
using gl::util::is_constant;
1516
using gl::util::range_size;

0 commit comments

Comments
 (0)