[libcxx-commits] [libcxx] [libc++] fold_right_last (PR #195533)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun May 3 08:14:25 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Skyfrei (Skyfrei)
<details>
<summary>Changes</summary>
Implementation of fold_right_last which takes default values the last iterator.
I wasn't fully sure if I had to return an optional or not as std document says it should return an optional but the other pr creating a fold_right does not return an optional. I tried sticking to most of the implementations of #<!-- -->174060
Finishes: #<!-- -->174061
---
Full diff: https://github.com/llvm/llvm-project/pull/195533.diff
2 Files Affected:
- (modified) libcxx/include/__algorithm/ranges_fold.h (+58)
- (added) libcxx/test/std/algorithms/alg.nonmodifying/alg.fold/ranges.fold_right_last.pass.cpp (+51)
``````````diff
diff --git a/libcxx/include/__algorithm/ranges_fold.h b/libcxx/include/__algorithm/ranges_fold.h
index 50776a2f1b808..b6e22d944c788 100644
--- a/libcxx/include/__algorithm/ranges_fold.h
+++ b/libcxx/include/__algorithm/ranges_fold.h
@@ -31,6 +31,7 @@
#include <__utility/forward.h>
#include <__utility/move.h>
#include <optional>
+#include <__iterator/reverse_iterator.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -187,6 +188,63 @@ struct __fold_left_first {
};
inline constexpr auto fold_left_first = __fold_left_first();
+
+template <class _Fp, class _Tp, class _Ip, class _Rp, class _Up = decay_t<_Rp>>
+concept __indirectly_binary_right_foldable_impl =
+ convertible_to<_Rp, _Up> &&
+ movable<_Tp> &&
+ movable<_Up> &&
+ convertible_to<_Tp, _Up> &&
+ invocable<_Fp&, iter_reference_t<_Ip>, _Up> &&
+ assignable_from<_Up&, invoke_result_t<_Fp&, iter_reference_t<_Ip>, _Up>>;
+
+template <class _Fp, class _Tp, class _Ip>
+concept __indirectly_binary_right_foldable =
+ copy_constructible<_Fp> &&
+ invocable<_Fp&, iter_reference_t<_Ip>, _Tp> &&
+ __indirectly_binary_right_foldable_impl<_Fp, _Tp, _Ip, invoke_result_t<_Fp&, iter_reference_t<_Ip>, _Tp>>;
+
+struct __fold_right_last{
+
+ template <bidirectional_iterator _Iter,
+ sentinel_for<_Iter> _Sp,
+ __indirectly_binary_right_foldable<iter_value_t<_Iter>, _Iter> _Func>
+ requires constructible_from<iter_value_t<_Iter>, iter_reference_t<_Iter>>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto
+ operator()(_Iter __first, _Sp __last, _Func __func){
+ using _Value = iter_value_t<_Iter>;
+ using _Up = decay_t<invoke_result_t<_Func&, _Value, _Value>>;
+
+ if (__first == __last)
+ return std::optional<_Up>(nullopt);
+
+ _Iter __tail = ranges::next(__first, __last);
+ --__tail;
+
+ _Up __result(*__tail);
+
+ __identity __proj;
+ std::__for_each(
+ std::make_reverse_iterator(__tail),
+ std::make_reverse_iterator(__first),
+ [&](auto&& __element) {
+ __result = std::invoke(__func, std::forward<decltype(__element)>(__element), std::move(__result));
+ },
+ __proj);
+
+ return std::optional<_Up>(in_place, std::move(__result));
+ }
+
+ template <bidirectional_range _Range,
+ __indirectly_binary_right_foldable<range_value_t<_Range>, iterator_t<_Range>> _Func>
+ requires constructible_from<range_value_t<_Range>, range_reference_t<_Range>>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto
+ operator()(_Range&& __range, _Func __func) {
+ return operator()(ranges::begin(__range), ranges::end(__range), std::ref(__func));
+ }
+
+};
+inline constexpr auto fold_right_last = __fold_right_last();
} // namespace ranges
#endif // _LIBCPP_STD_VER >= 23
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.fold/ranges.fold_right_last.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.fold/ranges.fold_right_last.pass.cpp
new file mode 100644
index 0000000000000..7c5be11098614
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.fold/ranges.fold_right_last.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===
+
+#include <algorithm>
+#include <cassert>
+#include <concepts>
+#include <deque>
+#include <forward_list>
+#include <functional>
+#include <iterator>
+#include <list>
+#include <optional>
+#include <ranges>
+#include <set>
+#include <string_view>
+#include <string>
+#include <vector>
+
+#include "test_macros.h"
+#include "test_range.h"
+#include "invocable_with_telemetry.h"
+#include "maths.h"
+
+constexpr bool test() {
+ auto op = [](int a, int b) { return a + b; };
+ {
+ std::vector<int> v = {1, 2, 3};
+ auto res = std::ranges::fold_right_last(v, op);
+ assert(res.has_value());
+ assert(res.value() == 6);
+ }
+
+ {
+ std::vector<int> empty = {};
+ auto res = std::ranges::fold_right_last(empty, op);
+ assert(!res.has_value());
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/195533
More information about the libcxx-commits
mailing list