|
1 | 1 | #pragma once
|
2 | 2 |
|
3 | 3 | #include <functional>
|
| 4 | +#include <iterator> |
4 | 5 | #if __cplusplus >= 202002L
|
5 | 6 | #include <stdx/tuple.hpp>
|
6 | 7 | #else
|
7 | 8 | #include <tuple>
|
8 | 9 | #endif
|
| 10 | +#include <type_traits> |
9 | 11 |
|
10 | 12 | namespace stdx {
|
11 | 13 | inline namespace v1 {
|
@@ -48,25 +50,90 @@ CONSTEXPR_INVOKE auto transform_n(InputIt first, Size n, OutputIt d_first,
|
48 | 50 | return {d_first, first, first_n...};
|
49 | 51 | }
|
50 | 52 |
|
| 53 | +template <typename Op, typename... Is> |
| 54 | +using for_each_result = detail::result_tuple_t<Op, Is...>; |
| 55 | + |
51 | 56 | template <typename InputIt, typename Operation, typename... InputItN>
|
52 | 57 | CONSTEXPR_INVOKE auto for_each(InputIt first, InputIt last, Operation op,
|
53 |
| - InputItN... first_n) -> Operation { |
| 58 | + InputItN... first_n) |
| 59 | + -> for_each_result<Operation, InputItN...> { |
54 | 60 | while (first != last) {
|
55 | 61 | std::invoke(op, *first, *first_n...);
|
56 | 62 | static_cast<void>(++first), (static_cast<void>(++first_n), ...);
|
57 | 63 | }
|
58 |
| - return op; |
| 64 | + return {op, first_n...}; |
59 | 65 | }
|
60 | 66 |
|
61 | 67 | template <typename InputIt, typename Size, typename Operation,
|
62 | 68 | typename... InputItN>
|
63 | 69 | CONSTEXPR_INVOKE auto for_each_n(InputIt first, Size n, Operation op,
|
64 |
| - InputItN... first_n) -> Operation { |
| 70 | + InputItN... first_n) |
| 71 | + -> for_each_result<Operation, InputIt, InputItN...> { |
65 | 72 | while (n-- > 0) {
|
66 | 73 | std::invoke(op, *first, *first_n...);
|
67 | 74 | static_cast<void>(++first), (static_cast<void>(++first_n), ...);
|
68 | 75 | }
|
69 |
| - return op; |
| 76 | + return {op, first, first_n...}; |
| 77 | +} |
| 78 | + |
| 79 | +namespace detail { |
| 80 | +template <typename FwdIt, typename N, typename Operation, typename... FwdItN> |
| 81 | +CONSTEXPR_INVOKE auto for_each_butlastn(std::forward_iterator_tag, FwdIt first, |
| 82 | + FwdIt last, N n, Operation op, |
| 83 | + FwdItN... first_n) |
| 84 | + -> for_each_result<Operation, FwdIt, FwdItN...> { |
| 85 | + auto adv_it = first; |
| 86 | + for (auto i = N{}; i < n; ++i) { |
| 87 | + if (adv_it == last) { |
| 88 | + break; |
| 89 | + } |
| 90 | + ++adv_it; |
| 91 | + } |
| 92 | + |
| 93 | + while (adv_it != last) { |
| 94 | + std::invoke(op, *first, *first_n...); |
| 95 | + static_cast<void>(++first), (static_cast<void>(++first_n), ...); |
| 96 | + ++adv_it; |
| 97 | + } |
| 98 | + return {op, first, first_n...}; |
| 99 | +} |
| 100 | + |
| 101 | +template <typename RandIt, typename N, typename Operation, typename... RandItN> |
| 102 | +CONSTEXPR_INVOKE auto for_each_butlastn(std::random_access_iterator_tag, |
| 103 | + RandIt first, RandIt last, N n, |
| 104 | + Operation op, RandItN... first_n) { |
| 105 | + auto const sz = std::distance(first, last); |
| 106 | + return for_each_n(first, sz - static_cast<decltype(sz)>(n), op, first_n...); |
| 107 | +} |
| 108 | +} // namespace detail |
| 109 | + |
| 110 | +template <typename FwdIt, typename N, typename Operation, typename... FwdItN> |
| 111 | +CONSTEXPR_INVOKE auto for_each_butlastn(FwdIt first, FwdIt last, N n, |
| 112 | + Operation op, FwdItN... first_n) { |
| 113 | + return detail::for_each_butlastn( |
| 114 | + typename std::iterator_traits<FwdIt>::iterator_category{}, first, last, |
| 115 | + n, op, first_n...); |
| 116 | +} |
| 117 | + |
| 118 | +template <typename FwdIt, typename Operation, typename... FwdItN> |
| 119 | +CONSTEXPR_INVOKE auto for_each_butlast(FwdIt first, FwdIt last, Operation op, |
| 120 | + FwdItN... first_n) { |
| 121 | + return for_each_butlastn(first, last, 1, op, first_n...); |
| 122 | +} |
| 123 | + |
| 124 | +template <typename FwdIt, typename IOp, typename MOp, typename FOp> |
| 125 | +CONSTEXPR_INVOKE auto initial_medial_final(FwdIt first, FwdIt last, IOp iop, |
| 126 | + MOp mop, FOp fop) |
| 127 | + -> for_each_result<IOp, MOp, FOp> { |
| 128 | + if (first != last) { |
| 129 | + iop(*first); |
| 130 | + auto [op, it] = for_each_butlast(++first, last, mop); |
| 131 | + if (it != last) { |
| 132 | + fop(*it); |
| 133 | + } |
| 134 | + return {iop, op, fop}; |
| 135 | + } |
| 136 | + return {iop, mop, fop}; |
70 | 137 | }
|
71 | 138 |
|
72 | 139 | #undef CONSTEXPR_INVOKE
|
|
0 commit comments