[libcxx-commits] [libcxx] [libc++] Implement `ranges::fold_left_first` and `ranges::fold_left_first_with_iter` (PR #180214)

Connector Switch via libcxx-commits libcxx-commits at lists.llvm.org
Fri Feb 6 07:51:53 PST 2026


================
@@ -126,6 +130,63 @@ struct __fold_left {
 };
 
 inline constexpr auto fold_left = __fold_left();
+
+struct __fold_left_first_with_iter {
+  template <input_iterator _Iter,
+            sentinel_for<_Iter> _Sent,
+            __indirectly_binary_left_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, _Sent __last, _Func __func) {
+    using _Up = decltype(fold_left(std::move(__first), __last, iter_value_t<_Iter>(*__first), __func));
+
+    if (__first == __last)
+      return fold_left_first_with_iter_result<_Iter, optional<_Up>>{std::move(__first), optional<_Up>()};
+
+    _Up __result(*__first);
+    ++__first;
+    __identity __proj;
+    auto __end = std::__for_each(
+        std::move(__first),
+        std::move(__last),
+        [&](auto&& __element) {
+          __result = std::invoke(__func, std::move(__result), std::forward<decltype(__element)>(__element));
+        },
+        __proj);
+
+    return fold_left_first_with_iter_result<_Iter, optional<_Up>>{std::move(__end), optional<_Up>(std::move(__result))};
+  }
+
+  template <input_range _Range, __indirectly_binary_left_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) {
+    auto __result = operator()(ranges::begin(__range), ranges::end(__range), std::ref(__func));
+
+    using _Up = decltype(fold_left(
+        ranges::begin(__range), ranges::end(__range), range_value_t<_Range>(*ranges::begin(__range)), __func));
+    return fold_left_first_with_iter_result<borrowed_iterator_t<_Range>, optional<_Up>>{
+        std::move(__result.in), std::move(__result.value)};
+  }
----------------
c8ef wrote:

This logic is necessary as per standards, otherwise the rvalue range test will fail.

https://github.com/llvm/llvm-project/pull/180214


More information about the libcxx-commits mailing list