@@ -173,6 +173,21 @@ constexpr auto contains_type(
173173 stdx::detail::tuple_impl<IndexSeq, index_function_list<Fs...>, Us...> const
174174 &) -> std::bool_constant<(is_index_for<T, Fs, Us...> or ...) or
175175 (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+ }
176191} // namespace detail
177192
178193template <tuplelike Tuple, typename T>
@@ -183,36 +198,29 @@ template <template <typename> typename Proj = std::type_identity_t,
183198 tuplelike Tuple>
184199[[nodiscard]] constexpr auto sort (Tuple &&t) {
185200 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>();
196202 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]>]...};
199205 }(std::make_index_sequence<T::size ()>{});
200206}
201207
202208namespace 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+ };
208216
209217template <tuplelike T, template <typename > typename Proj = std::type_identity_t >
210218 requires (tuple_size_v<T> > 1 )
211219[[nodiscard]] constexpr auto count_chunks () {
212220 auto count = std::size_t {1 };
213221 [&]<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 > )),
216224 ...);
217225 }(std::make_index_sequence<stdx::tuple_size_v<T> - 1 >{});
218226 return count;
@@ -232,7 +240,7 @@ template <tuplelike T, template <typename> typename Proj = std::type_identity_t>
232240 std::array<chunk, count_chunks<T, Proj>()> chunks{};
233241 ++chunks[index].size ;
234242 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 > ) {
236244 chunks[++index].offset = I + 1 ;
237245 }
238246 ++chunks[index].size ;
@@ -333,6 +341,55 @@ template <tuplelike Tuple> constexpr auto to_unsorted_set(Tuple &&t) {
333341 std::forward<Tuple>(t))...};
334342 }(std::make_index_sequence<U::size ()>{});
335343}
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+ }
336393} // namespace v1
337394} // namespace stdx
338395
0 commit comments