[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