[libcxx-commits] [libcxx] [libc++][ranges] implement `ranges::chunk_view` for `forward_range` (PR #85741)

Xiaoyang Liu via libcxx-commits libcxx-commits at lists.llvm.org
Tue Mar 19 10:52:21 PDT 2024


https://github.com/xiaoyang-sde updated https://github.com/llvm/llvm-project/pull/85741

>From 7a38a42d7954be707562a7aa4a8915ea6b6cd980 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Mon, 18 Mar 2024 23:29:02 -0700
Subject: [PATCH 1/2] [libc++] [ranges] implement 'ranges::chunk_view' for
 'forward_range'

---
 libcxx/include/CMakeLists.txt        |   1 +
 libcxx/include/__ranges/chunk_view.h | 356 +++++++++++++++++++++++++++
 libcxx/include/ranges                |   1 +
 3 files changed, 358 insertions(+)
 create mode 100644 libcxx/include/__ranges/chunk_view.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 6ed8d21d98a15a..88a91ce67bda7a 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -625,6 +625,7 @@ set(files
   __ranges/all.h
   __ranges/as_rvalue_view.h
   __ranges/chunk_by_view.h
+  __ranges/chunk_view.h
   __ranges/common_view.h
   __ranges/concepts.h
   __ranges/container_compatible_range.h
diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
new file mode 100644
index 00000000000000..e3ffdd376207e1
--- /dev/null
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -0,0 +1,356 @@
+// -*- 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___RANGES_CHUNK_VIEW_H
+#define _LIBCPP___RANGES_CHUNK_VIEW_H
+
+#include <__concepts/constructible.h>
+#include <__config>
+#include <__functional/bind_back.h>
+#include <__iterator/advance.h>
+#include <__iterator/concepts.h>
+#include <__iterator/default_sentinel.h>
+#include <__iterator/distance.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/subrange.h>
+#include <__ranges/take_view.h>
+#include <__ranges/view_interface.h>
+#include <__type_traits/make_unsigned.h>
+#include <__type_traits/maybe_const.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+
+template <class _Integer>
+constexpr _Integer __div_ceil(_Integer __num, _Integer __denom) {
+  _Integer __r = __num / __denom;
+  if (__num % __denom) {
+    ++__r;
+  }
+  return __r;
+}
+
+template <view _View>
+  requires input_range<_View>
+class chunk_view : public view_interface<chunk_view<_View>> {};
+
+template <view _View>
+  requires forward_range<_View>
+class chunk_view<_View> : public view_interface<chunk_view<_View>> {
+private:
+  _LIBCPP_NO_UNIQUE_ADDRESS _View __base_;
+  range_difference_t<_View> __n_;
+
+  template <bool>
+  class __iterator;
+
+public:
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit chunk_view(_View __base, range_difference_t<_View> __n)
+      : __base_(std::move(__base)), __n_(__n) {
+    _LIBCPP_ASSERT_UNCATEGORIZED(__n > 0, "__n must be greater than 0");
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
+    requires copy_constructible<_View>
+  {
+    return __base_;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+    requires(!__simple_view<_View>)
+  {
+    return __iterator<false>(this, ranges::begin(__base_));
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+    requires forward_range<const _View>
+  {
+    return __iterator<true>(this, ranges::begin(__base_));
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+    requires(!__simple_view<_View>)
+  {
+    if constexpr (common_range<_View> && sized_range<_View>) {
+      auto __missing = (__n_ - ranges::distance(__base_) % __n_) % __n_;
+      return __iterator<false>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<_View> && !bidirectional_range<_View>) {
+      return __iterator<false>(this, ranges::end(__base_));
+    } else {
+      return default_sentinel;
+    }
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+    requires forward_range<_View>
+  {
+    if constexpr (common_range<const _View> && sized_range<const _View>) {
+      auto __missing = (__n_ - ranges::distance(__base_) % __n_) % __n_;
+      return __iterator<true>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<const _View> && !bidirectional_range<const _View>) {
+      return __iterator<true>(this, ranges::end(__base_));
+    } else {
+      return default_sentinel;
+    }
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+    requires sized_range<_View>
+  {
+    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+    requires sized_range<const _View>
+  {
+    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
+  }
+};
+
+template <class _View>
+chunk_view(_View&&, range_difference_t<_View>) -> chunk_view<views::all_t<_View>>;
+
+template <class _View>
+inline constexpr bool enable_borrowed_range<chunk_view<_View>> = enable_borrowed_range<_View> && forward_range<_View>;
+
+template <view _View>
+  requires forward_range<_View>
+template <bool _Const>
+class chunk_view<_View>::__iterator {
+private:
+  friend chunk_view;
+
+  using _Parent = __maybe_const<_Const, chunk_view>;
+  using _Base   = __maybe_const<_Const, _View>;
+
+  iterator_t<_Base> __current_         = iterator_t<_Base>();
+  sentinel_t<_Base> __end_             = sentinel_t<_Base>();
+  range_difference_t<_Base> __n_       = 0;
+  range_difference_t<_Base> __missing_ = 0;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(
+      _Parent* __parent, iterator_t<_Base> __current, range_difference_t<_Base> __missing = 0)
+      : __current_(std::move(__current)),
+        __end_(ranges::end(__parent->__base_), __n_(__parent->__n_)),
+        __missing_(__missing) {}
+
+public:
+  using iterator_category = input_iterator_tag;
+  using iterator_concept =
+      conditional_t<random_access_range<_Base>,
+                    random_access_iterator_tag,
+                    conditional_t<bidirectional_range<_Base>, bidirectional_iterator_tag, forward_iterator_tag>>;
+  using value_type      = decltype(views::take(subrange(__current_, __end_), __n_));
+  using difference_type = range_difference_t<_Base>;
+
+  _LIBCPP_HIDE_FROM_ABI __iterator() = default;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
+    requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>> &&
+                 convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
+      : __current_(std::move(__i.__current_)),
+        __end_(std::move(__i.__end_)),
+        __n_(__i.__n_),
+        __missing_(__i.__missing_) {}
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() const { return __current_; }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const {
+    _LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Dereferencing past-the-end chunk_view iterator");
+    return views::take(subrange(__current_, __end_), __n_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+    _LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Incrementing past-the-end chunk_view iterator");
+    __missing_ = ranges::advance(__current_, __n_, __end_);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) {
+    auto __tmp = *this;
+    ++*this;
+    return __tmp;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
+    requires bidirectional_range<_Base>
+  {
+    ranges::advance(__current_, __missing_ - __n_);
+    __missing_ = 0;
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
+    requires bidirectional_range<_Base>
+  {
+    auto __tmp = *this;
+    --*this;
+    return __tmp;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(const difference_type __offset)
+    requires random_access_range<_Base>
+  {
+    if (__offset > 0) {
+      ranges::advance(__current_, __n_ * (__offset - 1));
+      __missing_ = ranges::advance(__current_, __n_, __end_);
+    } else if (__offset < 0) {
+      ranges::advance(__current_, __n_ * __offset + __missing_);
+      __missing_ = 0;
+    }
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(const difference_type __offset)
+    requires random_access_range<_Base>
+  {
+    return *this += -__offset;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr value_type operator[](const difference_type __offset) const
+    requires random_access_range<_Base>
+  {
+    return *(*this + __offset);
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  operator==(const __iterator& __x, const __iterator& __y) {
+    return __x.__current_ == __y.__current_;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  operator==(const __iterator& __x, default_sentinel_t) {
+    return __x.__current_ == __x.__end_;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  operator==(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base>
+  {
+    return __x.__current_ < __y.__current_;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  operator>(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base>
+  {
+    return __y < __x;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  operator<=(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base>
+  {
+    return !(__y < __x);
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  operator>=(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base>
+  {
+    return !(__x < __y);
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr auto
+  operator<=>(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
+  {
+    return __x.__current_ <=> __y.__current_;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator
+  operator+(const __iterator& __x, const difference_type __y)
+    requires random_access_range<_Base>
+  {
+    return __iterator{__x} += __y;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator
+  operator+(const difference_type __x, const __iterator& __y)
+    requires random_access_range<_Base>
+  {
+    return __y + __x;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator
+  operator-(const __iterator& __x, difference_type __y)
+    requires random_access_range<_Base>
+  {
+    return __iterator{__x} -= __y;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(const __iterator& __x, const __iterator& __y)
+    requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
+  {
+    return (__x.__current_ - __y.__current_ + __x.__missing_ - __y.__missing_) / __x.n_;
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(const default_sentinel_t, const __iterator& __x)
+    requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
+  {
+    return __div_ceil(__x.__end_ - __x.__current_, __x.__n_);
+  }
+
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(const __iterator& __x, const default_sentinel_t __y)
+    requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
+  {
+    return -(__y - __x);
+  }
+};
+
+namespace views {
+namespace __chunk {
+struct __fn {
+  template <class _Range, convertible_to<range_difference_t<_Range>> _Np>
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto
+  operator()(_Range&& __range,
+             _Np&& __n) const noexcept(noexcept(chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n))))
+      -> decltype(chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n))) {
+    return chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n));
+  }
+
+  template <class _Np>
+    requires constructible_from<decay_t<_Np>, _Np>
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto
+  operator()(_Np&& __n) const noexcept(is_nothrow_constructible_v<decay_t<_Np>, _Np>) {
+    return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Np>(__n)));
+  }
+};
+} // namespace __chunk
+
+inline namespace __cpo {
+inline constexpr auto chunk = __chunk::__fn{};
+} // namespace __cpo
+} // namespace views
+
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_CHUNK_VIEW_H
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 167d2137eaf454..1a63cef09dfb6b 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -380,6 +380,7 @@ namespace std {
 #include <__ranges/all.h>
 #include <__ranges/as_rvalue_view.h>
 #include <__ranges/chunk_by_view.h>
+#include <__ranges/chunk_view.h>
 #include <__ranges/common_view.h>
 #include <__ranges/concepts.h>
 #include <__ranges/counted.h>

>From 060cafd65ff6f9bce32ae3f5a26892ecb816ed88 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Tue, 19 Mar 2024 10:52:06 -0700
Subject: [PATCH 2/2] [libc++][ranges] add missing headers to 'chunk_view.h'

---
 libcxx/include/__ranges/chunk_view.h | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index e3ffdd376207e1..817a41025bf203 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -10,15 +10,18 @@
 #define _LIBCPP___RANGES_CHUNK_VIEW_H
 
 #include <__concepts/constructible.h>
+#include <__concepts/convertible_to.h>
 #include <__config>
 #include <__functional/bind_back.h>
 #include <__iterator/advance.h>
 #include <__iterator/concepts.h>
 #include <__iterator/default_sentinel.h>
 #include <__iterator/distance.h>
+#include <__iterator/iterator_traits.h>
 #include <__ranges/access.h>
 #include <__ranges/all.h>
 #include <__ranges/concepts.h>
+#include <__ranges/enable_borrowed_range.h>
 #include <__ranges/subrange.h>
 #include <__ranges/take_view.h>
 #include <__ranges/view_interface.h>
@@ -324,17 +327,16 @@ namespace views {
 namespace __chunk {
 struct __fn {
   template <class _Range, convertible_to<range_difference_t<_Range>> _Np>
-  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto
-  operator()(_Range&& __range,
-             _Np&& __n) const noexcept(noexcept(chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n))))
-      -> decltype(chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n))) {
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const
+      noexcept(noexcept(chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n))))
+          -> decltype(chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n))) {
     return chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n));
   }
 
   template <class _Np>
     requires constructible_from<decay_t<_Np>, _Np>
-  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto
-  operator()(_Np&& __n) const noexcept(is_nothrow_constructible_v<decay_t<_Np>, _Np>) {
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Np&& __n) const
+      noexcept(is_nothrow_constructible_v<decay_t<_Np>, _Np>) {
     return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Np>(__n)));
   }
 };



More information about the libcxx-commits mailing list