Skip to content

Commit 178c313

Browse files
committed
P2322R6 ranges::fold
1 parent 433b7af commit 178c313

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
}
@@ -1169,6 +1172,91 @@
11691172
@\libconcept{indirectly_comparable}@<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
11701173
constexpr bool ends_with(R1&& r1, R2&& r2, Pred pred = {},
11711174
Proj1 proj1 = {}, Proj2 proj2 = {});
1175+
1176+
// \ref{alg.fold}, fold
1177+
template<class F>
1178+
class @\exposid{flipped}@ { // \expos
1179+
F @\exposid{f}@; // \expos
1180+
1181+
public:
1182+
template<class T, class U> requires @\libconcept{invocable}@<F&, U, T>
1183+
invoke_result_t<F&, U, T> operator()(T&&, U&&);
1184+
};
1185+
1186+
template<class F, class T, class I, class U>
1187+
concept @\defexposconcept{indirectly-binary-left-foldable-impl}@ = // \expos
1188+
@\libconcept{movable}@<T> && @\libconcept{movable}@<U> &&
1189+
@\libconcept{convertible_to}@<T, U> && @\libconcept{invocable}@<F&, U, iter_reference_t<I>> &&
1190+
@\libconcept{assignable_from}@<U&, invoke_result_t<F&, U, iter_reference_t<I>>>;
1191+
1192+
template<class F, class T, class I>
1193+
concept @\defexposconcept{indirectly-binary-left-foldable}@ = // \expos
1194+
@\libconcept{copy_constructible}@<F> && @\libconcept{indirectly_readable}@<I> &&
1195+
@\libconcept{invocable}@<F&, T, iter_reference_t<I>> &&
1196+
@\libconcept{convertible_to}@<invoke_result_t<F&, T, iter_reference_t<I>>,
1197+
decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>> &&
1198+
@\exposconcept{indirectly-binary-left-foldable-impl}@<F, T, I,
1199+
decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>>;
1200+
1201+
template<class F, class T, class I>
1202+
concept @\defexposconcept{indirectly-binary-right-foldable}@ = // \expos
1203+
@\exposconcept{indirectly-binary-left-foldable}@<@\exposid{flipped}@<F>, T, I>;
1204+
1205+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
1206+
@\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
1207+
constexpr auto fold_left(I first, S last, T init, F f);
1208+
1209+
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
1210+
constexpr auto fold_left(R&& r, T init, F f);
1211+
1212+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
1213+
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
1214+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
1215+
constexpr auto fold_left_first(I first, S last, F f);
1216+
1217+
template <@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
1218+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
1219+
constexpr auto fold_left_first(R&& r, F f);
1220+
1221+
template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
1222+
@\exposconcept{indirectly-binary-right-foldable}@<T, I> F>
1223+
constexpr auto fold_right(I first, S last, T init, F f);
1224+
1225+
template<@\libconcept{bidirectional_range}@ R, class T,
1226+
@\exposconcept{indirectly-binary-right-foldable}@<T, iterator_t<R>> F>
1227+
constexpr auto fold_right(R&& r, T init, F f);
1228+
1229+
template <@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
1230+
indirectly-binary-right-foldable<iter_value_t<I>, I> F>
1231+
requires constructible_from<iter_value_t<I>, iter_reference_t<I>>
1232+
constexpr auto fold_right_last(I first, S last, F f);
1233+
1234+
template <@\libconcept{bidirectional_range}@ R,
1235+
@\exposconcept{indirectly-binary-right-foldable}@<range_value_t<R>, iterator_t<R>> F>
1236+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
1237+
constexpr auto fold_right_last(R&& r, F f);
1238+
1239+
template<class I, class T>
1240+
using fold_left_with_iter_result = in_value_result<I, T>;
1241+
template<class I, class T>
1242+
using fold_left_first_with_iter_result = in_value_result<I, T>;
1243+
1244+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
1245+
@\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
1246+
constexpr @\seebelow@ fold_left_with_iter(I first, S last, T init, F f);
1247+
1248+
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
1249+
constexpr @\seebelow@ fold_left_with_iter(R&& r, T init, F f);
1250+
1251+
template <@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
1252+
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
1253+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
1254+
constexpr @\seebelow@ fold_left_first_with_iter(I first, S last, F f);
1255+
1256+
template <@\libconcept{input_range}@ R,
1257+
@\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
1258+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
1259+
constexpr @\seebelow@ fold_left_first_with_iter(R&& r, F f);
11721260
}
11731261

11741262
// \ref{alg.modifying.operations}, mutating sequence operations
@@ -3058,6 +3146,24 @@
30583146
}
30593147
};
30603148

3149+
template<class I, class T>
3150+
struct in_value_result {
3151+
[[no_unique_address]] I in;
3152+
[[no_unique_address]] T value;
3153+
3154+
template<class I2, class T2>
3155+
requires @\libconcept{convertible_to}@<const I&, I2> && @\libconcept{convertible_to}@<const T&, T2>
3156+
constexpr operator in_value_result<I2, T2>() const & {
3157+
return {in, value};
3158+
}
3159+
3160+
template<class I2, class T2>
3161+
requires @\libconcept{convertible_to}@<I, I2> && @\libconcept{convertible_to}@<T, T2>
3162+
constexpr operator in_value_result<I2, T2>() && {
3163+
return {std::move(in), std::move(value)};
3164+
}
3165+
};
3166+
30613167
template<class O, class T>
30623168
struct out_value_result {
30633169
[[no_unique_address]] O out;
@@ -4384,6 +4490,170 @@
43844490
\end{codeblock}
43854491
\end{itemdescr}
43864492

4493+
\rSec2[alg.fold]{Fold}
4494+
4495+
\indexlibraryglobal{fold_left}%
4496+
\begin{itemdecl}
4497+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
4498+
constexpr auto ranges::fold_left(I first, S last, T init, F f);
4499+
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
4500+
constexpr auto ranges::fold_left(R&& r, T init, F f);
4501+
\end{itemdecl}
4502+
4503+
\begin{itemdescr}
4504+
\pnum
4505+
\returns
4506+
\begin{codeblock}
4507+
ranges::fold_left_with_iter(std::move(first), last, std::move(init), f).value
4508+
\end{codeblock}
4509+
\end{itemdescr}
4510+
4511+
\indexlibraryglobal{fold_left_first}%
4512+
\begin{itemdecl}
4513+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
4514+
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
4515+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
4516+
constexpr auto ranges::fold_left_first(I first, S last, F f);
4517+
template <@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
4518+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
4519+
constexpr auto ranges::fold_left_first(R&& r, F f);
4520+
\end{itemdecl}
4521+
4522+
\begin{itemdescr}
4523+
\pnum
4524+
\returns
4525+
\begin{codeblock}
4526+
ranges::fold_left_first_with_iter(std::move(first), last, f).value
4527+
\end{codeblock}
4528+
\end{itemdescr}
4529+
4530+
\indexlibraryglobal{fold_right}%
4531+
\begin{itemdecl}
4532+
template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
4533+
@\exposconcept{indirectly-binary-right-foldable}@<T, I> F>
4534+
constexpr auto ranges::fold_right(I first, S last, T init, F f);
4535+
template<@\libconcept{bidirectional_range}@ R, class T,
4536+
@\exposconcept{indirectly-binary-right-foldable}@<T, iterator_t<R>> F>
4537+
constexpr auto ranges::fold_right(R&& r, T init, F f);
4538+
\end{itemdecl}
4539+
4540+
\begin{itemdescr}
4541+
\pnum
4542+
\effects
4543+
Equivalent to:
4544+
\begin{codeblock}
4545+
using U = decay_t<invoke_result_t<F&, iter_reference_t<I>, T>>;
4546+
if (first == last)
4547+
return U(std::move(init));
4548+
I tail = ranges::next(first, last);
4549+
U accum = invoke(f, *--tail, std::move(init));
4550+
while (first != tail)
4551+
accum = invoke(f, *--tail, std::move(accum));
4552+
return accum;
4553+
\end{codeblock}
4554+
\end{itemdescr}
4555+
4556+
\indexlibraryglobal{fold_right_last}%
4557+
\begin{itemdecl}
4558+
template <@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
4559+
@\exposconcept{indirectly-binary-right-foldable}@<iter_value_t<I>, I> F>
4560+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
4561+
constexpr auto ranges::fold_right_last(I first, S last, F f);
4562+
template <@\libconcept{bidirectional_range}@ R,
4563+
@\exposconcept{indirectly-binary-right-foldable}@<range_value_t<R>, iterator_t<R>> F>
4564+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
4565+
constexpr auto ranges::fold_right_last(R&& r, F f);
4566+
\end{itemdecl}
4567+
4568+
\begin{itemdescr}
4569+
\pnum
4570+
Let \tcode{U} be
4571+
\tcode{decltype(ranges::fold_right(first, last, iter_value_t<I>(*first), f))}.
4572+
4573+
\pnum
4574+
\effects
4575+
Equivalent to:
4576+
\begin{codeblock}
4577+
if (first == last)
4578+
return optional<U>();
4579+
I tail = ranges::prev(ranges::next(first, std::move(last)));
4580+
return optional<U>(in_place,
4581+
ranges::fold_right(std::move(first), tail, iter_value_t<I>(*tail), std::move(f)));
4582+
\end{codeblock}
4583+
\end{itemdescr}
4584+
4585+
\indexlibraryglobal{fold_left_with_iter}%
4586+
\begin{itemdecl}
4587+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
4588+
@\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
4589+
constexpr @\seebelow@ fold_left_with_iter(I first, S last, T init, F f);
4590+
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
4591+
constexpr @\seebelow@ fold_left_with_iter(R&& r, T init, F f);
4592+
\end{itemdecl}
4593+
4594+
\begin{itemdescr}
4595+
\pnum
4596+
Let \tcode{U} be \tcode{decay_t<invoke_result_t<F\&, T, iter_reference_t<I>>>}.
4597+
4598+
\pnum
4599+
\effects
4600+
Equivalent to:
4601+
\begin{codeblock}
4602+
if (first == last)
4603+
return {std::move(first), U(std::move(init))};
4604+
U accum = invoke(f, std::move(init), *first);
4605+
for (++first; first != last; ++first)
4606+
accum = invoke(f, std::move(accum), *first);
4607+
return {std::move(first), std::move(accum)};
4608+
\end{codeblock}
4609+
4610+
\pnum
4611+
\remarks
4612+
The return type is
4613+
\tcode{fold_left_with_iter_result<I, U>} for the first overload and
4614+
\tcode{fold_left_with_iter_result<borrowed_iterator_t<R>, U>}
4615+
for the second overload.
4616+
\end{itemdescr}
4617+
4618+
\indexlibraryglobal{fold_left_first_with_iter}%
4619+
\begin{itemdecl}
4620+
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
4621+
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
4622+
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
4623+
constexpr @\seebelow@ fold_left_first_with_iter(I first, S last, F f)
4624+
template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
4625+
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
4626+
constexpr @\seebelow@ fold_left_first_with_iter(R&& r, F f);
4627+
\end{itemdecl}
4628+
4629+
\begin{itemdescr}
4630+
\pnum
4631+
Let \tcode{U} be
4632+
\begin{codeblock}
4633+
decltype(ranges::fold_left(std::move(first), last, iter_value_t<I>(*first), f))
4634+
\end{codeblock}
4635+
4636+
\pnum
4637+
\effects
4638+
Equivalent to:
4639+
\begin{codeblock}
4640+
if (first == last)
4641+
return {std::move(first), optional<U>()};
4642+
optional<U> init(in_place, *first);
4643+
for (++first; first != last; ++first)
4644+
*init = invoke(f, std::move(*init), *first);
4645+
return {std::move(first), std::move(init)};
4646+
\end{codeblock}
4647+
4648+
\pnum
4649+
\remarks
4650+
The return type is
4651+
\tcode{fold_left_first_with_iter_result<I, optional<U>>}
4652+
for the first overload and
4653+
\tcode{fold_left_first_with_iter_result<borrowed_iterator_t<R>, optional<U>>}
4654+
for the second overload.
4655+
\end{itemdescr}
4656+
43874657
\rSec1[alg.modifying.operations]{Mutating sequence operations}
43884658

43894659
\rSec2[alg.copy]{Copy}

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,7 @@
673673
// also in \libheader{algorithm}, \libheader{functional}, \libheader{iterator}, \libheader{memory}, \libheader{ranges}
674674
#define @\defnlibxname{cpp_lib_ranges_chunk}@ 202202L // also in \libheader{ranges}
675675
#define @\defnlibxname{cpp_lib_ranges_chunk_by}@ 202202L // also in \libheader{ranges}
676+
#define @\defnlibxname{cpp_lib_ranges_fold}@ 202207L // also in \libheader{algorithm}
676677
#define @\defnlibxname{cpp_lib_ranges_iota}@ 202202L // also in \libheader{numeric}
677678
#define @\defnlibxname{cpp_lib_ranges_join_with}@ 202202L // also in \libheader{ranges}
678679
#define @\defnlibxname{cpp_lib_ranges_slide}@ 202202L // also in \libheader{ranges}

0 commit comments

Comments
 (0)