[clang] [clang-tools-extra] [llvm] [libcxx] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)

Konstantin Varlamov via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 20 11:14:59 PST 2023


================
@@ -0,0 +1,118 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_FOLD_H
+#define _LIBCPP___ALGORITHM_FOLD_H
+
+#include <__concepts/assignable.h>
+#include <__concepts/convertible_to.h>
+#include <__concepts/invocable.h>
+#include <__concepts/movable.h>
+#include <__config>
+#include <__functional/invoke.h>
+#include <__functional/reference_wrapper.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/dangling.h>
+#include <__type_traits/decay.h>
+#include <__type_traits/invoke.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+template <class _Ip, class _Tp>
+struct in_value_result {
+  _Ip in;
+  _Tp result;
+};
+
+template <class _Ip, class _Tp>
+using fold_left_with_iter_result = in_value_result<_Ip, _Tp>;
+
+template <class _Fp, class _Tp, class _Ip, class _Rp, class _Up = decay_t<_Rp>>
+concept __indirectly_binary_left_foldable_impl =
+    convertible_to<_Rp, _Up> &&                    //
+    movable<_Tp> &&                                //
+    movable<_Up> &&                                //
+    convertible_to<_Tp, _Up> &&                    //
+    invocable<_Fp&, _Up, iter_reference_t<_Ip>> && //
+    assignable_from<_Up&, invoke_result_t<_Fp&, _Up, iter_reference_t<_Ip>>>;
+
+template <class _Fp, class _Tp, class _Ip>
+concept __indirectly_binary_left_foldable =
+    copy_constructible<_Fp> &&                     //
+    invocable<_Fp&, _Tp, iter_reference_t<_Ip>> && //
+    __indirectly_binary_left_foldable_impl<_Fp, _Tp, _Ip, invoke_result_t<_Fp&, _Tp, iter_reference_t<_Ip>>>;
+
+struct __fold_left_with_iter {
+  template <input_iterator _Ip, sentinel_for<_Ip> _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp>
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto
+  operator()(_Ip __first, _Sp __last, _Tp __init, _Fp __f) {
+    using _Up = decay_t<invoke_result_t<_Fp&, _Tp, iter_reference_t<_Ip>>>;
+
+    if (__first == __last) {
+      return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), _Up(std::move(__init))};
+    }
+
+    _Up __result = std::invoke(__f, std::move(__init), *__first);
+    for (++__first; __first != __last; ++__first) {
+      __result = std::invoke(__f, std::move(__result), *__first);
+    }
+
+    return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), std::move(__result)};
+  }
+
+  template <input_range _Rp, class _Tp, __indirectly_binary_left_foldable<_Tp, iterator_t<_Rp>> _Fp>
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Rp&& __r, _Tp __init, _Fp __f) {
+    auto __result = operator()(ranges::begin(__r), ranges::end(__r), std::move(__init), std::ref(__f));
+
+    using _Up = decay_t<invoke_result_t<_Fp&, _Tp, range_reference_t<_Rp>>>;
+    return fold_left_with_iter_result<borrowed_iterator_t<_Rp>, _Up>{
+        std::move(__result.in), std::move(__result.result)};
+  }
+};
+
+inline namespace __cpo {
+inline constexpr auto fold_left_with_iter = __fold_left_with_iter();
+} // namespace __cpo
+
+struct __fold_left {
+  template <input_iterator _Ip, sentinel_for<_Ip> _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp>
----------------
var-const wrote:

@EricWF This discussion has [already happened](https://discord.com/channels/636084430946959380/956590603808931870), and I can confirm that the outcome of it was to use `_Iter` and `_Sent`. Maintaining consistency is one of the purposes of doing a code review, and I don't think the fact that our code base is not perfect in this regard allows dismissing that. If you would like to reopen that discussion, you are also quite welcome to come up with a new proposal.

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


More information about the cfe-commits mailing list