@@ -173,6 +173,21 @@ constexpr auto contains_type(
173
173
stdx::detail::tuple_impl<IndexSeq, index_function_list<Fs...>, Us...> const
174
174
&) -> std::bool_constant<(is_index_for<T, Fs, Us...> or ...) or
175
175
(std::is_same_v<T, Us> or ...)>;
176
+
177
+ template <tuplelike T, template <typename > typename Proj = std::type_identity_t >
178
+ [[nodiscard]] constexpr auto sorted_indices () {
179
+ return []<std::size_t ... Is>(std::index_sequence<Is...>)
180
+ -> std::array<std::size_t , sizeof ...(Is)> {
181
+ using P = std::pair<std::string_view, std::size_t >;
182
+ auto a = std::array<P, sizeof ...(Is)>{
183
+ P{stdx::type_as_string<Proj<tuple_element_t <Is, T>>>(), Is}...};
184
+ std::sort (a.begin (), a.end (), [](auto const &p1, auto const &p2) {
185
+ return p1.first < p2.first ;
186
+ });
187
+ return {a[Is].second ...};
188
+ }
189
+ (std::make_index_sequence<T::size ()>{});
190
+ }
176
191
} // namespace detail
177
192
178
193
template <tuplelike Tuple, typename T>
@@ -183,36 +198,29 @@ template <template <typename> typename Proj = std::type_identity_t,
183
198
tuplelike Tuple>
184
199
[[nodiscard]] constexpr auto sort (Tuple &&t) {
185
200
using T = stdx::remove_cvref_t <Tuple>;
186
- using P = std::pair<std::string_view, std::size_t >;
187
- constexpr auto indices = []<std::size_t ... Is>(std::index_sequence<Is...>) {
188
- auto a = std::array<P, sizeof ...(Is)>{
189
- P{stdx::type_as_string<Proj<tuple_element_t <Is, T>>>(), Is}...};
190
- std::sort (a.begin (), a.end (), [](auto const &p1, auto const &p2) {
191
- return p1.first < p2.first ;
192
- });
193
- return a;
194
- }(std::make_index_sequence<T::size ()>{});
195
-
201
+ constexpr auto indices = detail::sorted_indices<T, Proj>();
196
202
return [&]<std::size_t ... Is>(std::index_sequence<Is...>) {
197
- return stdx::tuple<tuple_element_t <indices[Is]. second , T>...>{
198
- std::forward<Tuple>(t)[index<indices[Is]. second >]...};
203
+ return stdx::tuple<tuple_element_t <indices[Is], T>...>{
204
+ std::forward<Tuple>(t)[index<indices[Is]>]...};
199
205
}(std::make_index_sequence<T::size ()>{});
200
206
}
201
207
202
208
namespace detail {
203
- template <tuplelike T, template <typename > typename Proj, std::size_t I>
204
- [[nodiscard]] constexpr auto test_adjacent () -> bool {
205
- return std::is_same_v<Proj<stdx::tuple_element_t <I, T>>,
206
- Proj<stdx::tuple_element_t <I + 1 , T>>>;
207
- }
209
+
210
+ template <tuplelike T, template <typename > typename Proj> struct test_pair_t {
211
+ template <std::size_t I, std::size_t J>
212
+ constexpr static auto value =
213
+ std::is_same_v<Proj<stdx::tuple_element_t <I, T>>,
214
+ Proj<stdx::tuple_element_t <J, T>>>;
215
+ };
208
216
209
217
template <tuplelike T, template <typename > typename Proj = std::type_identity_t >
210
218
requires (tuple_size_v<T> > 1 )
211
219
[[nodiscard]] constexpr auto count_chunks () {
212
220
auto count = std::size_t {1 };
213
221
[&]<std::size_t ... Is>(std::index_sequence<Is...>) {
214
- ((count +=
215
- static_cast <std:: size_t >( not detail::test_adjacent <T, Proj, Is>() )),
222
+ ((count += static_cast <std:: size_t >(
223
+ not test_pair_t <T, Proj>:: template value<Is , Is + 1 > )),
216
224
...);
217
225
}(std::make_index_sequence<stdx::tuple_size_v<T> - 1 >{});
218
226
return count;
@@ -232,7 +240,7 @@ template <tuplelike T, template <typename> typename Proj = std::type_identity_t>
232
240
std::array<chunk, count_chunks<T, Proj>()> chunks{};
233
241
++chunks[index].size ;
234
242
auto check_next_chunk = [&]<std::size_t I>() {
235
- if (not detail::test_adjacent <T, Proj, I>() ) {
243
+ if (not test_pair_t <T, Proj>:: template value<I , I + 1 > ) {
236
244
chunks[++index].offset = I + 1 ;
237
245
}
238
246
++chunks[index].size ;
@@ -333,6 +341,55 @@ template <tuplelike Tuple> constexpr auto to_unsorted_set(Tuple &&t) {
333
341
std::forward<Tuple>(t))...};
334
342
}(std::make_index_sequence<U::size ()>{});
335
343
}
344
+
345
+ template <template <typename > typename Proj = std::type_identity_t ,
346
+ tuplelike Tuple>
347
+ [[nodiscard]] constexpr auto gather_by (Tuple &&t) {
348
+ using tuple_t = std::remove_cvref_t <Tuple>;
349
+ if constexpr (tuple_size_v<tuple_t > == 0 ) {
350
+ return stdx::tuple{};
351
+ } else if constexpr (tuple_size_v<tuple_t > == 1 ) {
352
+ return stdx::make_tuple (std::forward<Tuple>(t));
353
+ } else {
354
+ constexpr auto sorted_idxs = detail::sorted_indices<tuple_t , Proj>();
355
+ constexpr auto tests =
356
+ [&]<std::size_t ... Is>(std::index_sequence<Is...>) {
357
+ return std::array<bool , stdx::tuple_size_v<tuple_t > - 1 >{
358
+ detail::test_pair_t <tuple_t , Proj>::template value<
359
+ sorted_idxs[Is], sorted_idxs[Is + 1 ]>...};
360
+ }(std::make_index_sequence<stdx::tuple_size_v<tuple_t > - 1 >{});
361
+
362
+ constexpr auto chunks = [&] {
363
+ constexpr auto chunk_count =
364
+ std::count (std::begin (tests), std::end (tests), false ) + 1 ;
365
+ std::array<detail::chunk, chunk_count> cs{};
366
+
367
+ auto index = std::size_t {};
368
+ ++cs[index].size ;
369
+ for (auto i = std::size_t {}; i < std::size (tests); ++i) {
370
+ if (not tests[i]) {
371
+ cs[++index].offset = i + 1 ;
372
+ }
373
+ ++cs[index].size ;
374
+ }
375
+ return cs;
376
+ }();
377
+
378
+ return [&]<std::size_t ... Is>(std::index_sequence<Is...>) {
379
+ return stdx::make_tuple ([&]<std::size_t ... Js>(
380
+ std::index_sequence<Js...>) {
381
+ constexpr auto offset = chunks[Is].offset ;
382
+ return stdx::tuple<
383
+ tuple_element_t <sorted_idxs[offset + Js], tuple_t >...>{
384
+ std::forward<Tuple>(t)[index<sorted_idxs[offset + Js]>]...};
385
+ }(std::make_index_sequence<chunks[Is].size >{})...);
386
+ }(std::make_index_sequence<chunks.size ()>{});
387
+ }
388
+ }
389
+
390
+ template <tuplelike Tuple> [[nodiscard]] constexpr auto gather (Tuple &&t) {
391
+ return gather_by (std::forward<Tuple>(t));
392
+ }
336
393
} // namespace v1
337
394
} // namespace stdx
338
395
0 commit comments