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

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Jan 3 00:32:24 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxxabi

Author: Will Hawkins (hawkinsw)

<details>
<summary>Changes</summary>

Implement `ranges::stride_view` in libc++. Migrating to this GitHub from Phabricator (https://reviews.llvm.org/D156924). 

Closes #<!-- -->105198

---

Patch is 211.42 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/65200.diff


42 Files Affected:

- (modified) libcxx/docs/FeatureTestMacroTable.rst (+2) 
- (modified) libcxx/docs/ReleaseNotes/20.rst (+1) 
- (modified) libcxx/include/CMakeLists.txt (+1) 
- (modified) libcxx/include/__cxx03/module.modulemap (+1) 
- (added) libcxx/include/__ranges/stride_view.h (+414) 
- (modified) libcxx/include/module.modulemap.in (+4) 
- (modified) libcxx/include/ranges (+12) 
- (modified) libcxx/include/version (+2) 
- (added) libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp (+27) 
- (added) libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/dereference.pass.cpp (+34) 
- (added) libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp (+45) 
- (added) libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/iterator.nodiscard.verify.cpp (+114) 
- (added) libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp (+26) 
- (added) libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/nodiscard.verify.cpp (+73) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp (+30) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+30) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp (+149) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp (+105) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp (+64) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/borrowing.compile.pass.cpp (+19) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp (+43) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.pass.cpp (+96) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp (+49) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp (+111) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp (+132) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.copy.pass.cpp (+374) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp (+39) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/decrement.pass.cpp (+93) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp (+97) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/greater_than.pass.cpp (+426) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp (+205) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_move.pass.cpp (+97) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_swap.pass.cpp (+88) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/less_than.pass.cpp (+426) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp (+426) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus.pass.cpp (+103) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus_equal.pass.cpp (+109) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp (+54) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp (+39) 
- (added) libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h (+296) 
- (modified) libcxx/utils/generate_feature_test_macro_components.py (+5) 
- (modified) libcxxabi/CMakeLists.txt (+2-1) 


``````````diff
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 32911d0f64449..46a7231cef5d4 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -388,6 +388,8 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_starts_ends_with``                      ``202106L``
     ---------------------------------------------------------- -----------------
+    ``__cpp_lib_ranges_stride``                                ``202207L``
+    ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_to_container``                          ``202202L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_zip``                                   *unimplemented*
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index 572d4321dc46f..ab6e25cf0854e 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -47,6 +47,7 @@ Implemented Papers
 - ``std::jthread`` and ``<stop_token>`` are not guarded behind ``-fexperimental-library`` anymore
 - P2674R1: A trait for implicit lifetime types (`Github <https://github.com/llvm/llvm-project/issues/105259>`__)
 - P0429R9: A Standard ``flat_map`` (`Github <https://github.com/llvm/llvm-project/issues/105190>`__)
+- P1899: ``stride_view`` (`Github <https://github.com/llvm/llvm-project/issues/105198>` __)
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index eb423ae923b4f..a913765c8c907 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -740,6 +740,7 @@ set(files
   __ranges/single_view.h
   __ranges/size.h
   __ranges/split_view.h
+  __ranges/stride_view.h
   __ranges/subrange.h
   __ranges/take_view.h
   __ranges/take_while_view.h
diff --git a/libcxx/include/__cxx03/module.modulemap b/libcxx/include/__cxx03/module.modulemap
index 34a2d0f25fc45..45e90c9b23830 100644
--- a/libcxx/include/__cxx03/module.modulemap
+++ b/libcxx/include/__cxx03/module.modulemap
@@ -1753,6 +1753,7 @@ module cxx03_std_private_ranges_size                       [system] {
   export std_private_type_traits_make_unsigned
 }
 module cxx03_std_private_ranges_split_view                 [system] { header "__ranges/split_view.h" }
+module cxx03_std_private_ranges_stride_view                [system] { header "__ranges/stride_view.h" }
 module cxx03_std_private_ranges_subrange                   [system] {
   header "__ranges/subrange.h"
   export std_private_ranges_subrange_fwd
diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
new file mode 100644
index 0000000000000..5ca398382948b
--- /dev/null
+++ b/libcxx/include/__ranges/stride_view.h
@@ -0,0 +1,414 @@
+// -*- 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 <__assert>
+#include <__compare/three_way_comparable.h>
+#include <__concepts/constructible.h>
+#include <__concepts/convertible_to.h>
+#include <__concepts/derived_from.h>
+#include <__concepts/equality_comparable.h>
+#include <__concepts/relation.h>
+#include <__config>
+#include <__functional/bind_back.h>
+#include <__functional/operations.h>
+#include <__functional/ranges_operations.h>
+#include <__iterator/advance.h>
+#include <__iterator/concepts.h>
+#include <__iterator/default_sentinel.h>
+#include <__iterator/distance.h>
+#include <__iterator/indirectly_comparable.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/enable_borrowed_range.h>
+#include <__ranges/range_adaptor.h>
+#include <__ranges/view_interface.h>
+#include <__type_traits/make_unsigned.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 _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_ARGUMENT_WITHIN_DOMAIN(__stride > 0, "The value of stride must be greater than 0");
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
+    requires copy_constructible<_View>
+  {
+    return __base_;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_difference_t<_View> stride() const noexcept { return __stride_; }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+    requires(!__simple_view<_View>)
+  {
+    return __iterator</*_Const=*/false>(this, ranges::begin(__base_), 0);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+    requires range<const _View>
+  {
+    return __iterator</*_Const=*/true>(this, ranges::begin(__base_), 0);
+  }
+
+  [[nodiscard]] _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</*_Const=*/false>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<_View> && !bidirectional_range<_View>) {
+      return __iterator</*_Const=*/false>(this, ranges::end(__base_), 0);
+    } else {
+      return default_sentinel;
+    }
+  }
+
+  [[nodiscard]] _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</*_Const=*/true>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<_View> && !bidirectional_range<_View>) {
+      return __iterator</*_Const=*/true>(this, ranges::end(__base_), 0);
+    } else {
+      return default_sentinel;
+    }
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+    requires sized_range<_View>
+  {
+    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
+  }
+
+  [[nodiscard]] _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 _LIBCPP_NODEBUG = typename iterator_traits<iterator_t<_View>>::iterator_category;
+  using iterator_category =
+      _If<derived_from<_Cat, random_access_iterator_tag>,
+          /* then */ random_access_iterator_tag,
+          /* else */ _Cat >;
+};
+
+template <input_range _View>
+  requires view<_View>
+template <bool _Const>
+class stride_view<_View>::__iterator : public __stride_iterator_category<_View> {
+  using _Parent _LIBCPP_NODEBUG = __maybe_const<_Const, stride_view<_View>>;
+  using _Base _LIBCPP_NODEBUG   = __maybe_const<_Const, _View>;
+
+  _LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_Base> __current_     = iterator_t<_Base>();
+  _LIBCPP_NO_UNIQUE_ADDRESS ranges::sentinel_t<_Base> __end_ = ranges::sentinel_t<_Base>();
+  range_difference_t<_Base> __stride_                        = 0;
+  range_difference_t<_Base> __missing_                       = 0;
+
+  friend stride_view;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(
+      _Parent* __parent, ranges::iterator_t<_Base> __current, range_difference_t<_Base> __missing)
+      : __current_(std::move(__current)),
+        __end_(ranges::end(__parent->__base_)),
+        __stride_(__parent->__stride_),
+        __missing_(__missing) {}
+
+  static consteval auto __get_stride_view_iterator_concept() {
+    if constexpr (random_access_range<_Base>) {
+      return random_access_iterator_tag{};
+    } else if constexpr (bidirectional_range<_Base>) {
+      return bidirectional_iterator_tag{};
+    } else if constexpr (forward_range<_Base>) {
+      return forward_iterator_tag{};
+    } else {
+      return input_iterator_tag{};
+    }
+  }
+
+public:
+  using difference_type  = range_difference_t<_Base>;
+  using value_type       = range_value_t<_Base>;
+  using iterator_concept = decltype(__get_stride_view_iterator_concept());
+  // using iterator_category = inherited;
+
+  _LIBCPP_HIDE_FROM_ABI __iterator()
+    requires default_initializable<iterator_t<_Base>>
+  = default;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
+    requires _Const && convertible_to<ranges::iterator_t<_View>, iterator_t<_Base>> &&
+                 convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
+      : __current_(std::move(__i.__current_)),
+        __end_(std::move(__i.__end_)),
+        __stride_(__i.__stride_),
+        __missing_(__i.__missing_) {}
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> const& base() const& noexcept { return __current_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot dereference an iterator at the end.");
+    return *__current_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot increment an iterator already at the end.");
+    __missing_ = ranges::advance(__current_, __stride_, __end_);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot increment an iterator already at the end.");
+    ++*this;
+  }
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
+    requires forward_range<_Base>
+  {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot increment an iterator already at the end.");
+    auto __tmp = *this;
+    ++*this;
+    return __tmp;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
+    requires bidirectional_range<_Base>
+  {
+    ranges::advance(__current_, __missing_ - __stride_);
+    __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+=(difference_type __n)
+    requires random_access_range<_Base>
+  {
+    if (__n > 0) {
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(ranges::distance(__current_, __end_) > __stride_ * (__n - 1),
+                                          "Advancing the iterator beyond the end is not allowed.");
+      ranges::advance(__current_, __stride_ * (__n - 1));
+      __missing_ = ranges::advance(__current_, __stride_, __end_);
+
+    } else if (__n < 0) {
+      ranges::advance(__current_, __stride_ * __n + __missing_);
+      __missing_ = 0;
+    }
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
+    requires random_access_range<_Base>
+  {
+    return *this += -__n;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const
+    requires random_access_range<_Base>
+  {
+    return *(*this + __n);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, default_sentinel_t) {
+    return __x.__current_ == __x.__end_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, __iterator const& __y)
+    requires equality_comparable<iterator_t<_Base>>
+  {
+    return __x.__current_ == __y.__current_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base>
+  {
+    return __x.__current_ < __y.__current_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base>
+  {
+    return __y < __x;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base>
+  {
+    return !(__y < __x);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base>
+  {
+    return !(__x < __y);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
+  {
+    return __x.__current_ <=> __y.__current_;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator const& __i, difference_type __s)
+    requires random_access_range<_Base>
+  {
+    auto __r = __i;
+    __r += __s;
+    return __r;
+  }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __s, __iterator const& __i)
+    requires random_access_range<_Base>
+  {
+    auto __r = __i;
+    __r += __s;
+    return __r;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator const& __i, difference_type __s)
+    requires random_access_range<_Base>
+  {
+    auto __r = __i;
+    __r -= __s;
+    return __r;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(__iterator const& __x, __iterator const& __y)
+    requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
+  {
+    if constexpr (forward_range<_Base>) {
+      auto __n = __x.__current_ - __y.__current_;
+      return (__n + __x.__missing_ - __y.__missing_) / __x.__stride_;
+    }
+    auto __n = __x.__current_ - __y.__current_;
+    if (__n < 0) {
+      return -ranges::__div_ceil(-__n, __x.__stride_);
+    }
+    return ranges::__div_ceil(__n, __x.__stride_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(default_sentinel_t, __iterator const& __x)
+    requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
+  {
+    return ranges::__div_ceil(__x.__end_ - __x.__current_, __x.__stride_);
+  }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(__iterator const& __x, default_sentinel_t __y)
+    requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
+  {
+    return -(__y - __x);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_rvalue_reference_t<_Base>
+  iter_move(__iterator const& __it) noexcept(noexcept(ranges::iter_move(__it.__current_))) {
+    return ranges::iter_move(__it.__current_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr void
+  iter_swap(__iterator const& __x,
+            __iterator const& __y) noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_)))
+    requires indirectly_swappable<iterator_t<_Base>>
+  {
+    return ranges::iter_swap(__x.__current_, __y.__current_);
+  }
+}; // class stride_view::__iterator
+
+template <class _Tp>
+inline constexpr bool enable_borrowed_range<stride_view<_Tp>> = enable_borrowed_range<_Tp>;
+
+namespace views {
+namespace __stride_view {
+struct __fn {
+  // clang-format off
+  template <viewable_range _Range>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
+  constexpr auto operator()(_Range&& __range, range_difference_t<_Range> __n) const
+    noexcept(noexcept(stride_view{std::forward<_Range>(__range), __n}))
+    -> decltype(      stride_view{std::forward<_Range>(__range), __n})
+    { return          stride_view(std::forward<_Range>(__range), __n); }
+  // clang-format on
+
+  template <class _Np>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Np&& __n) const {
+    return __pipeable(std::__bind_back(*this, std::forward<_Np>(__n)));
+  }
+};
+} // namespace __stride_view
+
+inline namespace __cpo {
+inline constexpr auto stride = __stride_view::__fn{};
+} // namespace __cpo
+} // namespace views
+
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_STRIDE_VIEW_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 4434a5446e35b..3ea811b3e5438 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1926,6 +1926,10 @@ module std [system] {
     module subrange_fwd {
       header "__fwd/subrange.h"
     }
+    module stride_view {
+      header "__ranges/stride_view.h"
+      export std.functional.bind_back
+    }
     module take_view {
       header "__ranges/take_view.h"
       export std.functional.bind_back
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 9f725b12ac6c2..e48bcc87c5952 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -396,6 +396,17 @@ namespace std::ranges {
   class chunk_by_view;                                                      // C++23
 
   namespace views { inline constexpr unspecified chunk_by = unspecified; }  // C++23
+
+  // [range.stride.view], stride view
+  template<input_range V>
+    requires view<V>
+  class stride_view;                                                       // C++23
+
+  template<class V>
+    constexpr bool enable_borrowed_range<stride_view<V>> =
+      enable_borrowed_range<V>;                                            // C++23
+
+  namespace views { inline constexpr unspecified stride = unspecified; }   // C++23
 }
 
 namespace std {
@@ -485,6 +496,7 @@ namespace std {
 #    include <__ranges/from_range.h>
 #    include <__ranges/join_with_view.h>
 #    include <__ranges/repeat_view.h>
+#    include <__ranges/stride_view.h>
 #    include <__ranges/to.h>
 #    include <__ranges/zip_transform_view.h>
 #    include <__ranges/zip_view.h>
diff --git a/libcxx/include/version b/libcxx/include/version
index ab781466f5ed5..2fb1ad8b4c2c1 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -216,6 +216,7 @@ __cpp_lib_ranges_join_with                              202202L <ranges>
 __cpp_lib_ranges_repeat                                 202207L <ranges>
 __cpp_lib_ranges_slide                                  202202L <ranges>
 __cpp_lib_ranges_starts_ends_with                       202106L <algorithm>
+__cpp_lib_ranges_stride                                 202207L <ranges>
 __cpp_lib_ranges_to_container                           202202L <ranges>
 __cpp_lib_ranges_zip                                    202110L <ranges> <tuple> <utility>
 __cpp_lib_ratio                                         202306L <ratio>
@@ -532,6 +533,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_ranges_repeat                        202207L
 // # define __cpp_lib_ranges_slide                         202202L
 # define __cpp_lib_ranges_starts_ends_with              202...
[truncated]

``````````

</details>


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


More information about the libcxx-commits mailing list