[libcxx-commits] [libcxx] [libc++][ranges] Implement `ranges::stride_view`. (PR #65200)

Will Hawkins via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jan 2 18:24:48 PST 2024


================
@@ -0,0 +1,396 @@
+// -*- 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_STRIDE_VIEW_H
+#define _LIBCPP___RANGES_STRIDE_VIEW_H
+
+#include "__concepts/relation.h"
+#include "__functional/ranges_operations.h"
+#include "__iterator/indirectly_comparable.h"
+#include <__config>
+
+#include <__compare/three_way_comparable.h>
+#include <__concepts/convertible_to.h>
+#include <__concepts/derived_from.h>
+#include <__concepts/equality_comparable.h>
+#include <__functional/bind_back.h>
+#include <__functional/operations.h>
+#include <__iterator/advance.h>
+#include <__iterator/concepts.h>
+#include <__iterator/default_sentinel.h>
+#include <__iterator/distance.h>
+#include <__iterator/iter_move.h>
+#include <__iterator/iter_swap.h>
+#include <__iterator/iterator_traits.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/range_adaptor.h>
+#include <__ranges/view_interface.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 _Value>
+_LIBCPP_HIDE_FROM_ABI constexpr _Value __div_ceil(_Value __left, _Value __right) {
+  _Value __r = __left / __right;
+  if (__left % __right) {
+    __r++;
+  }
+  return __r;
+}
+
+template <input_range _View>
+  requires view<_View>
+class stride_view : public view_interface<stride_view<_View>> {
+  _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
+  range_difference_t<_View> __stride_     = 0;
+
+  template <bool _Const>
+  class __iterator;
+
+public:
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit stride_view(_View __base, range_difference_t<_View> __stride)
+      : __base_(std::move(__base)), __stride_(__stride) {
+    _LIBCPP_ASSERT_UNCATEGORIZED(__stride > 0, "The value of stride must be greater than 0");
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
+    requires copy_constructible<_View>
+  {
+    return __base_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr range_difference_t<_View> stride() const noexcept { return __stride_; }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+    requires(!__simple_view<_View>)
+  {
+    return __iterator<false>(this, ranges::begin(__base_), 0);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+    requires range<const _View>
+  {
+    return __iterator<true>(this, ranges::begin(__base_), 0);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+    requires(!__simple_view<_View>)
+  {
+    if constexpr (common_range<_View> && sized_range<_View> && forward_range<_View>) {
+      auto __missing = (__stride_ - ranges::distance(__base_) % __stride_) % __stride_;
+      return __iterator<false>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<_View> && !bidirectional_range<_View>) {
+      return __iterator<false>(this, ranges::end(__base_), 0);
+    } else {
+      return default_sentinel;
+    }
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+    requires(range<const _View>)
+  {
+    if constexpr (common_range<const _View> && sized_range<const _View> && forward_range<const _View>) {
+      auto __missing = (__stride_ - ranges::distance(__base_) % __stride_) % __stride_;
+      return __iterator<true>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<_View> && !bidirectional_range<_View>) {
+      return __iterator<true>(this, ranges::end(__base_), 0);
+    } else {
+      return default_sentinel;
+    }
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+    requires sized_range<_View>
+  {
+    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+    requires sized_range<const _View>
+  {
+    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
+  }
+}; // class stride_view
+
+template <class _Range>
+stride_view(_Range&&, range_difference_t<_Range>) -> stride_view<views::all_t<_Range>>;
+
+template <class _View>
+struct __stride_iterator_category {};
+
+template <forward_range _View>
+struct __stride_iterator_category<_View> {
+  using _Cat = typename iterator_traits<iterator_t<_View>>::iterator_category;
+  using iterator_category =
+      _If<derived_from<_Cat, random_access_iterator_tag>,
+          random_access_iterator_tag,
+          /* else */ _Cat >;
+};
----------------
hawkinsw wrote:

I am more than happy to incorporate it directly into the iterator. However, it does appear that this is the pattern used in the other range adaptors. Do we want this adaptor to have a slightly different implementation pattern? 

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


More information about the libcxx-commits mailing list