Skip to content

Commit f2e451a

Browse files
committed
some more fixes
1 parent 2623a03 commit f2e451a

7 files changed

Lines changed: 228 additions & 85 deletions

File tree

include/gl/util/ranges.hpp

Lines changed: 147 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99

1010
namespace gl::util {
1111

12-
inline constexpr auto deref_view =
13-
std::views::transform([](auto&& p) -> decltype(auto) { return *p; });
14-
1512
template <std::ranges::range R>
1613
constexpr auto range_size(R&& r) {
1714
if constexpr (std::ranges::sized_range<R>)
@@ -39,4 +36,151 @@ template <std::ranges::forward_range R>
3936
return std::ranges::all_of(range, [&k](const auto& val) { return val == k; });
4037
}
4138

39+
inline constexpr auto deref_view =
40+
std::views::transform([](auto&& p) -> decltype(auto) { return *p; });
41+
42+
// TODO: add tests
43+
44+
/// @brief A generic view that concatenates two ranges/views.
45+
/// @todo Replace with `std::views::concat` (Requires C++26)
46+
template <std::ranges::view V1, std::ranges::view V2>
47+
class concat_view : public std::ranges::view_interface<concat_view<V1, V2>> {
48+
public:
49+
concat_view() = default;
50+
51+
constexpr concat_view(V1 v1, V2 v2) : _v1(std::move(v1)), _v2(std::move(v2)) {}
52+
53+
constexpr auto begin() {
54+
return iterator<false>(
55+
std::ranges::begin(this->_v1),
56+
std::ranges::end(this->_v1),
57+
std::ranges::begin(this->_v2)
58+
);
59+
}
60+
61+
constexpr auto begin() const
62+
requires std::ranges::range<const V1> && std::ranges::range<const V2>
63+
{
64+
return iterator<true>(
65+
std::ranges::begin(this->_v1),
66+
std::ranges::end(this->_v1),
67+
std::ranges::begin(this->_v2)
68+
);
69+
}
70+
71+
constexpr auto end() {
72+
return sentinel<false>(std::ranges::end(this->_v2));
73+
}
74+
75+
constexpr auto end() const
76+
requires std::ranges::range<const V1> && std::ranges::range<const V2>
77+
{
78+
return sentinel<true>(std::ranges::end(this->_v2));
79+
}
80+
81+
private:
82+
V1 _v1;
83+
V2 _v2;
84+
85+
template <bool Const>
86+
class sentinel; // forward declare
87+
88+
template <bool Const>
89+
class iterator {
90+
private:
91+
using BaseV1 = std::conditional_t<Const, const V1, V1>;
92+
using BaseV2 = std::conditional_t<Const, const V2, V2>;
93+
94+
public:
95+
using difference_type = std::common_type_t<
96+
std::ranges::range_difference_t<BaseV1>,
97+
std::ranges::range_difference_t<BaseV2>>;
98+
using value_type = std::
99+
common_type_t<std::ranges::range_value_t<BaseV1>, std::ranges::range_value_t<BaseV2>>;
100+
using reference = std::common_reference_t<
101+
std::ranges::range_reference_t<BaseV1>,
102+
std::ranges::range_reference_t<BaseV2>>;
103+
using iterator_category = std::forward_iterator_tag;
104+
using iterator_concept = std::forward_iterator_tag;
105+
106+
iterator() = default;
107+
108+
constexpr iterator(
109+
std::ranges::iterator_t<BaseV1> it1,
110+
std::ranges::sentinel_t<BaseV1> end1,
111+
std::ranges::iterator_t<BaseV2> it2
112+
)
113+
: _it1(std::move(it1)), _end1(std::move(end1)), _it2(std::move(it2)) {}
114+
115+
constexpr reference operator*() const {
116+
return (this->_it1 != this->_end1) ? *this->_it1 : *this->_it2;
117+
}
118+
119+
constexpr iterator& operator++() {
120+
(this->_it1 != this->_end1) ? ++this->_it1 : ++this->_it2;
121+
return *this;
122+
}
123+
124+
constexpr iterator operator++(int) {
125+
iterator tmp = *this;
126+
++*this;
127+
return tmp;
128+
}
129+
130+
constexpr bool operator==(const iterator& other) const {
131+
return this->_it1 == other._it1 && this->_it2 == other._it2;
132+
}
133+
134+
constexpr bool operator==(const sentinel<Const>& s) const {
135+
return this->_it1 == this->_end1 && this->_it2 == s.end2();
136+
}
137+
138+
private:
139+
std::ranges::iterator_t<BaseV1> _it1{};
140+
std::ranges::sentinel_t<BaseV1> _end1{};
141+
std::ranges::iterator_t<BaseV2> _it2{};
142+
143+
friend class concat_view;
144+
};
145+
146+
template <bool Const>
147+
class sentinel {
148+
private:
149+
using BaseV2 = std::conditional_t<Const, const V2, V2>;
150+
151+
public:
152+
sentinel() = default;
153+
154+
constexpr explicit sentinel(std::ranges::sentinel_t<BaseV2> end2)
155+
: _end2(std::move(end2)) {}
156+
157+
constexpr auto end2() const {
158+
return this->_end2;
159+
}
160+
161+
private:
162+
std::ranges::sentinel_t<BaseV2> _end2{};
163+
164+
friend class concat_view;
165+
friend class iterator<Const>;
166+
};
167+
};
168+
169+
namespace detail {
170+
171+
struct concat_fn {
172+
template <std::ranges::viewable_range R1, std::ranges::viewable_range R2>
173+
constexpr auto operator()(R1&& r1, R2&& r2) const {
174+
return concat_view<std::views::all_t<R1>, std::views::all_t<R2>>(
175+
std::views::all(std::forward<R1>(r1)), std::views::all(std::forward<R2>(r2))
176+
);
177+
}
178+
};
179+
180+
} // namespace detail
181+
182+
/// @brief Concatenates two ranges sequentially into a single view.
183+
/// @todo replace with `std::views::concat`
184+
inline constexpr detail::concat_fn concat{};
185+
42186
} // namespace gl::util

include/hgl/impl/flat_incidence_list.hpp

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
#pragma once
66

7-
#include "gl/types/core.hpp"
87
#include "hgl/constants.hpp"
98
#include "hgl/decl/impl_tags.hpp"
109
#include "hgl/directional_tags.hpp"
1110
#include "hgl/impl/layout_tags.hpp"
1211
#include "hgl/types.hpp"
12+
#include "hgl/util.hpp"
1313

1414
#include <algorithm>
1515
#include <concepts>
@@ -496,15 +496,10 @@ class flat_incidence_list<hgl::bf_directed_t, ImplTag> final {
496496
) const noexcept {
497497
const auto idx = to_idx(id);
498498
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;
499+
return util::concat(this->_tail_storage[idx], this->_head_storage[idx]);
505500
}
506501
else {
507-
return std::invoke(storage_proj, this)[idx];
502+
return (this->*storage_proj)[idx];
508503
}
509504
}
510505

@@ -545,10 +540,7 @@ class flat_incidence_list<hgl::bf_directed_t, ImplTag> final {
545540
[[nodiscard]] gl_attr_force_inline auto _get(const id_type id) const noexcept {
546541
if constexpr (Element == layout_tag::major_element) { // get major
547542
const auto idx = to_idx(id);
548-
return std::array<storage_const_segment_type, 2uz>{
549-
this->_tail_storage[idx], this->_head_storage[idx]
550-
}
551-
| std::views::join;
543+
return util::concat(this->_tail_storage[idx], this->_head_storage[idx]);
552544
}
553545
else { // get minor
554546
return std::views::iota(initial_id_v<id_type>, this->_tail_storage.size())
@@ -563,14 +555,14 @@ class flat_incidence_list<hgl::bf_directed_t, ImplTag> final {
563555
[[nodiscard]] gl_attr_force_inline auto _get(const id_type id, const auto&& storage_proj)
564556
const noexcept {
565557
if constexpr (Element == layout_tag::major_element) { // get major
566-
return std::invoke(storage_proj, this)[to_idx(id)];
558+
return (this->*storage_proj)[to_idx(id)];
567559
}
568560
else { // get minor
569561
return std::views::iota(initial_id_v<id_type>, this->_tail_storage.size())
570562
| std::views::filter(
571-
[this, &storage = std::invoke(storage_proj, this), minor_id = id](
572-
id_type major_id
573-
) { return detail::contains(storage[to_idx(major_id)], minor_id); }
563+
[this, &storage = this->*storage_proj, minor_id = id](id_type major_id) {
564+
return detail::contains(storage[to_idx(major_id)], minor_id);
565+
}
574566
);
575567
}
576568
}
@@ -597,11 +589,11 @@ class flat_incidence_list<hgl::bf_directed_t, ImplTag> final {
597589
[[nodiscard]] gl_attr_force_inline size_type
598590
_size(const id_type id, const auto&& storage_proj) const noexcept {
599591
if constexpr (Element == layout_tag::major_element) { // size major
600-
return std::invoke(storage_proj, this)[to_idx(id)].size();
592+
return (this->*storage_proj)[to_idx(id)].size();
601593
}
602594
else { // size minor
603595
size_type size = 0uz;
604-
for (const auto segment : std::invoke(storage_proj, this))
596+
for (const auto segment : this->*storage_proj)
605597
if (detail::contains(segment, id))
606598
++size;
607599
return size;
@@ -636,7 +628,7 @@ class flat_incidence_list<hgl::bf_directed_t, ImplTag> final {
636628
[[nodiscard]] std::vector<size_type> _size_map(
637629
const size_type n_elements, const auto&& storage_proj
638630
) const noexcept {
639-
const auto& storage = std::invoke(storage_proj, this);
631+
const auto& storage = this->*storage_proj;
640632
if constexpr (Element == layout_tag::major_element) { // size major
641633
std::vector<size_type> size_map(n_elements, 0uz);
642634

include/hgl/impl/incidence_list.hpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
#pragma once
66

7-
#include "gl/types/core.hpp"
87
#include "hgl/constants.hpp"
98
#include "hgl/decl/impl_tags.hpp"
109
#include "hgl/directional_tags.hpp"
1110
#include "hgl/impl/layout_tags.hpp"
1211
#include "hgl/types.hpp"
12+
#include "hgl/util.hpp"
1313

1414
#include <algorithm>
1515
#include <concepts>
@@ -481,10 +481,7 @@ class incidence_list<hgl::bf_directed_t, ImplTag> final {
481481
[[nodiscard]] gl_attr_force_inline auto _get(const id_type id) const noexcept {
482482
if constexpr (Element == layout_tag::major_element) { // get major
483483
const auto idx = to_idx(id);
484-
return std::array<std::span<const minor_element_type>, 2>{
485-
this->_tail_storage[idx], this->_head_storage[idx]
486-
}
487-
| std::views::join;
484+
return util::concat(this->_tail_storage[idx], this->_head_storage[idx]);
488485
}
489486
else { // get minor
490487
return std::views::iota(initial_id_v<id_type>, this->_tail_storage.size())
@@ -499,14 +496,14 @@ class incidence_list<hgl::bf_directed_t, ImplTag> final {
499496
[[nodiscard]] gl_attr_force_inline auto _get(const id_type id, const Projection storage_proj)
500497
const noexcept {
501498
if constexpr (Element == layout_tag::major_element) { // get major
502-
return std::views::all(std::invoke(storage_proj, this)[to_idx(id)]);
499+
return std::views::all((this->*storage_proj)[to_idx(id)]);
503500
}
504501
else { // get minor
505502
return std::views::iota(initial_id_v<id_type>, this->_tail_storage.size())
506503
| std::views::filter(
507-
[this, &storage = std::invoke(storage_proj, this), minor_id = id](
508-
id_type major_id
509-
) { return this->_contains(storage[to_idx(major_id)], minor_id); }
504+
[this, &storage = this->*storage_proj, minor_id = id](id_type major_id) {
505+
return this->_contains(storage[to_idx(major_id)], minor_id);
506+
}
510507
);
511508
}
512509
}
@@ -533,11 +530,11 @@ class incidence_list<hgl::bf_directed_t, ImplTag> final {
533530
[[nodiscard]] gl_attr_force_inline size_type
534531
_size(const id_type id, const Projection storage_proj) const noexcept {
535532
if constexpr (Element == layout_tag::major_element) { // size major
536-
return std::invoke(storage_proj, this)[to_idx(id)].size();
533+
return (this->*storage_proj)[to_idx(id)].size();
537534
}
538535
else { // size minor
539536
size_type size = 0uz;
540-
for (const auto& minor_storage : std::invoke(storage_proj, this))
537+
for (const auto& minor_storage : this->*storage_proj)
541538
if (this->_contains(minor_storage, id))
542539
++size;
543540
return size;
@@ -571,15 +568,15 @@ class incidence_list<hgl::bf_directed_t, ImplTag> final {
571568
) const noexcept {
572569
if constexpr (Element == layout_tag::major_element) { // size major
573570
std::vector<size_type> size_map(n_elements, 0uz);
574-
const auto& storage = std::invoke(storage_proj, this);
571+
const auto& storage = this->*storage_proj;
575572
const auto n_segments = storage.size();
576573
for (auto i = 0uz; i < n_segments; ++i)
577574
size_map[i] = storage[i].size();
578575
return size_map;
579576
}
580577
else { // size minor
581578
std::vector<size_type> size_map(n_elements, 0uz);
582-
for (const auto& minor_storage : std::invoke(storage_proj, this))
579+
for (const auto& minor_storage : this->*storage_proj)
583580
for (const auto minor_id : minor_storage)
584581
++size_map[to_idx(minor_id)];
585582
return size_map;

include/hgl/util.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
namespace hgl::util {
1010

1111
using gl::util::all_equal;
12+
using gl::util::concat;
13+
using gl::util::concat_view;
1214
using gl::util::deref_view;
1315
using gl::util::is_constant;
1416
using gl::util::range_size;

0 commit comments

Comments
 (0)