Skip to content

Commit 4ee11f5

Browse files
authored
Merge 2022-07 LWG Motion 17
P2322R6 ranges::fold
2 parents b097af4 + 58e39f2 commit 4ee11f5

File tree

2 files changed

+271
-0
lines changed

2 files changed

+271
-0
lines changed

source/algorithms.tex

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,9 @@
642642
template<class I>
643643
struct in_found_result;
644644

645+
template<class I, class T>
646+
struct in_value_result;
647+
645648
template<class O, class T>
646649
struct out_value_result;
647650
}
@@ -1215,6 +1218,91 @@
12151218
@\libconcept{indirectly_comparable}@<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
12161219
constexpr bool ends_with(R1&& r1, R2&& r2, Pred pred = {},
12171220
Proj1 proj1 = {}, Proj2 proj2 = {});
1221+
1222+
// \ref{alg.fold}, fold
1223+
template<class F>
1224+
class @\exposid{flipped}@ { // \expos
1225+
F @\exposid{f}@; // \expos
1226+
1227+
public:
1228+
template<class T, class U> requires @\libconcept{invocable}@<F&, U, T>
1229+
invoke_result_t<F&, U, T> operator()(T&&, U&&);
1230+
};
1231+
1232+
template<class F, class T, class I, class U>
1233+
concept @\defexposconcept{indirectly-binary-left-foldable-impl}@ = // \expos
1234+
@\libconcept{movable}@<T> && @\libconcept{movable}@<U> &&
1235+
@\libconcept{convertible_to}@<T, U> && @\libconcept{invocable}@<F&, U, iter_reference_t<I>> &&
1236+
@\libconcept{assignable_from}@<U&, invoke_result_t<F&, U, iter_reference_t<I>>>;
1237+
1238+
template<class F, class T, class I>
1239+
concept @\defexposconcept{indirectly-binary-left-foldable}@ = // \expos
1240+
@\libconcept{copy_constructible}@<F> && @\libconcept{indirectly_readable}@<I> &&
1241+
@\libconcept{invocable}@<F&, T, iter_reference_t<I>> &&
1242+
@\libconcept{convertible_to}@<invoke_result_t<F&, T, iter_reference_t<I>>,
1243+
decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>> &&
1244+
@\exposconcept{indirectly-binary-left-foldable-impl}@<F, T, I,
1245+
decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>>;
1246+
1247+
template<class F, class T, class I>
1248+
concept @\defexposconcept{indirectly-binary-right-foldable}@ = // \expos
1249+
@\exposconcept{indirectly-binary-left-foldable}@<@\exposid{flipped}@<F>, T, I>;
1250+
1251+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
1252+
@\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
1253+
constexpr auto fold_left(I first, S last, T init, F f);
1254+
1255+
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
1256+
constexpr auto fold_left(R&& r, T init, F f);
1257+
1258+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
1259+
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
1260+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
1261+
constexpr auto fold_left_first(I first, S last, F f);
1262+
1263+
template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
1264+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
1265+
constexpr auto fold_left_first(R&& r, F f);
1266+
1267+
template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
1268+
@\exposconcept{indirectly-binary-right-foldable}@<T, I> F>
1269+
constexpr auto fold_right(I first, S last, T init, F f);
1270+
1271+
template<@\libconcept{bidirectional_range}@ R, class T,
1272+
@\exposconcept{indirectly-binary-right-foldable}@<T, iterator_t<R>> F>
1273+
constexpr auto fold_right(R&& r, T init, F f);
1274+
1275+
template <@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
1276+
@\exposconcept{indirectly-binary-right-foldable}@<iter_value_t<I>, I> F>
1277+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
1278+
constexpr auto fold_right_last(I first, S last, F f);
1279+
1280+
template<@\libconcept{bidirectional_range}@ R,
1281+
@\exposconcept{indirectly-binary-right-foldable}@<range_value_t<R>, iterator_t<R>> F>
1282+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
1283+
constexpr auto fold_right_last(R&& r, F f);
1284+
1285+
template<class I, class T>
1286+
using fold_left_with_iter_result = in_value_result<I, T>;
1287+
template<class I, class T>
1288+
using fold_left_first_with_iter_result = in_value_result<I, T>;
1289+
1290+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
1291+
@\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
1292+
constexpr @\seebelow@ fold_left_with_iter(I first, S last, T init, F f);
1293+
1294+
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
1295+
constexpr @\seebelow@ fold_left_with_iter(R&& r, T init, F f);
1296+
1297+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
1298+
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
1299+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
1300+
constexpr @\seebelow@ fold_left_first_with_iter(I first, S last, F f);
1301+
1302+
template<@\libconcept{input_range}@ R,
1303+
@\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
1304+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
1305+
constexpr @\seebelow@ fold_left_first_with_iter(R&& r, F f);
12181306
}
12191307

12201308
// \ref{alg.modifying.operations}, mutating sequence operations
@@ -3104,6 +3192,24 @@
31043192
}
31053193
};
31063194

3195+
template<class I, class T>
3196+
struct in_value_result {
3197+
[[no_unique_address]] I in;
3198+
[[no_unique_address]] T value;
3199+
3200+
template<class I2, class T2>
3201+
requires @\libconcept{convertible_to}@<const I&, I2> && @\libconcept{convertible_to}@<const T&, T2>
3202+
constexpr operator in_value_result<I2, T2>() const & {
3203+
return {in, value};
3204+
}
3205+
3206+
template<class I2, class T2>
3207+
requires @\libconcept{convertible_to}@<I, I2> && @\libconcept{convertible_to}@<T, T2>
3208+
constexpr operator in_value_result<I2, T2>() && {
3209+
return {std::move(in), std::move(value)};
3210+
}
3211+
};
3212+
31073213
template<class O, class T>
31083214
struct out_value_result {
31093215
[[no_unique_address]] O out;
@@ -4518,6 +4624,170 @@
45184624
\end{codeblock}
45194625
\end{itemdescr}
45204626

4627+
\rSec2[alg.fold]{Fold}
4628+
4629+
\indexlibraryglobal{fold_left}%
4630+
\begin{itemdecl}
4631+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
4632+
constexpr auto ranges::fold_left(I first, S last, T init, F f);
4633+
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
4634+
constexpr auto ranges::fold_left(R&& r, T init, F f);
4635+
\end{itemdecl}
4636+
4637+
\begin{itemdescr}
4638+
\pnum
4639+
\returns
4640+
\begin{codeblock}
4641+
ranges::fold_left_with_iter(std::move(first), last, std::move(init), f).value
4642+
\end{codeblock}
4643+
\end{itemdescr}
4644+
4645+
\indexlibraryglobal{fold_left_first}%
4646+
\begin{itemdecl}
4647+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
4648+
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
4649+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
4650+
constexpr auto ranges::fold_left_first(I first, S last, F f);
4651+
template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
4652+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
4653+
constexpr auto ranges::fold_left_first(R&& r, F f);
4654+
\end{itemdecl}
4655+
4656+
\begin{itemdescr}
4657+
\pnum
4658+
\returns
4659+
\begin{codeblock}
4660+
ranges::fold_left_first_with_iter(std::move(first), last, f).value
4661+
\end{codeblock}
4662+
\end{itemdescr}
4663+
4664+
\indexlibraryglobal{fold_right}%
4665+
\begin{itemdecl}
4666+
template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
4667+
@\exposconcept{indirectly-binary-right-foldable}@<T, I> F>
4668+
constexpr auto ranges::fold_right(I first, S last, T init, F f);
4669+
template<@\libconcept{bidirectional_range}@ R, class T,
4670+
@\exposconcept{indirectly-binary-right-foldable}@<T, iterator_t<R>> F>
4671+
constexpr auto ranges::fold_right(R&& r, T init, F f);
4672+
\end{itemdecl}
4673+
4674+
\begin{itemdescr}
4675+
\pnum
4676+
\effects
4677+
Equivalent to:
4678+
\begin{codeblock}
4679+
using U = decay_t<invoke_result_t<F&, iter_reference_t<I>, T>>;
4680+
if (first == last)
4681+
return U(std::move(init));
4682+
I tail = ranges::next(first, last);
4683+
U accum = invoke(f, *--tail, std::move(init));
4684+
while (first != tail)
4685+
accum = invoke(f, *--tail, std::move(accum));
4686+
return accum;
4687+
\end{codeblock}
4688+
\end{itemdescr}
4689+
4690+
\indexlibraryglobal{fold_right_last}%
4691+
\begin{itemdecl}
4692+
template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
4693+
@\exposconcept{indirectly-binary-right-foldable}@<iter_value_t<I>, I> F>
4694+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
4695+
constexpr auto ranges::fold_right_last(I first, S last, F f);
4696+
template<@\libconcept{bidirectional_range}@ R,
4697+
@\exposconcept{indirectly-binary-right-foldable}@<range_value_t<R>, iterator_t<R>> F>
4698+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
4699+
constexpr auto ranges::fold_right_last(R&& r, F f);
4700+
\end{itemdecl}
4701+
4702+
\begin{itemdescr}
4703+
\pnum
4704+
Let \tcode{U} be
4705+
\tcode{decltype(ranges::fold_right(first, last, iter_value_t<I>(*first), f))}.
4706+
4707+
\pnum
4708+
\effects
4709+
Equivalent to:
4710+
\begin{codeblock}
4711+
if (first == last)
4712+
return optional<U>();
4713+
I tail = ranges::prev(ranges::next(first, std::move(last)));
4714+
return optional<U>(in_place,
4715+
ranges::fold_right(std::move(first), tail, iter_value_t<I>(*tail), std::move(f)));
4716+
\end{codeblock}
4717+
\end{itemdescr}
4718+
4719+
\indexlibraryglobal{fold_left_with_iter}%
4720+
\begin{itemdecl}
4721+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
4722+
@\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
4723+
constexpr @\seebelow@ ranges::fold_left_with_iter(I first, S last, T init, F f);
4724+
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
4725+
constexpr @\seebelow@ ranges::fold_left_with_iter(R&& r, T init, F f);
4726+
\end{itemdecl}
4727+
4728+
\begin{itemdescr}
4729+
\pnum
4730+
Let \tcode{U} be \tcode{decay_t<invoke_result_t<F\&, T, iter_reference_t<I>>>}.
4731+
4732+
\pnum
4733+
\effects
4734+
Equivalent to:
4735+
\begin{codeblock}
4736+
if (first == last)
4737+
return {std::move(first), U(std::move(init))};
4738+
U accum = invoke(f, std::move(init), *first);
4739+
for (++first; first != last; ++first)
4740+
accum = invoke(f, std::move(accum), *first);
4741+
return {std::move(first), std::move(accum)};
4742+
\end{codeblock}
4743+
4744+
\pnum
4745+
\remarks
4746+
The return type is
4747+
\tcode{fold_left_with_iter_result<I, U>} for the first overload and
4748+
\tcode{fold_left_with_iter_result<borrowed_iterator_t<R>, U>}
4749+
for the second overload.
4750+
\end{itemdescr}
4751+
4752+
\indexlibraryglobal{fold_left_first_with_iter}%
4753+
\begin{itemdecl}
4754+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
4755+
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
4756+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
4757+
constexpr @\seebelow@ ranges::fold_left_first_with_iter(I first, S last, F f);
4758+
template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
4759+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
4760+
constexpr @\seebelow@ ranges::fold_left_first_with_iter(R&& r, F f);
4761+
\end{itemdecl}
4762+
4763+
\begin{itemdescr}
4764+
\pnum
4765+
Let \tcode{U} be
4766+
\begin{codeblock}
4767+
decltype(ranges::fold_left(std::move(first), last, iter_value_t<I>(*first), f))
4768+
\end{codeblock}
4769+
4770+
\pnum
4771+
\effects
4772+
Equivalent to:
4773+
\begin{codeblock}
4774+
if (first == last)
4775+
return {std::move(first), optional<U>()};
4776+
optional<U> init(in_place, *first);
4777+
for (++first; first != last; ++first)
4778+
*init = invoke(f, std::move(*init), *first);
4779+
return {std::move(first), std::move(init)};
4780+
\end{codeblock}
4781+
4782+
\pnum
4783+
\remarks
4784+
The return type is
4785+
\tcode{fold_left_first_with_iter_result<I, optional<U>>}
4786+
for the first overload and
4787+
\tcode{fold_left_first_with_iter_result<borrowed_iterator_t<R>, optional<U>>}
4788+
for the second overload.
4789+
\end{itemdescr}
4790+
45214791
\rSec1[alg.modifying.operations]{Mutating sequence operations}
45224792

45234793
\rSec2[alg.copy]{Copy}

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,7 @@
681681
#define @\defnlibxname{cpp_lib_ranges_chunk}@ 202202L // also in \libheader{ranges}
682682
#define @\defnlibxname{cpp_lib_ranges_chunk_by}@ 202202L // also in \libheader{ranges}
683683
#define @\defnlibxname{cpp_lib_ranges_contains}@ 202207L // also in \libheader{algorithm}
684+
#define @\defnlibxname{cpp_lib_ranges_fold}@ 202207L // also in \libheader{algorithm}
684685
#define @\defnlibxname{cpp_lib_ranges_iota}@ 202202L // also in \libheader{numeric}
685686
#define @\defnlibxname{cpp_lib_ranges_join_with}@ 202202L // also in \libheader{ranges}
686687
#define @\defnlibxname{cpp_lib_ranges_slide}@ 202202L // also in \libheader{ranges}

0 commit comments

Comments
 (0)