Skip to content

P2322R6 ranges::fold #5645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 270 additions & 0 deletions source/algorithms.tex
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,9 @@
template<class I>
struct in_found_result;

template<class I, class T>
struct in_value_result;

template<class O, class T>
struct out_value_result;
}
Expand Down Expand Up @@ -1215,6 +1218,91 @@
@\libconcept{indirectly_comparable}@<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
constexpr bool ends_with(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});

// \ref{alg.fold}, fold
template<class F>
class @\exposid{flipped}@ { // \expos
F @\exposid{f}@; // \expos

public:
template<class T, class U> requires @\libconcept{invocable}@<F&, U, T>
invoke_result_t<F&, U, T> operator()(T&&, U&&);
};

template<class F, class T, class I, class U>
concept @\defexposconcept{indirectly-binary-left-foldable-impl}@ = // \expos
@\libconcept{movable}@<T> && @\libconcept{movable}@<U> &&
@\libconcept{convertible_to}@<T, U> && @\libconcept{invocable}@<F&, U, iter_reference_t<I>> &&
@\libconcept{assignable_from}@<U&, invoke_result_t<F&, U, iter_reference_t<I>>>;

template<class F, class T, class I>
concept @\defexposconcept{indirectly-binary-left-foldable}@ = // \expos
@\libconcept{copy_constructible}@<F> && @\libconcept{indirectly_readable}@<I> &&
@\libconcept{invocable}@<F&, T, iter_reference_t<I>> &&
@\libconcept{convertible_to}@<invoke_result_t<F&, T, iter_reference_t<I>>,
decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>> &&
@\exposconcept{indirectly-binary-left-foldable-impl}@<F, T, I,
decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>>;

template<class F, class T, class I>
concept @\defexposconcept{indirectly-binary-right-foldable}@ = // \expos
@\exposconcept{indirectly-binary-left-foldable}@<@\exposid{flipped}@<F>, T, I>;

template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
@\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
constexpr auto fold_left(I first, S last, T init, F f);

template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
constexpr auto fold_left(R&& r, T init, F f);

template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
constexpr auto fold_left_first(I first, S last, F f);

template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
constexpr auto fold_left_first(R&& r, F f);

template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
@\exposconcept{indirectly-binary-right-foldable}@<T, I> F>
constexpr auto fold_right(I first, S last, T init, F f);

template<@\libconcept{bidirectional_range}@ R, class T,
@\exposconcept{indirectly-binary-right-foldable}@<T, iterator_t<R>> F>
constexpr auto fold_right(R&& r, T init, F f);

template <@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
@\exposconcept{indirectly-binary-right-foldable}@<iter_value_t<I>, I> F>
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
constexpr auto fold_right_last(I first, S last, F f);

template<@\libconcept{bidirectional_range}@ R,
@\exposconcept{indirectly-binary-right-foldable}@<range_value_t<R>, iterator_t<R>> F>
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
constexpr auto fold_right_last(R&& r, F f);

template<class I, class T>
using fold_left_with_iter_result = in_value_result<I, T>;
template<class I, class T>
using fold_left_first_with_iter_result = in_value_result<I, T>;

template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
@\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
constexpr @\seebelow@ fold_left_with_iter(I first, S last, T init, F f);

template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
constexpr @\seebelow@ fold_left_with_iter(R&& r, T init, F f);

template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
constexpr @\seebelow@ fold_left_first_with_iter(I first, S last, F f);

template<@\libconcept{input_range}@ R,
@\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
constexpr @\seebelow@ fold_left_first_with_iter(R&& r, F f);
}

// \ref{alg.modifying.operations}, mutating sequence operations
Expand Down Expand Up @@ -3104,6 +3192,24 @@
}
};

template<class I, class T>
struct in_value_result {
[[no_unique_address]] I in;
[[no_unique_address]] T value;

template<class I2, class T2>
requires @\libconcept{convertible_to}@<const I&, I2> && @\libconcept{convertible_to}@<const T&, T2>
constexpr operator in_value_result<I2, T2>() const & {
return {in, value};
}

template<class I2, class T2>
requires @\libconcept{convertible_to}@<I, I2> && @\libconcept{convertible_to}@<T, T2>
constexpr operator in_value_result<I2, T2>() && {
return {std::move(in), std::move(value)};
}
};

template<class O, class T>
struct out_value_result {
[[no_unique_address]] O out;
Expand Down Expand Up @@ -4518,6 +4624,170 @@
\end{codeblock}
\end{itemdescr}

\rSec2[alg.fold]{Fold}

\indexlibraryglobal{fold_left}%
\begin{itemdecl}
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
constexpr auto ranges::fold_left(I first, S last, T init, F f);
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
constexpr auto ranges::fold_left(R&& r, T init, F f);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
ranges::fold_left_with_iter(std::move(first), last, std::move(init), f).value
\end{codeblock}
\end{itemdescr}

\indexlibraryglobal{fold_left_first}%
\begin{itemdecl}
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
constexpr auto ranges::fold_left_first(I first, S last, F f);
template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
constexpr auto ranges::fold_left_first(R&& r, F f);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
ranges::fold_left_first_with_iter(std::move(first), last, f).value
\end{codeblock}
\end{itemdescr}

\indexlibraryglobal{fold_right}%
\begin{itemdecl}
template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
@\exposconcept{indirectly-binary-right-foldable}@<T, I> F>
constexpr auto ranges::fold_right(I first, S last, T init, F f);
template<@\libconcept{bidirectional_range}@ R, class T,
@\exposconcept{indirectly-binary-right-foldable}@<T, iterator_t<R>> F>
constexpr auto ranges::fold_right(R&& r, T init, F f);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
using U = decay_t<invoke_result_t<F&, iter_reference_t<I>, T>>;
if (first == last)
return U(std::move(init));
I tail = ranges::next(first, last);
U accum = invoke(f, *--tail, std::move(init));
while (first != tail)
accum = invoke(f, *--tail, std::move(accum));
return accum;
\end{codeblock}
\end{itemdescr}

\indexlibraryglobal{fold_right_last}%
\begin{itemdecl}
template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
@\exposconcept{indirectly-binary-right-foldable}@<iter_value_t<I>, I> F>
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
constexpr auto ranges::fold_right_last(I first, S last, F f);
template<@\libconcept{bidirectional_range}@ R,
@\exposconcept{indirectly-binary-right-foldable}@<range_value_t<R>, iterator_t<R>> F>
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
constexpr auto ranges::fold_right_last(R&& r, F f);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{U} be
\tcode{decltype(ranges::fold_right(first, last, iter_value_t<I>(*first), f))}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
if (first == last)
return optional<U>();
I tail = ranges::prev(ranges::next(first, std::move(last)));
return optional<U>(in_place,
ranges::fold_right(std::move(first), tail, iter_value_t<I>(*tail), std::move(f)));
\end{codeblock}
\end{itemdescr}

\indexlibraryglobal{fold_left_with_iter}%
\begin{itemdecl}
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S, class T,
@\exposconcept{indirectly-binary-left-foldable}@<T, I> F>
constexpr @\seebelow@ ranges::fold_left_with_iter(I first, S last, T init, F f);
template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@<T, iterator_t<R>> F>
constexpr @\seebelow@ ranges::fold_left_with_iter(R&& r, T init, F f);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{U} be \tcode{decay_t<invoke_result_t<F\&, T, iter_reference_t<I>>>}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
if (first == last)
return {std::move(first), U(std::move(init))};
U accum = invoke(f, std::move(init), *first);
for (++first; first != last; ++first)
accum = invoke(f, std::move(accum), *first);
return {std::move(first), std::move(accum)};
\end{codeblock}

\pnum
\remarks
The return type is
\tcode{fold_left_with_iter_result<I, U>} for the first overload and
\tcode{fold_left_with_iter_result<borrowed_iterator_t<R>, U>}
for the second overload.
\end{itemdescr}

\indexlibraryglobal{fold_left_first_with_iter}%
\begin{itemdecl}
template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@<I> S,
@\exposconcept{indirectly-binary-left-foldable}@<iter_value_t<I>, I> F>
requires @\libconcept{constructible_from}@<iter_value_t<I>, iter_reference_t<I>>
constexpr @\seebelow@ ranges::fold_left_first_with_iter(I first, S last, F f);
template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@<range_value_t<R>, iterator_t<R>> F>
requires @\libconcept{constructible_from}@<range_value_t<R>, range_reference_t<R>>
constexpr @\seebelow@ ranges::fold_left_first_with_iter(R&& r, F f);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{U} be
\begin{codeblock}
decltype(ranges::fold_left(std::move(first), last, iter_value_t<I>(*first), f))
\end{codeblock}

\pnum
\effects
Equivalent to:
\begin{codeblock}
if (first == last)
return {std::move(first), optional<U>()};
optional<U> init(in_place, *first);
for (++first; first != last; ++first)
*init = invoke(f, std::move(*init), *first);
return {std::move(first), std::move(init)};
\end{codeblock}

\pnum
\remarks
The return type is
\tcode{fold_left_first_with_iter_result<I, optional<U>>}
for the first overload and
\tcode{fold_left_first_with_iter_result<borrowed_iterator_t<R>, optional<U>>}
for the second overload.
\end{itemdescr}

\rSec1[alg.modifying.operations]{Mutating sequence operations}

\rSec2[alg.copy]{Copy}
Expand Down
1 change: 1 addition & 0 deletions source/support.tex
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@
#define @\defnlibxname{cpp_lib_ranges_chunk}@ 202202L // also in \libheader{ranges}
#define @\defnlibxname{cpp_lib_ranges_chunk_by}@ 202202L // also in \libheader{ranges}
#define @\defnlibxname{cpp_lib_ranges_contains}@ 202207L // also in \libheader{algorithm}
#define @\defnlibxname{cpp_lib_ranges_fold}@ 202207L // also in \libheader{algorithm}
#define @\defnlibxname{cpp_lib_ranges_iota}@ 202202L // also in \libheader{numeric}
#define @\defnlibxname{cpp_lib_ranges_join_with}@ 202202L // also in \libheader{ranges}
#define @\defnlibxname{cpp_lib_ranges_slide}@ 202202L // also in \libheader{ranges}
Expand Down