Skip to content

Commit ee4c4b9

Browse files
committed
Use structured bindings to create packs instead of old techniques involving std::index_sequence
1 parent 0fcddbb commit ee4c4b9

File tree

14 files changed

+148
-217
lines changed

14 files changed

+148
-217
lines changed

source/bounded/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ target_sources(bounded PUBLIC
6969
function_ptr.cpp
7070
hash.cpp
7171
homogeneous_equals.cpp
72+
index_sequence_struct.cpp
7273
integer.cpp
7374
integral.cpp
7475
integral_constant_of_integral.cpp

source/bounded/bounded.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export import bounded.destroy;
3131
export import bounded.equality_comparable;
3232
export import bounded.function_ptr;
3333
export import bounded.hash;
34+
export import bounded.index_sequence_struct;
3435
export import bounded.integer;
3536
export import bounded.integral;
3637
export import bounded.isomorphic_to_integral;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright David Stone 2025.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at
4+
// http://www.boost.org/LICENSE_1_0.txt)
5+
6+
export module bounded.index_sequence_struct;
7+
8+
import bounded.integer;
9+
import bounded.normalize;
10+
11+
import std_module;
12+
13+
namespace bounded {
14+
15+
export template<std::size_t size>
16+
struct index_sequence_struct {
17+
index_sequence_struct() = default;
18+
template<auto size_> requires (size_ == size)
19+
constexpr explicit index_sequence_struct(bounded::constant_t<size_>) {}
20+
template<std::size_t index>
21+
static constexpr auto get() {
22+
return bounded::constant<index>;
23+
}
24+
};
25+
26+
template<auto size>
27+
index_sequence_struct(bounded::constant_t<size>) -> index_sequence_struct<size>;
28+
29+
} // namespace bounded
30+
31+
namespace std {
32+
33+
template<std::size_t size>
34+
struct tuple_size<bounded::index_sequence_struct<size>> : std::integral_constant<std::size_t, size> {
35+
};
36+
37+
template<std::size_t index, std::size_t size>
38+
struct tuple_element<index, bounded::index_sequence_struct<size>> {
39+
using type = bounded::constant_t<bounded::normalize<index>>;
40+
};
41+
42+
} // namespace std

source/containers/algorithms/adjacent.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,8 @@ struct adjacent_iterator {
7373
}
7474
}
7575
constexpr auto operator*() const {
76-
return [&]<std::size_t... indexes>(std::index_sequence<indexes...>) {
77-
return tv::tuple<
78-
decltype(*m_its[bounded::constant<indexes>])...
79-
>(
80-
*m_its[bounded::constant<indexes>]...
81-
);
82-
}(bounded::make_index_sequence(group_size));
76+
auto const & [...its] = m_its;
77+
return tv::tuple<decltype(*its)...>(*its...);
8378
}
8479
friend constexpr auto operator+(adjacent_iterator lhs, bounded::bounded_integer auto const offset) -> adjacent_iterator {
8580
for (auto & it : lhs.m_its) {

source/containers/algorithms/concatenate_view.cpp

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,18 @@ constexpr auto compare_sentinels(LHS const & lhs, RHS const & rhs) -> bool {
4545
}
4646
}
4747

48-
template<typename LHS, typename RHS, std::size_t... indexes>
49-
constexpr auto have_same_ends(LHS const & lhs, RHS const & rhs, std::index_sequence<indexes...>) {
48+
template<typename LHS, typename RHS>
49+
constexpr auto have_same_ends(LHS const & lhs, RHS const & rhs) -> bool {
50+
static_assert(tv::tuple_size<LHS> == tv::tuple_size<RHS>);
51+
auto [...indexes] = bounded::index_sequence_struct(tv::tuple_size<LHS>);
5052
return (... and (
5153
compare_sentinels(
52-
containers::end(lhs[bounded::constant<indexes>]),
53-
containers::end(rhs[bounded::constant<indexes>])
54+
containers::end(lhs[indexes]),
55+
containers::end(rhs[indexes])
5456
)
5557
));
5658
}
5759

58-
template<typename LHS, typename RHS>
59-
constexpr auto assert_same_ends(LHS const & lhs, RHS const & rhs) {
60-
static_assert(tv::tuple_size<LHS> == tv::tuple_size<RHS>);
61-
BOUNDED_ASSERT(have_same_ends(lhs, rhs, bounded::make_index_sequence(tv::tuple_size<LHS>)));
62-
}
63-
6460
template<typename Category, typename RangeView>
6561
concept one_is_category = std::same_as<typename iterator_t<RangeView>::iterator_category, Category>;
6662

@@ -156,21 +152,20 @@ struct concatenate_view_iterator {
156152
);
157153
}
158154
};
159-
return [&]<std::size_t... indexes>(std::index_sequence<indexes...>) {
160-
// Use {} to enforce initialization order
161-
return tv::apply(
162-
tv::tuple{specific_range(bounded::constant<indexes>)...},
163-
bounded::construct<concatenate_view_iterator>
164-
);
165-
}(std::make_index_sequence<sizeof...(RangeViews)>());
155+
auto [...indexes] = bounded::index_sequence_struct<sizeof...(RangeViews)>();
156+
// Use {} to enforce initialization order
157+
return tv::apply(
158+
tv::tuple{specific_range(indexes)...},
159+
bounded::construct<concatenate_view_iterator>
160+
);
166161
}
167162

168163
template<typename... RHSRanges> requires(... and subtractable<iterator_t<RangeViews>, iterator_t<RHSRanges>>)
169164
friend constexpr auto operator-(
170165
concatenate_view_iterator const lhs,
171166
concatenate_view_iterator<RHSRanges...> const rhs
172167
) {
173-
::containers::assert_same_ends(lhs.m_range_views, rhs.m_range_views);
168+
BOUNDED_ASSERT(::containers::have_same_ends(lhs.m_range_views, rhs.m_range_views));
174169

175170
auto transform = [](auto const lhs_range, auto const rhs_range) {
176171
return containers::begin(lhs_range) - containers::begin(rhs_range);
@@ -202,7 +197,7 @@ struct concatenate_view_iterator {
202197
concatenate_view_iterator const lhs,
203198
concatenate_view_iterator<RHSRanges...> const rhs
204199
) {
205-
::containers::assert_same_ends(lhs.m_range_views, rhs.m_range_views);
200+
BOUNDED_ASSERT(::containers::have_same_ends(lhs.m_range_views, rhs.m_range_views));
206201
return lhs.begin_iterators() <=> rhs.begin_iterators();
207202
}
208203

@@ -213,7 +208,7 @@ struct concatenate_view_iterator {
213208

214209
template<typename... RHSRanges>
215210
friend constexpr auto operator==(concatenate_view_iterator const & lhs, concatenate_view_iterator<RHSRanges...> const & rhs) -> bool {
216-
::containers::assert_same_ends(lhs.m_range_views, rhs.m_range_views);
211+
BOUNDED_ASSERT(::containers::have_same_ends(lhs.m_range_views, rhs.m_range_views));
217212
return lhs.begin_iterators() == rhs.begin_iterators();
218213
}
219214

source/containers/algorithms/sort/double_buffered_ska_sort.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,15 @@ constexpr auto double_buffered_range_sort(range auto & source, range auto & buff
171171
return which;
172172
}
173173

174-
template<typename OriginalExtractor, typename CurrentExtractor, std::size_t... indexes>
175-
constexpr auto double_buffered_tuple_sort(range auto & source, range auto & buffer, OriginalExtractor const & original_extractor, CurrentExtractor const & current_extractor, std::index_sequence<indexes...>) -> bool {
174+
template<typename OriginalExtractor, typename CurrentExtractor>
175+
constexpr auto double_buffered_tuple_sort(
176+
range auto & source,
177+
range auto & buffer,
178+
OriginalExtractor const & original_extractor,
179+
CurrentExtractor const & current_extractor
180+
) -> bool {
181+
using key_t = std::decay_t<decltype(current_extractor(containers::front(source)))>;
182+
auto const [...indexes] = bounded::index_sequence_struct<std::tuple_size_v<key_t>>();
176183
auto which = false;
177184
auto do_iteration = [&]<auto index>(bounded::constant_t<index>) {
178185
using std::get;
@@ -186,7 +193,7 @@ constexpr auto double_buffered_tuple_sort(range auto & source, range auto & buff
186193
which = ::containers::double_buffered_sort_impl(source, buffer, original_extractor, extract_index);
187194
}
188195
};
189-
(..., do_iteration(bounded::constant<sizeof...(indexes) - indexes - 1>));
196+
(..., do_iteration(bounded::constant<sizeof...(indexes)> - indexes - 1_bi));
190197
return which;
191198
}
192199

@@ -201,7 +208,7 @@ constexpr auto double_buffered_sort_impl(range auto & source, range auto & buffe
201208
return ::containers::double_buffered_range_sort(source, buffer, original_extractor, current_extractor);
202209
} else {
203210
static_assert(tuple_like<key_t>);
204-
return ::containers::double_buffered_tuple_sort(source, buffer, original_extractor, current_extractor, std::make_index_sequence<std::tuple_size_v<key_t>>());
211+
return ::containers::double_buffered_tuple_sort(source, buffer, original_extractor, current_extractor);
205212
}
206213
}
207214

source/containers/algorithms/zip.cpp

Lines changed: 24 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,6 @@ namespace containers {
2929
template<typename... Iterators>
3030
struct zip_iterator;
3131

32-
template<typename... Ts>
33-
constexpr auto ref_or_value_tuple(Ts && ... args) {
34-
return tv::tuple<Ts...>(OPERATORS_FORWARD(args)...);
35-
}
36-
37-
template<std::size_t... indexes>
38-
constexpr auto dereference(auto const & tuple, std::index_sequence<indexes...>) {
39-
return ref_or_value_tuple(*tuple[bounded::constant<indexes>]...);
40-
}
41-
42-
template<typename... Iterators, std::size_t... indexes>
43-
constexpr auto add(tv::tuple<Iterators...> tuple, auto const offset, std::index_sequence<indexes...>) -> zip_iterator<Iterators...> {
44-
return zip_iterator<Iterators...>((std::move(tuple)[bounded::constant<indexes>] + offset)...);
45-
}
46-
4732
template<typename... Iterators>
4833
struct zip_difference_type_impl {
4934
static constexpr auto min_max = bounded::min(
@@ -77,17 +62,20 @@ struct zip_iterator {
7762
}
7863

7964
friend constexpr auto operator*(zip_iterator const & it) {
80-
return dereference(it.m_its, indexes);
65+
auto const & [...its] = it.m_its;
66+
return tv::tuple<decltype(*its)...>(*its...);
8167
}
82-
friend constexpr auto operator+(zip_iterator it, bounded::constant_t<1>) -> zip_iterator {
68+
friend constexpr auto operator+(zip_iterator it, bounded::constant_t<1> const offset) -> zip_iterator {
8369
if constexpr (sizeof...(Iterators) == 0) {
8470
std::unreachable();
8571
} else {
86-
return add(std::move(it).m_its, 1_bi, indexes);
72+
auto && [...its] = std::move(it).m_its;
73+
return zip_iterator((std::move(its) + offset)...);
8774
}
8875
}
8976
friend constexpr auto operator+(zip_iterator it, bounded::convertible_to<difference_type> auto const offset) -> zip_iterator {
90-
return add(std::move(it).m_its, offset, indexes);
77+
auto && [...its] = std::move(it).m_its;
78+
return zip_iterator((std::move(its) + offset)...);
9179
}
9280

9381
friend auto operator<=>(zip_iterator const &, zip_iterator const &) = default;
@@ -96,20 +84,9 @@ struct zip_iterator {
9684
friend struct zip_sentinel;
9785
template<typename... Sentinels>
9886
friend struct zip_smallest_sentinel;
99-
static constexpr auto indexes = std::make_index_sequence<sizeof...(Iterators)>();
10087
[[no_unique_address]] tv::tuple<Iterators...> m_its;
10188
};
10289

103-
template<std::size_t... indexes>
104-
constexpr auto all(auto const & lhs, auto const & rhs, std::index_sequence<indexes...>, auto const predicate) {
105-
return (... and predicate(lhs[bounded::constant<indexes>], rhs[bounded::constant<indexes>]));
106-
}
107-
108-
template<std::size_t... indexes>
109-
constexpr auto any(auto const & lhs, auto const & rhs, std::index_sequence<indexes...>, auto const predicate) {
110-
return (... or predicate(lhs[bounded::constant<indexes>], rhs[bounded::constant<indexes>]));
111-
}
112-
11390
template<typename... Sentinels>
11491
struct zip_sentinel {
11592
constexpr explicit zip_sentinel(Sentinels... sentinels):
@@ -118,10 +95,10 @@ struct zip_sentinel {
11895
}
11996
template<typename... Iterators> requires(sizeof...(Iterators) == sizeof...(Sentinels))
12097
friend constexpr auto operator==(zip_iterator<Iterators...> const & lhs, zip_sentinel const rhs) -> bool {
121-
constexpr auto indexes = std::make_index_sequence<sizeof...(Sentinels)>();
122-
if (all(lhs.m_its, rhs.m_sentinels, indexes, std::not_equal_to())) {
98+
auto const [...indexes] = bounded::index_sequence_struct<sizeof...(Sentinels)>();
99+
if ((... and (lhs.m_its[indexes] != rhs.m_sentinels[indexes]))) {
123100
return false;
124-
} else if (all(lhs.m_its, rhs.m_sentinels, indexes, std::equal_to())) {
101+
} else if ((... and (lhs.m_its[indexes] == rhs.m_sentinels[indexes]))) {
125102
return true;
126103
} else {
127104
throw std::runtime_error("Mismatched sizes for inputs to zip");
@@ -139,8 +116,8 @@ struct zip_smallest_sentinel {
139116
}
140117
template<typename... Iterators> requires(sizeof...(Iterators) == sizeof...(Sentinels))
141118
friend constexpr auto operator==(zip_iterator<Iterators...> const & lhs, zip_smallest_sentinel const rhs) -> bool {
142-
constexpr auto indexes = std::make_index_sequence<sizeof...(Sentinels)>();
143-
return any(lhs.m_its, rhs.m_sentinels, indexes, std::equal_to());
119+
auto const [...indexes] = bounded::index_sequence_struct<sizeof...(Sentinels)>();
120+
return (... or (lhs.m_its[indexes] == rhs.m_sentinels[indexes]));
144121
}
145122
private:
146123
[[no_unique_address]] tv::tuple<Sentinels...> m_sentinels;
@@ -154,38 +131,6 @@ constexpr auto all_are_equal() -> bool {
154131
return true;
155132
}
156133

157-
template<std::size_t... indexes>
158-
constexpr auto make_zip_iterator(auto && ranges, std::index_sequence<indexes...>, auto get) {
159-
return zip_iterator(
160-
get(OPERATORS_FORWARD(ranges)[bounded::constant<indexes>])...
161-
);
162-
}
163-
164-
// https://github.com/llvm/llvm-project/issues/59513
165-
struct use_begin {
166-
static constexpr auto operator()(auto && r) {
167-
return containers::begin(OPERATORS_FORWARD(r));
168-
}
169-
};
170-
struct use_end {
171-
static constexpr auto operator()(auto && r) {
172-
return containers::end(OPERATORS_FORWARD(r));
173-
}
174-
};
175-
176-
template<bool check_equal_sizes, std::size_t... indexes>
177-
constexpr auto make_zip_sentinel(auto && ranges, std::index_sequence<indexes...>) {
178-
if constexpr (check_equal_sizes) {
179-
return zip_sentinel(
180-
containers::end(OPERATORS_FORWARD(ranges)[bounded::constant<indexes>])...
181-
);
182-
} else {
183-
return zip_smallest_sentinel(
184-
containers::end(OPERATORS_FORWARD(ranges)[bounded::constant<indexes>])...
185-
);
186-
}
187-
}
188-
189134
template<typename Range>
190135
concept supports_begin = requires(Range r) {
191136
containers::begin(OPERATORS_FORWARD(r));
@@ -208,7 +153,6 @@ export template<bool check_equal_sizes, range... Ranges>
208153
struct zip_impl {
209154
private:
210155
static constexpr auto all_are_sized = (... and sized_range<Ranges>);
211-
static constexpr auto indexes = std::make_index_sequence<sizeof...(Ranges)>();
212156

213157
static constexpr auto as_tuple(Ranges && ... ranges) {
214158
if constexpr (all_are_sized and !check_equal_sizes and sizeof...(Ranges) != 0) {
@@ -221,18 +165,14 @@ struct zip_impl {
221165

222166
decltype(as_tuple(bounded::declval<Ranges>()...)) m_ranges;
223167

224-
static constexpr auto end_impl(auto && ranges) {
168+
static constexpr auto end_impl(auto && m_ranges) {
169+
auto && [...ranges] = OPERATORS_FORWARD(m_ranges);
225170
if constexpr (all_are_sized) {
226-
return ::containers::make_zip_iterator(
227-
OPERATORS_FORWARD(ranges),
228-
indexes,
229-
use_end()
230-
);
171+
return zip_iterator(::containers::end(OPERATORS_FORWARD(ranges))...);
172+
} else if constexpr (check_equal_sizes) {
173+
return zip_sentinel(containers::end(OPERATORS_FORWARD(ranges))...);
231174
} else {
232-
return ::containers::make_zip_sentinel<check_equal_sizes>(
233-
OPERATORS_FORWARD(ranges),
234-
indexes
235-
);
175+
return zip_smallest_sentinel(containers::end(OPERATORS_FORWARD(ranges))...);
236176
}
237177
}
238178

@@ -255,13 +195,16 @@ struct zip_impl {
255195
}
256196

257197
constexpr auto begin() const & requires all_support_begin<Ranges const &...> {
258-
return make_zip_iterator(m_ranges, indexes, use_begin());
198+
auto && [...ranges] = m_ranges;
199+
return zip_iterator(::containers::begin(OPERATORS_FORWARD(ranges))...);
259200
}
260201
constexpr auto begin() & requires all_support_begin<Ranges &...> {
261-
return make_zip_iterator(m_ranges, indexes, use_begin());
202+
auto && [...ranges] = m_ranges;
203+
return zip_iterator(::containers::begin(OPERATORS_FORWARD(ranges))...);
262204
}
263205
constexpr auto begin() && requires all_support_begin<Ranges &&...> {
264-
return make_zip_iterator(std::move(m_ranges), indexes, use_begin());
206+
auto && [...ranges] = std::move(m_ranges);
207+
return zip_iterator(::containers::begin(OPERATORS_FORWARD(ranges))...);
265208
}
266209

267210
constexpr auto end() const & requires all_support_end<Ranges const &...> {

0 commit comments

Comments
 (0)