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

Will Hawkins via libcxx-commits libcxx-commits at lists.llvm.org
Fri Dec 8 08:52:22 PST 2023


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

>From 2045e6f1ca1e41e8cde3e0c17376655b6e963179 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Tue, 8 Aug 2023 01:04:17 -0400
Subject: [PATCH 01/70] WIP: [libc++][ranges] Implement `ranges::stride_view`.

Differential Revision: https://reviews.llvm.org/D156924

Signed-off-by: Will Hawkins <hawkinsw at obs.cr>
---
 libcxx/docs/FeatureTestMacroTable.rst         |   2 +
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__ranges/stride_view.h         | 421 ++++++++++++++++++
 libcxx/include/module.modulemap.in            |   1 +
 libcxx/include/ranges                         |   1 +
 libcxx/include/version                        |   2 +
 libcxx/modules/std/ranges.inc                 |   9 +-
 .../ranges.version.compile.pass.cpp           |  31 ++
 .../version.version.compile.pass.cpp          |  31 ++
 .../range.stride.view/adaptor.pass.cpp        | 193 ++++++++
 .../range.stride.view/base.pass.cpp           |  70 +++
 .../range.stride.view/begin.pass.cpp          |  22 +
 .../range.stride.view/ctad.compile.pass.cpp   |  22 +
 .../enable_borrowed_range.compile.pass.cpp    |  32 ++
 .../range.stride.view/end.pass.cpp            |  22 +
 .../iterator/ctor.default.pass.cpp            |  49 ++
 .../range.stride.view/iterator/equal.pass.cpp |  89 ++++
 .../sentinel/ctor.default.pass.cpp            |  22 +
 .../range.stride.view/sentinel/equal.pass.cpp |  22 +
 .../range.stride.view/size.pass.cpp           |  46 ++
 .../range.adaptors/range.stride.view/test.h   | 183 ++++++++
 .../generate_feature_test_macro_components.py |   5 +
 22 files changed, 1275 insertions(+), 1 deletion(-)
 create mode 100644 libcxx/include/__ranges/stride_view.h
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/ctor.default.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/equal.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index d09f65b7cadc0e..01921cab8ee43b 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -364,6 +364,8 @@ Status
     --------------------------------------------------- -----------------
     ``__cpp_lib_ranges_starts_ends_with``               *unimplemented*
     --------------------------------------------------- -----------------
+    ``__cpp_lib_ranges_stride``                         ``202207L``
+    --------------------------------------------------- -----------------
     ``__cpp_lib_ranges_to_container``                   ``202202L``
     --------------------------------------------------- -----------------
     ``__cpp_lib_ranges_zip``                            *unimplemented*
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index d8faf6467b79ae..b73709fb343502 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -641,6 +641,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/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
new file mode 100644
index 00000000000000..880c8ce2950e47
--- /dev/null
+++ b/libcxx/include/__ranges/stride_view.h
@@ -0,0 +1,421 @@
+// -*- 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 <__config>
+
+#include <__compare/three_way_comparable.h>
+#include <__concepts/constructible.h>
+#include <__concepts/convertible_to.h>
+#include <__concepts/derived_from.h>
+#include <__functional/bind_back.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 <__iterator/next.h>
+#include <__iterator/reverse_iterator.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/non_propagating_cache.h>
+#include <__ranges/range_adaptor.h>
+#include <__ranges/size.h>
+#include <__ranges/subrange.h>
+#include <__ranges/view_interface.h>
+#include <__ranges/views.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/maybe_const.h>
+#include <__type_traits/remove_cvref.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 _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;
+  template <bool _Const>
+  class __sentinel;
+
+public:
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit stride_view(_View __base, range_difference_t<_View> __stride)
+      : __base_(std::move(__base)), __stride_(__stride) {}
+
+  _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 auto stride() { return __stride_; }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+    requires ranges::sized_range<_View>
+  {
+    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+    requires ranges::sized_range<const _View>
+  {
+    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+    requires(!__simple_view<_View>)
+  {
+    return __iterator<false>{*this, ranges::begin(__base_)};
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+    requires ranges::range<const _View>
+  {
+    return __iterator<true>{*this, ranges::begin(__base_)};
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+    requires(!__simple_view<_View> && 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};
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+    requires(!__simple_view<_View> && common_range<_View> && !bidirectional_range<_View>)
+  {
+    return __iterator<false>{*this, ranges::end(__base_)};
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+    requires(!__simple_view<_View>)
+  {
+    return std::default_sentinel;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+    requires(range<const _View> && 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};
+  }
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+    requires(range<const _View> && common_range<_View> && !bidirectional_range<_View>)
+  {
+    return __iterator<true>{*this, ranges::end(__base_)};
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+    requires(range<const _View>)
+  {
+    return std::default_sentinel;
+  }
+}; // class stride_view
+
+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 >;
+};
+
+template <input_range _View>
+  requires view<_View>
+template <bool _Const>
+class stride_view<_View>::__iterator : public __stride_iterator_category<_View> {
+  using _Parent = __maybe_const<_Const, stride_view<_View>>;
+  using _Base   = __maybe_const<_Const, _View>;
+
+public:
+  using difference_type = range_difference_t<_Base>;
+  using value_type      = range_value_t<_Base>;
+  using iterator_concept =
+      _If<random_access_range<_Base>,
+          random_access_iterator_tag,
+          _If<bidirectional_range<_Base>,
+              bidirectional_iterator_tag,
+              _If<forward_range<_Base>,
+                  forward_iterator_tag,
+                  /* else */ input_iterator_tag >>>;
+
+  _LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_Base> __current_     = iterator_t<_Base>();
+  _LIBCPP_NO_UNIQUE_ADDRESS ranges::sentinel_t<_Base> __end_ = ranges::sentinel_t<_Base>();
+  difference_type __stride_                                  = 0;
+  difference_type __missing_                                 = 0;
+
+  // 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 && std::convertible_to<ranges::iterator_t<_View>, ranges::iterator_t<_Base>> &&
+                 std::convertible_to<ranges::sentinel_t<_View>, ranges::sentinel_t<_Base>>
+      : __current_(std::move(__i.__current_)),
+        __end_(std::move(__i.__end_)),
+        __stride_(__i.__stride_),
+        __missing_(__i.__missing_) {}
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(
+      _Parent& __parent, ranges::iterator_t<_Base> __current, difference_type __missing = 0)
+      : __current_(std::move(__current)),
+        __end_(ranges::end(__parent.__base_)),
+        __stride_(__parent.__stride_),
+        __missing_(__missing) {}
+
+  _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> const& base() const& noexcept { return __current_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__current_; }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+    __missing_ = ranges::advance(__current_, __stride_, __end_);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
+    requires forward_range<_Base>
+  {
+    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 __s)
+    requires random_access_range<_Base>
+  {
+    if (__s > 0) {
+      ranges::advance(__current_, __stride_ * (__s - 1));
+      __missing_ = ranges::advance(__current_, __stride_, __end_);
+    } else if (__s < 0) {
+      ranges::advance(__current_, __stride_ * __s + __missing_);
+      __missing_ = 0;
+    }
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __s)
+    requires random_access_range<_Base>
+  {
+    return *this += -__s;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator[](difference_type __s) const
+    requires random_access_range<_Base>
+  {
+    return *(*this + __s);
+  }
+
+  _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 bool operator<=>(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
+  {
+    return __x.__current_ <=> __y.__current_;
+  }
+
+  _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;
+  }
+  _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;
+  }
+
+  _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;
+  }
+
+  _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>> && forward_range<_Base>
+  {
+    auto __n = __x.__current_ - __y.__current_;
+    return (__n + __x.__missing_ - __y.__missing_) / __x.__stride_;
+  }
+
+  _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>>
+  {
+    auto __n = __x.__current_ - __y.__current_;
+    if (__n < 0) {
+      return -ranges::__div_ceil(-__n, __x.__stride_);
+    }
+    return ranges::__div_ceil(__n, __x.__stride_);
+  }
+
+  _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_);
+  }
+  _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);
+  }
+
+  _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 <input_range _View>
+  requires view<_View>
+template <bool _Const>
+class stride_view<_View>::__sentinel {
+public:
+  sentinel_t<_View> __end_ = sentinel_t<_View>();
+
+  _LIBCPP_HIDE_FROM_ABI __sentinel() = default;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(stride_view<_View>& __parent)
+      : __end_(ranges::end(__parent.__base_)) {}
+
+  _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_View> base() const { return __end_; }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator<true> const& __x, __sentinel const& __y) {
+    return __x.__current_ == __y.__end_;
+  }
+}; // class stride_view::__sentinel
+
+template <class _Range>
+stride_view(_Range&&) -> stride_view<views::all_t<_Range>>;
+
+namespace views {
+namespace __stride {
+// removed this.
+struct __fn {
+  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};
+  }
+
+  template <class _Np>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Np&& __n) const {
+    return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Np>(__n)));
+  }
+};
+} // namespace __stride
+
+inline namespace __cpo {
+inline constexpr auto stride = __stride::__fn{};
+} // namespace __cpo
+} // namespace views
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___RANGES_STRIDE_VIEW_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 90ee7fbb2157c2..d73885bbf39206 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1697,6 +1697,7 @@ module std_private_ranges_size                       [system] {
   export std_private_type_traits_make_unsigned
 }
 module std_private_ranges_split_view                 [system] { header "__ranges/split_view.h" }
+module std_private_ranges_stride_view                 [system] { header "__ranges/stride_view.h" }
 module std_private_ranges_subrange                   [system] {
   header "__ranges/subrange.h"
   export std_private_ranges_subrange_fwd
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index f71a92f8a660b0..d00ccb22698df0 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -406,6 +406,7 @@ namespace std {
 #include <__ranges/single_view.h>
 #include <__ranges/size.h>
 #include <__ranges/split_view.h>
+#include <__ranges/stride_view.h>
 #include <__ranges/subrange.h>
 #include <__ranges/take_view.h>
 #include <__ranges/take_while_view.h>
diff --git a/libcxx/include/version b/libcxx/include/version
index e84790b888d333..ecf87fd95eaaf7 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -175,6 +175,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 <deque> <forward_list> <list>
                                                                 <map> <queue> <ranges>
                                                                 <set> <stack> <string>
@@ -466,6 +467,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 # define __cpp_lib_ranges_repeat                        202207L
 // # define __cpp_lib_ranges_slide                         202202L
 // # define __cpp_lib_ranges_starts_ends_with              202106L
+# define __cpp_lib_ranges_stride                        202207L
 # define __cpp_lib_ranges_to_container                  202202L
 // # define __cpp_lib_ranges_zip                           202110L
 // # define __cpp_lib_reference_from_temporary             202202L
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index a883103d812588..0f418971c700da 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -276,6 +276,13 @@ export namespace std {
     } // namespace views
 #endif // _LIBCPP_STD_VER >= 23
 
+    // [range.stride], stride view
+    using std::ranges::stride_view;
+
+    namespace views {
+      using std::ranges::views::stride;
+    }
+
 #if 0
     // [range.zip.transform], zip transform view
     using std::ranges::zip_transform_view;
@@ -322,7 +329,6 @@ export namespace std {
     }
 #endif // _LIBCPP_STD_VER >= 23
 
-#if 0
     // [range.stride], stride view
     using std::ranges::stride_view;
 
@@ -330,6 +336,7 @@ export namespace std {
       using std::ranges::views::stride;
     }
 
+#if 0
     using std::ranges::cartesian_product_view;
 
     namespace views {
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
index aa3a4964ad492e..af19eb26bfeb09 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
@@ -24,6 +24,7 @@
     __cpp_lib_ranges_join_with       202202L [C++23]
     __cpp_lib_ranges_repeat          202207L [C++23]
     __cpp_lib_ranges_slide           202202L [C++23]
+    __cpp_lib_ranges_stride          202207L [C++23]
     __cpp_lib_ranges_to_container    202202L [C++23]
     __cpp_lib_ranges_zip             202110L [C++23]
 */
@@ -65,6 +66,10 @@
 #   error "__cpp_lib_ranges_slide should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should not be defined before c++23"
 # endif
@@ -107,6 +112,10 @@
 #   error "__cpp_lib_ranges_slide should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should not be defined before c++23"
 # endif
@@ -149,6 +158,10 @@
 #   error "__cpp_lib_ranges_slide should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should not be defined before c++23"
 # endif
@@ -194,6 +207,10 @@
 #   error "__cpp_lib_ranges_slide should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should not be defined before c++23"
 # endif
@@ -284,6 +301,13 @@
 #   endif
 # endif
 
+# ifndef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should be defined in c++23"
+# endif
+# if __cpp_lib_ranges_stride != 202207L
+#   error "__cpp_lib_ranges_stride should have the value 202207L in c++23"
+# endif
+
 # ifndef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should be defined in c++23"
 # endif
@@ -386,6 +410,13 @@
 #   endif
 # endif
 
+# ifndef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should be defined in c++26"
+# endif
+# if __cpp_lib_ranges_stride != 202207L
+#   error "__cpp_lib_ranges_stride should have the value 202207L in c++26"
+# endif
+
 # ifndef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should be defined in c++26"
 # endif
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 0b00469892f607..9d84e92ed82a1b 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -163,6 +163,7 @@
     __cpp_lib_ranges_repeat                          202207L [C++23]
     __cpp_lib_ranges_slide                           202202L [C++23]
     __cpp_lib_ranges_starts_ends_with                202106L [C++23]
+    __cpp_lib_ranges_stride                          202207L [C++23]
     __cpp_lib_ranges_to_container                    202202L [C++23]
     __cpp_lib_ranges_zip                             202110L [C++23]
     __cpp_lib_ratio                                  202306L [C++26]
@@ -791,6 +792,10 @@
 #   error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should not be defined before c++23"
 # endif
@@ -1613,6 +1618,10 @@
 #   error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should not be defined before c++23"
 # endif
@@ -2606,6 +2615,10 @@
 #   error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should not be defined before c++23"
 # endif
@@ -3872,6 +3885,10 @@
 #   error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
 # endif
 
+# ifdef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should not be defined before c++23"
 # endif
@@ -5375,6 +5392,13 @@
 #   endif
 # endif
 
+# ifndef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should be defined in c++23"
+# endif
+# if __cpp_lib_ranges_stride != 202207L
+#   error "__cpp_lib_ranges_stride should have the value 202207L in c++23"
+# endif
+
 # ifndef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should be defined in c++23"
 # endif
@@ -7088,6 +7112,13 @@
 #   endif
 # endif
 
+# ifndef __cpp_lib_ranges_stride
+#   error "__cpp_lib_ranges_stride should be defined in c++26"
+# endif
+# if __cpp_lib_ranges_stride != 202207L
+#   error "__cpp_lib_ranges_stride should have the value 202207L in c++26"
+# endif
+
 # ifndef __cpp_lib_ranges_to_container
 #   error "__cpp_lib_ranges_to_container should be defined in c++26"
 # endif
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
new file mode 100644
index 00000000000000..8ad758a953426d
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -0,0 +1,193 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include "test.h"
+#include <iterator>
+#include <ranges>
+#include <utility>
+
+template <class View, class T>
+concept CanBePiped = requires(View&& view, T&& t) {
+  { std::forward<View>(view) | std::forward<T>(t) };
+};
+
+constexpr bool test() {
+  int arr[] = {1, 2, 3};
+
+  // Simple use cases.
+  {
+    {
+      BidirRange view(arr, arr + 3);
+      std::ranges::stride_view<BidirRange> strided(view, 1);
+      auto strided_iter = strided.begin();
+
+      assert(*strided_iter == arr[0]);
+
+      std::ranges::advance(strided_iter, 2);
+      assert(*strided_iter == arr[2]);
+    }
+    {
+      BidirRange view(arr, arr + 3);
+      std::ranges::stride_view<BidirRange> strided(view, 2);
+      auto strided_iter = strided.begin();
+
+      assert(*strided_iter == arr[0]);
+
+      std::ranges::advance(strided_iter, 1);
+      assert(*strided_iter == arr[2]);
+    }
+  }
+
+#if 0
+  // views::reverse(x) is equivalent to subrange{end, begin, size} if x is a
+  // sized subrange over reverse iterators
+  {
+    using It = bidirectional_iterator<int*>;
+    using Subrange = std::ranges::subrange<It, It, std::ranges::subrange_kind::sized>;
+
+    using ReverseIt = std::reverse_iterator<It>;
+    using ReverseSubrange = std::ranges::subrange<ReverseIt, ReverseIt, std::ranges::subrange_kind::sized>;
+
+    {
+      BidirRange view(buf, buf + 3);
+      ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3);
+      std::same_as<Subrange> auto result = std::views::reverse(subrange);
+      assert(base(result.begin()) == buf);
+      assert(base(result.end()) == buf + 3);
+    }
+    {
+      // std::move into views::reverse
+      BidirRange view(buf, buf + 3);
+      ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3);
+      std::same_as<Subrange> auto result = std::views::reverse(std::move(subrange));
+      assert(base(result.begin()) == buf);
+      assert(base(result.end()) == buf + 3);
+    }
+    {
+      // with a const subrange
+      BidirRange view(buf, buf + 3);
+      ReverseSubrange const subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3);
+      std::same_as<Subrange> auto result = std::views::reverse(subrange);
+      assert(base(result.begin()) == buf);
+      assert(base(result.end()) == buf + 3);
+    }
+  }
+
+  // views::reverse(x) is equivalent to subrange{end, begin} if x is an
+  // unsized subrange over reverse iterators
+  {
+    using It = bidirectional_iterator<int*>;
+    using Subrange = std::ranges::subrange<It, It, std::ranges::subrange_kind::unsized>;
+
+    using ReverseIt = std::reverse_iterator<It>;
+    using ReverseSubrange = std::ranges::subrange<ReverseIt, ReverseIt, std::ranges::subrange_kind::unsized>;
+
+    {
+      BidirRange view(buf, buf + 3);
+      ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)));
+      std::same_as<Subrange> auto result = std::views::reverse(subrange);
+      assert(base(result.begin()) == buf);
+      assert(base(result.end()) == buf + 3);
+    }
+    {
+      // std::move into views::reverse
+      BidirRange view(buf, buf + 3);
+      ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)));
+      std::same_as<Subrange> auto result = std::views::reverse(std::move(subrange));
+      assert(base(result.begin()) == buf);
+      assert(base(result.end()) == buf + 3);
+    }
+    {
+      // with a const subrange
+      BidirRange view(buf, buf + 3);
+      ReverseSubrange const subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)));
+      std::same_as<Subrange> auto result = std::views::reverse(subrange);
+      assert(base(result.begin()) == buf);
+      assert(base(result.end()) == buf + 3);
+    }
+  }
+
+  // Otherwise, views::reverse(x) is equivalent to ranges::reverse_view{x}
+  {
+    BidirRange view(buf, buf + 3);
+    std::same_as<std::ranges::reverse_view<BidirRange>> auto result = std::views::reverse(view);
+    assert(base(result.begin().base()) == buf + 3);
+    assert(base(result.end().base()) == buf);
+  }
+
+  // Test that std::views::reverse is a range adaptor
+  {
+    // Test `v | views::reverse`
+    {
+      BidirRange view(buf, buf + 3);
+      std::same_as<std::ranges::reverse_view<BidirRange>> auto result = view | std::views::reverse;
+      assert(base(result.begin().base()) == buf + 3);
+      assert(base(result.end().base()) == buf);
+    }
+
+    // Test `adaptor | views::reverse`
+    {
+      BidirRange view(buf, buf + 3);
+      auto f = [](int i) { return i; };
+      auto const partial = std::views::transform(f) | std::views::reverse;
+      using Result = std::ranges::reverse_view<std::ranges::transform_view<BidirRange, decltype(f)>>;
+      std::same_as<Result> auto result = partial(view);
+      assert(base(result.begin().base().base()) == buf + 3);
+      assert(base(result.end().base().base()) == buf);
+    }
+
+    // Test `views::reverse | adaptor`
+    {
+      BidirRange view(buf, buf + 3);
+      auto f = [](int i) { return i; };
+      auto const partial = std::views::reverse | std::views::transform(f);
+      using Result = std::ranges::transform_view<std::ranges::reverse_view<BidirRange>, decltype(f)>;
+      std::same_as<Result> auto result = partial(view);
+      assert(base(result.begin().base().base()) == buf + 3);
+      assert(base(result.end().base().base()) == buf);
+    }
+  }
+#endif // big block
+
+  // From:
+  // Test that std::views::reverse is a range adaptor
+  // Check SFINAE friendliness
+  {
+    struct NotAViewableRange {};
+    struct NotABidirRange {};
+    // Not invocable because there is no parameter.
+    static_assert(!std::is_invocable_v<decltype(std::views::stride)>);
+    // Not invocable because NotAViewableRange is, well, not a viewable range.
+    static_assert(!std::is_invocable_v<decltype(std::views::reverse), NotAViewableRange>);
+    // Is invocable because BidirRange is a viewable range.
+    static_assert(std::is_invocable_v<decltype(std::views::reverse), BidirRange>);
+
+    // Make sure that pipe operations work!
+    static_assert(CanBePiped<BidirRange, decltype(std::views::stride(std::ranges::range_difference_t<BidirRange>{}))>);
+    static_assert(CanBePiped<BidirRange&, decltype(std::views::stride(std::ranges::range_difference_t<BidirRange>{}))>);
+    static_assert(
+        !CanBePiped<NotABidirRange, decltype(std::views::stride(std::ranges::range_difference_t<BidirRange>{}))>);
+  }
+  // A final sanity check.
+  { static_assert(std::same_as<decltype(std::views::stride), decltype(std::ranges::views::stride)>); }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
new file mode 100644
index 00000000000000..badfd532453158
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include "test.h"
+#include <cassert>
+#include <ranges>
+
+template <typename T>
+concept can_call_base_on = requires(T t) { std::forward<T>(t).base(); };
+
+constexpr bool test() {
+  int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  // Check the const& overload
+  {
+    Range range(buff, buff + 8);
+    std::ranges::stride_view<Range<int>> const view(range, 3);
+    std::same_as<Range<int>> decltype(auto) result = view.base();
+    assert(result.wasCopyInitialized);
+    assert(result.begin() == buff);
+    assert(result.end() == buff + 8);
+  }
+
+  // Check the && overload
+  {
+    Range range(buff, buff + 8);
+    std::ranges::stride_view<Range<int>> view(range, 3);
+    std::same_as<Range<int>> decltype(auto) result = std::move(view).base();
+    assert(result.wasMoveInitialized);
+    assert(result.begin() == buff);
+    assert(result.end() == buff + 8);
+  }
+
+  // Check the && overload (again)
+  {
+    Range range(buff, buff + 8);
+    std::same_as<Range<int>> decltype(auto) result = std::ranges::stride_view<Range<int>>(range, 3).base();
+    assert(result.wasMoveInitialized);
+    assert(result.begin() == buff);
+    assert(result.end() == buff + 8);
+  }
+
+  // Ensure the const& overload is not considered when the base is not copy-constructible
+  {
+    static_assert(!can_call_base_on<std::ranges::stride_view<NoCopyRange> const&>);
+    static_assert(!can_call_base_on<std::ranges::stride_view<NoCopyRange>&>);
+    static_assert(can_call_base_on<std::ranges::stride_view<NoCopyRange>&&>);
+    static_assert(can_call_base_on<std::ranges::stride_view<NoCopyRange>>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp
new file mode 100644
index 00000000000000..68556f32f875b1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+constexpr bool test() { return true; }
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
new file mode 100644
index 00000000000000..68556f32f875b1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+constexpr bool test() { return true; }
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
new file mode 100644
index 00000000000000..646a9423f4523c
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include "test.h"
+#include <ranges>
+
+constexpr bool test() {
+  using std::ranges::enable_borrowed_range;
+  // Make sure that a stride_view over neither a borrowable nor an unborrowable view
+  // is itself borrowable.
+  static_assert(!enable_borrowed_range<std::ranges::stride_view<Range<int>>>);
+  static_assert(!enable_borrowed_range<std::ranges::stride_view<BorrowedRange<int>>>);
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp
new file mode 100644
index 00000000000000..68556f32f875b1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+constexpr bool test() { return true; }
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
new file mode 100644
index 00000000000000..cfc38b32926805
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include "../test.h"
+#include <cassert>
+#include <ranges>
+
+bool non_simple_view_iter_ctor_test() {
+  using StrideView             = std::ranges::stride_view<NotSimpleView>;
+  using StrideViewIterNonConst = std::ranges::iterator_t<StrideView>;
+  using StrideViewIterConst    = std::ranges::iterator_t<const StrideView>;
+
+  StrideView sv{NotSimpleView{}, 1};
+  StrideViewIterNonConst iter = {sv, sv.base().begin(), 0};
+  StrideViewIterConst iterb   = {iter};
+  assert(iterb.__end_.moved_from_a == true);
+  return true;
+}
+
+constexpr bool simpleview_iter_ctor_test() {
+  using StrideView     = std::ranges::stride_view<ForwardTracedMoveView>;
+  using StrideViewIter = std::ranges::iterator_t<StrideView>;
+
+  StrideView sv{ForwardTracedMoveView{}, 1};
+  StrideViewIter iter = {sv, sv.base().begin(), 0};
+  // Guarantee that when the iterator is given to the constructor that
+  // it is moved there.
+  assert(iter.base().moved);
+
+  return true;
+}
+
+int main(int, char**) {
+  simpleview_iter_ctor_test();
+  non_simple_view_iter_ctor_test();
+  static_assert(simpleview_iter_ctor_test());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
new file mode 100644
index 00000000000000..7f2711adc5179d
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+
+template <class Iter>
+constexpr void testOne() {
+  using Range      = std::ranges::subrange<Iter>;
+  using StrideView = std::ranges::stride_view<Range>;
+  static_assert(std::ranges::common_range<StrideView>);
+
+  {
+    // simple test
+    {
+      int buffer[] = {0, 1, 2, -1, 4, 5, 6};
+      Range input(Iter{buffer}, Iter{buffer + 7});
+      StrideView sv(input, 1);
+      StrideView sv_too(input, 2);
+      auto b = sv.begin(), e = sv.end();
+      auto b_too = sv_too.begin();
+
+      assert(b == b);
+      assert(!(b != b));
+
+      assert(e == e);
+      assert(!(e != e));
+
+      assert(!(b == e));
+      assert(b != e);
+
+      std::advance(b, 8);
+      std::advance(b_too, 4);
+
+      assert(b == b_too);
+      assert(!(b != b_too));
+
+      assert(b == b);
+      assert(!(b != b));
+
+      assert(e == e);
+      assert(!(e != e));
+
+      assert(b == e);
+      assert(!(b != e));
+    }
+
+    // Default-constructed iterators compare equal.
+    {
+      int buffer[] = {0, 1, 2, -1, 4, 5, 6};
+      Range input(Iter{buffer}, Iter{buffer + 7});
+      std::ranges::stride_view sv(input, 1);
+      using StrideViewIter = decltype(sv.begin());
+      StrideViewIter i1, i2;
+      assert(i1 == i2);
+      assert(!(i1 != i2));
+    }
+  }
+}
+
+constexpr bool test() {
+  testOne<forward_iterator<int*>>();
+  //testOne<bidirectional_iterator<int*>>();
+  //testOne<random_access_iterator<int*>>();
+  //testOne<contiguous_iterator<int*>>();
+  testOne<int*>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/ctor.default.pass.cpp
new file mode 100644
index 00000000000000..68556f32f875b1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/ctor.default.pass.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+constexpr bool test() { return true; }
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/equal.pass.cpp
new file mode 100644
index 00000000000000..68556f32f875b1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/equal.pass.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+constexpr bool test() { return true; }
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp
new file mode 100644
index 00000000000000..981395f9e2c329
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::ranges::stride_view
+
+#include <cassert>
+#include <ranges>
+
+bool runtime_test() {
+  auto iot    = std::views::iota(1, 22);
+  auto str    = std::views::stride(iot, 3);
+  auto result = str.size();
+  assert(result == 7);
+  return true;
+}
+
+constexpr bool test() {
+  {
+    constexpr auto iot = std::views::iota(1, 12);
+    constexpr auto str = std::views::stride(iot, 3);
+    assert(4 == str.size());
+    static_assert(4 == str.size(), "Striding by 3 through a 12 member list has size 4.");
+  }
+  {
+    constexpr auto iot = std::views::iota(1, 22);
+    constexpr auto str = std::views::stride(iot, 3);
+    assert(7 == str.size());
+    static_assert(7 == str.size(), "Striding by 3 through a 12 member list has size 4.");
+  }
+  return true;
+}
+
+int main(int, char**) {
+  runtime_test();
+  static_assert(test());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
new file mode 100644
index 00000000000000..4d13f05d48c01b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -0,0 +1,183 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
+
+#include "test_iterators.h"
+#include <iterator>
+#include <ranges>
+
+template <typename T = int>
+struct Range : std::ranges::view_base {
+  constexpr explicit Range(T* b, T* e) : begin_(b), end_(e) {}
+  constexpr Range(Range const& other) : begin_(other.begin_), end_(other.end_), wasCopyInitialized(true) {}
+  constexpr Range(Range&& other) : begin_(other.begin_), end_(other.end_), wasMoveInitialized(true) {}
+  Range& operator=(Range const&) = default;
+  Range& operator=(Range&&)      = default;
+  constexpr T* begin() const { return begin_; }
+  constexpr T* end() const { return end_; }
+
+  T* begin_;
+  T* end_;
+  bool wasCopyInitialized = false;
+  bool wasMoveInitialized = false;
+};
+
+template <typename T>
+Range(T, T) -> Range<T>;
+
+template <typename T>
+struct BorrowedRange : public Range<T> {};
+
+template <typename T>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange<T>> = true;
+
+struct NoCopyRange : std::ranges::view_base {
+  explicit NoCopyRange(int*, int*);
+  NoCopyRange(NoCopyRange const&)            = delete;
+  NoCopyRange(NoCopyRange&&)                 = default;
+  NoCopyRange& operator=(NoCopyRange const&) = default;
+  NoCopyRange& operator=(NoCopyRange&&)      = default;
+  int* begin() const;
+  int* end() const;
+};
+
+template <class Derived>
+struct ForwardIterBase {
+  using iterator_concept = std::forward_iterator_tag;
+  using value_type       = int;
+  using difference_type  = std::intptr_t;
+
+  constexpr int operator*() const { return 5; }
+
+  constexpr Derived& operator++() { return static_cast<Derived&>(*this); }
+  constexpr Derived operator++(int) { return {}; }
+
+  friend constexpr bool operator==(const ForwardIterBase&, const ForwardIterBase&) { return true; }
+};
+
+template <class Derived>
+struct InputIterBase {
+  using iterator_concept = std::input_iterator_tag;
+  using value_type       = int;
+  using difference_type  = std::intptr_t;
+
+  constexpr int operator*() const { return 5; }
+
+  constexpr Derived& operator++() { return static_cast<Derived&>(*this); }
+  constexpr Derived operator++(int) { return {}; }
+
+  friend constexpr bool operator==(const InputIterBase&, const InputIterBase&) { return true; }
+};
+
+struct NotSimpleViewIterB : ForwardIterBase<NotSimpleViewIterB> {
+  bool moved = false;
+
+  constexpr NotSimpleViewIterB()                          = default;
+  constexpr NotSimpleViewIterB(const NotSimpleViewIterB&) = default;
+  constexpr NotSimpleViewIterB(NotSimpleViewIterB&&) : moved{true} {}
+  constexpr NotSimpleViewIterB& operator=(NotSimpleViewIterB&&)      = default;
+  constexpr NotSimpleViewIterB& operator=(const NotSimpleViewIterB&) = default;
+};
+
+struct NotSimpleViewIterA : ForwardIterBase<NotSimpleViewIterA> {
+  bool moved         = false;
+  bool moved_from_a  = false;
+  bool copied_from_a = false;
+
+  constexpr NotSimpleViewIterA()                          = default;
+  constexpr NotSimpleViewIterA(const NotSimpleViewIterA&) = default;
+  constexpr NotSimpleViewIterA(const NotSimpleViewIterB&) : copied_from_a{true} {}
+  constexpr NotSimpleViewIterA(NotSimpleViewIterA&&) : moved{true} {}
+  constexpr NotSimpleViewIterA(NotSimpleViewIterB&&) : moved_from_a{true} {}
+  constexpr NotSimpleViewIterA& operator=(NotSimpleViewIterA&&)      = default;
+  constexpr NotSimpleViewIterA& operator=(const NotSimpleViewIterA&) = default;
+};
+
+struct NotSimpleView : std::ranges::view_base {
+  constexpr NotSimpleViewIterA begin() const { return {}; }
+  constexpr NotSimpleViewIterB begin() { return {}; }
+  constexpr NotSimpleViewIterA end() const { return {}; }
+  constexpr NotSimpleViewIterB end() { return {}; }
+
+  int* begin_;
+  int* end_;
+  bool wasCopyInitialized = false;
+  bool wasMoveInitialized = false;
+};
+
+struct ForwardTracedMoveIter : ForwardIterBase<ForwardTracedMoveIter> {
+  bool moved = false;
+
+  constexpr ForwardTracedMoveIter()                             = default;
+  constexpr ForwardTracedMoveIter(const ForwardTracedMoveIter&) = default;
+  constexpr ForwardTracedMoveIter(ForwardTracedMoveIter&&) : moved{true} {}
+  constexpr ForwardTracedMoveIter& operator=(ForwardTracedMoveIter&&)      = default;
+  constexpr ForwardTracedMoveIter& operator=(const ForwardTracedMoveIter&) = default;
+};
+
+struct ForwardTracedMoveView : std::ranges::view_base {
+  constexpr ForwardTracedMoveIter begin() const { return {}; }
+  constexpr ForwardTracedMoveIter end() const { return {}; }
+};
+
+struct BidirRange : std::ranges::view_base {
+  int* begin_;
+  int* end_;
+
+  constexpr BidirRange(int* b, int* e) : begin_(b), end_(e) {}
+
+  constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{begin_}; }
+  constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{begin_}; }
+  constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>{end_}; }
+  constexpr bidirectional_iterator<const int*> end() const { return bidirectional_iterator<const int*>{end_}; }
+};
+static_assert(std::ranges::bidirectional_range<BidirRange>);
+static_assert(std::ranges::common_range<BidirRange>);
+static_assert(std::ranges::view<BidirRange>);
+static_assert(std::copyable<BidirRange>);
+
+enum CopyCategory { MoveOnly, Copyable };
+template <CopyCategory CC>
+struct BidirSentRange : std::ranges::view_base {
+  using sent_t       = sentinel_wrapper<bidirectional_iterator<int*>>;
+  using sent_const_t = sentinel_wrapper<bidirectional_iterator<const int*>>;
+
+  int* begin_;
+  int* end_;
+
+  constexpr BidirSentRange(int* b, int* e) : begin_(b), end_(e) {}
+  constexpr BidirSentRange(const BidirSentRange&)
+    requires(CC == Copyable)
+  = default;
+  constexpr BidirSentRange(BidirSentRange&&)
+    requires(CC == MoveOnly)
+  = default;
+  constexpr BidirSentRange& operator=(const BidirSentRange&)
+    requires(CC == Copyable)
+  = default;
+  constexpr BidirSentRange& operator=(BidirSentRange&&)
+    requires(CC == MoveOnly)
+  = default;
+
+  constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{begin_}; }
+  constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{begin_}; }
+  constexpr sent_t end() { return sent_t{bidirectional_iterator<int*>{end_}}; }
+  constexpr sent_const_t end() const { return sent_const_t{bidirectional_iterator<const int*>{end_}}; }
+};
+static_assert(std::ranges::bidirectional_range<BidirSentRange<MoveOnly>>);
+static_assert(!std::ranges::common_range<BidirSentRange<MoveOnly>>);
+static_assert(std::ranges::view<BidirSentRange<MoveOnly>>);
+static_assert(!std::copyable<BidirSentRange<MoveOnly>>);
+static_assert(std::ranges::bidirectional_range<BidirSentRange<Copyable>>);
+static_assert(!std::ranges::common_range<BidirSentRange<Copyable>>);
+static_assert(std::ranges::view<BidirSentRange<Copyable>>);
+static_assert(std::copyable<BidirSentRange<Copyable>>);
+
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 8943ad2557433c..74d7a52dca7f37 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -939,6 +939,11 @@ def add_version_header(tc):
             "headers": ["algorithm"],
             "unimplemented": True,
         },
+        {
+            "name": "__cpp_lib_ranges_stride",
+            "values": {"c++23": 202207},
+            "headers": ["ranges"],
+        },
         {
             "name": "__cpp_lib_ranges_to_container",
             "values": {"c++23": 202202},

>From 52dcd3218285e5ca071c5e2064ab5c4cebe9b12f Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 4 Sep 2023 10:20:04 -0400
Subject: [PATCH 02/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add CTAD testing and refactor test classes.
---
 .../range.stride.view/ctad.compile.pass.cpp   | 33 ++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
index 68556f32f875b1..7831d792d64e77 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
@@ -12,7 +12,37 @@
 
 // std::views::stride_view
 
-constexpr bool test() { return true; }
+#include <concepts>
+#include <ranges>
+#include <utility>
+#include "test.h"
+
+constexpr bool test() {
+  int arr[]{1, 2, 3};
+
+  InstrumentedBasicView<int> bv{arr, arr + 3};
+  InstrumentedBasicRange<int> br{};
+
+  static_assert(std::same_as<
+      decltype(std::ranges::stride_view(bv, 2)),
+      std::ranges::stride_view<decltype(bv)>
+  >);
+  static_assert(std::same_as<
+      decltype(std::ranges::stride_view(std::move(bv), 2)),
+      std::ranges::stride_view<decltype(bv)>
+  >);
+
+  static_assert(std::same_as<
+      decltype(std::ranges::drop_view(br, 0)),
+      std::ranges::drop_view<std::ranges::ref_view<InstrumentedBasicRange<int>>>
+  >);
+
+  static_assert(std::same_as<
+      decltype(std::ranges::drop_view(std::move(br), 0)),
+      std::ranges::drop_view<std::ranges::owning_view<InstrumentedBasicRange<int>>>
+  >);
+  return true;
+}
 
 int main(int, char**) {
   test();
@@ -20,3 +50,4 @@ int main(int, char**) {
 
   return 0;
 }
+

>From a99cc33b8987ef1ba850047d073d1bee8fc6e4c9 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 4 Sep 2023 10:23:04 -0400
Subject: [PATCH 03/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Refactor test classes. (previous fixup message was incorrect)
---
 .../range.stride.view/adaptor.pass.cpp        | 18 ++--
 .../range.stride.view/base.pass.cpp           | 24 +++---
 .../enable_borrowed_range.compile.pass.cpp    |  4 +-
 .../iterator/ctor.default.pass.cpp            |  4 +-
 .../range.adaptors/range.stride.view/test.h   | 82 ++++++++++---------
 5 files changed, 70 insertions(+), 62 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
index 8ad758a953426d..0de98ba259517f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -28,8 +28,8 @@ constexpr bool test() {
   // Simple use cases.
   {
     {
-      BidirRange view(arr, arr + 3);
-      std::ranges::stride_view<BidirRange> strided(view, 1);
+      BidirView view(arr, arr + 3);
+      std::ranges::stride_view<BidirView> strided(view, 1);
       auto strided_iter = strided.begin();
 
       assert(*strided_iter == arr[0]);
@@ -38,8 +38,8 @@ constexpr bool test() {
       assert(*strided_iter == arr[2]);
     }
     {
-      BidirRange view(arr, arr + 3);
-      std::ranges::stride_view<BidirRange> strided(view, 2);
+      BidirView view(arr, arr + 3);
+      std::ranges::stride_view<BidirView> strided(view, 2);
       auto strided_iter = strided.begin();
 
       assert(*strided_iter == arr[0]);
@@ -170,14 +170,14 @@ constexpr bool test() {
     static_assert(!std::is_invocable_v<decltype(std::views::stride)>);
     // Not invocable because NotAViewableRange is, well, not a viewable range.
     static_assert(!std::is_invocable_v<decltype(std::views::reverse), NotAViewableRange>);
-    // Is invocable because BidirRange is a viewable range.
-    static_assert(std::is_invocable_v<decltype(std::views::reverse), BidirRange>);
+    // Is invocable because BidirView is a viewable range.
+    static_assert(std::is_invocable_v<decltype(std::views::reverse), BidirView>);
 
     // Make sure that pipe operations work!
-    static_assert(CanBePiped<BidirRange, decltype(std::views::stride(std::ranges::range_difference_t<BidirRange>{}))>);
-    static_assert(CanBePiped<BidirRange&, decltype(std::views::stride(std::ranges::range_difference_t<BidirRange>{}))>);
+    static_assert(CanBePiped<BidirView, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
+    static_assert(CanBePiped<BidirView&, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
     static_assert(
-        !CanBePiped<NotABidirRange, decltype(std::views::stride(std::ranges::range_difference_t<BidirRange>{}))>);
+        !CanBePiped<NotABidirRange, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
   }
   // A final sanity check.
   { static_assert(std::same_as<decltype(std::views::stride), decltype(std::ranges::views::stride)>); }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
index badfd532453158..6b22b7e89c0158 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
@@ -24,9 +24,9 @@ constexpr bool test() {
 
   // Check the const& overload
   {
-    Range range(buff, buff + 8);
-    std::ranges::stride_view<Range<int>> const view(range, 3);
-    std::same_as<Range<int>> decltype(auto) result = view.base();
+    InstrumentedBasicView range(buff, buff + 8);
+    std::ranges::stride_view<InstrumentedBasicView<int>> const view(range, 3);
+    std::same_as<InstrumentedBasicView<int>> decltype(auto) result = view.base();
     assert(result.wasCopyInitialized);
     assert(result.begin() == buff);
     assert(result.end() == buff + 8);
@@ -34,9 +34,9 @@ constexpr bool test() {
 
   // Check the && overload
   {
-    Range range(buff, buff + 8);
-    std::ranges::stride_view<Range<int>> view(range, 3);
-    std::same_as<Range<int>> decltype(auto) result = std::move(view).base();
+    InstrumentedBasicView<int> range(buff, buff + 8);
+    std::ranges::stride_view<InstrumentedBasicView<int>> view(range, 3);
+    std::same_as<InstrumentedBasicView<int>> decltype(auto) result = std::move(view).base();
     assert(result.wasMoveInitialized);
     assert(result.begin() == buff);
     assert(result.end() == buff + 8);
@@ -44,8 +44,8 @@ constexpr bool test() {
 
   // Check the && overload (again)
   {
-    Range range(buff, buff + 8);
-    std::same_as<Range<int>> decltype(auto) result = std::ranges::stride_view<Range<int>>(range, 3).base();
+    InstrumentedBasicView range(buff, buff + 8);
+    std::same_as<InstrumentedBasicView<int>> decltype(auto) result = std::ranges::stride_view<InstrumentedBasicView<int>>(range, 3).base();
     assert(result.wasMoveInitialized);
     assert(result.begin() == buff);
     assert(result.end() == buff + 8);
@@ -53,10 +53,10 @@ constexpr bool test() {
 
   // Ensure the const& overload is not considered when the base is not copy-constructible
   {
-    static_assert(!can_call_base_on<std::ranges::stride_view<NoCopyRange> const&>);
-    static_assert(!can_call_base_on<std::ranges::stride_view<NoCopyRange>&>);
-    static_assert(can_call_base_on<std::ranges::stride_view<NoCopyRange>&&>);
-    static_assert(can_call_base_on<std::ranges::stride_view<NoCopyRange>>);
+    static_assert(!can_call_base_on<std::ranges::stride_view<NoCopyView> const&>);
+    static_assert(!can_call_base_on<std::ranges::stride_view<NoCopyView>&>);
+    static_assert(can_call_base_on<std::ranges::stride_view<NoCopyView>&&>);
+    static_assert(can_call_base_on<std::ranges::stride_view<NoCopyView>>);
   }
 
   return true;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
index 646a9423f4523c..7c28842fe65f69 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
@@ -19,8 +19,8 @@ constexpr bool test() {
   using std::ranges::enable_borrowed_range;
   // Make sure that a stride_view over neither a borrowable nor an unborrowable view
   // is itself borrowable.
-  static_assert(!enable_borrowed_range<std::ranges::stride_view<Range<int>>>);
-  static_assert(!enable_borrowed_range<std::ranges::stride_view<BorrowedRange<int>>>);
+  static_assert(!enable_borrowed_range<std::ranges::stride_view<InstrumentedBasicView<int>>>);
+  static_assert(!enable_borrowed_range<std::ranges::stride_view<InstrumentedBorrowedRange<int>>>);
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index cfc38b32926805..d0f466d3adeaef 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -17,11 +17,11 @@
 #include <ranges>
 
 bool non_simple_view_iter_ctor_test() {
-  using StrideView             = std::ranges::stride_view<NotSimpleView>;
+  using StrideView             = std::ranges::stride_view<InstrumentedNotSimpleView>;
   using StrideViewIterNonConst = std::ranges::iterator_t<StrideView>;
   using StrideViewIterConst    = std::ranges::iterator_t<const StrideView>;
 
-  StrideView sv{NotSimpleView{}, 1};
+  StrideView sv{InstrumentedNotSimpleView{}, 1};
   StrideViewIterNonConst iter = {sv, sv.base().begin(), 0};
   StrideViewIterConst iterb   = {iter};
   assert(iterb.__end_.moved_from_a == true);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 4d13f05d48c01b..d9931cb6e63202 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -14,12 +14,18 @@
 #include <ranges>
 
 template <typename T = int>
-struct Range : std::ranges::view_base {
-  constexpr explicit Range(T* b, T* e) : begin_(b), end_(e) {}
-  constexpr Range(Range const& other) : begin_(other.begin_), end_(other.end_), wasCopyInitialized(true) {}
-  constexpr Range(Range&& other) : begin_(other.begin_), end_(other.end_), wasMoveInitialized(true) {}
-  Range& operator=(Range const&) = default;
-  Range& operator=(Range&&)      = default;
+struct InstrumentedBasicRange {
+  T *begin() const;
+  T *end() const;
+};
+
+template <typename T = int>
+struct InstrumentedBasicView : std::ranges::view_base {
+  constexpr explicit InstrumentedBasicView(T* b, T* e) : begin_(b), end_(e) {}
+  constexpr InstrumentedBasicView(InstrumentedBasicView const& other) : begin_(other.begin_), end_(other.end_), wasCopyInitialized(true) {}
+  constexpr InstrumentedBasicView(InstrumentedBasicView&& other) : begin_(other.begin_), end_(other.end_), wasMoveInitialized(true) {}
+  InstrumentedBasicView& operator=(InstrumentedBasicView const&) = default;
+  InstrumentedBasicView& operator=(InstrumentedBasicView&&)      = default;
   constexpr T* begin() const { return begin_; }
   constexpr T* end() const { return end_; }
 
@@ -30,20 +36,20 @@ struct Range : std::ranges::view_base {
 };
 
 template <typename T>
-Range(T, T) -> Range<T>;
+InstrumentedBasicView(T, T) -> InstrumentedBasicView<T>;
 
 template <typename T>
-struct BorrowedRange : public Range<T> {};
+struct InstrumentedBorrowedRange : public InstrumentedBasicView<T> {};
 
 template <typename T>
-inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange<T>> = true;
-
-struct NoCopyRange : std::ranges::view_base {
-  explicit NoCopyRange(int*, int*);
-  NoCopyRange(NoCopyRange const&)            = delete;
-  NoCopyRange(NoCopyRange&&)                 = default;
-  NoCopyRange& operator=(NoCopyRange const&) = default;
-  NoCopyRange& operator=(NoCopyRange&&)      = default;
+inline constexpr bool std::ranges::enable_borrowed_range<InstrumentedBorrowedRange<T>> = true;
+
+struct NoCopyView : std::ranges::view_base {
+  explicit NoCopyView(int*, int*);
+  NoCopyView(NoCopyView const&)            = delete;
+  NoCopyView(NoCopyView&&)                 = default;
+  NoCopyView& operator=(NoCopyView const&) = default;
+  NoCopyView& operator=(NoCopyView&&)      = default;
   int* begin() const;
   int* end() const;
 };
@@ -100,7 +106,7 @@ struct NotSimpleViewIterA : ForwardIterBase<NotSimpleViewIterA> {
   constexpr NotSimpleViewIterA& operator=(const NotSimpleViewIterA&) = default;
 };
 
-struct NotSimpleView : std::ranges::view_base {
+struct InstrumentedNotSimpleView : std::ranges::view_base {
   constexpr NotSimpleViewIterA begin() const { return {}; }
   constexpr NotSimpleViewIterB begin() { return {}; }
   constexpr NotSimpleViewIterA end() const { return {}; }
@@ -127,42 +133,42 @@ struct ForwardTracedMoveView : std::ranges::view_base {
   constexpr ForwardTracedMoveIter end() const { return {}; }
 };
 
-struct BidirRange : std::ranges::view_base {
+struct BidirView : std::ranges::view_base {
   int* begin_;
   int* end_;
 
-  constexpr BidirRange(int* b, int* e) : begin_(b), end_(e) {}
+  constexpr BidirView(int* b, int* e) : begin_(b), end_(e) {}
 
   constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{begin_}; }
   constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{begin_}; }
   constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>{end_}; }
   constexpr bidirectional_iterator<const int*> end() const { return bidirectional_iterator<const int*>{end_}; }
 };
-static_assert(std::ranges::bidirectional_range<BidirRange>);
-static_assert(std::ranges::common_range<BidirRange>);
-static_assert(std::ranges::view<BidirRange>);
-static_assert(std::copyable<BidirRange>);
 
+static_assert(std::ranges::view<BidirView>);
+static_assert(std::copyable<BidirView>);
+
+/*
 enum CopyCategory { MoveOnly, Copyable };
 template <CopyCategory CC>
-struct BidirSentRange : std::ranges::view_base {
+struct BidirSentView : std::ranges::view_base {
   using sent_t       = sentinel_wrapper<bidirectional_iterator<int*>>;
   using sent_const_t = sentinel_wrapper<bidirectional_iterator<const int*>>;
 
   int* begin_;
   int* end_;
 
-  constexpr BidirSentRange(int* b, int* e) : begin_(b), end_(e) {}
-  constexpr BidirSentRange(const BidirSentRange&)
+  constexpr BidirSentView(int* b, int* e) : begin_(b), end_(e) {}
+  constexpr BidirSentView(const BidirSentView&)
     requires(CC == Copyable)
   = default;
-  constexpr BidirSentRange(BidirSentRange&&)
+  constexpr BidirSentView(BidirSentView&&)
     requires(CC == MoveOnly)
   = default;
-  constexpr BidirSentRange& operator=(const BidirSentRange&)
+  constexpr BidirSentView& operator=(const BidirSentView&)
     requires(CC == Copyable)
   = default;
-  constexpr BidirSentRange& operator=(BidirSentRange&&)
+  constexpr BidirSentView& operator=(BidirSentView&&)
     requires(CC == MoveOnly)
   = default;
 
@@ -171,13 +177,15 @@ struct BidirSentRange : std::ranges::view_base {
   constexpr sent_t end() { return sent_t{bidirectional_iterator<int*>{end_}}; }
   constexpr sent_const_t end() const { return sent_const_t{bidirectional_iterator<const int*>{end_}}; }
 };
-static_assert(std::ranges::bidirectional_range<BidirSentRange<MoveOnly>>);
-static_assert(!std::ranges::common_range<BidirSentRange<MoveOnly>>);
-static_assert(std::ranges::view<BidirSentRange<MoveOnly>>);
-static_assert(!std::copyable<BidirSentRange<MoveOnly>>);
-static_assert(std::ranges::bidirectional_range<BidirSentRange<Copyable>>);
-static_assert(!std::ranges::common_range<BidirSentRange<Copyable>>);
-static_assert(std::ranges::view<BidirSentRange<Copyable>>);
-static_assert(std::copyable<BidirSentRange<Copyable>>);
+// TODO: Clean up.
+static_assert(std::ranges::bidirectional_range<BidirSentView<MoveOnly>>);
+static_assert(!std::ranges::common_range<BidirSentView<MoveOnly>>);
+static_assert(std::ranges::view<BidirSentView<MoveOnly>>);
+static_assert(!std::copyable<BidirSentView<MoveOnly>>);
+static_assert(std::ranges::bidirectional_range<BidirSentView<Copyable>>);
+static_assert(!std::ranges::common_range<BidirSentView<Copyable>>);
+static_assert(std::ranges::view<BidirSentView<Copyable>>);
+static_assert(std::copyable<BidirSentView<Copyable>>);
+*/
 
 #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H

>From e5157cfbb8d0a93f95eabdbb0a0bf4d745688918 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 8 Sep 2023 23:26:02 -0400
Subject: [PATCH 04/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Cleanup adaptor tests and fix typo in category definition.
---
 .../range.stride.view/adaptor.pass.cpp        | 186 ++++++------------
 .../range.adaptors/range.stride.view/test.h   |  56 +++++-
 2 files changed, 111 insertions(+), 131 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
index 0de98ba259517f..ba0efe36b98243 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -12,7 +12,9 @@
 
 // std::views::stride_view
 
+#include "__ranges/stride_view.h"
 #include "test.h"
+#include <concepts>
 #include <iterator>
 #include <ranges>
 #include <utility>
@@ -23,149 +25,84 @@ concept CanBePiped = requires(View&& view, T&& t) {
 };
 
 constexpr bool test() {
-  int arr[] = {1, 2, 3};
+  constexpr int array_n = 3;
+  int arr[array_n]      = {1, 2, 3};
 
-  // Simple use cases.
+  // Test that `std::views::stride` is a range adaptor.
   {
+    // Check various forms of
+    // view | stride
     {
-      BidirView view(arr, arr + 3);
-      std::ranges::stride_view<BidirView> strided(view, 1);
-      auto strided_iter = strided.begin();
-
-      assert(*strided_iter == arr[0]);
-
-      std::ranges::advance(strided_iter, 2);
-      assert(*strided_iter == arr[2]);
-    }
-    {
-      BidirView view(arr, arr + 3);
-      std::ranges::stride_view<BidirView> strided(view, 2);
-      auto strided_iter = strided.begin();
-
-      assert(*strided_iter == arr[0]);
-
-      std::ranges::advance(strided_iter, 1);
-      assert(*strided_iter == arr[2]);
+      {
+        BidirView view(arr, arr + array_n);
+        //std::ranges::stride_view<BidirView> strided(view, 1);
+        std::same_as<std::ranges::stride_view<BidirView>> decltype(auto) strided = view | std::views::stride(1);
+        auto strided_iter                                                        = strided.begin();
+
+        // Check that the begin() iter views arr[0]
+        assert(*strided_iter == arr[0]);
+
+        // Check that the strided_iter, after advancing it 2 * 1 steps, views arr[2].
+        std::ranges::advance(strided_iter, 2);
+        assert(*strided_iter == arr[2]);
+      }
+      {
+        BidirView view(arr, arr + array_n);
+        std::same_as<std::ranges::stride_view<BidirView>> decltype(auto) strided = view | std::views::stride(2);
+        auto strided_iter                                                        = strided.begin();
+
+        assert(*strided_iter == arr[0]);
+
+        // Same test as above, just advance one time with a bigger step (1 * 2 steps).
+        std::ranges::advance(strided_iter, 1);
+        assert(*strided_iter == arr[2]);
+      }
     }
   }
 
-#if 0
-  // views::reverse(x) is equivalent to subrange{end, begin, size} if x is a
-  // sized subrange over reverse iterators
+  // Check various forms of
+  // adaptor | stride
   {
-    using It = bidirectional_iterator<int*>;
-    using Subrange = std::ranges::subrange<It, It, std::ranges::subrange_kind::sized>;
-
-    using ReverseIt = std::reverse_iterator<It>;
-    using ReverseSubrange = std::ranges::subrange<ReverseIt, ReverseIt, std::ranges::subrange_kind::sized>;
-
+    // Parallels the two tests from above.
+    constexpr auto identity_lambda = [](int i) { return i * 2; };
     {
-      BidirRange view(buf, buf + 3);
-      ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3);
-      std::same_as<Subrange> auto result = std::views::reverse(subrange);
-      assert(base(result.begin()) == buf);
-      assert(base(result.end()) == buf + 3);
+      BidirView view(arr, arr + array_n);
+      const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(1);
+
+      const auto transform_stride_applied = transform_stride_partial(view);
+      auto transform_stride_applied_iter  = transform_stride_applied.begin();
+      assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[0]));
+      std::ranges::advance(transform_stride_applied_iter, 2);
+      assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[2]));
     }
-    {
-      // std::move into views::reverse
-      BidirRange view(buf, buf + 3);
-      ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3);
-      std::same_as<Subrange> auto result = std::views::reverse(std::move(subrange));
-      assert(base(result.begin()) == buf);
-      assert(base(result.end()) == buf + 3);
-    }
-    {
-      // with a const subrange
-      BidirRange view(buf, buf + 3);
-      ReverseSubrange const subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3);
-      std::same_as<Subrange> auto result = std::views::reverse(subrange);
-      assert(base(result.begin()) == buf);
-      assert(base(result.end()) == buf + 3);
-    }
-  }
-
-  // views::reverse(x) is equivalent to subrange{end, begin} if x is an
-  // unsized subrange over reverse iterators
-  {
-    using It = bidirectional_iterator<int*>;
-    using Subrange = std::ranges::subrange<It, It, std::ranges::subrange_kind::unsized>;
-
-    using ReverseIt = std::reverse_iterator<It>;
-    using ReverseSubrange = std::ranges::subrange<ReverseIt, ReverseIt, std::ranges::subrange_kind::unsized>;
 
     {
-      BidirRange view(buf, buf + 3);
-      ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)));
-      std::same_as<Subrange> auto result = std::views::reverse(subrange);
-      assert(base(result.begin()) == buf);
-      assert(base(result.end()) == buf + 3);
-    }
-    {
-      // std::move into views::reverse
-      BidirRange view(buf, buf + 3);
-      ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)));
-      std::same_as<Subrange> auto result = std::views::reverse(std::move(subrange));
-      assert(base(result.begin()) == buf);
-      assert(base(result.end()) == buf + 3);
-    }
-    {
-      // with a const subrange
-      BidirRange view(buf, buf + 3);
-      ReverseSubrange const subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)));
-      std::same_as<Subrange> auto result = std::views::reverse(subrange);
-      assert(base(result.begin()) == buf);
-      assert(base(result.end()) == buf + 3);
+      BidirView view(arr, arr + array_n);
+      const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(2);
+
+      const auto transform_stride_applied = transform_stride_partial(view);
+      auto transform_stride_applied_iter  = transform_stride_applied.begin();
+      assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[0]));
+      std::ranges::advance(transform_stride_applied_iter, 1);
+      assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[2]));
     }
   }
 
-  // Otherwise, views::reverse(x) is equivalent to ranges::reverse_view{x}
   {
-    BidirRange view(buf, buf + 3);
-    std::same_as<std::ranges::reverse_view<BidirRange>> auto result = std::views::reverse(view);
-    assert(base(result.begin().base()) == buf + 3);
-    assert(base(result.end().base()) == buf);
-  }
-
-  // Test that std::views::reverse is a range adaptor
-  {
-    // Test `v | views::reverse`
-    {
-      BidirRange view(buf, buf + 3);
-      std::same_as<std::ranges::reverse_view<BidirRange>> auto result = view | std::views::reverse;
-      assert(base(result.begin().base()) == buf + 3);
-      assert(base(result.end().base()) == buf);
-    }
-
-    // Test `adaptor | views::reverse`
-    {
-      BidirRange view(buf, buf + 3);
-      auto f = [](int i) { return i; };
-      auto const partial = std::views::transform(f) | std::views::reverse;
-      using Result = std::ranges::reverse_view<std::ranges::transform_view<BidirRange, decltype(f)>>;
-      std::same_as<Result> auto result = partial(view);
-      assert(base(result.begin().base().base()) == buf + 3);
-      assert(base(result.end().base().base()) == buf);
-    }
-
-    // Test `views::reverse | adaptor`
-    {
-      BidirRange view(buf, buf + 3);
-      auto f = [](int i) { return i; };
-      auto const partial = std::views::reverse | std::views::transform(f);
-      using Result = std::ranges::transform_view<std::ranges::reverse_view<BidirRange>, decltype(f)>;
-      std::same_as<Result> auto result = partial(view);
-      assert(base(result.begin().base().base()) == buf + 3);
-      assert(base(result.end().base().base()) == buf);
-    }
+    using ForwardStrideView      = std::ranges::stride_view<ForwardView>;
+    using BidirStrideView        = std::ranges::stride_view<BidirView>;
+    using RandomAccessStrideView = std::ranges::stride_view<RandomAccessView>;
+
+    static_assert(std::ranges::forward_range<ForwardStrideView>);
+    static_assert(std::ranges::bidirectional_range<BidirStrideView>);
+    static_assert(std::ranges::random_access_range<RandomAccessStrideView>);
+    // TODO: check sized_range
   }
-#endif // big block
 
-  // From:
-  // Test that std::views::reverse is a range adaptor
   // Check SFINAE friendliness
   {
     struct NotAViewableRange {};
-    struct NotABidirRange {};
+    struct NotARange {};
     // Not invocable because there is no parameter.
     static_assert(!std::is_invocable_v<decltype(std::views::stride)>);
     // Not invocable because NotAViewableRange is, well, not a viewable range.
@@ -176,8 +113,7 @@ constexpr bool test() {
     // Make sure that pipe operations work!
     static_assert(CanBePiped<BidirView, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
     static_assert(CanBePiped<BidirView&, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
-    static_assert(
-        !CanBePiped<NotABidirRange, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
+    static_assert(!CanBePiped<NotARange, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
   }
   // A final sanity check.
   { static_assert(std::same_as<decltype(std::views::stride), decltype(std::ranges::views::stride)>); }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index d9931cb6e63202..d06ef2c3b923c8 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -15,15 +15,17 @@
 
 template <typename T = int>
 struct InstrumentedBasicRange {
-  T *begin() const;
-  T *end() const;
+  T* begin() const;
+  T* end() const;
 };
 
 template <typename T = int>
 struct InstrumentedBasicView : std::ranges::view_base {
   constexpr explicit InstrumentedBasicView(T* b, T* e) : begin_(b), end_(e) {}
-  constexpr InstrumentedBasicView(InstrumentedBasicView const& other) : begin_(other.begin_), end_(other.end_), wasCopyInitialized(true) {}
-  constexpr InstrumentedBasicView(InstrumentedBasicView&& other) : begin_(other.begin_), end_(other.end_), wasMoveInitialized(true) {}
+  constexpr InstrumentedBasicView(InstrumentedBasicView const& other)
+      : begin_(other.begin_), end_(other.end_), wasCopyInitialized(true) {}
+  constexpr InstrumentedBasicView(InstrumentedBasicView&& other)
+      : begin_(other.begin_), end_(other.end_), wasMoveInitialized(true) {}
   InstrumentedBasicView& operator=(InstrumentedBasicView const&) = default;
   InstrumentedBasicView& operator=(InstrumentedBasicView&&)      = default;
   constexpr T* begin() const { return begin_; }
@@ -141,13 +143,55 @@ struct BidirView : std::ranges::view_base {
 
   constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{begin_}; }
   constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{begin_}; }
-  constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>{end_}; }
-  constexpr bidirectional_iterator<const int*> end() const { return bidirectional_iterator<const int*>{end_}; }
+  constexpr sentinel_wrapper<bidirectional_iterator<int*>> end() {
+    return sentinel_wrapper<bidirectional_iterator<int*>>{bidirectional_iterator<int*>{end_}};
+  }
+  constexpr sentinel_wrapper<bidirectional_iterator<const int*>> end() const {
+    return sentinel_wrapper<bidirectional_iterator<const int*>>{bidirectional_iterator<const int*>{end_}};
+  }
 };
 
 static_assert(std::ranges::view<BidirView>);
 static_assert(std::copyable<BidirView>);
 
+struct ForwardView : public std::ranges::view_base {
+  int* begin_;
+  int* end_;
+
+  constexpr ForwardView(int* b, int* e) : begin_(b), end_(e) {}
+
+  constexpr forward_iterator<int*> begin() { return forward_iterator<int*>{begin_}; }
+  constexpr forward_iterator<const int*> begin() const { return forward_iterator<const int*>{begin_}; }
+  constexpr sentinel_wrapper<forward_iterator<int*>> end() {
+    return sentinel_wrapper<forward_iterator<int*>>{forward_iterator<int*>{end_}};
+  }
+  constexpr sentinel_wrapper<forward_iterator<const int*>> end() const {
+    return sentinel_wrapper<forward_iterator<const int*>>{forward_iterator<const int*>{end_}};
+  }
+};
+
+static_assert(std::ranges::view<ForwardView>);
+static_assert(std::copyable<ForwardView>);
+
+struct RandomAccessView : std::ranges::view_base {
+  int* begin_;
+  int* end_;
+
+  constexpr RandomAccessView(int* b, int* e) : begin_(b), end_(e) {}
+
+  constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{begin_}; }
+  //constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; }
+  constexpr sentinel_wrapper<random_access_iterator<int*>> end() {
+    return sentinel_wrapper<random_access_iterator<int*>>{random_access_iterator<int*>{end_}};
+  }
+  //constexpr sentinel_wrapper<random_access_iterator<const int*>> end() const { return sentinel_wrapper<random_access_iterator<const int*>>{random_access_iterator<const int*>{end_}}; }
+  constexpr std::size_t size() const { return end_ - begin_; }
+};
+
+static_assert(std::ranges::view<RandomAccessView>);
+static_assert(std::ranges::random_access_range<RandomAccessView>);
+static_assert(std::copyable<RandomAccessView>);
+
 /*
 enum CopyCategory { MoveOnly, Copyable };
 template <CopyCategory CC>

>From 8814ddd4406e6367a901d03953ec745c6eeb7a45 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Sun, 10 Sep 2023 14:01:14 -0400
Subject: [PATCH 05/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fix typo in begin for random_access_range.
---
 libcxx/include/__ranges/stride_view.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 880c8ce2950e47..f85247c825d815 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -257,7 +257,7 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
     return *this += -__s;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator[](difference_type __s) const
+  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __s) const
     requires random_access_range<_Base>
   {
     return *(*this + __s);

>From 0d286dc8e51a4b5e232ee620bccb2e47e4f060af Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 11 Sep 2023 10:03:21 -0400
Subject: [PATCH 06/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add test for no default ctor.
---
 .../range.stride.view/ctor.default.pass.cpp   | 29 +++++++++++++++++++
 1 file changed, 29 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.default.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.default.pass.cpp
new file mode 100644
index 00000000000000..09cb8c20ea3185
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.default.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include "test.h"
+#include <type_traits>
+
+constexpr bool test() {
+  // There is no default ctor for stride_view.
+  static_assert(!std::is_default_constructible_v<std::ranges::stride_view<BidirView>>);
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From e5ad90c511eb549285427675fa2ebdd077c878c6 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 13 Sep 2023 09:29:41 -0400
Subject: [PATCH 08/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Address comments from @EricWF.
---
 libcxx/include/__ranges/stride_view.h | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index f85247c825d815..ff3b36073efa18 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -148,6 +148,18 @@ class stride_view : public view_interface<stride_view<_View>> {
   }
 }; // class stride_view
 
+template<class _View>
+struct __stride_view_iterator_concept { using type = input_iterator_tag; };
+
+template<random_access_range _View>
+struct __stride_view_iterator_concept<_View> { using type = random_access_iterator_tag; };
+
+template<bidirectional_range _View>
+struct __stride_view_iterator_concept<_View> { using type = bidirectional_iterator_tag; };
+
+template<forward_range _View>
+struct __stride_view_iterator_concept<_View> { using type = forward_iterator_tag; };
+
 template <class _View>
 struct __stride_iterator_category {};
 
@@ -170,14 +182,7 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
 public:
   using difference_type = range_difference_t<_Base>;
   using value_type      = range_value_t<_Base>;
-  using iterator_concept =
-      _If<random_access_range<_Base>,
-          random_access_iterator_tag,
-          _If<bidirectional_range<_Base>,
-              bidirectional_iterator_tag,
-              _If<forward_range<_Base>,
-                  forward_iterator_tag,
-                  /* else */ input_iterator_tag >>>;
+  using iterator_concept = typename __stride_view_iterator_concept<_View>::type;
 
   _LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_Base> __current_     = iterator_t<_Base>();
   _LIBCPP_NO_UNIQUE_ADDRESS ranges::sentinel_t<_Base> __end_ = ranges::sentinel_t<_Base>();
@@ -392,7 +397,6 @@ stride_view(_Range&&) -> stride_view<views::all_t<_Range>>;
 
 namespace views {
 namespace __stride {
-// removed this.
 struct __fn {
   template <viewable_range _Range>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, range_difference_t<_Range> __n) const

>From c3948e90daadd3cdbae88eaed57daca7f9185a60 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 13 Sep 2023 09:47:11 -0400
Subject: [PATCH 09/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Forgot to run clang-format before commiting.
---
 libcxx/include/__ranges/stride_view.h | 28 +++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index ff3b36073efa18..fc1fb89b3ba0ed 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -148,17 +148,25 @@ class stride_view : public view_interface<stride_view<_View>> {
   }
 }; // class stride_view
 
-template<class _View>
-struct __stride_view_iterator_concept { using type = input_iterator_tag; };
+template <class _View>
+struct __stride_view_iterator_concept {
+  using type = input_iterator_tag;
+};
 
-template<random_access_range _View>
-struct __stride_view_iterator_concept<_View> { using type = random_access_iterator_tag; };
+template <random_access_range _View>
+struct __stride_view_iterator_concept<_View> {
+  using type = random_access_iterator_tag;
+};
 
-template<bidirectional_range _View>
-struct __stride_view_iterator_concept<_View> { using type = bidirectional_iterator_tag; };
+template <bidirectional_range _View>
+struct __stride_view_iterator_concept<_View> {
+  using type = bidirectional_iterator_tag;
+};
 
-template<forward_range _View>
-struct __stride_view_iterator_concept<_View> { using type = forward_iterator_tag; };
+template <forward_range _View>
+struct __stride_view_iterator_concept<_View> {
+  using type = forward_iterator_tag;
+};
 
 template <class _View>
 struct __stride_iterator_category {};
@@ -180,8 +188,8 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
   using _Base   = __maybe_const<_Const, _View>;
 
 public:
-  using difference_type = range_difference_t<_Base>;
-  using value_type      = range_value_t<_Base>;
+  using difference_type  = range_difference_t<_Base>;
+  using value_type       = range_value_t<_Base>;
   using iterator_concept = typename __stride_view_iterator_concept<_View>::type;
 
   _LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_Base> __current_     = iterator_t<_Base>();

>From f0d0f20ba66a4dd4d342f114645354b44af4ee6e Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 15 Sep 2023 09:54:24 -0400
Subject: [PATCH 10/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Respond to JMazurkiewicz's helpful comments.
---
 libcxx/include/__ranges/stride_view.h         | 34 ++++---------------
 libcxx/include/module.modulemap.in            |  2 +-
 libcxx/modules/std/ranges.inc                 |  2 ++
 .../range.stride.view/stride.pass.cpp         | 32 +++++++++++++++++
 4 files changed, 41 insertions(+), 29 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index fc1fb89b3ba0ed..9bf30e6c2815b9 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -25,7 +25,6 @@
 #include <__iterator/iter_swap.h>
 #include <__iterator/iterator_traits.h>
 #include <__iterator/next.h>
-#include <__iterator/reverse_iterator.h>
 #include <__ranges/access.h>
 #include <__ranges/all.h>
 #include <__ranges/concepts.h>
@@ -69,8 +68,6 @@ class stride_view : public view_interface<stride_view<_View>> {
 
   template <bool _Const>
   class __iterator;
-  template <bool _Const>
-  class __sentinel;
 
 public:
   _LIBCPP_HIDE_FROM_ABI constexpr explicit stride_view(_View __base, range_difference_t<_View> __stride)
@@ -84,16 +81,16 @@ class stride_view : public view_interface<stride_view<_View>> {
 
   _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto stride() { return __stride_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr range_difference_t<_View> stride() const noexcept { return __stride_; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto size()
-    requires ranges::sized_range<_View>
+    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 ranges::sized_range<const _View>
+    requires sized_range<const _View>
   {
     return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
   }
@@ -105,7 +102,7 @@ class stride_view : public view_interface<stride_view<_View>> {
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
-    requires ranges::range<const _View>
+    requires range<const _View>
   {
     return __iterator<true>{*this, ranges::begin(__base_)};
   }
@@ -203,8 +200,8 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
   = default;
 
   _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
-    requires _Const && std::convertible_to<ranges::iterator_t<_View>, ranges::iterator_t<_Base>> &&
-                 std::convertible_to<ranges::sentinel_t<_View>, ranges::sentinel_t<_Base>>
+    requires _Const && std::convertible_to<ranges::iterator_t<_View>, iterator_t<_Base>> &&
+                 std::convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
       : __current_(std::move(__i.__current_)),
         __end_(std::move(__i.__end_)),
         __stride_(__i.__stride_),
@@ -381,25 +378,6 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
   }
 }; // class stride_view::__iterator
 
-template <input_range _View>
-  requires view<_View>
-template <bool _Const>
-class stride_view<_View>::__sentinel {
-public:
-  sentinel_t<_View> __end_ = sentinel_t<_View>();
-
-  _LIBCPP_HIDE_FROM_ABI __sentinel() = default;
-
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(stride_view<_View>& __parent)
-      : __end_(ranges::end(__parent.__base_)) {}
-
-  _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_View> base() const { return __end_; }
-
-  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator<true> const& __x, __sentinel const& __y) {
-    return __x.__current_ == __y.__end_;
-  }
-}; // class stride_view::__sentinel
-
 template <class _Range>
 stride_view(_Range&&) -> stride_view<views::all_t<_Range>>;
 
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index d73885bbf39206..f9c841fd18872f 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1697,7 +1697,7 @@ module std_private_ranges_size                       [system] {
   export std_private_type_traits_make_unsigned
 }
 module std_private_ranges_split_view                 [system] { header "__ranges/split_view.h" }
-module std_private_ranges_stride_view                 [system] { header "__ranges/stride_view.h" }
+module std_private_ranges_stride_view                [system] { header "__ranges/stride_view.h" }
 module std_private_ranges_subrange                   [system] {
   header "__ranges/subrange.h"
   export std_private_ranges_subrange_fwd
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index 0f418971c700da..85384202e4758c 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -276,12 +276,14 @@ export namespace std {
     } // namespace views
 #endif // _LIBCPP_STD_VER >= 23
 
+#if _LIBCPP_STD_VER >= 23
     // [range.stride], stride view
     using std::ranges::stride_view;
 
     namespace views {
       using std::ranges::views::stride;
     }
+#endif // _LIBCPP_STD_VER >= 23
 
 #if 0
     // [range.zip.transform], zip transform view
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
new file mode 100644
index 00000000000000..80092fc6738703
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include "test.h"
+#include <ranges>
+#include <type_traits>
+#include <utility>
+
+constexpr bool test() {
+  static_assert(noexcept(std::declval<std::ranges::stride_view<BidirView>>().stride()));
+  static_assert(std::is_same_v<std::ranges::range_difference_t<BidirView>,
+                               decltype(std::declval<std::ranges::stride_view<BidirView>>().stride())>);
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 9bc1121f038a743cd5835048fdfe9d6d37018f59 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 15 Sep 2023 18:21:54 -0400
Subject: [PATCH 11/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Make aspects of std::ranges::stride_view::__iterator private.
---
 libcxx/include/__ranges/stride_view.h         | 12 ++--
 .../iterator/ctor.default.pass.cpp            | 13 +++--
 .../range.adaptors/range.stride.view/test.h   | 58 +++++++++----------
 3 files changed, 44 insertions(+), 39 deletions(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 9bf30e6c2815b9..e2ef0cdc30ee54 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -184,16 +184,18 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
   using _Parent = __maybe_const<_Const, stride_view<_View>>;
   using _Base   = __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;
+
 public:
   using difference_type  = range_difference_t<_Base>;
   using value_type       = range_value_t<_Base>;
   using iterator_concept = typename __stride_view_iterator_concept<_View>::type;
 
-  _LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_Base> __current_     = iterator_t<_Base>();
-  _LIBCPP_NO_UNIQUE_ADDRESS ranges::sentinel_t<_Base> __end_ = ranges::sentinel_t<_Base>();
-  difference_type __stride_                                  = 0;
-  difference_type __missing_                                 = 0;
-
   // using iterator_category = inherited;
   _LIBCPP_HIDE_FROM_ABI __iterator()
     requires default_initializable<iterator_t<_Base>>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index d0f466d3adeaef..a4a6ba56727663 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -15,16 +15,19 @@
 #include "../test.h"
 #include <cassert>
 #include <ranges>
+#include <type_traits>
 
-bool non_simple_view_iter_ctor_test() {
-  using StrideView             = std::ranges::stride_view<InstrumentedNotSimpleView>;
+constexpr bool non_simple_view_iter_ctor_test() {
+  using StrideView             = std::ranges::stride_view<NotSimpleView>;
   using StrideViewIterNonConst = std::ranges::iterator_t<StrideView>;
   using StrideViewIterConst    = std::ranges::iterator_t<const StrideView>;
 
-  StrideView sv{InstrumentedNotSimpleView{}, 1};
+  StrideView sv{NotSimpleView{}, 1};
   StrideViewIterNonConst iter = {sv, sv.base().begin(), 0};
-  StrideViewIterConst iterb   = {iter};
-  assert(iterb.__end_.moved_from_a == true);
+  // StrideViewIterNonConst constructs its new __current_ and __end_ by
+  // moving the same members from the given iterator. When that is not possible
+  // for either of those two values, it should fail.
+  static_assert(!std::is_constructible_v<StrideViewIterConst, decltype(iter)>);
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index d06ef2c3b923c8..e6640cd892e9d6 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -84,40 +84,40 @@ struct InputIterBase {
   friend constexpr bool operator==(const InputIterBase&, const InputIterBase&) { return true; }
 };
 
-struct NotSimpleViewIterB : ForwardIterBase<NotSimpleViewIterB> {
-  bool moved = false;
-
-  constexpr NotSimpleViewIterB()                          = default;
-  constexpr NotSimpleViewIterB(const NotSimpleViewIterB&) = default;
-  constexpr NotSimpleViewIterB(NotSimpleViewIterB&&) : moved{true} {}
-  constexpr NotSimpleViewIterB& operator=(NotSimpleViewIterB&&)      = default;
-  constexpr NotSimpleViewIterB& operator=(const NotSimpleViewIterB&) = default;
+struct NotSimpleViewIter : ForwardIterBase<NotSimpleViewIter> {
+  constexpr NotSimpleViewIter()                                    = default;
+  constexpr NotSimpleViewIter(const NotSimpleViewIter&)            = default;
+  constexpr NotSimpleViewIter(NotSimpleViewIter&&)                 = default;
+  constexpr NotSimpleViewIter& operator=(NotSimpleViewIter&&)      = default;
+  constexpr NotSimpleViewIter& operator=(const NotSimpleViewIter&) = default;
 };
 
-struct NotSimpleViewIterA : ForwardIterBase<NotSimpleViewIterA> {
-  bool moved         = false;
-  bool moved_from_a  = false;
-  bool copied_from_a = false;
-
-  constexpr NotSimpleViewIterA()                          = default;
-  constexpr NotSimpleViewIterA(const NotSimpleViewIterA&) = default;
-  constexpr NotSimpleViewIterA(const NotSimpleViewIterB&) : copied_from_a{true} {}
-  constexpr NotSimpleViewIterA(NotSimpleViewIterA&&) : moved{true} {}
-  constexpr NotSimpleViewIterA(NotSimpleViewIterB&&) : moved_from_a{true} {}
-  constexpr NotSimpleViewIterA& operator=(NotSimpleViewIterA&&)      = default;
-  constexpr NotSimpleViewIterA& operator=(const NotSimpleViewIterA&) = default;
+struct NotSimpleViewIterEnd : ForwardIterBase<NotSimpleViewIter> {
+  constexpr NotSimpleViewIterEnd()                                       = default;
+  constexpr NotSimpleViewIterEnd(const NotSimpleViewIterEnd&)            = default;
+  constexpr NotSimpleViewIterEnd(NotSimpleViewIterEnd&&)                 = default;
+  constexpr NotSimpleViewIterEnd& operator=(NotSimpleViewIterEnd&&)      = default;
+  constexpr NotSimpleViewIterEnd& operator=(const NotSimpleViewIterEnd&) = default;
 };
 
-struct InstrumentedNotSimpleView : std::ranges::view_base {
-  constexpr NotSimpleViewIterA begin() const { return {}; }
-  constexpr NotSimpleViewIterB begin() { return {}; }
-  constexpr NotSimpleViewIterA end() const { return {}; }
-  constexpr NotSimpleViewIterB end() { return {}; }
+struct ConstNotSimpleViewIter : ForwardIterBase<ConstNotSimpleViewIter> {
+  constexpr ConstNotSimpleViewIter()                              = default;
+  constexpr ConstNotSimpleViewIter(const ConstNotSimpleViewIter&) = default;
+  constexpr ConstNotSimpleViewIter(const NotSimpleViewIter&) {}
+  constexpr ConstNotSimpleViewIter(ConstNotSimpleViewIter&&) = default;
 
-  int* begin_;
-  int* end_;
-  bool wasCopyInitialized = false;
-  bool wasMoveInitialized = false;
+  constexpr ConstNotSimpleViewIter(NotSimpleViewIter&&) {}
+  constexpr ConstNotSimpleViewIter(NotSimpleViewIterEnd&&) = delete;
+
+  constexpr ConstNotSimpleViewIter& operator=(ConstNotSimpleViewIter&&)      = default;
+  constexpr ConstNotSimpleViewIter& operator=(const ConstNotSimpleViewIter&) = default;
+};
+
+struct NotSimpleView : std::ranges::view_base {
+  constexpr ConstNotSimpleViewIter begin() const { return {}; }
+  constexpr NotSimpleViewIter begin() { return {}; }
+  constexpr ConstNotSimpleViewIter end() const { return {}; }
+  constexpr NotSimpleViewIterEnd end() { return {}; }
 };
 
 struct ForwardTracedMoveIter : ForwardIterBase<ForwardTracedMoveIter> {

>From 12ddc6f2f7c0a7ede0e5f237747b3520c8af07ea Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 18 Sep 2023 12:31:07 -0400
Subject: [PATCH 12/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Remove duplicate module declaration of stride_view.
---
 libcxx/modules/std/ranges.inc | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index 85384202e4758c..7066c26011f14a 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -282,7 +282,7 @@ export namespace std {
 
     namespace views {
       using std::ranges::views::stride;
-    }
+    } // namespace views
 #endif // _LIBCPP_STD_VER >= 23
 
 #if 0
@@ -331,13 +331,6 @@ export namespace std {
     }
 #endif // _LIBCPP_STD_VER >= 23
 
-    // [range.stride], stride view
-    using std::ranges::stride_view;
-
-    namespace views {
-      using std::ranges::views::stride;
-    }
-
 #if 0
     using std::ranges::cartesian_product_view;
 

>From 4f6ee2d9fa34ba0529d93185164e8c9142722c67 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 4 Oct 2023 19:44:22 -0400
Subject: [PATCH 13/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Address first of Konstantin's helpful comments.
---
 libcxx/include/__ranges/stride_view.h         | 92 ++++++++++---------
 .../range.stride.view/ctor.pass.cpp           | 32 +++++++
 .../iterator/ctor.default.pass.cpp            | 44 ++++-----
 3 files changed, 101 insertions(+), 67 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index e2ef0cdc30ee54..47ecf3c5850667 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -71,7 +71,9 @@ class stride_view : public view_interface<stride_view<_View>> {
 
 public:
   _LIBCPP_HIDE_FROM_ABI constexpr explicit stride_view(_View __base, range_difference_t<_View> __stride)
-      : __base_(std::move(__base)), __stride_(__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>
@@ -83,68 +85,72 @@ class stride_view : public view_interface<stride_view<_View>> {
 
   _LIBCPP_HIDE_FROM_ABI constexpr range_difference_t<_View> stride() const noexcept { return __stride_; }
 
-  _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_));
-  }
-
   _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
     requires(!__simple_view<_View>)
   {
-    return __iterator<false>{*this, ranges::begin(__base_)};
+    return __iterator<false>(this, ranges::begin(__base_));
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
     requires range<const _View>
   {
-    return __iterator<true>{*this, ranges::begin(__base_)};
+    return __iterator<true>(this, ranges::begin(__base_));
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto end()
     requires(!__simple_view<_View> && 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};
+    return __iterator<false>(this, ranges::end(__base_), __missing);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto end()
     requires(!__simple_view<_View> && common_range<_View> && !bidirectional_range<_View>)
   {
-    return __iterator<false>{*this, ranges::end(__base_)};
+    return __iterator<false>(this, ranges::end(__base_));
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto end()
     requires(!__simple_view<_View>)
   {
-    return std::default_sentinel;
+    return default_sentinel;
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
     requires(range<const _View> && 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};
+    return __iterator<true>(this, ranges::end(__base_), __missing);
   }
   _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
     requires(range<const _View> && common_range<_View> && !bidirectional_range<_View>)
   {
-    return __iterator<true>{*this, ranges::end(__base_)};
+    return __iterator<true>(this, ranges::end(__base_));
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
     requires(range<const _View>)
   {
-    return std::default_sentinel;
+    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>>;
+
+namespace views {
 template <class _View>
 struct __stride_view_iterator_concept {
   using type = input_iterator_tag;
@@ -191,31 +197,31 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
 
   friend stride_view;
 
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(
+      _Parent* __parent, ranges::iterator_t<_Base> __current, range_difference_t<_Base> __missing = 0)
+      : __current_(std::move(__current)),
+        __end_(ranges::end(__parent->__base_)),
+        __stride_(__parent->__stride_),
+        __missing_(__missing) {}
+
 public:
   using difference_type  = range_difference_t<_Base>;
   using value_type       = range_value_t<_Base>;
   using iterator_concept = typename __stride_view_iterator_concept<_View>::type;
-
   // 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 && std::convertible_to<ranges::iterator_t<_View>, iterator_t<_Base>> &&
-                 std::convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
+    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_) {}
 
-  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(
-      _Parent& __parent, ranges::iterator_t<_Base> __current, difference_type __missing = 0)
-      : __current_(std::move(__current)),
-        __end_(ranges::end(__parent.__base_)),
-        __stride_(__parent.__stride_),
-        __missing_(__missing) {}
-
   _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> const& base() const& noexcept { return __current_; }
   _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); }
 
@@ -250,29 +256,29 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
     return __tmp;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __s)
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n)
     requires random_access_range<_Base>
   {
-    if (__s > 0) {
-      ranges::advance(__current_, __stride_ * (__s - 1));
+    if (__n > 0) {
+      ranges::advance(__current_, __stride_ * (__n - 1));
       __missing_ = ranges::advance(__current_, __stride_, __end_);
-    } else if (__s < 0) {
-      ranges::advance(__current_, __stride_ * __s + __missing_);
+    } else if (__n < 0) {
+      ranges::advance(__current_, __stride_ * __n + __missing_);
       __missing_ = 0;
     }
     return *this;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __s)
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
     requires random_access_range<_Base>
   {
-    return *this += -__s;
+    return *this += -__n;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __s) const
+  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const
     requires random_access_range<_Base>
   {
-    return *(*this + __s);
+    return *(*this + __n);
   }
 
   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, default_sentinel_t) {
@@ -380,17 +386,13 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
   }
 }; // class stride_view::__iterator
 
-template <class _Range>
-stride_view(_Range&&) -> stride_view<views::all_t<_Range>>;
-
-namespace views {
 namespace __stride {
 struct __fn {
   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};
+    return stride_view(std::forward<_Range>(__range), __n);
   }
 
   template <class _Np>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
new file mode 100644
index 00000000000000..126a7af66093e7
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include "test.h"
+#include <exception>
+#include <ranges>
+#include <type_traits>
+
+bool test() {
+  // Make sure that a constructor with a negative stride asserts.
+
+  int arr[] = {1, 2, 3};
+  ForwardView sc{arr, arr + 3};
+  auto sv = std::ranges::stride_view(sc, 0);
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index a4a6ba56727663..acd26c35a5db2b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -13,40 +13,40 @@
 // std::views::stride_view
 
 #include "../test.h"
+#include "__concepts/same_as.h"
+#include "__ranges/stride_view.h"
 #include <cassert>
 #include <ranges>
 #include <type_traits>
 
 constexpr bool non_simple_view_iter_ctor_test() {
-  using StrideView             = std::ranges::stride_view<NotSimpleView>;
-  using StrideViewIterNonConst = std::ranges::iterator_t<StrideView>;
-  using StrideViewIterConst    = std::ranges::iterator_t<const StrideView>;
-
-  StrideView sv{NotSimpleView{}, 1};
-  StrideViewIterNonConst iter = {sv, sv.base().begin(), 0};
-  // StrideViewIterNonConst constructs its new __current_ and __end_ by
-  // moving the same members from the given iterator. When that is not possible
-  // for either of those two values, it should fail.
-  static_assert(!std::is_constructible_v<StrideViewIterConst, decltype(iter)>);
-  return true;
-}
+  using NotSimpleStrideView     = std::ranges::stride_view<NotSimpleView>;
+  using NotSimpleStrideViewIter = std::ranges::iterator_t<NotSimpleStrideView>;
+
+  using SimpleStrideView     = std::ranges::stride_view<ForwardTracedMoveView>;
+  using SimpleStrideViewIter = std::ranges::iterator_t<SimpleStrideView>;
+
+  NotSimpleStrideView nsv{NotSimpleView{}, 1};
+  [[maybe_unused]] NotSimpleStrideViewIter nsv_iter = nsv.begin();
 
-constexpr bool simpleview_iter_ctor_test() {
-  using StrideView     = std::ranges::stride_view<ForwardTracedMoveView>;
-  using StrideViewIter = std::ranges::iterator_t<StrideView>;
+  SimpleStrideView sv{ForwardTracedMoveView{}, 1};
+  [[maybe_unused]] SimpleStrideViewIter ssv_iter = sv.begin();
 
-  StrideView sv{ForwardTracedMoveView{}, 1};
-  StrideViewIter iter = {sv, sv.base().begin(), 0};
-  // Guarantee that when the iterator is given to the constructor that
-  // it is moved there.
-  assert(iter.base().moved);
+  using NotSimpleStrideViewIterConst = std::ranges::iterator_t<const NotSimpleStrideView>;
+  using SimpleStrideViewIterConst    = std::ranges::iterator_t<const SimpleStrideView>;
 
+  // .begin on a stride view over a non-simple view will give us a
+  // stride_view iterator with its _Const == false. Compare that type
+  // with an iterator on a stride view over a simple view that will give
+  // us an iterator with its _Const == true. They should *not* be the same.
+  static_assert(!std::is_same_v<decltype(ssv_iter), decltype(nsv_iter)>);
+  static_assert(!std::is_same_v<NotSimpleStrideViewIterConst, decltype(nsv_iter)>);
+  static_assert(std::is_same_v<SimpleStrideViewIterConst, decltype(ssv_iter)>);
   return true;
 }
 
 int main(int, char**) {
-  simpleview_iter_ctor_test();
   non_simple_view_iter_ctor_test();
-  static_assert(simpleview_iter_ctor_test());
+  static_assert(non_simple_view_iter_ctor_test());
   return 0;
 }

>From bb41260ef2f454f9c21f41b55d529359b6825d1b Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Thu, 5 Oct 2023 22:47:19 -0400
Subject: [PATCH 14/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add the first (of hopefully many more) precondition check tests.
---
 .../range.stride.view/ctor.assert.pass.cpp    | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
new file mode 100644
index 00000000000000..89c55d434745dc
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: no-exceptions
+// UNSUPPORTED: !libcpp-hardening-mode=debug
+// XFAIL: availability-verbose_abort-missing
+
+// <ranges>
+
+// Call stride_view() ctor empty stride <= 0
+
+#include "check_assertion.h"
+#include <ranges>
+
+void test() {
+  int range[] = {1, 2, 3};
+  // Keep up to date with assertion message from the ctor.
+  TEST_LIBCPP_ASSERT_FAILURE(
+      [&range] { std::ranges::stride_view sv(range, 0); }(), "The value of stride must be greater than 0");
+  TEST_LIBCPP_ASSERT_FAILURE(
+      [&range] { std::ranges::stride_view sv(range, -1); }(), "The value of stride must be greater than 0");
+}
+
+int main() {
+  test();
+  return 0;
+}

>From b927fe058e92ecea514320293e0edef7108e20b2 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Thu, 5 Oct 2023 23:04:20 -0400
Subject: [PATCH 15/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Remove unneeded includes and a redundant test.
---
 libcxx/include/__ranges/stride_view.h         | 21 ------------
 .../range.stride.view/ctor.pass.cpp           | 32 -------------------
 2 files changed, 53 deletions(-)
 delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 47ecf3c5850667..4ccd7051a4c232 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -12,34 +12,13 @@
 
 #include <__config>
 
-#include <__compare/three_way_comparable.h>
-#include <__concepts/constructible.h>
-#include <__concepts/convertible_to.h>
-#include <__concepts/derived_from.h>
 #include <__functional/bind_back.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 <__iterator/next.h>
-#include <__ranges/access.h>
 #include <__ranges/all.h>
 #include <__ranges/concepts.h>
-#include <__ranges/enable_borrowed_range.h>
-#include <__ranges/non_propagating_cache.h>
-#include <__ranges/range_adaptor.h>
-#include <__ranges/size.h>
-#include <__ranges/subrange.h>
 #include <__ranges/view_interface.h>
-#include <__ranges/views.h>
-#include <__type_traits/conditional.h>
-#include <__type_traits/maybe_const.h>
-#include <__type_traits/remove_cvref.h>
-#include <__utility/forward.h>
-#include <__utility/move.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
deleted file mode 100644
index 126a7af66093e7..00000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// ranges
-
-// std::views::stride_view
-
-#include "test.h"
-#include <exception>
-#include <ranges>
-#include <type_traits>
-
-bool test() {
-  // Make sure that a constructor with a negative stride asserts.
-
-  int arr[] = {1, 2, 3};
-  ForwardView sc{arr, arr + 3};
-  auto sv = std::ranges::stride_view(sc, 0);
-  return true;
-}
-
-int main(int, char**) {
-  test();
-  return 0;
-}

>From ddce4da98b7cd59b0ec1df4b315c274583f52567 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 6 Oct 2023 08:58:05 -0400
Subject: [PATCH 16/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Remove sentinel tests -- that class no longer exists.
---
 .../sentinel/ctor.default.pass.cpp            | 22 -------------------
 .../range.stride.view/sentinel/equal.pass.cpp | 22 -------------------
 2 files changed, 44 deletions(-)
 delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/ctor.default.pass.cpp
 delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/equal.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/ctor.default.pass.cpp
deleted file mode 100644
index 68556f32f875b1..00000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/ctor.default.pass.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// ranges
-
-// std::views::stride_view
-
-constexpr bool test() { return true; }
-
-int main(int, char**) {
-  test();
-  static_assert(test());
-
-  return 0;
-}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/equal.pass.cpp
deleted file mode 100644
index 68556f32f875b1..00000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/sentinel/equal.pass.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// ranges
-
-// std::views::stride_view
-
-constexpr bool test() { return true; }
-
-int main(int, char**) {
-  test();
-  static_assert(test());
-
-  return 0;
-}

>From af415a56ae63521963651282b42e99f78731d5a1 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 6 Oct 2023 09:04:27 -0400
Subject: [PATCH 17/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fix formatting of some test files.
---
 .../range.stride.view/base.pass.cpp           |  3 +-
 .../range.stride.view/ctad.compile.pass.cpp   | 28 ++++++-------------
 2 files changed, 11 insertions(+), 20 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
index 6b22b7e89c0158..4d06840ff7f8f3 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
@@ -45,7 +45,8 @@ constexpr bool test() {
   // Check the && overload (again)
   {
     InstrumentedBasicView range(buff, buff + 8);
-    std::same_as<InstrumentedBasicView<int>> decltype(auto) result = std::ranges::stride_view<InstrumentedBasicView<int>>(range, 3).base();
+    std::same_as<InstrumentedBasicView<int>> decltype(auto) result =
+        std::ranges::stride_view<InstrumentedBasicView<int>>(range, 3).base();
     assert(result.wasMoveInitialized);
     assert(result.begin() == buff);
     assert(result.end() == buff + 8);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
index 7831d792d64e77..ab8768502b1d06 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
@@ -23,24 +23,15 @@ constexpr bool test() {
   InstrumentedBasicView<int> bv{arr, arr + 3};
   InstrumentedBasicRange<int> br{};
 
-  static_assert(std::same_as<
-      decltype(std::ranges::stride_view(bv, 2)),
-      std::ranges::stride_view<decltype(bv)>
-  >);
-  static_assert(std::same_as<
-      decltype(std::ranges::stride_view(std::move(bv), 2)),
-      std::ranges::stride_view<decltype(bv)>
-  >);
-
-  static_assert(std::same_as<
-      decltype(std::ranges::drop_view(br, 0)),
-      std::ranges::drop_view<std::ranges::ref_view<InstrumentedBasicRange<int>>>
-  >);
-
-  static_assert(std::same_as<
-      decltype(std::ranges::drop_view(std::move(br), 0)),
-      std::ranges::drop_view<std::ranges::owning_view<InstrumentedBasicRange<int>>>
-  >);
+  static_assert(std::same_as< decltype(std::ranges::stride_view(bv, 2)), std::ranges::stride_view<decltype(bv)> >);
+  static_assert(
+      std::same_as< decltype(std::ranges::stride_view(std::move(bv), 2)), std::ranges::stride_view<decltype(bv)> >);
+
+  static_assert(std::same_as< decltype(std::ranges::drop_view(br, 0)),
+                              std::ranges::drop_view<std::ranges::ref_view<InstrumentedBasicRange<int>>> >);
+
+  static_assert(std::same_as< decltype(std::ranges::drop_view(std::move(br), 0)),
+                              std::ranges::drop_view<std::ranges::owning_view<InstrumentedBasicRange<int>>> >);
   return true;
 }
 
@@ -50,4 +41,3 @@ int main(int, char**) {
 
   return 0;
 }
-

>From 94f69853017120a1f6113b2072a08dcc7d4550a1 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 6 Oct 2023 17:20:49 -0400
Subject: [PATCH 18/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Rename ctor assertion tests.
---
 .../range.adaptors/range.stride.view/ctor.assert.pass.cpp     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
index 89c55d434745dc..54336576584802 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
@@ -18,7 +18,7 @@
 #include "check_assertion.h"
 #include <ranges>
 
-void test() {
+void stride_view_over_only_input_ranges() {
   int range[] = {1, 2, 3};
   // Keep up to date with assertion message from the ctor.
   TEST_LIBCPP_ASSERT_FAILURE(
@@ -28,6 +28,6 @@ void test() {
 }
 
 int main() {
-  test();
+  stride_view_over_only_input_ranges();
   return 0;
 }

>From 096f90df17fc28157d06ea03b10747ed2026a9d5 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 6 Oct 2023 17:21:38 -0400
Subject: [PATCH 19/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add test for input_range requirement.
---
 .../range.stride.view/concept.pass.cpp        | 57 +++++++++++++++++++
 .../range.adaptors/range.stride.view/test.h   |  5 ++
 2 files changed, 62 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp
new file mode 100644
index 00000000000000..ad23f7284fdd95
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include "__ranges/stride_view.h"
+#include "test.h"
+
+// Do not use for execution -- only useful for testing compilation/type conditions.
+template <typename T>
+struct non_input_iterator {
+  struct __invalid_iterator_tag {};
+  using value_type       = T;
+  using difference_type  = int;
+  using iterator_concept = __invalid_iterator_tag;
+
+  constexpr non_input_iterator& operator++() { return *this; }
+  constexpr void operator++(int) {}
+  constexpr T operator*() const { return T{}; }
+
+  friend constexpr bool operator==(const non_input_iterator&, const non_input_iterator&) { return true; }
+};
+
+template <typename T>
+inline constexpr bool std::ranges::enable_borrowed_range<non_input_iterator<T>> = true;
+
+class almost_input_range : public std::ranges::view_base {
+public:
+  constexpr auto begin() const { return non_input_iterator<int>{}; }
+  constexpr auto end() const { return non_input_iterator<int>{}; }
+};
+
+constexpr bool test() {
+  // Ensure that the almost_input_range is a valid range.
+  static_assert(std::ranges::range<almost_input_range>);
+  // Ensure that the non_input_iterator is, well, not an input iterator.
+  static_assert(!std::input_iterator<non_input_iterator<int>>);
+
+  static_assert(!CanStrideView<almost_input_range, 1>, "A non input range cannot be the subject of a stride view.");
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index e6640cd892e9d6..87c57d19d337c4 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -13,6 +13,11 @@
 #include <iterator>
 #include <ranges>
 
+template <typename I, std::ranges::range_difference_t<I> D>
+concept CanStrideView = requires {
+  std::ranges::stride_view<I>{I{}, D};
+};
+
 template <typename T = int>
 struct InstrumentedBasicRange {
   T* begin() const;

>From 82e844b1b2af0e2dc8ce76aa2b58cc57f7f4e01e Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 9 Oct 2023 12:27:21 -0400
Subject: [PATCH 20/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add additional testing for view requirements and explicit ctor.
---
 .../range.stride.view/concept.pass.cpp           | 13 ++++++++++++-
 .../{ctor.default.pass.cpp => ctor.pass.cpp}     | 16 ++++++++++++----
 .../range.adaptors/range.stride.view/test.h      |  2 ++
 3 files changed, 26 insertions(+), 5 deletions(-)
 rename libcxx/test/std/ranges/range.adaptors/range.stride.view/{ctor.default.pass.cpp => ctor.pass.cpp} (61%)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp
index ad23f7284fdd95..395ab4a55b9b8f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp
@@ -39,13 +39,24 @@ class almost_input_range : public std::ranges::view_base {
   constexpr auto end() const { return non_input_iterator<int>{}; }
 };
 
+class non_view_range {
+public:
+  constexpr int* begin() const { return nullptr; }
+  constexpr int* end() const { return nullptr; }
+};
+
 constexpr bool test() {
   // Ensure that the almost_input_range is a valid range.
   static_assert(std::ranges::range<almost_input_range>);
   // Ensure that the non_input_iterator is, well, not an input iterator.
   static_assert(!std::input_iterator<non_input_iterator<int>>);
-
   static_assert(!CanStrideView<almost_input_range, 1>, "A non input range cannot be the subject of a stride view.");
+
+  // Ensure that a range that is not a view cannot be the subject of a stride_view.
+  static_assert(std::ranges::range<non_view_range>, "non_view_range must be a range.");
+  static_assert(std::movable<non_view_range>, "non_view_range must be movable.");
+  static_assert(!std::ranges::view<non_view_range>, "A non-view range cannot be the subject of a stride_view.\n");
+
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
similarity index 61%
rename from libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.default.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
index 09cb8c20ea3185..6891b5e62a187a 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
@@ -13,17 +13,25 @@
 // std::views::stride_view
 
 #include "test.h"
+#include "test_convertible.h"
 #include <type_traits>
 
-constexpr bool test() {
+constexpr bool test_no_default_ctor() {
   // There is no default ctor for stride_view.
   static_assert(!std::is_default_constructible_v<std::ranges::stride_view<BidirView>>);
   return true;
 }
 
-int main(int, char**) {
-  test();
-  static_assert(test());
+constexpr bool test_no_implicit_ctor() {
+  // Test that the stride_view can only be explicitly constructed.
+  static_assert(!test_convertible<std::ranges::stride_view<ForwardView>, ForwardView, int>());
+  return true;
+}
 
+int main(int, char**) {
+  test_no_implicit_ctor();
+  static_assert(test_no_implicit_ctor());
+  test_no_default_ctor();
+  static_assert(test_no_default_ctor());
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 87c57d19d337c4..a0d5540c53f0f5 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -9,6 +9,8 @@
 #ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
 #define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
 
+#include "__concepts/movable.h"
+#include "__ranges/concepts.h"
 #include "test_iterators.h"
 #include <iterator>
 #include <ranges>

>From 0eb36ae635bb8108635551094647132157a72ef9 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 13 Oct 2023 01:00:59 -0400
Subject: [PATCH 21/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add additional testing for stride views over move-only types.
---
 .../range.stride.view/base.pass.cpp           | 38 +++++++-----
 .../range.stride.view/ctad.compile.pass.cpp   |  4 +-
 .../range.stride.view/ctor.pass.cpp           | 16 +++++
 .../enable_borrowed_range.compile.pass.cpp    |  2 +-
 .../range.adaptors/range.stride.view/test.h   | 62 +++++++++++++------
 5 files changed, 83 insertions(+), 39 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
index 4d06840ff7f8f3..062262ffde577c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
@@ -24,40 +24,46 @@ constexpr bool test() {
 
   // Check the const& overload
   {
-    InstrumentedBasicView range(buff, buff + 8);
-    std::ranges::stride_view<InstrumentedBasicView<int>> const view(range, 3);
-    std::same_as<InstrumentedBasicView<int>> decltype(auto) result = view.base();
-    assert(result.wasCopyInitialized);
+    bool moved(false), copied(false);
+    MovedCopiedTrackedBasicView range(buff, buff + 8, &moved, &copied);
+    std::ranges::stride_view<MovedCopiedTrackedBasicView<int>> const view(std::move(range), 3);
+    assert(moved);
+    assert(!copied);
+    std::same_as<MovedCopiedTrackedBasicView<int>> decltype(auto) result = view.base();
     assert(result.begin() == buff);
     assert(result.end() == buff + 8);
   }
 
   // Check the && overload
   {
-    InstrumentedBasicView<int> range(buff, buff + 8);
-    std::ranges::stride_view<InstrumentedBasicView<int>> view(range, 3);
-    std::same_as<InstrumentedBasicView<int>> decltype(auto) result = std::move(view).base();
-    assert(result.wasMoveInitialized);
+    bool moved(false), copied(false);
+    MovedCopiedTrackedBasicView range(buff, buff + 8, &moved, &copied);
+    std::ranges::stride_view<MovedCopiedTrackedBasicView<int>> view(std::move(range), 3);
+    assert(moved);
+    assert(!copied);
+    std::same_as<MovedCopiedTrackedBasicView<int>> decltype(auto) result = std::move(view).base();
     assert(result.begin() == buff);
     assert(result.end() == buff + 8);
   }
 
   // Check the && overload (again)
   {
-    InstrumentedBasicView range(buff, buff + 8);
-    std::same_as<InstrumentedBasicView<int>> decltype(auto) result =
-        std::ranges::stride_view<InstrumentedBasicView<int>>(range, 3).base();
-    assert(result.wasMoveInitialized);
+    bool moved(false), copied(false);
+    MovedCopiedTrackedBasicView range(buff, buff + 8, &moved, &copied);
+    std::same_as<MovedCopiedTrackedBasicView<int>> decltype(auto) result =
+        std::ranges::stride_view<MovedCopiedTrackedBasicView<int>>(std::move(range), 3).base();
+    assert(moved);
+    assert(!copied);
     assert(result.begin() == buff);
     assert(result.end() == buff + 8);
   }
 
   // Ensure the const& overload is not considered when the base is not copy-constructible
   {
-    static_assert(!can_call_base_on<std::ranges::stride_view<NoCopyView> const&>);
-    static_assert(!can_call_base_on<std::ranges::stride_view<NoCopyView>&>);
-    static_assert(can_call_base_on<std::ranges::stride_view<NoCopyView>&&>);
-    static_assert(can_call_base_on<std::ranges::stride_view<NoCopyView>>);
+    static_assert(!can_call_base_on<std::ranges::stride_view<MovedOnlyTrackedBasicView<>> const&>);
+    static_assert(!can_call_base_on<std::ranges::stride_view<MovedOnlyTrackedBasicView<>>&>);
+    static_assert(can_call_base_on<std::ranges::stride_view<MovedOnlyTrackedBasicView<>>&&>);
+    static_assert(can_call_base_on<std::ranges::stride_view<MovedOnlyTrackedBasicView<>>>);
   }
 
   return true;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
index ab8768502b1d06..4cceca699d2158 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
@@ -12,15 +12,15 @@
 
 // std::views::stride_view
 
+#include "test.h"
 #include <concepts>
 #include <ranges>
 #include <utility>
-#include "test.h"
 
 constexpr bool test() {
   int arr[]{1, 2, 3};
 
-  InstrumentedBasicView<int> bv{arr, arr + 3};
+  MovedCopiedTrackedBasicView<int> bv{arr, arr + 3};
   InstrumentedBasicRange<int> br{};
 
   static_assert(std::same_as< decltype(std::ranges::stride_view(bv, 2)), std::ranges::stride_view<decltype(bv)> >);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
index 6891b5e62a187a..a205386fa0a9d1 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
@@ -28,10 +28,26 @@ constexpr bool test_no_implicit_ctor() {
   return true;
 }
 
+constexpr bool test_move_ctor() {
+  int arr[] = {1, 2, 3};
+  // Test that the stride_view ctor properly moves from the base (and works with a move-only type).
+  static_assert(!std::is_copy_constructible_v<MovedOnlyTrackedBasicView<int>>);
+  static_assert(std::is_move_constructible_v<MovedOnlyTrackedBasicView<int>>);
+
+  bool moved(false), copied(false);
+  MovedOnlyTrackedBasicView<int> mov(arr, arr + 3, &moved, &copied);
+  std::ranges::stride_view<MovedOnlyTrackedBasicView<int>> mosv(std::move(mov), 2);
+  assert(moved);
+  assert(!copied);
+  return true;
+}
+
 int main(int, char**) {
   test_no_implicit_ctor();
   static_assert(test_no_implicit_ctor());
   test_no_default_ctor();
   static_assert(test_no_default_ctor());
+  test_move_ctor();
+  static_assert(test_move_ctor());
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
index 7c28842fe65f69..4add46949a6aec 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
@@ -19,7 +19,7 @@ constexpr bool test() {
   using std::ranges::enable_borrowed_range;
   // Make sure that a stride_view over neither a borrowable nor an unborrowable view
   // is itself borrowable.
-  static_assert(!enable_borrowed_range<std::ranges::stride_view<InstrumentedBasicView<int>>>);
+  static_assert(!enable_borrowed_range<std::ranges::stride_view<MovedCopiedTrackedBasicView<int>>>);
   static_assert(!enable_borrowed_range<std::ranges::stride_view<InstrumentedBorrowedRange<int>>>);
   return true;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index a0d5540c53f0f5..71120fb3577410 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -26,41 +26,63 @@ struct InstrumentedBasicRange {
   T* end() const;
 };
 
+struct MovedCopiedTrackedView {
+  constexpr explicit MovedCopiedTrackedView(bool* moved = nullptr, bool* copied = nullptr)
+      : wasMoveInitialized_(moved), wasCopyInitialized_(copied) {}
+  constexpr MovedCopiedTrackedView(MovedCopiedTrackedView const& other)
+      : wasMoveInitialized_(other.wasMoveInitialized_), wasCopyInitialized_(other.wasCopyInitialized_) {
+    *wasCopyInitialized_ = true;
+  }
+  constexpr MovedCopiedTrackedView(MovedCopiedTrackedView&& other)
+      : wasMoveInitialized_(other.wasMoveInitialized_), wasCopyInitialized_(other.wasCopyInitialized_) {
+    *wasMoveInitialized_ = true;
+  }
+  MovedCopiedTrackedView& operator=(MovedCopiedTrackedView const&) = default;
+  MovedCopiedTrackedView& operator=(MovedCopiedTrackedView&&)      = default;
+
+  bool* wasMoveInitialized_ = nullptr;
+  bool* wasCopyInitialized_ = nullptr;
+};
+
 template <typename T = int>
-struct InstrumentedBasicView : std::ranges::view_base {
-  constexpr explicit InstrumentedBasicView(T* b, T* e) : begin_(b), end_(e) {}
-  constexpr InstrumentedBasicView(InstrumentedBasicView const& other)
-      : begin_(other.begin_), end_(other.end_), wasCopyInitialized(true) {}
-  constexpr InstrumentedBasicView(InstrumentedBasicView&& other)
-      : begin_(other.begin_), end_(other.end_), wasMoveInitialized(true) {}
-  InstrumentedBasicView& operator=(InstrumentedBasicView const&) = default;
-  InstrumentedBasicView& operator=(InstrumentedBasicView&&)      = default;
+struct MovedCopiedTrackedBasicView : MovedCopiedTrackedView, std::ranges::view_base {
+  constexpr explicit MovedCopiedTrackedBasicView(T* b, T* e, bool* moved = nullptr, bool* copied = nullptr)
+      : MovedCopiedTrackedView(moved, copied), begin_(b), end_(e) {}
+  constexpr MovedCopiedTrackedBasicView(const MovedCopiedTrackedBasicView& other)
+      : MovedCopiedTrackedView(other), begin_(other.begin_), end_(other.end_) {}
+  constexpr MovedCopiedTrackedBasicView(MovedCopiedTrackedBasicView&& other)
+      : MovedCopiedTrackedView(std::move(other)), begin_(other.begin_), end_(other.end_) {}
+  MovedCopiedTrackedBasicView& operator=(MovedCopiedTrackedBasicView const&) = default;
+  MovedCopiedTrackedBasicView& operator=(MovedCopiedTrackedBasicView&&)      = default;
   constexpr T* begin() const { return begin_; }
   constexpr T* end() const { return end_; }
 
   T* begin_;
   T* end_;
-  bool wasCopyInitialized = false;
-  bool wasMoveInitialized = false;
 };
 
 template <typename T>
-InstrumentedBasicView(T, T) -> InstrumentedBasicView<T>;
+MovedCopiedTrackedBasicView(T, T, bool*, bool*) -> MovedCopiedTrackedBasicView<T>;
 
 template <typename T>
-struct InstrumentedBorrowedRange : public InstrumentedBasicView<T> {};
+struct InstrumentedBorrowedRange : public MovedCopiedTrackedBasicView<T> {};
 
 template <typename T>
 inline constexpr bool std::ranges::enable_borrowed_range<InstrumentedBorrowedRange<T>> = true;
 
-struct NoCopyView : std::ranges::view_base {
-  explicit NoCopyView(int*, int*);
-  NoCopyView(NoCopyView const&)            = delete;
-  NoCopyView(NoCopyView&&)                 = default;
-  NoCopyView& operator=(NoCopyView const&) = default;
-  NoCopyView& operator=(NoCopyView&&)      = default;
-  int* begin() const;
-  int* end() const;
+template <typename T = int>
+struct MovedOnlyTrackedBasicView : MovedCopiedTrackedView, std::ranges::view_base {
+  constexpr explicit MovedOnlyTrackedBasicView(T* b, T* e, bool* moved = nullptr, bool* copied = nullptr)
+      : MovedCopiedTrackedView(moved, copied), begin_(b), end_(e) {}
+  constexpr MovedOnlyTrackedBasicView(MovedOnlyTrackedBasicView&& other)
+      : MovedCopiedTrackedView(std::move(other)), begin_(other.begin_), end_(other.end_) {}
+  MovedOnlyTrackedBasicView& operator=(MovedOnlyTrackedBasicView const&) = delete;
+  MovedOnlyTrackedBasicView& operator=(MovedOnlyTrackedBasicView&&)      = default;
+  constexpr T* begin() const { return begin_; }
+  constexpr T* end() const { return end_; }
+
+  T* begin_;
+  T* end_;
 };
 
 template <class Derived>

>From 3a8b3f33fe62a98f37de410179d203f124371cda Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 13 Oct 2023 01:59:35 -0400
Subject: [PATCH 22/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fix formatting issue with adaptor.pass.cpp.
---
 .../ranges/range.adaptors/range.stride.view/adaptor.pass.cpp   | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
index ba0efe36b98243..60ed5587933a06 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -29,8 +29,7 @@ constexpr bool test() {
   int arr[array_n]      = {1, 2, 3};
 
   // Test that `std::views::stride` is a range adaptor.
-  {
-    // Check various forms of
+  { // Check various forms of
     // view | stride
     {
       {

>From d7fde5c1ed4c89db5d61f73087c5c6998b8466b4 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 13 Oct 2023 10:12:35 -0400
Subject: [PATCH 23/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add test for enable/disable size() when strided range is unsized.
---
 .../range.stride.view/size.pass.cpp           | 30 ++++++++++++++-----
 .../range.adaptors/range.stride.view/test.h   |  9 ++++++
 2 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp
index 981395f9e2c329..c270c77f6f9f32 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp
@@ -12,6 +12,7 @@
 
 // std::ranges::stride_view
 
+#include "test.h"
 #include <cassert>
 #include <ranges>
 
@@ -25,16 +26,29 @@ bool runtime_test() {
 
 constexpr bool test() {
   {
-    constexpr auto iot = std::views::iota(1, 12);
-    constexpr auto str = std::views::stride(iot, 3);
-    assert(4 == str.size());
-    static_assert(4 == str.size(), "Striding by 3 through a 12 member list has size 4.");
+    // Test with ranges that are sized_range true.
+    constexpr auto iot_twelve = std::views::iota(1, 12);
+    static_assert(std::ranges::sized_range<decltype(iot_twelve)>);
+    constexpr auto str_iot_twelve = std::views::stride(iot_twelve, 3);
+    static_assert(std::ranges::sized_range<decltype(str_iot_twelve)>);
+    assert(4 == str_iot_twelve.size());
+    static_assert(4 == str_iot_twelve.size(), "Striding by 3 through a 12 member list has size 4.");
+
+    constexpr auto iot_twenty_two = std::views::iota(1, 22);
+    static_assert(std::ranges::sized_range<decltype(iot_twenty_two)>);
+    constexpr auto str_iot_twenty_two = std::views::stride(iot_twenty_two, 3);
+    static_assert(std::ranges::sized_range<decltype(str_iot_twenty_two)>);
+
+    assert(7 == str_iot_twenty_two.size());
+    static_assert(7 == str_iot_twenty_two.size(), "Striding by 3 through a 22 member list has size 4.");
   }
+
   {
-    constexpr auto iot = std::views::iota(1, 22);
-    constexpr auto str = std::views::stride(iot, 3);
-    assert(7 == str.size());
-    static_assert(7 == str.size(), "Striding by 3 through a 12 member list has size 4.");
+    // Test with ranges that are not sized_range true.
+    constexpr auto unsized_range = UnsizedBasicRange();
+    static_assert(!std::ranges::sized_range<decltype(unsized_range)>);
+    constexpr auto str_unsized = std::views::stride(unsized_range, 3);
+    static_assert(!std::ranges::sized_range<decltype(str_unsized)>);
   }
   return true;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 71120fb3577410..8eb7423e03f651 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -11,6 +11,8 @@
 
 #include "__concepts/movable.h"
 #include "__ranges/concepts.h"
+#include "__ranges/enable_view.h"
+#include "__ranges/size.h"
 #include "test_iterators.h"
 #include <iterator>
 #include <ranges>
@@ -261,4 +263,11 @@ static_assert(std::ranges::view<BidirSentView<Copyable>>);
 static_assert(std::copyable<BidirSentView<Copyable>>);
 */
 
+struct UnsizedBasicRangeIterator : ForwardIterBase<UnsizedBasicRangeIterator> {};
+
+struct UnsizedBasicRange : std::ranges::view_base {
+  UnsizedBasicRangeIterator begin() const;
+  UnsizedBasicRangeIterator end() const;
+};
+
 #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H

>From 65dd587d5df8c9ce3a7edaa67b6d1435e93baddf Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 13 Oct 2023 18:11:49 -0400
Subject: [PATCH 24/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add test for iterator concept type and cleanup end() implementations.
---
 libcxx/include/__ranges/stride_view.h         |  76 +++++--------
 .../range.stride.view/iterator/begin.pass.cpp |  76 +++++++++++++
 .../range.adaptors/range.stride.view/test.h   | 100 +++++++-----------
 3 files changed, 145 insertions(+), 107 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 4ccd7051a4c232..0239a6c595df83 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -76,41 +76,30 @@ class stride_view : public view_interface<stride_view<_View>> {
     return __iterator<true>(this, ranges::begin(__base_));
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto end()
-    requires(!__simple_view<_View> && 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);
-  }
-
-  _LIBCPP_HIDE_FROM_ABI constexpr auto end()
-    requires(!__simple_view<_View> && common_range<_View> && !bidirectional_range<_View>)
-  {
-    return __iterator<false>(this, ranges::end(__base_));
-  }
-
   _LIBCPP_HIDE_FROM_ABI constexpr auto end()
     requires(!__simple_view<_View>)
   {
-    return default_sentinel;
-  }
-
-  _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
-    requires(range<const _View> && 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);
-  }
-  _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
-    requires(range<const _View> && common_range<_View> && !bidirectional_range<_View>)
-  {
-    return __iterator<true>(this, ranges::end(__base_));
+    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_));
+    } else {
+      return default_sentinel;
+    }
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
     requires(range<const _View>)
   {
-    return default_sentinel;
+    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_));
+    } else {
+      return default_sentinel;
+    }
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto size()
@@ -130,25 +119,6 @@ template <class _Range>
 stride_view(_Range&&, range_difference_t<_Range>) -> stride_view<views::all_t<_Range>>;
 
 namespace views {
-template <class _View>
-struct __stride_view_iterator_concept {
-  using type = input_iterator_tag;
-};
-
-template <random_access_range _View>
-struct __stride_view_iterator_concept<_View> {
-  using type = random_access_iterator_tag;
-};
-
-template <bidirectional_range _View>
-struct __stride_view_iterator_concept<_View> {
-  using type = bidirectional_iterator_tag;
-};
-
-template <forward_range _View>
-struct __stride_view_iterator_concept<_View> {
-  using type = forward_iterator_tag;
-};
 
 template <class _View>
 struct __stride_iterator_category {};
@@ -183,10 +153,22 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
         __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 = typename __stride_view_iterator_concept<_View>::type;
+  using iterator_concept = decltype(__get_stride_view_iterator_concept());
   // using iterator_category = inherited;
 
   _LIBCPP_HIDE_FROM_ABI __iterator()
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
new file mode 100644
index 00000000000000..3216a9ab85e84b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view::iterator
+
+#include "../test.h"
+#include "__iterator/concepts.h"
+#include "__ranges/stride_view.h"
+#include <ranges>
+#include <type_traits>
+
+constexpr bool iterator_concept_test() {
+  {
+    int arr[] = {1, 2, 3};
+    // Iterator of stride over random access view should have random access concept.
+    auto rav = RandomAccessView(arr, arr + 3);
+    auto str = std::ranges::stride_view<RandomAccessView>(rav, 1);
+    static_assert(std::random_access_iterator<decltype(rav.begin())>);
+    static_assert(std::random_access_iterator<decltype(str.begin())>);
+  }
+
+  {
+    int arr[] = {1, 2, 3};
+    // Iterator of stride over bidirectional view should have bidirectional view concept.
+    auto rav = BidirView(arr, arr + 3);
+    auto str = std::ranges::stride_view<BidirView>(rav, 1);
+    static_assert(std::bidirectional_iterator<decltype(rav.begin())>);
+    static_assert(std::bidirectional_iterator<decltype(str.begin())>);
+    static_assert(!std::random_access_iterator<decltype(rav.begin())>);
+    static_assert(!std::random_access_iterator<decltype(str.begin())>);
+  }
+
+  {
+    int arr[] = {1, 2, 3};
+    // Iterator of stride over forward view should have forward view concept.
+    auto rav = ForwardView(arr, arr + 3);
+    auto str = std::ranges::stride_view<ForwardView>(rav, 1);
+    static_assert(std::forward_iterator<decltype(rav.begin())>);
+    static_assert(std::forward_iterator<decltype(str.begin())>);
+    static_assert(!std::bidirectional_iterator<decltype(rav.begin())>);
+    static_assert(!std::bidirectional_iterator<decltype(str.begin())>);
+    static_assert(!std::random_access_iterator<decltype(rav.begin())>);
+    static_assert(!std::random_access_iterator<decltype(str.begin())>);
+  }
+
+  {
+    int arr[] = {1, 2, 3};
+    // Iterator of stride over forward view should have forward view concept.
+    auto rav = InputView(arr, arr + 3);
+    auto str = std::ranges::stride_view<InputView>(rav, 1);
+    static_assert(std::input_iterator<decltype(rav.begin())>);
+    static_assert(std::input_iterator<decltype(str.begin())>);
+    static_assert(!std::forward_iterator<decltype(rav.begin())>);
+    static_assert(!std::forward_iterator<decltype(str.begin())>);
+    static_assert(!std::bidirectional_iterator<decltype(rav.begin())>);
+    static_assert(!std::bidirectional_iterator<decltype(str.begin())>);
+    static_assert(!std::random_access_iterator<decltype(rav.begin())>);
+    static_assert(!std::random_access_iterator<decltype(str.begin())>);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  iterator_concept_test();
+  static_assert(iterator_concept_test());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 8eb7423e03f651..6bef25b8618882 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -151,21 +151,25 @@ struct NotSimpleView : std::ranges::view_base {
   constexpr NotSimpleViewIterEnd end() { return {}; }
 };
 
-struct ForwardTracedMoveIter : ForwardIterBase<ForwardTracedMoveIter> {
-  bool moved = false;
+struct RandomAccessView : std::ranges::view_base {
+  int* begin_;
+  int* end_;
 
-  constexpr ForwardTracedMoveIter()                             = default;
-  constexpr ForwardTracedMoveIter(const ForwardTracedMoveIter&) = default;
-  constexpr ForwardTracedMoveIter(ForwardTracedMoveIter&&) : moved{true} {}
-  constexpr ForwardTracedMoveIter& operator=(ForwardTracedMoveIter&&)      = default;
-  constexpr ForwardTracedMoveIter& operator=(const ForwardTracedMoveIter&) = default;
-};
+  constexpr RandomAccessView(int* b, int* e) : begin_(b), end_(e) {}
 
-struct ForwardTracedMoveView : std::ranges::view_base {
-  constexpr ForwardTracedMoveIter begin() const { return {}; }
-  constexpr ForwardTracedMoveIter end() const { return {}; }
+  constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{begin_}; }
+  //constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; }
+  constexpr sentinel_wrapper<random_access_iterator<int*>> end() {
+    return sentinel_wrapper<random_access_iterator<int*>>{random_access_iterator<int*>{end_}};
+  }
+  //constexpr sentinel_wrapper<random_access_iterator<const int*>> end() const { return sentinel_wrapper<random_access_iterator<const int*>>{random_access_iterator<const int*>{end_}}; }
+  constexpr std::size_t size() const { return end_ - begin_; }
 };
 
+static_assert(std::ranges::view<RandomAccessView>);
+static_assert(std::ranges::random_access_range<RandomAccessView>);
+static_assert(std::copyable<RandomAccessView>);
+
 struct BidirView : std::ranges::view_base {
   int* begin_;
   int* end_;
@@ -182,7 +186,23 @@ struct BidirView : std::ranges::view_base {
   }
 };
 
+struct ForwardTracedMoveIter : ForwardIterBase<ForwardTracedMoveIter> {
+  bool moved = false;
+
+  constexpr ForwardTracedMoveIter()                             = default;
+  constexpr ForwardTracedMoveIter(const ForwardTracedMoveIter&) = default;
+  constexpr ForwardTracedMoveIter(ForwardTracedMoveIter&&) : moved{true} {}
+  constexpr ForwardTracedMoveIter& operator=(ForwardTracedMoveIter&&)      = default;
+  constexpr ForwardTracedMoveIter& operator=(const ForwardTracedMoveIter&) = default;
+};
+
+struct ForwardTracedMoveView : std::ranges::view_base {
+  constexpr ForwardTracedMoveIter begin() const { return {}; }
+  constexpr ForwardTracedMoveIter end() const { return {}; }
+};
+
 static_assert(std::ranges::view<BidirView>);
+static_assert(std::ranges::bidirectional_range<BidirView>);
 static_assert(std::copyable<BidirView>);
 
 struct ForwardView : public std::ranges::view_base {
@@ -202,66 +222,26 @@ struct ForwardView : public std::ranges::view_base {
 };
 
 static_assert(std::ranges::view<ForwardView>);
+static_assert(std::ranges::forward_range<ForwardView>);
 static_assert(std::copyable<ForwardView>);
 
-struct RandomAccessView : std::ranges::view_base {
+struct InputView : std::ranges::view_base {
   int* begin_;
   int* end_;
 
-  constexpr RandomAccessView(int* b, int* e) : begin_(b), end_(e) {}
+  constexpr InputView(int* b, int* e) : begin_(b), end_(e) {}
 
-  constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{begin_}; }
+  constexpr cpp20_input_iterator<int*> begin() { return cpp20_input_iterator<int*>{begin_}; }
   //constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; }
-  constexpr sentinel_wrapper<random_access_iterator<int*>> end() {
-    return sentinel_wrapper<random_access_iterator<int*>>{random_access_iterator<int*>{end_}};
+  constexpr sentinel_wrapper<cpp20_input_iterator<int*>> end() {
+    return sentinel_wrapper<cpp20_input_iterator<int*>>{cpp20_input_iterator<int*>{end_}};
   }
-  //constexpr sentinel_wrapper<random_access_iterator<const int*>> end() const { return sentinel_wrapper<random_access_iterator<const int*>>{random_access_iterator<const int*>{end_}}; }
   constexpr std::size_t size() const { return end_ - begin_; }
 };
 
-static_assert(std::ranges::view<RandomAccessView>);
-static_assert(std::ranges::random_access_range<RandomAccessView>);
-static_assert(std::copyable<RandomAccessView>);
-
-/*
-enum CopyCategory { MoveOnly, Copyable };
-template <CopyCategory CC>
-struct BidirSentView : std::ranges::view_base {
-  using sent_t       = sentinel_wrapper<bidirectional_iterator<int*>>;
-  using sent_const_t = sentinel_wrapper<bidirectional_iterator<const int*>>;
-
-  int* begin_;
-  int* end_;
-
-  constexpr BidirSentView(int* b, int* e) : begin_(b), end_(e) {}
-  constexpr BidirSentView(const BidirSentView&)
-    requires(CC == Copyable)
-  = default;
-  constexpr BidirSentView(BidirSentView&&)
-    requires(CC == MoveOnly)
-  = default;
-  constexpr BidirSentView& operator=(const BidirSentView&)
-    requires(CC == Copyable)
-  = default;
-  constexpr BidirSentView& operator=(BidirSentView&&)
-    requires(CC == MoveOnly)
-  = default;
-
-  constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{begin_}; }
-  constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{begin_}; }
-  constexpr sent_t end() { return sent_t{bidirectional_iterator<int*>{end_}}; }
-  constexpr sent_const_t end() const { return sent_const_t{bidirectional_iterator<const int*>{end_}}; }
-};
-// TODO: Clean up.
-static_assert(std::ranges::bidirectional_range<BidirSentView<MoveOnly>>);
-static_assert(!std::ranges::common_range<BidirSentView<MoveOnly>>);
-static_assert(std::ranges::view<BidirSentView<MoveOnly>>);
-static_assert(!std::copyable<BidirSentView<MoveOnly>>);
-static_assert(std::ranges::bidirectional_range<BidirSentView<Copyable>>);
-static_assert(!std::ranges::common_range<BidirSentView<Copyable>>);
-static_assert(std::ranges::view<BidirSentView<Copyable>>);
-static_assert(std::copyable<BidirSentView<Copyable>>);
-*/
+static_assert(std::ranges::view<InputView>);
+static_assert(std::ranges::input_range<InputView>);
+static_assert(std::copyable<InputView>);
 
 struct UnsizedBasicRangeIterator : ForwardIterBase<UnsizedBasicRangeIterator> {};
 

>From f246da6dccced1786d18e016e2f9d20efdbbf0e9 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 13 Oct 2023 18:42:20 -0400
Subject: [PATCH 25/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fixed typo in comment in documentation of iterator concept testing.
---
 .../range.adaptors/range.stride.view/iterator/begin.pass.cpp   | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
index 3216a9ab85e84b..b6b871bd691069 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
@@ -14,7 +14,6 @@
 
 #include "../test.h"
 #include "__iterator/concepts.h"
-#include "__ranges/stride_view.h"
 #include <ranges>
 #include <type_traits>
 
@@ -54,7 +53,7 @@ constexpr bool iterator_concept_test() {
 
   {
     int arr[] = {1, 2, 3};
-    // Iterator of stride over forward view should have forward view concept.
+    // Iterator of stride over input view should have input view concept.
     auto rav = InputView(arr, arr + 3);
     auto str = std::ranges::stride_view<InputView>(rav, 1);
     static_assert(std::input_iterator<decltype(rav.begin())>);

>From 5977f4d3b7972664ebddf8aecfa7fe7a65fe7c1e Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 13 Oct 2023 18:44:57 -0400
Subject: [PATCH 26/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add operator++ precondition assertion (and test that it works).
---
 libcxx/include/__ranges/stride_view.h         |  1 +
 .../iterator/increment.pass.cpp               | 34 +++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 0239a6c595df83..ba05c34553fcf5 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -189,6 +189,7 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
   _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__current_; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+    _LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __end_, "Cannot increment an iterator already at the end.");
     __missing_ = ranges::advance(__current_, __stride_, __end_);
     return *this;
   }
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
new file mode 100644
index 00000000000000..0100dd1708b0da
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: no-exceptions
+// UNSUPPORTED: !libcpp-hardening-mode=debug
+// XFAIL: availability-verbose_abort-missing
+
+// <ranges>
+
+// Call ....
+
+#include "check_assertion.h"
+#include "../../test/std/ranges/range.adaptors/range.stride.view/test.h"
+#include <ranges>
+
+void cannot_increment_at_the_end_iterator() {
+  int range[]   = {1, 2, 3};
+  auto iv       = InputView(range, range + 3);
+  auto striv    = std::ranges::views::stride(iv, 3);
+  auto striv_it = striv.begin();
+  striv_it++;
+  TEST_LIBCPP_ASSERT_FAILURE(striv_it++, "Cannot increment an iterator already at the end.");
+}
+
+int main() {
+  cannot_increment_at_the_end_iterator();
+  return 0;
+}

>From dc5195acabbc3ff5b426730f9e597d1a3dd66852 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 16 Oct 2023 10:30:07 -0400
Subject: [PATCH 27/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fix off-by-one error in iterator equal test.
---
 .../range.adaptors/range.stride.view/iterator/equal.pass.cpp  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
index 7f2711adc5179d..ff5196d26476ce 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
@@ -26,8 +26,8 @@ constexpr void testOne() {
   {
     // simple test
     {
-      int buffer[] = {0, 1, 2, -1, 4, 5, 6};
-      Range input(Iter{buffer}, Iter{buffer + 7});
+      int buffer[] = {0, 1, 2, -1, 4, 5, 6, 7};
+      Range input(Iter{buffer}, Iter{buffer + 8});
       StrideView sv(input, 1);
       StrideView sv_too(input, 2);
       auto b = sv.begin(), e = sv.end();

>From 399be4832e9ab027d83eeda0df8a5f1d7110ce45 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 16 Oct 2023 10:32:30 -0400
Subject: [PATCH 28/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add test for non-default constructible iterator of strided-over range.
---
 .../iterator/ctor.default.pass.cpp            | 38 ++++++++++++++++++-
 .../range.adaptors/range.stride.view/test.h   |  5 +++
 2 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index acd26c35a5db2b..02c261db280171 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -13,8 +13,6 @@
 // std::views::stride_view
 
 #include "../test.h"
-#include "__concepts/same_as.h"
-#include "__ranges/stride_view.h"
 #include <cassert>
 #include <ranges>
 #include <type_traits>
@@ -45,8 +43,44 @@ constexpr bool non_simple_view_iter_ctor_test() {
   return true;
 }
 
+struct NonDefaultConstructibleIterator : InputIterBase<NonDefaultConstructibleIterator> {
+  NonDefaultConstructibleIterator() = delete;
+  constexpr NonDefaultConstructibleIterator(int) {}
+};
+
+struct View : std::ranges::view_base {
+  constexpr NonDefaultConstructibleIterator begin() const { return NonDefaultConstructibleIterator{5}; }
+  constexpr std::default_sentinel_t end() const { return {}; }
+};
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<View> = true;
+
+constexpr bool iterator_default_constructible() {
+  {
+    // If the type of the iterator of the range being strided is non-default
+    // constructible, then the stride view's iterator should not be default
+    // constructible, either!
+    constexpr View v{};
+    constexpr auto stride   = std::ranges::stride_view(v, 1);
+    using stride_iterator_t = decltype(stride.begin());
+    static_assert(!std::is_default_constructible<stride_iterator_t>(), "");
+  }
+  {
+    // If the type of the iterator of the range being strided is default
+    // constructible, then the stride view's iterator should be default
+    // constructible, too!
+    constexpr int arr[]     = {1, 2, 3};
+    auto stride             = std::ranges::stride_view(arr, 1);
+    using stride_iterator_t = decltype(stride.begin());
+    static_assert(std::is_default_constructible<stride_iterator_t>(), "");
+  }
+
+  return true;
+}
+
 int main(int, char**) {
   non_simple_view_iter_ctor_test();
   static_assert(non_simple_view_iter_ctor_test());
+  static_assert(iterator_default_constructible());
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 6bef25b8618882..3bf7d7b8a4f005 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -10,6 +10,7 @@
 #define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
 
 #include "__concepts/movable.h"
+#include "__iterator/default_sentinel.h"
 #include "__ranges/concepts.h"
 #include "__ranges/enable_view.h"
 #include "__ranges/size.h"
@@ -99,6 +100,8 @@ struct ForwardIterBase {
   constexpr Derived operator++(int) { return {}; }
 
   friend constexpr bool operator==(const ForwardIterBase&, const ForwardIterBase&) { return true; }
+  friend constexpr bool operator==(const std::default_sentinel_t&, const ForwardIterBase&) { return true; }
+  friend constexpr bool operator==(const ForwardIterBase&, const std::default_sentinel_t&) { return true; }
 };
 
 template <class Derived>
@@ -113,6 +116,8 @@ struct InputIterBase {
   constexpr Derived operator++(int) { return {}; }
 
   friend constexpr bool operator==(const InputIterBase&, const InputIterBase&) { return true; }
+  friend constexpr bool operator==(const std::default_sentinel_t&, const InputIterBase&) { return true; }
+  friend constexpr bool operator==(const InputIterBase&, const std::default_sentinel_t&) { return true; }
 };
 
 struct NotSimpleViewIter : ForwardIterBase<NotSimpleViewIter> {

>From e4a8715309f71a89557bac290dd53e0ebb4a25c4 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 16 Oct 2023 16:27:26 -0400
Subject: [PATCH 29/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Move stride_view::iterator out of the views namespace.
---
 libcxx/include/__ranges/stride_view.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index ba05c34553fcf5..b699868c0234a9 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -118,8 +118,6 @@ class stride_view : public view_interface<stride_view<_View>> {
 template <class _Range>
 stride_view(_Range&&, range_difference_t<_Range>) -> stride_view<views::all_t<_Range>>;
 
-namespace views {
-
 template <class _View>
 struct __stride_iterator_category {};
 
@@ -348,6 +346,7 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
   }
 }; // class stride_view::__iterator
 
+namespace views {
 namespace __stride {
 struct __fn {
   template <viewable_range _Range>

>From d53f0c7c78944136d88b8786ef60f5f07c4bd826 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 23 Oct 2023 17:50:37 -0400
Subject: [PATCH 30/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fix incorrect return type of base method in iterator.
---
 libcxx/include/__ranges/stride_view.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index b699868c0234a9..f923e7f3795faa 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -181,8 +181,8 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
         __stride_(__i.__stride_),
         __missing_(__i.__missing_) {}
 
-  _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> const& base() const& noexcept { return __current_; }
-  _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); }
+  _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> const& base() const& noexcept { return __current_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); }
 
   _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__current_; }
 

>From 6f5cc23dc5e00c693ca030d6d25666ba416ece68 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 23 Oct 2023 17:52:06 -0400
Subject: [PATCH 31/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Refactor stride_view test types.
---
 .../range.adaptors/range.stride.view/test.h   | 193 ++++++++++--------
 1 file changed, 112 insertions(+), 81 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 3bf7d7b8a4f005..b2ea7098d75bc0 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -9,11 +9,16 @@
 #ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
 #define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
 
+#include "__concepts/equality_comparable.h"
 #include "__concepts/movable.h"
+#include "__concepts/semiregular.h"
 #include "__iterator/default_sentinel.h"
+#include "__ranges/access.h"
 #include "__ranges/concepts.h"
+#include "__ranges/enable_borrowed_range.h"
 #include "__ranges/enable_view.h"
 #include "__ranges/size.h"
+#include "__ranges/stride_view.h"
 #include "test_iterators.h"
 #include <iterator>
 #include <ranges>
@@ -115,12 +120,12 @@ struct InputIterBase {
   constexpr Derived& operator++() { return static_cast<Derived&>(*this); }
   constexpr Derived operator++(int) { return {}; }
 
-  friend constexpr bool operator==(const InputIterBase&, const InputIterBase&) { return true; }
-  friend constexpr bool operator==(const std::default_sentinel_t&, const InputIterBase&) { return true; }
-  friend constexpr bool operator==(const InputIterBase&, const std::default_sentinel_t&) { return true; }
+  friend constexpr bool operator==(const Derived&, const Derived&) { return true; }
+  friend constexpr bool operator==(const std::default_sentinel_t&, const Derived&) { return true; }
+  friend constexpr bool operator==(const Derived&, const std::default_sentinel_t&) { return true; }
 };
 
-struct NotSimpleViewIter : ForwardIterBase<NotSimpleViewIter> {
+struct NotSimpleViewIter : InputIterBase<NotSimpleViewIter> {
   constexpr NotSimpleViewIter()                                    = default;
   constexpr NotSimpleViewIter(const NotSimpleViewIter&)            = default;
   constexpr NotSimpleViewIter(NotSimpleViewIter&&)                 = default;
@@ -128,7 +133,7 @@ struct NotSimpleViewIter : ForwardIterBase<NotSimpleViewIter> {
   constexpr NotSimpleViewIter& operator=(const NotSimpleViewIter&) = default;
 };
 
-struct NotSimpleViewIterEnd : ForwardIterBase<NotSimpleViewIter> {
+struct NotSimpleViewIterEnd : InputIterBase<NotSimpleViewIterEnd> {
   constexpr NotSimpleViewIterEnd()                                       = default;
   constexpr NotSimpleViewIterEnd(const NotSimpleViewIterEnd&)            = default;
   constexpr NotSimpleViewIterEnd(NotSimpleViewIterEnd&&)                 = default;
@@ -136,60 +141,128 @@ struct NotSimpleViewIterEnd : ForwardIterBase<NotSimpleViewIter> {
   constexpr NotSimpleViewIterEnd& operator=(const NotSimpleViewIterEnd&) = default;
 };
 
-struct ConstNotSimpleViewIter : ForwardIterBase<ConstNotSimpleViewIter> {
-  constexpr ConstNotSimpleViewIter()                              = default;
-  constexpr ConstNotSimpleViewIter(const ConstNotSimpleViewIter&) = default;
-  constexpr ConstNotSimpleViewIter(const NotSimpleViewIter&) {}
-  constexpr ConstNotSimpleViewIter(ConstNotSimpleViewIter&&) = default;
+template <bool Convertible>
+struct NotSimpleViewConstIter : InputIterBase<NotSimpleViewConstIter<Convertible>> {
+  constexpr NotSimpleViewConstIter()                              = default;
+  constexpr NotSimpleViewConstIter(const NotSimpleViewConstIter&) = default;
+  constexpr NotSimpleViewConstIter(const NotSimpleViewIter&)
+    requires Convertible
+  {}
+  constexpr NotSimpleViewConstIter(NotSimpleViewConstIter&&) = default;
 
-  constexpr ConstNotSimpleViewIter(NotSimpleViewIter&&) {}
-  constexpr ConstNotSimpleViewIter(NotSimpleViewIterEnd&&) = delete;
+  constexpr NotSimpleViewConstIter(NotSimpleViewIterEnd&&) = delete;
 
-  constexpr ConstNotSimpleViewIter& operator=(ConstNotSimpleViewIter&&)      = default;
-  constexpr ConstNotSimpleViewIter& operator=(const ConstNotSimpleViewIter&) = default;
+  constexpr NotSimpleViewConstIter& operator=(NotSimpleViewConstIter&&)      = default;
+  constexpr NotSimpleViewConstIter& operator=(const NotSimpleViewConstIter&) = default;
 };
 
-struct NotSimpleView : std::ranges::view_base {
-  constexpr ConstNotSimpleViewIter begin() const { return {}; }
+template <bool Convertible>
+constexpr bool operator==(const NotSimpleViewConstIter<Convertible>&, const NotSimpleViewIterEnd&) {
+  return true;
+}
+template <bool Convertible>
+constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIter<Convertible>&) {
+  return true;
+}
+
+constexpr bool operator==(const NotSimpleViewIter&, const NotSimpleViewIterEnd&) { return true; }
+constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewIter&) { return true; }
+
+template <bool Convertible = false>
+struct NotSimpleViewDifferentBegin : std::ranges::view_base {
+  constexpr NotSimpleViewConstIter<Convertible> begin() const { return {}; }
   constexpr NotSimpleViewIter begin() { return {}; }
-  constexpr ConstNotSimpleViewIter end() const { return {}; }
+  constexpr NotSimpleViewIterEnd end() const { return {}; }
   constexpr NotSimpleViewIterEnd end() { return {}; }
 };
 
-struct RandomAccessView : std::ranges::view_base {
-  int* begin_;
-  int* end_;
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentBegin<true>> = true;
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentBegin<false>> = true;
 
-  constexpr RandomAccessView(int* b, int* e) : begin_(b), end_(e) {}
+/*
+ * XXXArrayView classes for use throughout the stride view tests.
+ */
 
-  constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{begin_}; }
-  //constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; }
-  constexpr sentinel_wrapper<random_access_iterator<int*>> end() {
-    return sentinel_wrapper<random_access_iterator<int*>>{random_access_iterator<int*>{end_}};
+template <typename T>
+struct RandomAccessArrayView : std::ranges::view_base {
+  T* begin_;
+  T* end_;
+
+  constexpr RandomAccessArrayView(T* b, T* e) : begin_(b), end_(e) {}
+
+  constexpr random_access_iterator<T*> begin() { return random_access_iterator<T*>{begin_}; }
+  constexpr random_access_iterator<const T*> begin() const { return random_access_iterator<const T*>{begin_}; }
+  constexpr sentinel_wrapper<random_access_iterator<T*>> end() {
+    return sentinel_wrapper<random_access_iterator<T*>>{random_access_iterator<T*>{end_}};
+  }
+  constexpr sentinel_wrapper<random_access_iterator<const T*>> end() const {
+    return sentinel_wrapper<random_access_iterator<const T*>>{random_access_iterator<const T*>{end_}};
   }
-  //constexpr sentinel_wrapper<random_access_iterator<const int*>> end() const { return sentinel_wrapper<random_access_iterator<const int*>>{random_access_iterator<const int*>{end_}}; }
   constexpr std::size_t size() const { return end_ - begin_; }
 };
+static_assert(std::ranges::view<RandomAccessArrayView<int>>);
+static_assert(std::ranges::random_access_range<RandomAccessArrayView<int>>);
+static_assert(std::copyable<RandomAccessArrayView<int>>);
 
-static_assert(std::ranges::view<RandomAccessView>);
-static_assert(std::ranges::random_access_range<RandomAccessView>);
-static_assert(std::copyable<RandomAccessView>);
+template <typename T>
+struct BidirArrayView : std::ranges::view_base {
+  T* begin_;
+  T* end_;
 
-struct BidirView : std::ranges::view_base {
-  int* begin_;
-  int* end_;
+  constexpr BidirArrayView(T* b, T* e) : begin_(b), end_(e) {}
 
-  constexpr BidirView(int* b, int* e) : begin_(b), end_(e) {}
+  constexpr bidirectional_iterator<T*> begin() { return bidirectional_iterator<T*>{begin_}; }
+  constexpr bidirectional_iterator<const T*> begin() const { return bidirectional_iterator<const T*>{begin_}; }
+  constexpr sentinel_wrapper<bidirectional_iterator<T*>> end() {
+    return sentinel_wrapper<bidirectional_iterator<T*>>{bidirectional_iterator<T*>{end_}};
+  }
+  constexpr sentinel_wrapper<bidirectional_iterator<const T*>> end() const {
+    return sentinel_wrapper<bidirectional_iterator<const T*>>{bidirectional_iterator<const T*>{end_}};
+  }
+};
+static_assert(std::ranges::view<BidirArrayView<int>>);
+static_assert(std::ranges::bidirectional_range<BidirArrayView<int>>);
+static_assert(std::copyable<BidirArrayView<int>>);
+
+template <typename T>
+struct ForwardArrayView : public std::ranges::view_base {
+  T* begin_;
+  T* end_;
 
-  constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{begin_}; }
-  constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{begin_}; }
-  constexpr sentinel_wrapper<bidirectional_iterator<int*>> end() {
-    return sentinel_wrapper<bidirectional_iterator<int*>>{bidirectional_iterator<int*>{end_}};
+  constexpr ForwardArrayView(T* b, T* e) : begin_(b), end_(e) {}
+
+  constexpr forward_iterator<T*> begin() { return forward_iterator<T*>{begin_}; }
+  constexpr forward_iterator<const T*> begin() const { return forward_iterator<const T*>{begin_}; }
+  constexpr sentinel_wrapper<forward_iterator<T*>> end() {
+    return sentinel_wrapper<forward_iterator<T*>>{forward_iterator<T*>{end_}};
   }
-  constexpr sentinel_wrapper<bidirectional_iterator<const int*>> end() const {
-    return sentinel_wrapper<bidirectional_iterator<const int*>>{bidirectional_iterator<const int*>{end_}};
+  constexpr sentinel_wrapper<forward_iterator<const T*>> end() const {
+    return sentinel_wrapper<forward_iterator<const T*>>{forward_iterator<const T*>{end_}};
   }
 };
+static_assert(std::ranges::view<ForwardArrayView<int>>);
+static_assert(std::ranges::forward_range<ForwardArrayView<int>>);
+static_assert(std::copyable<ForwardArrayView<int>>);
+
+template <typename T>
+struct InputArrayView : std::ranges::view_base {
+  T* begin_;
+  T* end_;
+
+  constexpr InputArrayView(T* b, T* e) : begin_(b), end_(e) {}
+
+  constexpr cpp20_input_iterator<T*> begin() { return cpp20_input_iterator<T*>{begin_}; }
+  constexpr random_access_iterator<const T*> begin() const { return random_access_iterator<const T*>{begin_}; }
+  constexpr sentinel_wrapper<cpp20_input_iterator<T*>> end() {
+    return sentinel_wrapper<cpp20_input_iterator<T*>>{cpp20_input_iterator<T*>{end_}};
+  }
+  constexpr std::size_t size() const { return end_ - begin_; }
+};
+static_assert(std::ranges::view<InputArrayView<int>>);
+static_assert(std::ranges::input_range<InputArrayView<int>>);
+static_assert(std::copyable<InputArrayView<int>>);
 
 struct ForwardTracedMoveIter : ForwardIterBase<ForwardTracedMoveIter> {
   bool moved = false;
@@ -206,48 +279,6 @@ struct ForwardTracedMoveView : std::ranges::view_base {
   constexpr ForwardTracedMoveIter end() const { return {}; }
 };
 
-static_assert(std::ranges::view<BidirView>);
-static_assert(std::ranges::bidirectional_range<BidirView>);
-static_assert(std::copyable<BidirView>);
-
-struct ForwardView : public std::ranges::view_base {
-  int* begin_;
-  int* end_;
-
-  constexpr ForwardView(int* b, int* e) : begin_(b), end_(e) {}
-
-  constexpr forward_iterator<int*> begin() { return forward_iterator<int*>{begin_}; }
-  constexpr forward_iterator<const int*> begin() const { return forward_iterator<const int*>{begin_}; }
-  constexpr sentinel_wrapper<forward_iterator<int*>> end() {
-    return sentinel_wrapper<forward_iterator<int*>>{forward_iterator<int*>{end_}};
-  }
-  constexpr sentinel_wrapper<forward_iterator<const int*>> end() const {
-    return sentinel_wrapper<forward_iterator<const int*>>{forward_iterator<const int*>{end_}};
-  }
-};
-
-static_assert(std::ranges::view<ForwardView>);
-static_assert(std::ranges::forward_range<ForwardView>);
-static_assert(std::copyable<ForwardView>);
-
-struct InputView : std::ranges::view_base {
-  int* begin_;
-  int* end_;
-
-  constexpr InputView(int* b, int* e) : begin_(b), end_(e) {}
-
-  constexpr cpp20_input_iterator<int*> begin() { return cpp20_input_iterator<int*>{begin_}; }
-  //constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; }
-  constexpr sentinel_wrapper<cpp20_input_iterator<int*>> end() {
-    return sentinel_wrapper<cpp20_input_iterator<int*>>{cpp20_input_iterator<int*>{end_}};
-  }
-  constexpr std::size_t size() const { return end_ - begin_; }
-};
-
-static_assert(std::ranges::view<InputView>);
-static_assert(std::ranges::input_range<InputView>);
-static_assert(std::copyable<InputView>);
-
 struct UnsizedBasicRangeIterator : ForwardIterBase<UnsizedBasicRangeIterator> {};
 
 struct UnsizedBasicRange : std::ranges::view_base {

>From 77fb246f4a341ec17136f18c610d30b1a113cac7 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 23 Oct 2023 17:55:20 -0400
Subject: [PATCH 32/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

More refactoring and adding a (first test) for convertible iterators.
---
 .../range.stride.view/adaptor.pass.cpp        | 35 ++++++-----
 .../range.stride.view/ctor.pass.cpp           |  4 +-
 .../range.stride.view/iterator/begin.pass.cpp | 16 ++---
 .../iterator/ctor.default.pass.cpp            | 61 ++++++++++++-------
 .../range.stride.view/stride.pass.cpp         |  6 +-
 5 files changed, 71 insertions(+), 51 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
index 60ed5587933a06..02e57c8865709b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -33,10 +33,11 @@ constexpr bool test() {
     // view | stride
     {
       {
-        BidirView view(arr, arr + array_n);
+        BidirArrayView<int> view(arr, arr + array_n);
         //std::ranges::stride_view<BidirView> strided(view, 1);
-        std::same_as<std::ranges::stride_view<BidirView>> decltype(auto) strided = view | std::views::stride(1);
-        auto strided_iter                                                        = strided.begin();
+        std::same_as<std::ranges::stride_view<BidirArrayView<int>>> decltype(auto) strided =
+            view | std::views::stride(1);
+        auto strided_iter = strided.begin();
 
         // Check that the begin() iter views arr[0]
         assert(*strided_iter == arr[0]);
@@ -46,9 +47,10 @@ constexpr bool test() {
         assert(*strided_iter == arr[2]);
       }
       {
-        BidirView view(arr, arr + array_n);
-        std::same_as<std::ranges::stride_view<BidirView>> decltype(auto) strided = view | std::views::stride(2);
-        auto strided_iter                                                        = strided.begin();
+        BidirArrayView<int> view(arr, arr + array_n);
+        std::same_as<std::ranges::stride_view<BidirArrayView<int>>> decltype(auto) strided =
+            view | std::views::stride(2);
+        auto strided_iter = strided.begin();
 
         assert(*strided_iter == arr[0]);
 
@@ -65,7 +67,7 @@ constexpr bool test() {
     // Parallels the two tests from above.
     constexpr auto identity_lambda = [](int i) { return i * 2; };
     {
-      BidirView view(arr, arr + array_n);
+      BidirArrayView<int> view(arr, arr + array_n);
       const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(1);
 
       const auto transform_stride_applied = transform_stride_partial(view);
@@ -76,7 +78,7 @@ constexpr bool test() {
     }
 
     {
-      BidirView view(arr, arr + array_n);
+      BidirArrayView<int> view(arr, arr + array_n);
       const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(2);
 
       const auto transform_stride_applied = transform_stride_partial(view);
@@ -88,9 +90,9 @@ constexpr bool test() {
   }
 
   {
-    using ForwardStrideView      = std::ranges::stride_view<ForwardView>;
-    using BidirStrideView        = std::ranges::stride_view<BidirView>;
-    using RandomAccessStrideView = std::ranges::stride_view<RandomAccessView>;
+    using ForwardStrideView      = std::ranges::stride_view<ForwardArrayView<int>>;
+    using BidirStrideView        = std::ranges::stride_view<BidirArrayView<int>>;
+    using RandomAccessStrideView = std::ranges::stride_view<RandomAccessArrayView<int>>;
 
     static_assert(std::ranges::forward_range<ForwardStrideView>);
     static_assert(std::ranges::bidirectional_range<BidirStrideView>);
@@ -107,12 +109,15 @@ constexpr bool test() {
     // Not invocable because NotAViewableRange is, well, not a viewable range.
     static_assert(!std::is_invocable_v<decltype(std::views::reverse), NotAViewableRange>);
     // Is invocable because BidirView is a viewable range.
-    static_assert(std::is_invocable_v<decltype(std::views::reverse), BidirView>);
+    static_assert(std::is_invocable_v<decltype(std::views::reverse), BidirArrayView<int>>);
 
     // Make sure that pipe operations work!
-    static_assert(CanBePiped<BidirView, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
-    static_assert(CanBePiped<BidirView&, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
-    static_assert(!CanBePiped<NotARange, decltype(std::views::stride(std::ranges::range_difference_t<BidirView>{}))>);
+    static_assert(CanBePiped<BidirArrayView<int>,
+                             decltype(std::views::stride(std::ranges::range_difference_t<BidirArrayView<int>>{}))>);
+    static_assert(CanBePiped<BidirArrayView<int>&,
+                             decltype(std::views::stride(std::ranges::range_difference_t<BidirArrayView<int>>{}))>);
+    static_assert(
+        !CanBePiped<NotARange, decltype(std::views::stride(std::ranges::range_difference_t<BidirArrayView<int>>{}))>);
   }
   // A final sanity check.
   { static_assert(std::same_as<decltype(std::views::stride), decltype(std::ranges::views::stride)>); }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
index a205386fa0a9d1..30256ac12b77e4 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
@@ -18,13 +18,13 @@
 
 constexpr bool test_no_default_ctor() {
   // There is no default ctor for stride_view.
-  static_assert(!std::is_default_constructible_v<std::ranges::stride_view<BidirView>>);
+  static_assert(!std::is_default_constructible_v<std::ranges::stride_view<BidirArrayView<int>>>);
   return true;
 }
 
 constexpr bool test_no_implicit_ctor() {
   // Test that the stride_view can only be explicitly constructed.
-  static_assert(!test_convertible<std::ranges::stride_view<ForwardView>, ForwardView, int>());
+  static_assert(!test_convertible<std::ranges::stride_view<ForwardArrayView<int>>, ForwardArrayView<int>, int>());
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
index b6b871bd691069..6a9b1df59961bd 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
@@ -21,8 +21,8 @@ constexpr bool iterator_concept_test() {
   {
     int arr[] = {1, 2, 3};
     // Iterator of stride over random access view should have random access concept.
-    auto rav = RandomAccessView(arr, arr + 3);
-    auto str = std::ranges::stride_view<RandomAccessView>(rav, 1);
+    auto rav = RandomAccessArrayView<int>(arr, arr + 3);
+    auto str = std::ranges::stride_view<RandomAccessArrayView<int>>(rav, 1);
     static_assert(std::random_access_iterator<decltype(rav.begin())>);
     static_assert(std::random_access_iterator<decltype(str.begin())>);
   }
@@ -30,8 +30,8 @@ constexpr bool iterator_concept_test() {
   {
     int arr[] = {1, 2, 3};
     // Iterator of stride over bidirectional view should have bidirectional view concept.
-    auto rav = BidirView(arr, arr + 3);
-    auto str = std::ranges::stride_view<BidirView>(rav, 1);
+    auto rav = BidirArrayView<int>(arr, arr + 3);
+    auto str = std::ranges::stride_view<BidirArrayView<int>>(rav, 1);
     static_assert(std::bidirectional_iterator<decltype(rav.begin())>);
     static_assert(std::bidirectional_iterator<decltype(str.begin())>);
     static_assert(!std::random_access_iterator<decltype(rav.begin())>);
@@ -41,8 +41,8 @@ constexpr bool iterator_concept_test() {
   {
     int arr[] = {1, 2, 3};
     // Iterator of stride over forward view should have forward view concept.
-    auto rav = ForwardView(arr, arr + 3);
-    auto str = std::ranges::stride_view<ForwardView>(rav, 1);
+    auto rav = ForwardArrayView<int>(arr, arr + 3);
+    auto str = std::ranges::stride_view<ForwardArrayView<int>>(rav, 1);
     static_assert(std::forward_iterator<decltype(rav.begin())>);
     static_assert(std::forward_iterator<decltype(str.begin())>);
     static_assert(!std::bidirectional_iterator<decltype(rav.begin())>);
@@ -54,8 +54,8 @@ constexpr bool iterator_concept_test() {
   {
     int arr[] = {1, 2, 3};
     // Iterator of stride over input view should have input view concept.
-    auto rav = InputView(arr, arr + 3);
-    auto str = std::ranges::stride_view<InputView>(rav, 1);
+    auto rav = InputArrayView<int>(arr, arr + 3);
+    auto str = std::ranges::stride_view<InputArrayView<int>>(rav, 1);
     static_assert(std::input_iterator<decltype(rav.begin())>);
     static_assert(std::input_iterator<decltype(str.begin())>);
     static_assert(!std::forward_iterator<decltype(rav.begin())>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index 02c261db280171..567c9b1af0be0f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -13,33 +13,19 @@
 // std::views::stride_view
 
 #include "../test.h"
+#include "__concepts/convertible_to.h"
+#include "__ranges/access.h"
+#include "__ranges/concepts.h"
+#include "__ranges/stride_view.h"
 #include <cassert>
 #include <ranges>
 #include <type_traits>
 
 constexpr bool non_simple_view_iter_ctor_test() {
-  using NotSimpleStrideView     = std::ranges::stride_view<NotSimpleView>;
-  using NotSimpleStrideViewIter = std::ranges::iterator_t<NotSimpleStrideView>;
-
-  using SimpleStrideView     = std::ranges::stride_view<ForwardTracedMoveView>;
-  using SimpleStrideViewIter = std::ranges::iterator_t<SimpleStrideView>;
-
-  NotSimpleStrideView nsv{NotSimpleView{}, 1};
-  [[maybe_unused]] NotSimpleStrideViewIter nsv_iter = nsv.begin();
-
-  SimpleStrideView sv{ForwardTracedMoveView{}, 1};
-  [[maybe_unused]] SimpleStrideViewIter ssv_iter = sv.begin();
-
+  using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false>>;
+  using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
   using NotSimpleStrideViewIterConst = std::ranges::iterator_t<const NotSimpleStrideView>;
-  using SimpleStrideViewIterConst    = std::ranges::iterator_t<const SimpleStrideView>;
-
-  // .begin on a stride view over a non-simple view will give us a
-  // stride_view iterator with its _Const == false. Compare that type
-  // with an iterator on a stride view over a simple view that will give
-  // us an iterator with its _Const == true. They should *not* be the same.
-  static_assert(!std::is_same_v<decltype(ssv_iter), decltype(nsv_iter)>);
-  static_assert(!std::is_same_v<NotSimpleStrideViewIterConst, decltype(nsv_iter)>);
-  static_assert(std::is_same_v<SimpleStrideViewIterConst, decltype(ssv_iter)>);
+  static_assert(!std::is_same_v<NotSimpleStrideViewIterConst, NotSimpleStrideViewIter>);
   return true;
 }
 
@@ -63,7 +49,7 @@ constexpr bool iterator_default_constructible() {
     constexpr View v{};
     constexpr auto stride   = std::ranges::stride_view(v, 1);
     using stride_iterator_t = decltype(stride.begin());
-    static_assert(!std::is_default_constructible<stride_iterator_t>(), "");
+    static_assert(!std::is_default_constructible<stride_iterator_t>());
   }
   {
     // If the type of the iterator of the range being strided is default
@@ -72,9 +58,37 @@ constexpr bool iterator_default_constructible() {
     constexpr int arr[]     = {1, 2, 3};
     auto stride             = std::ranges::stride_view(arr, 1);
     using stride_iterator_t = decltype(stride.begin());
-    static_assert(std::is_default_constructible<stride_iterator_t>(), "");
+    static_assert(std::is_default_constructible<stride_iterator_t>());
+  }
+
+  return true;
+}
+
+constexpr bool non_const_iterator_copy_ctor() {
+  {
+    // Instantiate a stride view over a non-simple view whose const/non-const iterators are not-convertible.
+    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false>>;
+    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
+    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
+
+    // It should not be possible to construct a stride view iterator from a non-const stride view iterator
+    // when the strided-over type has inconvertible iterator types.
+    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
+    static_assert(!std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
+    static_assert(!std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
   }
+  {
+    // Instantiate a stride view over a non-simple view whose const/non-const iterators are convertible.
+    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<true>>;
+    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
+    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
 
+    // It should be possible to construct a stride view iterator from a non-const stride view iterator
+    // when the strided-over type has convertible iterator types.
+    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
+    static_assert(std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
+    static_assert(std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
+  }
   return true;
 }
 
@@ -82,5 +96,6 @@ int main(int, char**) {
   non_simple_view_iter_ctor_test();
   static_assert(non_simple_view_iter_ctor_test());
   static_assert(iterator_default_constructible());
+  static_assert(non_const_iterator_copy_ctor());
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
index 80092fc6738703..154f747f49bd7f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
@@ -18,9 +18,9 @@
 #include <utility>
 
 constexpr bool test() {
-  static_assert(noexcept(std::declval<std::ranges::stride_view<BidirView>>().stride()));
-  static_assert(std::is_same_v<std::ranges::range_difference_t<BidirView>,
-                               decltype(std::declval<std::ranges::stride_view<BidirView>>().stride())>);
+  static_assert(noexcept(std::declval<std::ranges::stride_view<BidirArrayView<int>>>().stride()));
+  static_assert(std::is_same_v<std::ranges::range_difference_t<BidirArrayView<int>>,
+                               decltype(std::declval<std::ranges::stride_view<BidirArrayView<int>>>().stride())>);
   return true;
 }
 

>From 479f15302b8301a82d3d556f0f058a3e517d8391 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Thu, 26 Oct 2023 23:05:18 -0400
Subject: [PATCH 33/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Make sure that all necessary includes are, well, included..
---
 libcxx/include/__ranges/stride_view.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index f923e7f3795faa..93eb4a47371780 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -12,12 +12,21 @@
 
 #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 <__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)

>From f77d91e93aa61e1cdcb4e240630b2a8899486c76 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Thu, 26 Oct 2023 23:07:41 -0400
Subject: [PATCH 34/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add additional iterator copy constructor covertible to tests.
---
 .../iterator/ctor.default.pass.cpp            | 34 ++++++++++++++++---
 .../range.adaptors/range.stride.view/test.h   | 34 +++++++++++++++++++
 2 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index 567c9b1af0be0f..d782413375e4d4 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -66,25 +66,51 @@ constexpr bool iterator_default_constructible() {
 
 constexpr bool non_const_iterator_copy_ctor() {
   {
-    // Instantiate a stride view over a non-simple view whose const/non-const iterators are not-convertible.
+    // Instantiate a stride view over a non-simple view whose const/non-const begin iterators are not-convertible.
     using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false>>;
     using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
     using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
 
     // It should not be possible to construct a stride view iterator from a non-const stride view iterator
-    // when the strided-over type has inconvertible iterator types.
+    // when the strided-over type has inconvertible begin iterator types.
     static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
     static_assert(!std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
     static_assert(!std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
   }
   {
-    // Instantiate a stride view over a non-simple view whose const/non-const iterators are convertible.
+    // Instantiate a stride view over a non-simple view whose const/non-const begin iterators are convertible.
     using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<true>>;
     using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
     using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
 
     // It should be possible to construct a stride view iterator from a non-const stride view iterator
-    // when the strided-over type has convertible iterator types.
+    // when the strided-over type has convertible begin iterator types.
+    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
+    static_assert(std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
+    static_assert(std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
+  }
+
+  {
+    // Instantiate a stride view over a non-simple view whose const/non-const end iterators are not convertible.
+    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentEnd<false>>;
+    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
+    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
+
+    // It should not be possible to construct a stride view iterator from a non-const stride view iterator
+    // when the strided-over type has inconvertible end iterator types.
+    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
+    static_assert(!std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
+    static_assert(!std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
+  }
+
+  {
+    // Instantiate a stride view over a non-simple view whose const/non-const end iterators are convertible.
+    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentEnd<true>>;
+    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
+    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
+
+    // It should not be possible to construct a stride view iterator from a non-const stride view iterator
+    // when the strided-over type has inconvertible end iterator types.
     static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
     static_assert(std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
     static_assert(std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index b2ea7098d75bc0..993b595093f04a 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -141,6 +141,18 @@ struct NotSimpleViewIterEnd : InputIterBase<NotSimpleViewIterEnd> {
   constexpr NotSimpleViewIterEnd& operator=(const NotSimpleViewIterEnd&) = default;
 };
 
+template <bool Convertible>
+struct NotSimpleViewConstIterEnd : InputIterBase<NotSimpleViewConstIterEnd<Convertible>> {
+  constexpr NotSimpleViewConstIterEnd()                                 = default;
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewConstIterEnd&) = default;
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewIterEnd&)
+    requires Convertible
+  {}
+  constexpr NotSimpleViewConstIterEnd(NotSimpleViewConstIterEnd&&)                 = default;
+  constexpr NotSimpleViewConstIterEnd& operator=(NotSimpleViewConstIterEnd&&)      = default;
+  constexpr NotSimpleViewConstIterEnd& operator=(const NotSimpleViewConstIterEnd&) = default;
+};
+
 template <bool Convertible>
 struct NotSimpleViewConstIter : InputIterBase<NotSimpleViewConstIter<Convertible>> {
   constexpr NotSimpleViewConstIter()                              = default;
@@ -168,6 +180,15 @@ constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstI
 constexpr bool operator==(const NotSimpleViewIter&, const NotSimpleViewIterEnd&) { return true; }
 constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewIter&) { return true; }
 
+template <bool Convertible>
+constexpr bool operator==(const NotSimpleViewConstIter<false>&, const NotSimpleViewConstIterEnd<Convertible>&) {
+  return true;
+}
+template <bool Convertible>
+constexpr bool operator==(const NotSimpleViewConstIterEnd<Convertible>&, const NotSimpleViewConstIter<false>&) {
+  return true;
+}
+
 template <bool Convertible = false>
 struct NotSimpleViewDifferentBegin : std::ranges::view_base {
   constexpr NotSimpleViewConstIter<Convertible> begin() const { return {}; }
@@ -181,6 +202,19 @@ inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentB
 template <>
 inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentBegin<false>> = true;
 
+template <bool Convertible = false>
+struct NotSimpleViewDifferentEnd : std::ranges::view_base {
+  constexpr NotSimpleViewConstIter<false> begin() const { return {}; }
+  constexpr NotSimpleViewConstIter<false> begin() { return {}; }
+  constexpr NotSimpleViewConstIterEnd<Convertible> end() const { return {}; }
+  constexpr NotSimpleViewIterEnd end() { return {}; }
+};
+
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentEnd<true>> = true;
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentEnd<false>> = true;
+
 /*
  * XXXArrayView classes for use throughout the stride view tests.
  */

>From 34b937b5c71c20b4fbb78e7c90f3ee124621a13b Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 27 Oct 2023 01:53:03 -0400
Subject: [PATCH 35/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Include __iterator/advance.h to support ranges::advance.
---
 libcxx/include/__ranges/stride_view.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 93eb4a47371780..add002687a869a 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -17,6 +17,7 @@
 #include <__concepts/derived_from.h>
 #include <__concepts/equality_comparable.h>
 #include <__functional/bind_back.h>
+#include <__iterator/advance.h>
 #include <__iterator/concepts.h>
 #include <__iterator/default_sentinel.h>
 #include <__iterator/distance.h>

>From ce900eef1fe1db855c6061f3785e7bf5f19a25f7 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 27 Oct 2023 09:08:17 -0400
Subject: [PATCH 36/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fixup libcxx iterator increment assertion test.
---
 .../range.stride.view/iterator/increment.pass.cpp             | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
index 0100dd1708b0da..667b74e4c3d516 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
@@ -16,13 +16,11 @@
 // Call ....
 
 #include "check_assertion.h"
-#include "../../test/std/ranges/range.adaptors/range.stride.view/test.h"
 #include <ranges>
 
 void cannot_increment_at_the_end_iterator() {
   int range[]   = {1, 2, 3};
-  auto iv       = InputView(range, range + 3);
-  auto striv    = std::ranges::views::stride(iv, 3);
+  auto striv    = std::ranges::views::stride(range, 3);
   auto striv_it = striv.begin();
   striv_it++;
   TEST_LIBCPP_ASSERT_FAILURE(striv_it++, "Cannot increment an iterator already at the end.");

>From 1d323fd2d6f99a0b27d003eb1c15109748f0a948 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Sun, 29 Oct 2023 15:55:29 -0400
Subject: [PATCH 37/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add test for move-only constructor for iterators for stride views over non simple views.
---
 .../iterator/ctor.default.pass.cpp            | 133 +++++++++++++++++-
 .../range.adaptors/range.stride.view/test.h   |  90 ------------
 2 files changed, 126 insertions(+), 97 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index d782413375e4d4..b27c686ccaf102 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -14,12 +14,107 @@
 
 #include "../test.h"
 #include "__concepts/convertible_to.h"
+#include "__iterator/concepts.h"
 #include "__ranges/access.h"
 #include "__ranges/concepts.h"
 #include "__ranges/stride_view.h"
 #include <cassert>
 #include <ranges>
 #include <type_traits>
+#include <utility>
+
+struct NotSimpleViewIter : InputIterBase<NotSimpleViewIter> {};
+struct NotSimpleViewIterEnd : InputIterBase<NotSimpleViewIterEnd> {};
+constexpr bool operator==(const NotSimpleViewIter&, const NotSimpleViewIterEnd&) { return true; }
+constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewIter&) { return true; }
+
+template <bool Convertible, bool Copyable>
+struct NotSimpleViewConstIterEnd : InputIterBase<NotSimpleViewConstIterEnd<Convertible, Copyable>> {
+  constexpr NotSimpleViewConstIterEnd() = default;
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewConstIterEnd&&) {}
+  constexpr NotSimpleViewConstIterEnd& operator=(const NotSimpleViewConstIterEnd&) {}
+  constexpr NotSimpleViewConstIterEnd& operator=(const NotSimpleViewConstIterEnd&&) {}
+
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewConstIterEnd&)
+    requires Copyable
+  {}
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewIterEnd&)
+    requires Convertible
+  {}
+};
+
+template <bool Convertible, bool Copyable>
+struct NotSimpleViewConstIter : InputIterBase<NotSimpleViewConstIter<Convertible, Copyable>> {
+  constexpr NotSimpleViewConstIter() = default;
+  constexpr NotSimpleViewConstIter(const NotSimpleViewConstIter&&) {}
+  constexpr NotSimpleViewConstIter& operator=(const NotSimpleViewConstIter&&) {}
+  constexpr NotSimpleViewConstIter& operator=(const NotSimpleViewConstIter&) {}
+
+  constexpr NotSimpleViewConstIter(const NotSimpleViewConstIter&)
+    requires Copyable
+  {}
+  constexpr NotSimpleViewConstIter(const NotSimpleViewIter&)
+    requires Convertible
+  {}
+};
+
+template <bool Convertible, bool Copyable>
+constexpr bool operator==(const NotSimpleViewConstIter<Convertible, Copyable>&, const NotSimpleViewIterEnd&) {
+  return true;
+}
+template <bool Convertible, bool Copyable>
+constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIter<Convertible, Copyable>&) {
+  return true;
+}
+template <bool Convertible, bool Copyable>
+constexpr bool operator==(const NotSimpleViewConstIterEnd<Convertible, Copyable>&, const NotSimpleViewIterEnd&) {
+  return true;
+}
+template <bool Convertible, bool Copyable>
+constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIterEnd<Convertible, Copyable>&) {
+  return true;
+}
+template <bool Convertible, bool Copyable>
+constexpr bool operator==(const NotSimpleViewIter&, const NotSimpleViewConstIterEnd<Convertible, Copyable>&) {
+  return true;
+}
+template <bool Convertible, bool Copyable>
+constexpr bool operator==(const NotSimpleViewConstIterEnd<Convertible, Copyable>&, const NotSimpleViewIter&) {
+  return true;
+}
+
+/* 
+ * There are (at least) two ways that a view can be non-simple:
+ * 1. The iterator type for const begin is different than the iterator type for begin
+ * 2. The iterator type for const end is different that the iterator type for end
+ *
+ * So, let's create two different classes where that is the case so that we can test
+ * for those conditions individually. We parameterize with a template to decide
+ * whether to 
+ * 1. enable converting constructors between the non-const and the const version.
+ * That feature is important for testing the stride_view::__iterator<true> converting
+ * constructor from a stride_view::_iterator<false> iterator.
+ * 2. enable copyability. That feature is important for testing whether the requirement
+ * the that copy constructor for the stride_view::__iterator<false> type actually moves
+ * the underlying iterator.
+ */
+template <bool Convertible = false, bool Copyable = true>
+struct NotSimpleViewDifferentBegin : std::ranges::view_base {
+  constexpr NotSimpleViewConstIter<Convertible, Copyable> begin() const { return {}; }
+  constexpr NotSimpleViewIter begin() { return {}; }
+  constexpr NotSimpleViewIterEnd end() const { return {}; }
+  constexpr NotSimpleViewIterEnd end() { return {}; }
+};
+
+template <bool Convertible = false, bool Copyable = true>
+struct NotSimpleViewDifferentEnd : std::ranges::view_base {
+  constexpr NotSimpleViewIter begin() const { return {}; }
+  constexpr NotSimpleViewIter begin() { return {}; }
+  constexpr NotSimpleViewConstIterEnd<Convertible, Copyable> end() const {
+    return std::move(NotSimpleViewConstIterEnd<Convertible, Copyable>{});
+  }
+  constexpr NotSimpleViewIterEnd end() { return {}; }
+};
 
 constexpr bool non_simple_view_iter_ctor_test() {
   using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false>>;
@@ -34,19 +129,19 @@ struct NonDefaultConstructibleIterator : InputIterBase<NonDefaultConstructibleIt
   constexpr NonDefaultConstructibleIterator(int) {}
 };
 
-struct View : std::ranges::view_base {
+struct ViewWithNonDefaultConstructibleIterator : std::ranges::view_base {
   constexpr NonDefaultConstructibleIterator begin() const { return NonDefaultConstructibleIterator{5}; }
   constexpr std::default_sentinel_t end() const { return {}; }
 };
 template <>
-inline constexpr bool std::ranges::enable_borrowed_range<View> = true;
+inline constexpr bool std::ranges::enable_borrowed_range<ViewWithNonDefaultConstructibleIterator> = true;
 
 constexpr bool iterator_default_constructible() {
   {
     // If the type of the iterator of the range being strided is non-default
     // constructible, then the stride view's iterator should not be default
     // constructible, either!
-    constexpr View v{};
+    constexpr ViewWithNonDefaultConstructibleIterator v{};
     constexpr auto stride   = std::ranges::stride_view(v, 1);
     using stride_iterator_t = decltype(stride.begin());
     static_assert(!std::is_default_constructible<stride_iterator_t>());
@@ -67,7 +162,7 @@ constexpr bool iterator_default_constructible() {
 constexpr bool non_const_iterator_copy_ctor() {
   {
     // Instantiate a stride view over a non-simple view whose const/non-const begin iterators are not-convertible.
-    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false>>;
+    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false, true>>;
     using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
     using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
 
@@ -79,7 +174,7 @@ constexpr bool non_const_iterator_copy_ctor() {
   }
   {
     // Instantiate a stride view over a non-simple view whose const/non-const begin iterators are convertible.
-    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<true>>;
+    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<true, true>>;
     using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
     using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
 
@@ -92,10 +187,12 @@ constexpr bool non_const_iterator_copy_ctor() {
 
   {
     // Instantiate a stride view over a non-simple view whose const/non-const end iterators are not convertible.
-    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentEnd<false>>;
+    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentEnd<false, true>>;
     using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
     using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
 
+    static_assert(std::ranges::__can_borrow<const NotSimpleStrideView&>);
+
     // It should not be possible to construct a stride view iterator from a non-const stride view iterator
     // when the strided-over type has inconvertible end iterator types.
     static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
@@ -105,14 +202,36 @@ constexpr bool non_const_iterator_copy_ctor() {
 
   {
     // Instantiate a stride view over a non-simple view whose const/non-const end iterators are convertible.
-    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentEnd<true>>;
+    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentEnd<true, true>>;
     using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
     using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
 
     // It should not be possible to construct a stride view iterator from a non-const stride view iterator
     // when the strided-over type has inconvertible end iterator types.
+    static_assert(std::is_copy_constructible_v<NotSimpleStrideViewConstIter>);
+    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
+    static_assert(std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
+    static_assert(std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
+  }
+
+  {
+    // Instantiate a stride view over a non-simple view whose iterators are not copyable but whose const
+    // and non-const end iterators are convertible.
+    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<true, false>>;
+    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
+    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
+
+    // It should not be possible to copy construct a stride view iterator from a non-const stride view iterator
+    // when the strided-over type has non copyable end iterator type.
+    static_assert(!std::is_copy_constructible_v<NotSimpleStrideViewConstIter>);
+
+    // Given the difference between the (non-) constness of the end iterator types and the fact that
+    // they can be converted between, it should
+    // 1. not be a simple view
     static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
+    // 2. the types should be convertible
     static_assert(std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
+    // 3. and a const thing should be constructible from a non const thing because they are convertible.
     static_assert(std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
   }
   return true;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 993b595093f04a..967c75c9cf0022 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -125,96 +125,6 @@ struct InputIterBase {
   friend constexpr bool operator==(const Derived&, const std::default_sentinel_t&) { return true; }
 };
 
-struct NotSimpleViewIter : InputIterBase<NotSimpleViewIter> {
-  constexpr NotSimpleViewIter()                                    = default;
-  constexpr NotSimpleViewIter(const NotSimpleViewIter&)            = default;
-  constexpr NotSimpleViewIter(NotSimpleViewIter&&)                 = default;
-  constexpr NotSimpleViewIter& operator=(NotSimpleViewIter&&)      = default;
-  constexpr NotSimpleViewIter& operator=(const NotSimpleViewIter&) = default;
-};
-
-struct NotSimpleViewIterEnd : InputIterBase<NotSimpleViewIterEnd> {
-  constexpr NotSimpleViewIterEnd()                                       = default;
-  constexpr NotSimpleViewIterEnd(const NotSimpleViewIterEnd&)            = default;
-  constexpr NotSimpleViewIterEnd(NotSimpleViewIterEnd&&)                 = default;
-  constexpr NotSimpleViewIterEnd& operator=(NotSimpleViewIterEnd&&)      = default;
-  constexpr NotSimpleViewIterEnd& operator=(const NotSimpleViewIterEnd&) = default;
-};
-
-template <bool Convertible>
-struct NotSimpleViewConstIterEnd : InputIterBase<NotSimpleViewConstIterEnd<Convertible>> {
-  constexpr NotSimpleViewConstIterEnd()                                 = default;
-  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewConstIterEnd&) = default;
-  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewIterEnd&)
-    requires Convertible
-  {}
-  constexpr NotSimpleViewConstIterEnd(NotSimpleViewConstIterEnd&&)                 = default;
-  constexpr NotSimpleViewConstIterEnd& operator=(NotSimpleViewConstIterEnd&&)      = default;
-  constexpr NotSimpleViewConstIterEnd& operator=(const NotSimpleViewConstIterEnd&) = default;
-};
-
-template <bool Convertible>
-struct NotSimpleViewConstIter : InputIterBase<NotSimpleViewConstIter<Convertible>> {
-  constexpr NotSimpleViewConstIter()                              = default;
-  constexpr NotSimpleViewConstIter(const NotSimpleViewConstIter&) = default;
-  constexpr NotSimpleViewConstIter(const NotSimpleViewIter&)
-    requires Convertible
-  {}
-  constexpr NotSimpleViewConstIter(NotSimpleViewConstIter&&) = default;
-
-  constexpr NotSimpleViewConstIter(NotSimpleViewIterEnd&&) = delete;
-
-  constexpr NotSimpleViewConstIter& operator=(NotSimpleViewConstIter&&)      = default;
-  constexpr NotSimpleViewConstIter& operator=(const NotSimpleViewConstIter&) = default;
-};
-
-template <bool Convertible>
-constexpr bool operator==(const NotSimpleViewConstIter<Convertible>&, const NotSimpleViewIterEnd&) {
-  return true;
-}
-template <bool Convertible>
-constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIter<Convertible>&) {
-  return true;
-}
-
-constexpr bool operator==(const NotSimpleViewIter&, const NotSimpleViewIterEnd&) { return true; }
-constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewIter&) { return true; }
-
-template <bool Convertible>
-constexpr bool operator==(const NotSimpleViewConstIter<false>&, const NotSimpleViewConstIterEnd<Convertible>&) {
-  return true;
-}
-template <bool Convertible>
-constexpr bool operator==(const NotSimpleViewConstIterEnd<Convertible>&, const NotSimpleViewConstIter<false>&) {
-  return true;
-}
-
-template <bool Convertible = false>
-struct NotSimpleViewDifferentBegin : std::ranges::view_base {
-  constexpr NotSimpleViewConstIter<Convertible> begin() const { return {}; }
-  constexpr NotSimpleViewIter begin() { return {}; }
-  constexpr NotSimpleViewIterEnd end() const { return {}; }
-  constexpr NotSimpleViewIterEnd end() { return {}; }
-};
-
-template <>
-inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentBegin<true>> = true;
-template <>
-inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentBegin<false>> = true;
-
-template <bool Convertible = false>
-struct NotSimpleViewDifferentEnd : std::ranges::view_base {
-  constexpr NotSimpleViewConstIter<false> begin() const { return {}; }
-  constexpr NotSimpleViewConstIter<false> begin() { return {}; }
-  constexpr NotSimpleViewConstIterEnd<Convertible> end() const { return {}; }
-  constexpr NotSimpleViewIterEnd end() { return {}; }
-};
-
-template <>
-inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentEnd<true>> = true;
-template <>
-inline constexpr bool std::ranges::enable_borrowed_range<NotSimpleViewDifferentEnd<false>> = true;
-
 /*
  * XXXArrayView classes for use throughout the stride view tests.
  */

>From b54824ff7e4ac86fe715671731aea405f4324e41 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 30 Oct 2023 09:15:46 -0400
Subject: [PATCH 38/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fix formatting issue with iterator/ctor.default.pass.cpp.
---
 .../range.stride.view/iterator/ctor.default.pass.cpp            | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index b27c686ccaf102..5a954fc73ef3e9 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -90,7 +90,7 @@ constexpr bool operator==(const NotSimpleViewConstIterEnd<Convertible, Copyable>
  *
  * So, let's create two different classes where that is the case so that we can test
  * for those conditions individually. We parameterize with a template to decide
- * whether to 
+ * whether to
  * 1. enable converting constructors between the non-const and the const version.
  * That feature is important for testing the stride_view::__iterator<true> converting
  * constructor from a stride_view::_iterator<false> iterator.

>From 88213d4bddac7d148d6c5df0dc8b076a777cf96d Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 30 Oct 2023 10:28:15 -0400
Subject: [PATCH 39/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Remove default parameter missing in __iterator ctor.
---
 libcxx/include/__ranges/stride_view.h | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index add002687a869a..ecf6065e20b701 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -77,13 +77,13 @@ class stride_view : public view_interface<stride_view<_View>> {
   _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
     requires(!__simple_view<_View>)
   {
-    return __iterator<false>(this, ranges::begin(__base_));
+    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_));
+    return __iterator<true>(this, ranges::begin(__base_), 0);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto end()
@@ -93,7 +93,7 @@ class stride_view : public view_interface<stride_view<_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_));
+      return __iterator<false>(this, ranges::end(__base_), 0);
     } else {
       return default_sentinel;
     }
@@ -106,7 +106,7 @@ class stride_view : public view_interface<stride_view<_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_));
+      return __iterator<true>(this, ranges::end(__base_), 0);
     } else {
       return default_sentinel;
     }
@@ -155,7 +155,7 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
   friend stride_view;
 
   _LIBCPP_HIDE_FROM_ABI constexpr __iterator(
-      _Parent* __parent, ranges::iterator_t<_Base> __current, range_difference_t<_Base> __missing = 0)
+      _Parent* __parent, ranges::iterator_t<_Base> __current, range_difference_t<_Base> __missing)
       : __current_(std::move(__current)),
         __end_(ranges::end(__parent->__base_)),
         __stride_(__parent->__stride_),

>From c1aa5b0912bfd6456674f241d07a2c8f5fa6f441 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 30 Oct 2023 22:44:57 -0400
Subject: [PATCH 40/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fix minor formatting nit.
---
 .../range.stride.view/iterator/ctor.default.pass.cpp            | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index 5a954fc73ef3e9..56620b758ad6b0 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -83,7 +83,7 @@ constexpr bool operator==(const NotSimpleViewConstIterEnd<Convertible, Copyable>
   return true;
 }
 
-/* 
+/*
  * There are (at least) two ways that a view can be non-simple:
  * 1. The iterator type for const begin is different than the iterator type for begin
  * 2. The iterator type for const end is different that the iterator type for end

>From 04ca3eab16a676035ef0c7e809cb588297e1e6ae Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 30 Oct 2023 22:45:25 -0400
Subject: [PATCH 41/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add test for __iterator::base noexcept.
---
 .../range.stride.view/iterator/base.pass.cpp  | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
new file mode 100644
index 00000000000000..3fbc312b9f307a
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view
+
+#include "../test.h"
+#include <ranges>
+
+constexpr bool base_noexcept() {
+  {
+    // If the type of the iterator of the range being strided is default
+    // constructible, then the stride view's iterator should be default
+    // constructible, too!
+    int arr[]                         = {1, 2, 3};
+    auto stride                       = std::ranges::stride_view(arr, 1);
+    [[maybe_unused]] auto stride_iter = stride.begin();
+
+    static_assert(noexcept(stride_iter.base()));
+    static_assert(!noexcept((std::move(stride_iter).base())));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  base_noexcept();
+  static_assert(base_noexcept());
+  return 0;
+}

>From 792d7e73b7d6606f90f8edbc297be07cccd83f6d Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 1 Nov 2023 09:40:27 -0400
Subject: [PATCH 42/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Test for (non) constness of iterator returned by __iterator::base.
---
 .../range.stride.view/iterator/base.pass.cpp  | 23 ++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
index 3fbc312b9f307a..579bcea2d7186d 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
@@ -14,25 +14,42 @@
 
 #include "../test.h"
 #include <ranges>
+#include <type_traits>
 
 constexpr bool base_noexcept() {
   {
-    // If the type of the iterator of the range being strided is default
-    // constructible, then the stride view's iterator should be default
-    // constructible, too!
     int arr[]                         = {1, 2, 3};
     auto stride                       = std::ranges::stride_view(arr, 1);
     [[maybe_unused]] auto stride_iter = stride.begin();
 
+    // Check that calling base on an iterator where this is an lvalue reference
+    // is noexcept.
     static_assert(noexcept(stride_iter.base()));
+    // Calling base on an iterator where this is an rvalue reference may except.
     static_assert(!noexcept((std::move(stride_iter).base())));
   }
 
   return true;
 }
 
+constexpr bool base_const() {
+  {
+    int arr[]                         = {1, 2, 3};
+    auto stride                       = std::ranges::stride_view(arr, 1);
+    [[maybe_unused]] auto stride_iter = stride.begin();
+
+    // Calling base on an iterator where this is lvalue returns a const ref to an iterator.
+    static_assert(std::is_const_v<std::remove_reference_t<decltype(stride_iter.base())>>);
+    // Calling base on an iterator where this is an rvalue reference returns a non-const iterator.
+    static_assert(!std::is_const_v<decltype(std::move(stride_iter).base())>);
+  }
+
+  return true;
+}
 int main(int, char**) {
   base_noexcept();
   static_assert(base_noexcept());
+  base_const();
+  static_assert(base_const());
   return 0;
 }

>From 8654f057f9da8d5263eb42a567703f0068337646 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 1 Nov 2023 12:53:19 -0400
Subject: [PATCH 43/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add assertion for valid __current_ in __iterator::operator* (and test).
---
 libcxx/include/__ranges/stride_view.h         | 13 ++++--
 .../range.stride.view/iterator/end.pass.cpp   | 41 +++++++++++++++++++
 2 files changed, 51 insertions(+), 3 deletions(-)
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index ecf6065e20b701..ea8cfc730d4832 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -10,6 +10,9 @@
 #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>
@@ -17,6 +20,7 @@
 #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>
@@ -194,7 +198,10 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
   _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> const& base() const& noexcept { return __current_; }
   _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__current_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const {
+    _LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __end_, "Cannot dereference an iterator at the end.");
+    return *__current_;
+  }
 
   _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
     _LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __end_, "Cannot increment an iterator already at the end.");
@@ -361,8 +368,8 @@ namespace __stride {
 struct __fn {
   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}) {
+      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);
   }
 
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp
new file mode 100644
index 00000000000000..16516574070a04
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: no-exceptions
+// UNSUPPORTED: !libcpp-hardening-mode=debug
+// XFAIL: availability-verbose_abort-missing
+
+// <ranges>
+
+// Call ....
+
+#include "check_assertion.h"
+#include <ranges>
+
+void cannot_dereference_at_the_end_iterator() {
+  int range[]   = {1, 2, 3};
+  auto striv    = std::ranges::views::stride(range, 3);
+  auto striv_it = striv.begin();
+  striv_it++;
+  TEST_LIBCPP_ASSERT_FAILURE(*striv_it, "Cannot dereference an iterator at the end.");
+}
+
+void cannot_dereference_past_the_end_iterator() {
+  int range[]   = {1, 2, 3};
+  auto striv    = std::ranges::views::stride(range, 4);
+  auto striv_it = striv.begin();
+  striv_it++;
+  TEST_LIBCPP_ASSERT_FAILURE(*striv_it, "Cannot dereference an iterator at the end.");
+}
+
+int main() {
+  cannot_dereference_at_the_end_iterator();
+  cannot_dereference_past_the_end_iterator();
+  return 0;
+}

>From dbf42d8a8c01def77aaa413b452d31843915e000 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 1 Nov 2023 17:13:24 -0400
Subject: [PATCH 44/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fix small formatting error in noexcept specification.
---
 libcxx/include/__ranges/stride_view.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index ea8cfc730d4832..c2f7a9d35135dd 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -368,8 +368,8 @@ namespace __stride {
 struct __fn {
   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}) {
+      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);
   }
 

>From 4b4e3c04cbe7a12164ca377d7f056e7134c6b01f Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 3 Nov 2023 09:05:01 -0400
Subject: [PATCH 45/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add assertion to __iterator::operator+= for valid stride length and test.
---
 libcxx/include/__ranges/stride_view.h         |  6 ++--
 .../iterator/operator_plus_equal.pass.cpp     | 30 +++++++++++++++++++
 2 files changed, 34 insertions(+), 2 deletions(-)
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index c2f7a9d35135dd..8be633b65d914c 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -237,6 +237,8 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
     requires random_access_range<_Base>
   {
     if (__n > 0) {
+      _LIBCPP_ASSERT_UNCATEGORIZED(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) {
@@ -368,8 +370,8 @@ namespace __stride {
 struct __fn {
   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}) {
+      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);
   }
 
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
new file mode 100644
index 00000000000000..caec0a2de71c63
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: no-exceptions
+// UNSUPPORTED: !libcpp-hardening-mode=debug
+// XFAIL: availability-verbose_abort-missing
+
+// <ranges>
+
+// Call ....
+
+#include "check_assertion.h"
+#include <ranges>
+
+void operator_plus_equal_past_end_is_illegal() {
+  int range[]   = {1, 2, 3};
+  auto striv    = std::ranges::views::stride(range, 2);
+  auto striv_it = striv.begin();
+  TEST_LIBCPP_ASSERT_FAILURE(striv_it += 3, "Advancing the iterator beyond the end is not allowed.");
+}
+int main() {
+  operator_plus_equal_past_end_is_illegal();
+  return 0;
+}

>From 279ba60ac22f8d1b3e3d522ad2bdf3b46ef0b2fd Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 3 Nov 2023 09:52:38 -0400
Subject: [PATCH 46/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add tests for __iterator::operator at .
---
 libcxx/include/__ranges/stride_view.h         |   1 +
 .../iterator/operator.pass.cpp                | 132 ++++++++++++++++++
 2 files changed, 133 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 8be633b65d914c..c7f9a4922f7d0a 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -241,6 +241,7 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<_View>
                                    "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;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
new file mode 100644
index 00000000000000..b3672765e891a5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
@@ -0,0 +1,132 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// ranges
+
+// std::views::stride_view::iterator
+
+#include "../test.h"
+#include "__iterator/concepts.h"
+#include "__ranges/access.h"
+#include <ranges>
+#include <type_traits>
+
+template <class T>
+concept is_plus_equalable = requires(T& __t) { __t += 1; };
+template <class T>
+concept is_minus_equalable = requires(T& __t) { __t -= 1; };
+
+template <class T>
+concept is_plusable = requires(T& __t) { __t + 1; };
+template <class T>
+concept is_minusable = requires(T& __t) { __t - 1; };
+
+template <class T>
+concept is_relationally_comparable = requires(T& __t) {
+  __t < __t;
+  __t > __t;
+  __t <= __t;
+  __t >= __t;
+};
+
+template <class T>
+concept is_plus_plusable_post = requires(T& __t) { __t++; };
+template <class T>
+concept is_plus_plusable_pre = requires(T& __t) { ++__t; };
+template <class T>
+concept is_minus_minusable_post = requires(T& __t) { __t--; };
+template <class T>
+concept is_minus_minusable_pre = requires(T& __t) { --__t; };
+
+constexpr bool operator_tests() {
+  {
+    // What operators are valid for an iterator derived from a stride view
+    // over an input view.
+    int arr[] = {1, 2, 3};
+    auto rav  = InputArrayView<int>(arr, arr + 3);
+    auto str  = std::ranges::stride_view<InputArrayView<int>>(rav, 1);
+
+    auto strb = str.begin();
+
+    static_assert(is_plus_plusable_post<decltype(strb)>);
+    static_assert(is_plus_plusable_pre<decltype(strb)>);
+    static_assert(!is_minus_minusable_post<decltype(strb)>);
+    static_assert(!is_minus_minusable_pre<decltype(strb)>);
+    static_assert(!is_plus_equalable<decltype(strb)>);
+    static_assert(!is_minus_equalable<decltype(strb)>);
+    static_assert(!is_plusable<decltype(strb)>);
+    static_assert(!is_minusable<decltype(strb)>);
+    static_assert(!is_relationally_comparable<decltype(strb)>);
+  }
+  {
+    // What operators are valid for an iterator derived from a stride view
+    // over a forward  view.
+    int arr[] = {1, 2, 3};
+    auto rav  = ForwardArrayView<int>(arr, arr + 3);
+    auto str  = std::ranges::stride_view<ForwardArrayView<int>>(rav, 1);
+
+    auto strb = str.begin();
+
+    static_assert(is_plus_plusable_post<decltype(strb)>);
+    static_assert(is_plus_plusable_pre<decltype(strb)>);
+    static_assert(!is_minus_minusable_post<decltype(strb)>);
+    static_assert(!is_minus_minusable_pre<decltype(strb)>);
+    static_assert(!is_plus_equalable<decltype(strb)>);
+    static_assert(!is_minus_equalable<decltype(strb)>);
+    static_assert(!is_plusable<decltype(strb)>);
+    static_assert(!is_minusable<decltype(strb)>);
+    static_assert(!is_relationally_comparable<decltype(strb)>);
+  }
+  {
+    // What operators are valid for an iterator derived from a stride view
+    // over a bidirectional view.
+    int arr[] = {1, 2, 3};
+    auto rav  = BidirArrayView<int>(arr, arr + 3);
+    auto str  = std::ranges::stride_view<BidirArrayView<int>>(rav, 1);
+
+    auto strb = str.begin();
+
+    static_assert(is_plus_plusable_post<decltype(strb)>);
+    static_assert(is_plus_plusable_pre<decltype(strb)>);
+    static_assert(is_minus_minusable_post<decltype(strb)>);
+    static_assert(is_minus_minusable_pre<decltype(strb)>);
+    static_assert(!is_plus_equalable<decltype(strb)>);
+    static_assert(!is_minus_equalable<decltype(strb)>);
+    static_assert(!is_plusable<decltype(strb)>);
+    static_assert(!is_minusable<decltype(strb)>);
+    static_assert(!is_relationally_comparable<decltype(strb)>);
+  }
+  {
+    // What operators are valid for an iterator derived from a stride view
+    // over a random access view.
+    int arr[] = {1, 2, 3};
+    auto rav  = RandomAccessArrayView<int>(arr, arr + 3);
+    auto str  = std::ranges::stride_view<RandomAccessArrayView<int>>(rav, 1);
+
+    auto strb = str.begin();
+
+    static_assert(is_plus_plusable_post<decltype(strb)>);
+    static_assert(is_plus_plusable_pre<decltype(strb)>);
+    static_assert(is_minus_minusable_post<decltype(strb)>);
+    static_assert(is_minus_minusable_pre<decltype(strb)>);
+    static_assert(is_plus_equalable<decltype(strb)>);
+    static_assert(is_minus_equalable<decltype(strb)>);
+    static_assert(is_plusable<decltype(strb)>);
+    static_assert(is_minusable<decltype(strb)>);
+    static_assert(is_relationally_comparable<decltype(strb)>);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  operator_tests();
+  static_assert(operator_tests());
+  return 0;
+}

>From 93d9d67a05e1243290a8cc793b250a60b412a772 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 10 Nov 2023 10:55:55 -0500
Subject: [PATCH 47/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add new support for interator-to-range support.
---
 .../ranges/range.adaptors/range.stride.view/test.h   | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 967c75c9cf0022..957cab30446978 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -12,6 +12,7 @@
 #include "__concepts/equality_comparable.h"
 #include "__concepts/movable.h"
 #include "__concepts/semiregular.h"
+#include "__iterator/concepts.h"
 #include "__iterator/default_sentinel.h"
 #include "__ranges/access.h"
 #include "__ranges/concepts.h"
@@ -208,6 +209,17 @@ static_assert(std::ranges::view<InputArrayView<int>>);
 static_assert(std::ranges::input_range<InputArrayView<int>>);
 static_assert(std::copyable<InputArrayView<int>>);
 
+template <std::input_iterator T, std::sentinel_for<T> S = sentinel_wrapper<T>>
+struct InputArrayViewNp : std::ranges::view_base {
+  T begin_;
+  T end_;
+
+  constexpr InputArrayViewNp(T b, T e) : begin_(b), end_(e) {}
+
+  constexpr T begin() { return begin_; }
+  constexpr sentinel_wrapper<T> end() { return sentinel_wrapper<T>{end_}; }
+};
+
 struct ForwardTracedMoveIter : ForwardIterBase<ForwardTracedMoveIter> {
   bool moved = false;
 

>From e7c8ad6067c331426bf99720a39a4d620f09440a Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 10 Nov 2023 10:56:31 -0500
Subject: [PATCH 48/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Test operator- between two stride_view::_iterator-s.
---
 .../iterator/operator.pass.cpp                | 51 +++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
index b3672765e891a5..2b2f17b9feed6e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
@@ -13,10 +13,14 @@
 // std::views::stride_view::iterator
 
 #include "../test.h"
+#include "__concepts/constructible.h"
 #include "__iterator/concepts.h"
 #include "__ranges/access.h"
+#include "__ranges/concepts.h"
+#include "test_iterators.h"
 #include <ranges>
 #include <type_traits>
+#include <vector>
 
 template <class T>
 concept is_plus_equalable = requires(T& __t) { __t += 1; };
@@ -45,6 +49,9 @@ concept is_minus_minusable_post = requires(T& __t) { __t--; };
 template <class T>
 concept is_minus_minusable_pre = requires(T& __t) { --__t; };
 
+template <class T>
+concept can_calculate_distance_between_non_sentinel = requires(T& __t) { __t - __t; };
+
 constexpr bool operator_tests() {
   {
     // What operators are valid for an iterator derived from a stride view
@@ -122,6 +129,50 @@ constexpr bool operator_tests() {
     static_assert(is_minusable<decltype(strb)>);
     static_assert(is_relationally_comparable<decltype(strb)>);
   }
+
+  {
+    // Test the non-forward-range operator- between two iterators.
+    int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    auto rav_zero    = InputArrayViewNp<int*>(arr, arr + 10);
+    auto rav_one     = InputArrayViewNp<int*>(arr + 1, arr + 10);
+    auto stride_zoff = std::ranges::stride_view(rav_zero, 3);
+    auto stride_ooff = std::ranges::stride_view(rav_one, 3);
+
+    auto stride_zoff_base = stride_zoff.begin();
+    auto stride_ooff_base = stride_ooff.begin();
+
+    auto stride_zoff_one   = stride_zoff_base;
+    auto stride_zoff_four  = stride_zoff_base + 1;
+    auto stride_zoff_seven = stride_zoff_base + 2;
+
+    auto stride_ooff_two  = stride_ooff_base;
+    auto stride_ooff_five = stride_ooff_base + 1;
+
+    static_assert(!std::ranges::forward_range<decltype(std::move(stride_zoff_base).base())>);
+    static_assert(std::sized_sentinel_for<decltype(std::move(stride_zoff_base).base()),
+                                          decltype(std::move(stride_zoff_base).base())>);
+    static_assert(can_calculate_distance_between_non_sentinel<decltype(stride_zoff_base)>);
+
+    assert(*stride_zoff_one == 1);
+    assert(*stride_zoff_four == 4);
+
+    assert(*stride_ooff_two == 2);
+    assert(*stride_ooff_five == 5);
+
+    // Check positive __n with exact multiple of left's stride.
+    assert(stride_zoff_four - stride_zoff_one == 1);
+    assert(stride_zoff_seven - stride_zoff_one == 2);
+    // Check positive __n with non-exact multiple of left's stride.
+    assert(stride_ooff_two - stride_zoff_one == 1);
+    assert(stride_ooff_five - stride_zoff_one == 2);
+
+    // Check negative __n with exact multiple of left's stride.
+    assert(stride_zoff_one - stride_zoff_four == -1);
+    assert(stride_zoff_one - stride_zoff_seven == -2);
+    // Check negative __n with non-exact multiple of left's stride.
+    assert(stride_zoff_one - stride_ooff_two == -1);
+    assert(stride_zoff_one - stride_ooff_five == -2);
+  }
   return true;
 }
 

>From eb1fd71e29d47cb9bba953bcd72c5432df4378b8 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 10 Nov 2023 16:11:10 -0500
Subject: [PATCH 49/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Fix small formatting error.
---
 libcxx/include/__ranges/stride_view.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index c7f9a4922f7d0a..772551abadc39d 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -371,8 +371,8 @@ namespace __stride {
 struct __fn {
   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}) {
+      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);
   }
 

>From 8c8e93312214eebae9505bb0050cc69acdc8b3ac Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 13 Nov 2023 19:01:36 -0500
Subject: [PATCH 50/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Remove extraneous testing view classes.
---
 .../range.stride.view/adaptor.pass.cpp        |  48 +++----
 .../range.stride.view/ctor.pass.cpp           |   7 +-
 .../range.stride.view/iterator/begin.pass.cpp |  17 +--
 .../iterator/operator.pass.cpp                |  44 ++++---
 .../range.stride.view/stride.pass.cpp         |   8 +-
 .../range.adaptors/range.stride.view/test.h   | 120 +++++-------------
 6 files changed, 103 insertions(+), 141 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
index 02e57c8865709b..50a349cd6207df 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -14,6 +14,7 @@
 
 #include "__ranges/stride_view.h"
 #include "test.h"
+#include "test_iterators.h"
 #include <concepts>
 #include <iterator>
 #include <ranges>
@@ -33,11 +34,10 @@ constexpr bool test() {
     // view | stride
     {
       {
-        BidirArrayView<int> view(arr, arr + array_n);
-        //std::ranges::stride_view<BidirView> strided(view, 1);
-        std::same_as<std::ranges::stride_view<BidirArrayView<int>>> decltype(auto) strided =
-            view | std::views::stride(1);
-        auto strided_iter = strided.begin();
+        using View = InputView<bidirectional_iterator<int*>>;
+        View view(bidirectional_iterator(arr), bidirectional_iterator(arr + array_n));
+        std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(1);
+        auto strided_iter                                                   = strided.begin();
 
         // Check that the begin() iter views arr[0]
         assert(*strided_iter == arr[0]);
@@ -47,10 +47,10 @@ constexpr bool test() {
         assert(*strided_iter == arr[2]);
       }
       {
-        BidirArrayView<int> view(arr, arr + array_n);
-        std::same_as<std::ranges::stride_view<BidirArrayView<int>>> decltype(auto) strided =
-            view | std::views::stride(2);
-        auto strided_iter = strided.begin();
+        using View = InputView<bidirectional_iterator<int*>>;
+        View view(bidirectional_iterator(arr), bidirectional_iterator(arr + array_n));
+        std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(2);
+        auto strided_iter                                                   = strided.begin();
 
         assert(*strided_iter == arr[0]);
 
@@ -65,20 +65,22 @@ constexpr bool test() {
   // adaptor | stride
   {
     // Parallels the two tests from above.
-    constexpr auto identity_lambda = [](int i) { return i * 2; };
+    constexpr const auto identity_lambda = [](const int i) { return i * 2; };
     {
-      BidirArrayView<int> view(arr, arr + array_n);
+      using View = InputView<bidirectional_iterator<int*>>;
+      View view(bidirectional_iterator(arr), bidirectional_iterator(arr + array_n));
       const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(1);
 
-      const auto transform_stride_applied = transform_stride_partial(view);
-      auto transform_stride_applied_iter  = transform_stride_applied.begin();
+      auto transform_stride_applied      = transform_stride_partial(view);
+      auto transform_stride_applied_iter = transform_stride_applied.begin();
       assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[0]));
       std::ranges::advance(transform_stride_applied_iter, 2);
       assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[2]));
     }
 
     {
-      BidirArrayView<int> view(arr, arr + array_n);
+      using View = InputView<bidirectional_iterator<int*>>;
+      View view(bidirectional_iterator(arr), bidirectional_iterator(arr + array_n));
       const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(2);
 
       const auto transform_stride_applied = transform_stride_partial(view);
@@ -90,9 +92,9 @@ constexpr bool test() {
   }
 
   {
-    using ForwardStrideView      = std::ranges::stride_view<ForwardArrayView<int>>;
-    using BidirStrideView        = std::ranges::stride_view<BidirArrayView<int>>;
-    using RandomAccessStrideView = std::ranges::stride_view<RandomAccessArrayView<int>>;
+    using ForwardStrideView      = std::ranges::stride_view<InputView<forward_iterator<int*>>>;
+    using BidirStrideView        = std::ranges::stride_view<InputView<bidirectional_iterator<int*>>>;
+    using RandomAccessStrideView = std::ranges::stride_view<InputView<random_access_iterator<int*>>>;
 
     static_assert(std::ranges::forward_range<ForwardStrideView>);
     static_assert(std::ranges::bidirectional_range<BidirStrideView>);
@@ -102,6 +104,7 @@ constexpr bool test() {
 
   // Check SFINAE friendliness
   {
+    using View = InputView<bidirectional_iterator<int*>>;
     struct NotAViewableRange {};
     struct NotARange {};
     // Not invocable because there is no parameter.
@@ -109,15 +112,12 @@ constexpr bool test() {
     // Not invocable because NotAViewableRange is, well, not a viewable range.
     static_assert(!std::is_invocable_v<decltype(std::views::reverse), NotAViewableRange>);
     // Is invocable because BidirView is a viewable range.
-    static_assert(std::is_invocable_v<decltype(std::views::reverse), BidirArrayView<int>>);
+    static_assert(std::is_invocable_v<decltype(std::views::reverse), View>);
 
     // Make sure that pipe operations work!
-    static_assert(CanBePiped<BidirArrayView<int>,
-                             decltype(std::views::stride(std::ranges::range_difference_t<BidirArrayView<int>>{}))>);
-    static_assert(CanBePiped<BidirArrayView<int>&,
-                             decltype(std::views::stride(std::ranges::range_difference_t<BidirArrayView<int>>{}))>);
-    static_assert(
-        !CanBePiped<NotARange, decltype(std::views::stride(std::ranges::range_difference_t<BidirArrayView<int>>{}))>);
+    static_assert(CanBePiped<View, decltype(std::views::stride(std::ranges::range_difference_t<View>{}))>);
+    static_assert(CanBePiped<View&, decltype(std::views::stride(std::ranges::range_difference_t<View>{}))>);
+    static_assert(!CanBePiped<NotARange, decltype(std::views::stride(std::ranges::range_difference_t<View>{}))>);
   }
   // A final sanity check.
   { static_assert(std::same_as<decltype(std::views::stride), decltype(std::ranges::views::stride)>); }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
index 30256ac12b77e4..8d3cbcd1463cfa 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
@@ -14,17 +14,20 @@
 
 #include "test.h"
 #include "test_convertible.h"
+#include "test_iterators.h"
 #include <type_traits>
 
 constexpr bool test_no_default_ctor() {
   // There is no default ctor for stride_view.
-  static_assert(!std::is_default_constructible_v<std::ranges::stride_view<BidirArrayView<int>>>);
+  using View = InputView<cpp17_input_iterator<int*>>;
+  static_assert(!std::is_default_constructible_v<std::ranges::stride_view<View>>);
   return true;
 }
 
 constexpr bool test_no_implicit_ctor() {
+  using View = InputView<cpp17_input_iterator<int*>>;
   // Test that the stride_view can only be explicitly constructed.
-  static_assert(!test_convertible<std::ranges::stride_view<ForwardArrayView<int>>, ForwardArrayView<int>, int>());
+  static_assert(!test_convertible<std::ranges::stride_view<View>, View, int>());
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
index 6a9b1df59961bd..270d5cd0caaffa 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
@@ -14,6 +14,7 @@
 
 #include "../test.h"
 #include "__iterator/concepts.h"
+#include "test_iterators.h"
 #include <ranges>
 #include <type_traits>
 
@@ -21,8 +22,8 @@ constexpr bool iterator_concept_test() {
   {
     int arr[] = {1, 2, 3};
     // Iterator of stride over random access view should have random access concept.
-    auto rav = RandomAccessArrayView<int>(arr, arr + 3);
-    auto str = std::ranges::stride_view<RandomAccessArrayView<int>>(rav, 1);
+    auto rav = InputView<random_access_iterator<int*>>(random_access_iterator(arr), random_access_iterator(arr + 3));
+    auto str = std::ranges::stride_view<InputView<random_access_iterator<int*>>>(rav, 1);
     static_assert(std::random_access_iterator<decltype(rav.begin())>);
     static_assert(std::random_access_iterator<decltype(str.begin())>);
   }
@@ -30,8 +31,8 @@ constexpr bool iterator_concept_test() {
   {
     int arr[] = {1, 2, 3};
     // Iterator of stride over bidirectional view should have bidirectional view concept.
-    auto rav = BidirArrayView<int>(arr, arr + 3);
-    auto str = std::ranges::stride_view<BidirArrayView<int>>(rav, 1);
+    auto rav = InputView<bidirectional_iterator<int*>>(bidirectional_iterator(arr), bidirectional_iterator(arr + 3));
+    auto str = std::ranges::stride_view<InputView<bidirectional_iterator<int*>>>(rav, 1);
     static_assert(std::bidirectional_iterator<decltype(rav.begin())>);
     static_assert(std::bidirectional_iterator<decltype(str.begin())>);
     static_assert(!std::random_access_iterator<decltype(rav.begin())>);
@@ -41,8 +42,8 @@ constexpr bool iterator_concept_test() {
   {
     int arr[] = {1, 2, 3};
     // Iterator of stride over forward view should have forward view concept.
-    auto rav = ForwardArrayView<int>(arr, arr + 3);
-    auto str = std::ranges::stride_view<ForwardArrayView<int>>(rav, 1);
+    auto rav = InputView<forward_iterator<int*>>(forward_iterator(arr), forward_iterator(arr + 3));
+    auto str = std::ranges::stride_view<InputView<forward_iterator<int*>>>(rav, 1);
     static_assert(std::forward_iterator<decltype(rav.begin())>);
     static_assert(std::forward_iterator<decltype(str.begin())>);
     static_assert(!std::bidirectional_iterator<decltype(rav.begin())>);
@@ -54,8 +55,8 @@ constexpr bool iterator_concept_test() {
   {
     int arr[] = {1, 2, 3};
     // Iterator of stride over input view should have input view concept.
-    auto rav = InputArrayView<int>(arr, arr + 3);
-    auto str = std::ranges::stride_view<InputArrayView<int>>(rav, 1);
+    auto rav = InputView<cpp17_input_iterator<int*>>(cpp17_input_iterator(arr), cpp17_input_iterator(arr + 3));
+    auto str = std::ranges::stride_view<InputView<cpp17_input_iterator<int*>>>(rav, 1);
     static_assert(std::input_iterator<decltype(rav.begin())>);
     static_assert(std::input_iterator<decltype(str.begin())>);
     static_assert(!std::forward_iterator<decltype(rav.begin())>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
index 2b2f17b9feed6e..5118b35db82045 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
@@ -56,9 +56,10 @@ constexpr bool operator_tests() {
   {
     // What operators are valid for an iterator derived from a stride view
     // over an input view.
-    int arr[] = {1, 2, 3};
-    auto rav  = InputArrayView<int>(arr, arr + 3);
-    auto str  = std::ranges::stride_view<InputArrayView<int>>(rav, 1);
+    int arr[]  = {1, 2, 3};
+    using View = InputView<cpp17_input_iterator<int*>>;
+    auto rav   = View(cpp17_input_iterator(arr), cpp17_input_iterator(arr + 3));
+    auto str   = std::ranges::stride_view<View>(rav, 1);
 
     auto strb = str.begin();
 
@@ -75,9 +76,10 @@ constexpr bool operator_tests() {
   {
     // What operators are valid for an iterator derived from a stride view
     // over a forward  view.
-    int arr[] = {1, 2, 3};
-    auto rav  = ForwardArrayView<int>(arr, arr + 3);
-    auto str  = std::ranges::stride_view<ForwardArrayView<int>>(rav, 1);
+    int arr[]  = {1, 2, 3};
+    using View = InputView<forward_iterator<int*>>;
+    auto rav   = View(forward_iterator(arr), forward_iterator(arr + 3));
+    auto str   = std::ranges::stride_view<View>(rav, 1);
 
     auto strb = str.begin();
 
@@ -94,9 +96,10 @@ constexpr bool operator_tests() {
   {
     // What operators are valid for an iterator derived from a stride view
     // over a bidirectional view.
-    int arr[] = {1, 2, 3};
-    auto rav  = BidirArrayView<int>(arr, arr + 3);
-    auto str  = std::ranges::stride_view<BidirArrayView<int>>(rav, 1);
+    int arr[]  = {1, 2, 3};
+    using View = InputView<bidirectional_iterator<int*>>;
+    auto rav   = View(bidirectional_iterator(arr), bidirectional_iterator(arr + 3));
+    auto str   = std::ranges::stride_view<View>(rav, 1);
 
     auto strb = str.begin();
 
@@ -113,9 +116,10 @@ constexpr bool operator_tests() {
   {
     // What operators are valid for an iterator derived from a stride view
     // over a random access view.
-    int arr[] = {1, 2, 3};
-    auto rav  = RandomAccessArrayView<int>(arr, arr + 3);
-    auto str  = std::ranges::stride_view<RandomAccessArrayView<int>>(rav, 1);
+    int arr[]  = {1, 2, 3};
+    using View = InputView<random_access_iterator<int*>>;
+    auto rav   = View(random_access_iterator(arr), random_access_iterator(arr + 3));
+    auto str   = std::ranges::stride_view<View>(rav, 1);
 
     auto strb = str.begin();
 
@@ -131,10 +135,12 @@ constexpr bool operator_tests() {
   }
 
   {
-    // Test the non-forward-range operator- between two iterators.
+    // Test the non-forward-range operator- between two iterators (i.e., ceil).
     int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-    auto rav_zero    = InputArrayViewNp<int*>(arr, arr + 10);
-    auto rav_one     = InputArrayViewNp<int*>(arr + 1, arr + 10);
+    auto rav_zero =
+        InputView<SizedInputIterator, SizedInputIterator>(SizedInputIterator(arr), SizedInputIterator(arr + 10));
+    auto rav_one =
+        InputView<SizedInputIterator, SizedInputIterator>(SizedInputIterator(arr + 1), SizedInputIterator(arr + 10));
     auto stride_zoff = std::ranges::stride_view(rav_zero, 3);
     auto stride_ooff = std::ranges::stride_view(rav_one, 3);
 
@@ -142,19 +148,19 @@ constexpr bool operator_tests() {
     auto stride_ooff_base = stride_ooff.begin();
 
     auto stride_zoff_one   = stride_zoff_base;
-    auto stride_zoff_four  = stride_zoff_base + 1;
-    auto stride_zoff_seven = stride_zoff_base + 2;
+    auto stride_zoff_four  = ++stride_zoff_base;
+    auto stride_zoff_seven = ++stride_zoff_base;
 
     auto stride_ooff_two  = stride_ooff_base;
-    auto stride_ooff_five = stride_ooff_base + 1;
+    auto stride_ooff_five = ++stride_ooff_base;
 
-    static_assert(!std::ranges::forward_range<decltype(std::move(stride_zoff_base).base())>);
     static_assert(std::sized_sentinel_for<decltype(std::move(stride_zoff_base).base()),
                                           decltype(std::move(stride_zoff_base).base())>);
     static_assert(can_calculate_distance_between_non_sentinel<decltype(stride_zoff_base)>);
 
     assert(*stride_zoff_one == 1);
     assert(*stride_zoff_four == 4);
+    assert(*stride_zoff_seven == 7);
 
     assert(*stride_ooff_two == 2);
     assert(*stride_ooff_five == 5);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
index 154f747f49bd7f..25ffcce838bd44 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
@@ -13,14 +13,16 @@
 // std::views::stride_view
 
 #include "test.h"
+#include "test_iterators.h"
 #include <ranges>
 #include <type_traits>
 #include <utility>
 
 constexpr bool test() {
-  static_assert(noexcept(std::declval<std::ranges::stride_view<BidirArrayView<int>>>().stride()));
-  static_assert(std::is_same_v<std::ranges::range_difference_t<BidirArrayView<int>>,
-                               decltype(std::declval<std::ranges::stride_view<BidirArrayView<int>>>().stride())>);
+  using View = InputView<bidirectional_iterator<int*>>;
+  static_assert(noexcept(std::declval<std::ranges::stride_view<View>>().stride()));
+  static_assert(std::is_same_v<std::ranges::range_difference_t<View>,
+                               decltype(std::declval<std::ranges::stride_view<View>>().stride())>);
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 957cab30446978..4bda90fcf0e288 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -126,98 +126,18 @@ struct InputIterBase {
   friend constexpr bool operator==(const Derived&, const std::default_sentinel_t&) { return true; }
 };
 
-/*
- * XXXArrayView classes for use throughout the stride view tests.
- */
-
-template <typename T>
-struct RandomAccessArrayView : std::ranges::view_base {
-  T* begin_;
-  T* end_;
-
-  constexpr RandomAccessArrayView(T* b, T* e) : begin_(b), end_(e) {}
-
-  constexpr random_access_iterator<T*> begin() { return random_access_iterator<T*>{begin_}; }
-  constexpr random_access_iterator<const T*> begin() const { return random_access_iterator<const T*>{begin_}; }
-  constexpr sentinel_wrapper<random_access_iterator<T*>> end() {
-    return sentinel_wrapper<random_access_iterator<T*>>{random_access_iterator<T*>{end_}};
-  }
-  constexpr sentinel_wrapper<random_access_iterator<const T*>> end() const {
-    return sentinel_wrapper<random_access_iterator<const T*>>{random_access_iterator<const T*>{end_}};
-  }
-  constexpr std::size_t size() const { return end_ - begin_; }
-};
-static_assert(std::ranges::view<RandomAccessArrayView<int>>);
-static_assert(std::ranges::random_access_range<RandomAccessArrayView<int>>);
-static_assert(std::copyable<RandomAccessArrayView<int>>);
-
-template <typename T>
-struct BidirArrayView : std::ranges::view_base {
-  T* begin_;
-  T* end_;
-
-  constexpr BidirArrayView(T* b, T* e) : begin_(b), end_(e) {}
-
-  constexpr bidirectional_iterator<T*> begin() { return bidirectional_iterator<T*>{begin_}; }
-  constexpr bidirectional_iterator<const T*> begin() const { return bidirectional_iterator<const T*>{begin_}; }
-  constexpr sentinel_wrapper<bidirectional_iterator<T*>> end() {
-    return sentinel_wrapper<bidirectional_iterator<T*>>{bidirectional_iterator<T*>{end_}};
-  }
-  constexpr sentinel_wrapper<bidirectional_iterator<const T*>> end() const {
-    return sentinel_wrapper<bidirectional_iterator<const T*>>{bidirectional_iterator<const T*>{end_}};
-  }
-};
-static_assert(std::ranges::view<BidirArrayView<int>>);
-static_assert(std::ranges::bidirectional_range<BidirArrayView<int>>);
-static_assert(std::copyable<BidirArrayView<int>>);
-
-template <typename T>
-struct ForwardArrayView : public std::ranges::view_base {
-  T* begin_;
-  T* end_;
-
-  constexpr ForwardArrayView(T* b, T* e) : begin_(b), end_(e) {}
-
-  constexpr forward_iterator<T*> begin() { return forward_iterator<T*>{begin_}; }
-  constexpr forward_iterator<const T*> begin() const { return forward_iterator<const T*>{begin_}; }
-  constexpr sentinel_wrapper<forward_iterator<T*>> end() {
-    return sentinel_wrapper<forward_iterator<T*>>{forward_iterator<T*>{end_}};
-  }
-  constexpr sentinel_wrapper<forward_iterator<const T*>> end() const {
-    return sentinel_wrapper<forward_iterator<const T*>>{forward_iterator<const T*>{end_}};
-  }
-};
-static_assert(std::ranges::view<ForwardArrayView<int>>);
-static_assert(std::ranges::forward_range<ForwardArrayView<int>>);
-static_assert(std::copyable<ForwardArrayView<int>>);
-
-template <typename T>
-struct InputArrayView : std::ranges::view_base {
-  T* begin_;
-  T* end_;
-
-  constexpr InputArrayView(T* b, T* e) : begin_(b), end_(e) {}
-
-  constexpr cpp20_input_iterator<T*> begin() { return cpp20_input_iterator<T*>{begin_}; }
-  constexpr random_access_iterator<const T*> begin() const { return random_access_iterator<const T*>{begin_}; }
-  constexpr sentinel_wrapper<cpp20_input_iterator<T*>> end() {
-    return sentinel_wrapper<cpp20_input_iterator<T*>>{cpp20_input_iterator<T*>{end_}};
-  }
-  constexpr std::size_t size() const { return end_ - begin_; }
-};
-static_assert(std::ranges::view<InputArrayView<int>>);
-static_assert(std::ranges::input_range<InputArrayView<int>>);
-static_assert(std::copyable<InputArrayView<int>>);
-
+//TODO: Rename as View.
 template <std::input_iterator T, std::sentinel_for<T> S = sentinel_wrapper<T>>
-struct InputArrayViewNp : std::ranges::view_base {
+struct InputView : std::ranges::view_base {
   T begin_;
   T end_;
 
-  constexpr InputArrayViewNp(T b, T e) : begin_(b), end_(e) {}
+  constexpr InputView(T b, T e) : begin_(b), end_(e) {}
 
   constexpr T begin() { return begin_; }
+  constexpr T begin() const { return begin_; }
   constexpr sentinel_wrapper<T> end() { return sentinel_wrapper<T>{end_}; }
+  constexpr sentinel_wrapper<T> end() const { return sentinel_wrapper<T>{end_}; }
 };
 
 struct ForwardTracedMoveIter : ForwardIterBase<ForwardTracedMoveIter> {
@@ -242,4 +162,34 @@ struct UnsizedBasicRange : std::ranges::view_base {
   UnsizedBasicRangeIterator end() const;
 };
 
+// TODO: Cleanup
+struct SizedInputIterator {
+  using iterator_concept = std::input_iterator_tag;
+  using value_type       = int;
+  using difference_type  = std::intptr_t;
+
+  int* __v_;
+
+  constexpr SizedInputIterator() { __v_ = nullptr; }
+  constexpr SizedInputIterator(int* __v) { __v_ = __v; }
+  constexpr SizedInputIterator(const SizedInputIterator& sii) { __v_ = sii.__v_; }
+
+  constexpr int operator*() const { return *__v_; }
+  constexpr SizedInputIterator& operator++() {
+    __v_++;
+    return *this;
+  }
+  constexpr SizedInputIterator operator++(int) {
+    auto nv = __v_;
+    nv++;
+    return SizedInputIterator(nv);
+  }
+  friend constexpr bool operator==(const SizedInputIterator& left, const SizedInputIterator& right) {
+    return left.__v_ == right.__v_;
+  }
+  friend constexpr difference_type operator-(const SizedInputIterator& left, const SizedInputIterator& right) {
+    return left.__v_ - right.__v_;
+  }
+};
+
 #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H

>From fcaf83935c5d6615838ee2c365e0b2edf0dc608b Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 15 Nov 2023 10:42:54 -0500
Subject: [PATCH 51/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Update stride() tests per @var-const feedback.
---
 .../range.stride.view/stride.pass.cpp         | 24 ++++++++++++-------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
index 25ffcce838bd44..9b84817be4abb1 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
@@ -8,27 +8,33 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
+// constexpr range_difference_t<_View> stride() const noexcept;
 
-// std::views::stride_view
-
-#include "test.h"
 #include "test_iterators.h"
+#include "test.h"
 #include <ranges>
 #include <type_traits>
 #include <utility>
 
 constexpr bool test() {
-  using View = InputView<bidirectional_iterator<int*>>;
-  static_assert(noexcept(std::declval<std::ranges::stride_view<View>>().stride()));
-  static_assert(std::is_same_v<std::ranges::range_difference_t<View>,
-                               decltype(std::declval<std::ranges::stride_view<View>>().stride())>);
+  using View = InputView<cpp17_input_iterator<int*>>;
+  int arr[]{1, 2, 3};
+  auto arrv(View(cpp17_input_iterator(arr), cpp17_input_iterator(arr + 3)));
+  // Mark str const so that we confirm that stride is a const member function.
+  const std::ranges::stride_view<View> str(arrv, 1);
+
+  // Make sure that stride member function is noexcept.
+  static_assert(noexcept(str.stride()));
+  // Make sure that the type returned by stride matches what is expected.
+  static_assert(std::is_same_v<std::ranges::range_difference_t<View>, decltype(str.stride())>);
+  // Make sure that we get back a stride equal to the one that we gave in the ctor.
+  assert(str.stride() == 1);
+
   return true;
 }
 
 int main(int, char**) {
   test();
   static_assert(test());
-
   return 0;
 }

>From b011c4f87c395d906839092ed3cf4bf89239b273 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 15 Nov 2023 23:56:02 -0500
Subject: [PATCH 52/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Update stride_view ctor  tests per @var-const feedback.
---
 .../range.stride.view/ctor.pass.cpp           | 68 ++++++++++---------
 .../range.adaptors/range.stride.view/test.h   | 20 +++++-
 2 files changed, 55 insertions(+), 33 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
index 8d3cbcd1463cfa..a34d3cbb3863f6 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
@@ -8,49 +8,53 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
+// constexpr explicit stride_view(_View, range_difference_t<_View>)
 
-// std::views::stride_view
+#include <type_traits>
 
 #include "test.h"
 #include "test_convertible.h"
 #include "test_iterators.h"
-#include <type_traits>
 
-constexpr bool test_no_default_ctor() {
-  // There is no default ctor for stride_view.
-  using View = InputView<cpp17_input_iterator<int*>>;
-  static_assert(!std::is_default_constructible_v<std::ranges::stride_view<View>>);
-  return true;
-}
+// There is no default ctor for stride_view.
+using View = InputView<cpp17_input_iterator<int*>>;
+static_assert(!std::is_default_constructible_v<std::ranges::stride_view<View>>);
 
-constexpr bool test_no_implicit_ctor() {
-  using View = InputView<cpp17_input_iterator<int*>>;
-  // Test that the stride_view can only be explicitly constructed.
-  static_assert(!test_convertible<std::ranges::stride_view<View>, View, int>());
-  return true;
-}
+// Test that the stride_view can only be explicitly constructed.
+static_assert(!test_convertible<std::ranges::stride_view<View>, View, int>());
+
+constexpr bool test() {
+  {
+    int arr[] = {1, 2, 3};
+    // Test that what we will stride over is move only.
+    static_assert(!std::is_copy_constructible_v<MoveOnlyView<cpp17_input_iterator<int*>>>);
+    static_assert(std::is_move_constructible_v<MoveOnlyView<cpp17_input_iterator<int*>>>);
+
+    MoveOnlyView<cpp17_input_iterator<int*>> mov(cpp17_input_iterator(arr), cpp17_input_iterator(arr + 3));
+    // Because MoveOnlyView is, well, move only, we can test that it is moved
+    // from when the stride view is constructed.
+    std::ranges::stride_view<MoveOnlyView<cpp17_input_iterator<int*>>> mosv(std::move(mov), 1);
+
+    // While we are here, make sure that the ctor captured the proper things
+    assert(mosv.stride() == 1);
+
+    auto mosv_i = mosv.begin();
+    assert(*mosv_i == 1);
+
+    mosv_i++;
+    assert(*mosv_i == 2);
+
+    mosv_i++;
+    assert(*mosv_i == 3);
 
-constexpr bool test_move_ctor() {
-  int arr[] = {1, 2, 3};
-  // Test that the stride_view ctor properly moves from the base (and works with a move-only type).
-  static_assert(!std::is_copy_constructible_v<MovedOnlyTrackedBasicView<int>>);
-  static_assert(std::is_move_constructible_v<MovedOnlyTrackedBasicView<int>>);
-
-  bool moved(false), copied(false);
-  MovedOnlyTrackedBasicView<int> mov(arr, arr + 3, &moved, &copied);
-  std::ranges::stride_view<MovedOnlyTrackedBasicView<int>> mosv(std::move(mov), 2);
-  assert(moved);
-  assert(!copied);
+    mosv_i++;
+    assert(mosv_i == mosv.end());
+  }
   return true;
 }
 
 int main(int, char**) {
-  test_no_implicit_ctor();
-  static_assert(test_no_implicit_ctor());
-  test_no_default_ctor();
-  static_assert(test_no_default_ctor());
-  test_move_ctor();
-  static_assert(test_move_ctor());
+  test();
+  static_assert(test());
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 4bda90fcf0e288..159de0f78f5837 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -126,6 +126,24 @@ struct InputIterBase {
   friend constexpr bool operator==(const Derived&, const std::default_sentinel_t&) { return true; }
 };
 
+template <std::input_iterator T, std::sentinel_for<T> S = sentinel_wrapper<T>>
+struct MoveOnlyView : std::ranges::view_base {
+  T begin_;
+  T end_;
+
+  constexpr MoveOnlyView(T b, T e) : begin_(b), end_(e) {}
+
+  constexpr MoveOnlyView(const MoveOnlyView&)            = delete;
+  constexpr MoveOnlyView(MoveOnlyView&& other)           = default;
+  constexpr MoveOnlyView& operator=(MoveOnlyView&&)      = default;
+  constexpr MoveOnlyView& operator=(const MoveOnlyView&) = delete;
+
+  constexpr T begin() { return begin_; }
+  constexpr T begin() const { return begin_; }
+  constexpr sentinel_wrapper<T> end() { return sentinel_wrapper<T>{end_}; }
+  constexpr sentinel_wrapper<T> end() const { return sentinel_wrapper<T>{end_}; }
+};
+
 //TODO: Rename as View.
 template <std::input_iterator T, std::sentinel_for<T> S = sentinel_wrapper<T>>
 struct InputView : std::ranges::view_base {
@@ -171,7 +189,7 @@ struct SizedInputIterator {
   int* __v_;
 
   constexpr SizedInputIterator() { __v_ = nullptr; }
-  constexpr SizedInputIterator(int* __v) { __v_ = __v; }
+  constexpr SizedInputIterator(int* v) { __v_ = v; }
   constexpr SizedInputIterator(const SizedInputIterator& sii) { __v_ = sii.__v_; }
 
   constexpr int operator*() const { return *__v_; }

>From 9c0d8467d6c16c32fb6fac53ec890bd9d08ac116 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 17 Nov 2023 21:07:57 -0500
Subject: [PATCH 53/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

---
 .../range.stride.view/adaptor.pass.cpp        |  8 +--
 .../range.stride.view/ctor.pass.cpp           |  2 +-
 .../range.stride.view/size.pass.cpp           | 60 -------------------
 .../range.stride.view/size.verify.cpp         | 49 +++++++++++++++
 .../range.stride.view/stride.pass.cpp         |  2 +-
 5 files changed, 55 insertions(+), 66 deletions(-)
 delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
index 50a349cd6207df..d3dcd7b73436cd 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -35,7 +35,7 @@ constexpr bool test() {
     {
       {
         using View = InputView<bidirectional_iterator<int*>>;
-        View view(bidirectional_iterator(arr), bidirectional_iterator(arr + array_n));
+        View view(bidirectional_iterator<int*>(arr), bidirectional_iterator<int*>(arr + array_n));
         std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(1);
         auto strided_iter                                                   = strided.begin();
 
@@ -48,7 +48,7 @@ constexpr bool test() {
       }
       {
         using View = InputView<bidirectional_iterator<int*>>;
-        View view(bidirectional_iterator(arr), bidirectional_iterator(arr + array_n));
+        View view(bidirectional_iterator<int*>(arr), bidirectional_iterator<int*>(arr + array_n));
         std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(2);
         auto strided_iter                                                   = strided.begin();
 
@@ -68,7 +68,7 @@ constexpr bool test() {
     constexpr const auto identity_lambda = [](const int i) { return i * 2; };
     {
       using View = InputView<bidirectional_iterator<int*>>;
-      View view(bidirectional_iterator(arr), bidirectional_iterator(arr + array_n));
+      View view(bidirectional_iterator<int*>(arr), bidirectional_iterator<int*>(arr + array_n));
       const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(1);
 
       auto transform_stride_applied      = transform_stride_partial(view);
@@ -80,7 +80,7 @@ constexpr bool test() {
 
     {
       using View = InputView<bidirectional_iterator<int*>>;
-      View view(bidirectional_iterator(arr), bidirectional_iterator(arr + array_n));
+      View view(bidirectional_iterator<int*>(arr), bidirectional_iterator<int*>(arr + array_n));
       const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(2);
 
       const auto transform_stride_applied = transform_stride_partial(view);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
index a34d3cbb3863f6..b705d30a6c74ea 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
@@ -30,7 +30,7 @@ constexpr bool test() {
     static_assert(!std::is_copy_constructible_v<MoveOnlyView<cpp17_input_iterator<int*>>>);
     static_assert(std::is_move_constructible_v<MoveOnlyView<cpp17_input_iterator<int*>>>);
 
-    MoveOnlyView<cpp17_input_iterator<int*>> mov(cpp17_input_iterator(arr), cpp17_input_iterator(arr + 3));
+    MoveOnlyView<cpp17_input_iterator<int*>> mov(cpp17_input_iterator<int*>(arr), cpp17_input_iterator<int*>(arr + 3));
     // Because MoveOnlyView is, well, move only, we can test that it is moved
     // from when the stride view is constructed.
     std::ranges::stride_view<MoveOnlyView<cpp17_input_iterator<int*>>> mosv(std::move(mov), 1);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp
deleted file mode 100644
index c270c77f6f9f32..00000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.pass.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// ranges
-
-// std::ranges::stride_view
-
-#include "test.h"
-#include <cassert>
-#include <ranges>
-
-bool runtime_test() {
-  auto iot    = std::views::iota(1, 22);
-  auto str    = std::views::stride(iot, 3);
-  auto result = str.size();
-  assert(result == 7);
-  return true;
-}
-
-constexpr bool test() {
-  {
-    // Test with ranges that are sized_range true.
-    constexpr auto iot_twelve = std::views::iota(1, 12);
-    static_assert(std::ranges::sized_range<decltype(iot_twelve)>);
-    constexpr auto str_iot_twelve = std::views::stride(iot_twelve, 3);
-    static_assert(std::ranges::sized_range<decltype(str_iot_twelve)>);
-    assert(4 == str_iot_twelve.size());
-    static_assert(4 == str_iot_twelve.size(), "Striding by 3 through a 12 member list has size 4.");
-
-    constexpr auto iot_twenty_two = std::views::iota(1, 22);
-    static_assert(std::ranges::sized_range<decltype(iot_twenty_two)>);
-    constexpr auto str_iot_twenty_two = std::views::stride(iot_twenty_two, 3);
-    static_assert(std::ranges::sized_range<decltype(str_iot_twenty_two)>);
-
-    assert(7 == str_iot_twenty_two.size());
-    static_assert(7 == str_iot_twenty_two.size(), "Striding by 3 through a 22 member list has size 4.");
-  }
-
-  {
-    // Test with ranges that are not sized_range true.
-    constexpr auto unsized_range = UnsizedBasicRange();
-    static_assert(!std::ranges::sized_range<decltype(unsized_range)>);
-    constexpr auto str_unsized = std::views::stride(unsized_range, 3);
-    static_assert(!std::ranges::sized_range<decltype(str_unsized)>);
-  }
-  return true;
-}
-
-int main(int, char**) {
-  runtime_test();
-  static_assert(test());
-  return 0;
-}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp
new file mode 100644
index 00000000000000..c3d87a1dac7b22
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr auto size()
+
+#include <cassert>
+#include <ranges>
+
+#include "test.h"
+
+// There is no size member function on a stride view over a view that
+// is *not* a sized range
+static_assert(!std::ranges::sized_range<UnsizedBasicRange>);                           // expected-no-diagnostics
+static_assert(!std::ranges::sized_range<std::ranges::stride_view<UnsizedBasicRange>>); // expected-no-diagnosticss
+
+constexpr bool test() {
+  {
+    // Test with stride as exact multiple of number of elements in view strided over.
+    constexpr auto iota_twelve = std::views::iota(0, 12);
+    static_assert(std::ranges::sized_range<decltype(iota_twelve)>); // expected-no-diagnostics
+    constexpr auto stride_iota_twelve = std::views::stride(iota_twelve, 3);
+    static_assert(std::ranges::sized_range<decltype(stride_iota_twelve)>); // expected-no-diagnostics
+    static_assert(4 == stride_iota_twelve.size(),
+                  "Striding by 3 through a 12 member list has size 4."); // expected-no-diagnostics
+  }
+
+  {
+    // Test with stride as inexact multiple of number of elements in view strided over.
+    constexpr auto iota_twenty_two = std::views::iota(0, 22);
+    static_assert(std::ranges::sized_range<decltype(iota_twenty_two)>); // expected-no-diagnostics
+    constexpr auto stride_iota_twenty_two = std::views::stride(iota_twenty_two, 3);
+    static_assert(std::ranges::sized_range<decltype(stride_iota_twenty_two)>); // expected-no-diagnostics
+    static_assert(8 == stride_iota_twenty_two.size(),
+                  "Striding by 3 through a 22 member list has size 8."); // expected-no-diagnostics
+  }
+  return true;
+}
+
+int main(int, char**) {
+  static_assert(test());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
index 9b84817be4abb1..12c8338c22fb3b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
@@ -19,7 +19,7 @@
 constexpr bool test() {
   using View = InputView<cpp17_input_iterator<int*>>;
   int arr[]{1, 2, 3};
-  auto arrv(View(cpp17_input_iterator(arr), cpp17_input_iterator(arr + 3)));
+  auto arrv(View(cpp17_input_iterator<int*>(arr), cpp17_input_iterator<int*>(arr + 3)));
   // Mark str const so that we confirm that stride is a const member function.
   const std::ranges::stride_view<View> str(arrv, 1);
 

>From 06e038689deb1d694c6476e549b150f408c4b687 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 17 Nov 2023 21:48:08 -0500
Subject: [PATCH 54/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Move borrowed_range testing to a verify test (and other formatting).
---
 .../enable_borrowed_range.compile.pass.cpp    | 32 -------------------
 .../enable_borrowed_range.verify.cpp          | 28 ++++++++++++++++
 2 files changed, 28 insertions(+), 32 deletions(-)
 delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.verify.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
deleted file mode 100644
index 4add46949a6aec..00000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.compile.pass.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// ranges
-
-// std::views::stride_view
-
-#include "test.h"
-#include <ranges>
-
-constexpr bool test() {
-  using std::ranges::enable_borrowed_range;
-  // Make sure that a stride_view over neither a borrowable nor an unborrowable view
-  // is itself borrowable.
-  static_assert(!enable_borrowed_range<std::ranges::stride_view<MovedCopiedTrackedBasicView<int>>>);
-  static_assert(!enable_borrowed_range<std::ranges::stride_view<InstrumentedBorrowedRange<int>>>);
-  return true;
-}
-
-int main(int, char**) {
-  test();
-  static_assert(test());
-
-  return 0;
-}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.verify.cpp
new file mode 100644
index 00000000000000..a17c813527a44d
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/enable_borrowed_range.verify.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+#include <ranges>
+
+#include "test.h"
+
+// template<class T>
+// inline constexpr bool enable_borrowed_range<stride_view<T>> = false;
+
+// The stride_view is not one of those range adaptors that (under any circumstances)
+// is enabled as a borrowable range by default. In other words, we will have to make
+// a positively test case explicity
+
+template <>
+inline constexpr bool
+    std::ranges::enable_borrowed_range<std::ranges::stride_view<InputView<cpp17_input_iterator<int*>>>> = true;
+
+static_assert(std::ranges::borrowed_range<
+              std::ranges::stride_view<InputView<cpp17_input_iterator<int*>>>>);      // expected-no-diagnostics
+static_assert(!std::ranges::borrowed_range<InputView<bidirectional_iterator<int*>>>); // expected-no-diagnostics

>From ab23354151a5accecd5fe7d661f676a03aaf9a2d Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 20 Nov 2023 09:59:23 -0500
Subject: [PATCH 55/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Move concept testing to a verification test.
---
 .../range.stride.view/concept.pass.cpp        | 68 -------------------
 .../range.stride.view/concept.verify.cpp      | 40 +++++++++++
 .../range.adaptors/range.stride.view/test.h   |  7 ++
 3 files changed, 47 insertions(+), 68 deletions(-)
 delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.verify.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp
deleted file mode 100644
index 395ab4a55b9b8f..00000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.pass.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// ranges
-
-// std::views::stride_view
-
-#include "__ranges/stride_view.h"
-#include "test.h"
-
-// Do not use for execution -- only useful for testing compilation/type conditions.
-template <typename T>
-struct non_input_iterator {
-  struct __invalid_iterator_tag {};
-  using value_type       = T;
-  using difference_type  = int;
-  using iterator_concept = __invalid_iterator_tag;
-
-  constexpr non_input_iterator& operator++() { return *this; }
-  constexpr void operator++(int) {}
-  constexpr T operator*() const { return T{}; }
-
-  friend constexpr bool operator==(const non_input_iterator&, const non_input_iterator&) { return true; }
-};
-
-template <typename T>
-inline constexpr bool std::ranges::enable_borrowed_range<non_input_iterator<T>> = true;
-
-class almost_input_range : public std::ranges::view_base {
-public:
-  constexpr auto begin() const { return non_input_iterator<int>{}; }
-  constexpr auto end() const { return non_input_iterator<int>{}; }
-};
-
-class non_view_range {
-public:
-  constexpr int* begin() const { return nullptr; }
-  constexpr int* end() const { return nullptr; }
-};
-
-constexpr bool test() {
-  // Ensure that the almost_input_range is a valid range.
-  static_assert(std::ranges::range<almost_input_range>);
-  // Ensure that the non_input_iterator is, well, not an input iterator.
-  static_assert(!std::input_iterator<non_input_iterator<int>>);
-  static_assert(!CanStrideView<almost_input_range, 1>, "A non input range cannot be the subject of a stride view.");
-
-  // Ensure that a range that is not a view cannot be the subject of a stride_view.
-  static_assert(std::ranges::range<non_view_range>, "non_view_range must be a range.");
-  static_assert(std::movable<non_view_range>, "non_view_range must be movable.");
-  static_assert(!std::ranges::view<non_view_range>, "A non-view range cannot be the subject of a stride_view.\n");
-
-  return true;
-}
-
-int main(int, char**) {
-  test();
-  static_assert(test());
-
-  return 0;
-}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.verify.cpp
new file mode 100644
index 00000000000000..8a9a38eb9f3027
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.verify.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// template <input_range _View> requires view<_View>
+
+#include "__ranges/stride_view.h"
+#include "almost_satisfies_types.h"
+#include "test.h"
+#include "test_iterators.h"
+#include "test_range.h"
+
+// Ensure that the InputRangeNotIndirectlyReadable is a valid range.
+static_assert(std::ranges::range<InputRangeNotIndirectlyReadable>); // expected-no-diagnostics
+// Ensure that the InputRangeNotIndirectlyReadable's is not an input range ...
+static_assert(
+    !std::ranges::input_range<std::ranges::iterator_t<InputRangeNotIndirectlyReadable>>); // expected-no-diagnostics
+// Because CanStrideView requires that the range/view type be default constructible, let's double check that ...
+static_assert(std::is_constructible_v<InputRangeNotIndirectlyReadable>); // expected-no-diagnostics
+// And now, finally, let's make sure that we cannot stride over a range whose iterator is not an input iterator ...
+static_assert(!CanStrideView<InputRangeNotIndirectlyReadable, 1>); // expected-no-diagnostics
+
+// Ensure that a range that is not a view cannot be the subject of a stride_view.
+static_assert(std::ranges::range<non_view_range>);       // expected-no-diagnostics
+static_assert(std::ranges::input_range<non_view_range>); // expected-no-diagnostics
+static_assert(std::movable<non_view_range>);             // expected-no-diagnostics
+static_assert(!std::ranges::view<non_view_range>);       // expected-no-diagnostics
+static_assert(!CanStrideView<non_view_range, 1>);        // expected-no-diagnostics
+
+// And now, let's satisfy all the prerequisites and make sure that we can stride over a range (that is an input range and is a view!)
+static_assert(std::ranges::range<test_view<cpp17_input_iterator>>);       // expected-no-diagnostics
+static_assert(std::ranges::input_range<test_view<cpp17_input_iterator>>); // expected-no-diagnostics
+static_assert(std::ranges::view<test_view<cpp17_input_iterator>>);        // expected-no-diagnostics
+static_assert(CanStrideView<test_view<cpp17_input_iterator>, 1>);         // expected-no-diagnostics
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 159de0f78f5837..113efa3704a406 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -21,6 +21,7 @@
 #include "__ranges/size.h"
 #include "__ranges/stride_view.h"
 #include "test_iterators.h"
+#include "test_range.h"
 #include <iterator>
 #include <ranges>
 
@@ -35,6 +36,12 @@ struct InstrumentedBasicRange {
   T* end() const;
 };
 
+class non_view_range {
+public:
+  constexpr int* begin() const { return nullptr; }
+  constexpr int* end() const { return nullptr; }
+};
+
 struct MovedCopiedTrackedView {
   constexpr explicit MovedCopiedTrackedView(bool* moved = nullptr, bool* copied = nullptr)
       : wasMoveInitialized_(moved), wasCopyInitialized_(copied) {}

>From 4cab0abe5ccecd60cac1214022a34823054eedd9 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 22 Nov 2023 08:52:51 -0500
Subject: [PATCH 56/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Cleanup base tests per @varconst feedback.
---
 .../range.stride.view/base.pass.cpp           | 64 ++++++-------------
 .../range.adaptors/range.stride.view/test.h   | 22 ++++++-
 2 files changed, 40 insertions(+), 46 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
index 062262ffde577c..83e768c3badea4 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
@@ -8,64 +8,42 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
+// constexpr _View base() const& requires copy_constructible<_View>;
+// constexpr _View base() &&;
 
-// std::views::stride_view
-
-#include "test.h"
 #include <cassert>
 #include <ranges>
 
+#include "test.h"
+#include "test_iterators.h"
+
 template <typename T>
-concept can_call_base_on = requires(T t) { std::forward<T>(t).base(); };
+concept hasLValueQualifiedBase = requires(T&& t) { t.base(); };
 
 constexpr bool test() {
   int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
 
-  // Check the const& overload
-  {
-    bool moved(false), copied(false);
-    MovedCopiedTrackedBasicView range(buff, buff + 8, &moved, &copied);
-    std::ranges::stride_view<MovedCopiedTrackedBasicView<int>> const view(std::move(range), 3);
-    assert(moved);
-    assert(!copied);
-    std::same_as<MovedCopiedTrackedBasicView<int>> decltype(auto) result = view.base();
-    assert(result.begin() == buff);
-    assert(result.end() == buff + 8);
-  }
-
-  // Check the && overload
   {
-    bool moved(false), copied(false);
-    MovedCopiedTrackedBasicView range(buff, buff + 8, &moved, &copied);
-    std::ranges::stride_view<MovedCopiedTrackedBasicView<int>> view(std::move(range), 3);
-    assert(moved);
-    assert(!copied);
-    std::same_as<MovedCopiedTrackedBasicView<int>> decltype(auto) result = std::move(view).base();
-    assert(result.begin() == buff);
-    assert(result.end() == buff + 8);
+    using CopyableInputView = CopyableView<cpp17_input_iterator<int*>>;
+    auto str(std::ranges::stride_view<CopyableInputView>(
+        CopyableInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + 8)), 1));
+    assert(*str.base().begin() == *buff);
+    assert(*(std::move(str)).base().begin() == *buff);
+
+    ASSERT_SAME_TYPE(decltype(str.base()), CopyableInputView);
+    ASSERT_SAME_TYPE(decltype(std::move(str).base()), CopyableInputView);
+    static_assert(hasLValueQualifiedBase<decltype(str)>);
   }
 
-  // Check the && overload (again)
   {
-    bool moved(false), copied(false);
-    MovedCopiedTrackedBasicView range(buff, buff + 8, &moved, &copied);
-    std::same_as<MovedCopiedTrackedBasicView<int>> decltype(auto) result =
-        std::ranges::stride_view<MovedCopiedTrackedBasicView<int>>(std::move(range), 3).base();
-    assert(moved);
-    assert(!copied);
-    assert(result.begin() == buff);
-    assert(result.end() == buff + 8);
-  }
+    using MoveOnlyInputView = MoveOnlyView<cpp17_input_iterator<int*>>;
+    auto str(std::ranges::stride_view<MoveOnlyInputView>(
+        MoveOnlyInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + 8)), 1));
+    assert(*(std::move(str)).base().begin() == *buff);
 
-  // Ensure the const& overload is not considered when the base is not copy-constructible
-  {
-    static_assert(!can_call_base_on<std::ranges::stride_view<MovedOnlyTrackedBasicView<>> const&>);
-    static_assert(!can_call_base_on<std::ranges::stride_view<MovedOnlyTrackedBasicView<>>&>);
-    static_assert(can_call_base_on<std::ranges::stride_view<MovedOnlyTrackedBasicView<>>&&>);
-    static_assert(can_call_base_on<std::ranges::stride_view<MovedOnlyTrackedBasicView<>>>);
+    ASSERT_SAME_TYPE(decltype(std::move(str).base()), MoveOnlyInputView);
+    static_assert(!hasLValueQualifiedBase<decltype(str)>);
   }
-
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 113efa3704a406..634b8a34991efb 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -138,18 +138,34 @@ struct MoveOnlyView : std::ranges::view_base {
   T begin_;
   T end_;
 
-  constexpr MoveOnlyView(T b, T e) : begin_(b), end_(e) {}
+  constexpr explicit MoveOnlyView(T b, T e) : begin_(b), end_(e) {}
 
   constexpr MoveOnlyView(const MoveOnlyView&)            = delete;
   constexpr MoveOnlyView(MoveOnlyView&& other)           = default;
   constexpr MoveOnlyView& operator=(MoveOnlyView&&)      = default;
   constexpr MoveOnlyView& operator=(const MoveOnlyView&) = delete;
 
-  constexpr T begin() { return begin_; }
   constexpr T begin() const { return begin_; }
-  constexpr sentinel_wrapper<T> end() { return sentinel_wrapper<T>{end_}; }
   constexpr sentinel_wrapper<T> end() const { return sentinel_wrapper<T>{end_}; }
 };
+static_assert(std::ranges::view<MoveOnlyView<cpp17_input_iterator<int*>>>);
+static_assert(!std::copyable<MoveOnlyView<cpp17_input_iterator<int*>>>);
+
+template <std::input_iterator T, std::sentinel_for<T> S = sentinel_wrapper<T>>
+struct CopyableView : std::ranges::view_base {
+  T begin_;
+  T end_;
+
+  constexpr explicit CopyableView(T b, T e) : begin_(b), end_(e) {}
+
+  constexpr CopyableView(const CopyableView&)            = default;
+  constexpr CopyableView& operator=(const CopyableView&) = default;
+
+  constexpr T begin() const { return begin_; }
+  constexpr sentinel_wrapper<T> end() const { return sentinel_wrapper<T>{end_}; }
+};
+static_assert(std::ranges::view<CopyableView<cpp17_input_iterator<int*>>>);
+static_assert(std::copyable<CopyableView<cpp17_input_iterator<int*>>>);
 
 //TODO: Rename as View.
 template <std::input_iterator T, std::sentinel_for<T> S = sentinel_wrapper<T>>

>From 676e557b90e49644357810b127b73590e47e8d90 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 22 Nov 2023 09:08:36 -0500
Subject: [PATCH 57/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Clean libcxx assertion test main signature per @varconst feedback.
---
 .../range.adaptors/range.stride.view/ctor.assert.pass.cpp     | 3 ++-
 .../range.adaptors/range.stride.view/iterator/end.pass.cpp    | 3 ++-
 .../range.stride.view/iterator/increment.pass.cpp             | 3 ++-
 .../range.stride.view/iterator/operator_plus_equal.pass.cpp   | 4 +++-
 4 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
index 54336576584802..ced1aa5ac6776a 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
@@ -27,7 +27,8 @@ void stride_view_over_only_input_ranges() {
       [&range] { std::ranges::stride_view sv(range, -1); }(), "The value of stride must be greater than 0");
 }
 
-int main() {
+int main(int, char**) {
   stride_view_over_only_input_ranges();
+
   return 0;
 }
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp
index 16516574070a04..bf199f2adc22f1 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp
@@ -34,8 +34,9 @@ void cannot_dereference_past_the_end_iterator() {
   TEST_LIBCPP_ASSERT_FAILURE(*striv_it, "Cannot dereference an iterator at the end.");
 }
 
-int main() {
+int main(int, char**) {
   cannot_dereference_at_the_end_iterator();
   cannot_dereference_past_the_end_iterator();
+
   return 0;
 }
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
index 667b74e4c3d516..093076f21aa7f2 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
@@ -26,7 +26,8 @@ void cannot_increment_at_the_end_iterator() {
   TEST_LIBCPP_ASSERT_FAILURE(striv_it++, "Cannot increment an iterator already at the end.");
 }
 
-int main() {
+int main(int, char**) {
   cannot_increment_at_the_end_iterator();
+
   return 0;
 }
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
index caec0a2de71c63..db5373780d9e0b 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
@@ -24,7 +24,9 @@ void operator_plus_equal_past_end_is_illegal() {
   auto striv_it = striv.begin();
   TEST_LIBCPP_ASSERT_FAILURE(striv_it += 3, "Advancing the iterator beyond the end is not allowed.");
 }
-int main() {
+
+int main(int, char**) {
   operator_plus_equal_past_end_is_illegal();
+
   return 0;
 }

>From 17eb2b640a610bf1071124970920d791fec4cf80 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 27 Nov 2023 09:54:22 -0500
Subject: [PATCH 58/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

(Finally) remove all unneeded  comments.
---
 .../ranges/range.adaptors/range.stride.view/adaptor.pass.cpp   | 3 ---
 .../std/ranges/range.adaptors/range.stride.view/begin.pass.cpp | 2 --
 .../range.adaptors/range.stride.view/ctad.compile.pass.cpp     | 2 --
 .../std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp  | 1 +
 .../std/ranges/range.adaptors/range.stride.view/end.pass.cpp   | 2 --
 .../range.adaptors/range.stride.view/iterator/base.pass.cpp    | 3 +--
 .../range.adaptors/range.stride.view/iterator/begin.pass.cpp   | 3 +--
 .../range.stride.view/iterator/ctor.default.pass.cpp           | 3 +--
 .../range.adaptors/range.stride.view/iterator/equal.pass.cpp   | 2 --
 .../range.stride.view/iterator/operator.pass.cpp               | 3 +--
 .../ranges/range.adaptors/range.stride.view/size.verify.cpp    | 1 +
 .../ranges/range.adaptors/range.stride.view/stride.pass.cpp    | 1 +
 12 files changed, 7 insertions(+), 19 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
index d3dcd7b73436cd..f70f2302caf55c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -8,11 +8,8 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
-
 // std::views::stride_view
 
-#include "__ranges/stride_view.h"
 #include "test.h"
 #include "test_iterators.h"
 #include <concepts>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp
index 68556f32f875b1..3c4e6ff75fc5fc 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
-
 // std::views::stride_view
 
 constexpr bool test() { return true; }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
index 4cceca699d2158..f6f71802f861b5 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
-
 // std::views::stride_view
 
 #include "test.h"
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
index b705d30a6c74ea..445552873f5fb5 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
@@ -56,5 +56,6 @@ constexpr bool test() {
 int main(int, char**) {
   test();
   static_assert(test());
+
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp
index 68556f32f875b1..3c4e6ff75fc5fc 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
-
 // std::views::stride_view
 
 constexpr bool test() { return true; }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
index 579bcea2d7186d..e4e5d319dac87f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
-
 // std::views::stride_view
 
 #include "../test.h"
@@ -51,5 +49,6 @@ int main(int, char**) {
   static_assert(base_noexcept());
   base_const();
   static_assert(base_const());
+
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
index 270d5cd0caaffa..d7976134995454 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/begin.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
-
 // std::views::stride_view::iterator
 
 #include "../test.h"
@@ -72,5 +70,6 @@ constexpr bool iterator_concept_test() {
 int main(int, char**) {
   iterator_concept_test();
   static_assert(iterator_concept_test());
+
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
index 56620b758ad6b0..ad6a18e77d0756 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
-
 // std::views::stride_view
 
 #include "../test.h"
@@ -242,5 +240,6 @@ int main(int, char**) {
   static_assert(non_simple_view_iter_ctor_test());
   static_assert(iterator_default_constructible());
   static_assert(non_const_iterator_copy_ctor());
+
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
index ff5196d26476ce..a116141f942dfa 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
-
 // std::views::stride_view
 
 #include <cassert>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
index 5118b35db82045..6723c6acb60465 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
@@ -8,8 +8,6 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// ranges
-
 // std::views::stride_view::iterator
 
 #include "../test.h"
@@ -185,5 +183,6 @@ constexpr bool operator_tests() {
 int main(int, char**) {
   operator_tests();
   static_assert(operator_tests());
+
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp
index c3d87a1dac7b22..62cbd3ccd2708d 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp
@@ -45,5 +45,6 @@ constexpr bool test() {
 
 int main(int, char**) {
   static_assert(test());
+
   return 0;
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
index 12c8338c22fb3b..5107f809e63458 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
@@ -36,5 +36,6 @@ constexpr bool test() {
 int main(int, char**) {
   test();
   static_assert(test());
+
   return 0;
 }

>From d35121ba0d116b2332dac0c25ba3b1ef81283bb4 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 27 Nov 2023 10:36:53 -0500
Subject: [PATCH 59/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Address (some) of the comments on the adaptor tests. More work needed.
---
 .../range.stride.view/adaptor.pass.cpp        | 143 ++++++++----------
 1 file changed, 64 insertions(+), 79 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
index f70f2302caf55c..dda02680d1cedf 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -10,111 +10,96 @@
 
 // std::views::stride_view
 
+#include <ranges>
+
 #include "test.h"
 #include "test_iterators.h"
-#include <concepts>
-#include <iterator>
-#include <ranges>
-#include <utility>
 
 template <class View, class T>
 concept CanBePiped = requires(View&& view, T&& t) {
   { std::forward<View>(view) | std::forward<T>(t) };
 };
 
+constexpr InputView<cpp17_input_iterator<int*>> make_input_view(int* begin, int* end) {
+  return InputView<cpp17_input_iterator<int*>>(cpp17_input_iterator<int*>(begin), cpp17_input_iterator<int*>(end));
+}
+
+using ForwardStrideView      = std::ranges::stride_view<InputView<forward_iterator<int*>>>;
+using BidirStrideView        = std::ranges::stride_view<InputView<bidirectional_iterator<int*>>>;
+using RandomAccessStrideView = std::ranges::stride_view<InputView<random_access_iterator<int*>>>;
+
+static_assert(std::ranges::forward_range<ForwardStrideView>);
+static_assert(std::ranges::bidirectional_range<BidirStrideView>);
+static_assert(std::ranges::random_access_range<RandomAccessStrideView>);
+// TODO: check sized_range
+
 constexpr bool test() {
-  constexpr int array_n = 3;
-  int arr[array_n]      = {1, 2, 3};
+  constexpr int N = 3;
+  int arr[N]      = {1, 2, 3};
 
   // Test that `std::views::stride` is a range adaptor.
-  { // Check various forms of
-    // view | stride
-    {
-      {
-        using View = InputView<bidirectional_iterator<int*>>;
-        View view(bidirectional_iterator<int*>(arr), bidirectional_iterator<int*>(arr + array_n));
-        std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(1);
-        auto strided_iter                                                   = strided.begin();
-
-        // Check that the begin() iter views arr[0]
-        assert(*strided_iter == arr[0]);
-
-        // Check that the strided_iter, after advancing it 2 * 1 steps, views arr[2].
-        std::ranges::advance(strided_iter, 2);
-        assert(*strided_iter == arr[2]);
-      }
-      {
-        using View = InputView<bidirectional_iterator<int*>>;
-        View view(bidirectional_iterator<int*>(arr), bidirectional_iterator<int*>(arr + array_n));
-        std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(2);
-        auto strided_iter                                                   = strided.begin();
-
-        assert(*strided_iter == arr[0]);
-
-        // Same test as above, just advance one time with a bigger step (1 * 2 steps).
-        std::ranges::advance(strided_iter, 1);
-        assert(*strided_iter == arr[2]);
-      }
-    }
+  // Check various forms of
+
+  // view | stride
+  {
+    using View                                                          = InputView<cpp17_input_iterator<int*>>;
+    auto view                                                           = make_input_view(arr, arr + N);
+    std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(1);
+    auto strided_iter                                                   = strided.begin();
+
+    // Check that the begin() iter views arr[0]
+    assert(*strided_iter == arr[0]);
+
+    // Check that the strided_iter, after advancing it 2 * 1 steps, views arr[2].
+    std::ranges::advance(strided_iter, 2);
+    assert(*strided_iter == arr[2]);
+  }
+  {
+    using View                                                          = InputView<cpp17_input_iterator<int*>>;
+    auto view                                                           = make_input_view(arr, arr + N);
+    std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(2);
+    auto strided_iter                                                   = strided.begin();
+
+    assert(*strided_iter == arr[0]);
   }
 
-  // Check various forms of
   // adaptor | stride
+  // Parallels the two tests from above.
+  const auto i2 = [](int i) { return i * 2; };
   {
-    // Parallels the two tests from above.
-    constexpr const auto identity_lambda = [](const int i) { return i * 2; };
-    {
-      using View = InputView<bidirectional_iterator<int*>>;
-      View view(bidirectional_iterator<int*>(arr), bidirectional_iterator<int*>(arr + array_n));
-      const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(1);
-
-      auto transform_stride_applied      = transform_stride_partial(view);
-      auto transform_stride_applied_iter = transform_stride_applied.begin();
-      assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[0]));
-      std::ranges::advance(transform_stride_applied_iter, 2);
-      assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[2]));
-    }
-
-    {
-      using View = InputView<bidirectional_iterator<int*>>;
-      View view(bidirectional_iterator<int*>(arr), bidirectional_iterator<int*>(arr + array_n));
-      const auto transform_stride_partial = std::views::transform(identity_lambda) | std::views::stride(2);
-
-      const auto transform_stride_applied = transform_stride_partial(view);
-      auto transform_stride_applied_iter  = transform_stride_applied.begin();
-      assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[0]));
-      std::ranges::advance(transform_stride_applied_iter, 1);
-      assert(*transform_stride_applied_iter == std::invoke(identity_lambda, arr[2]));
-    }
+    auto view                           = make_input_view(arr, arr + N);
+    const auto transform_stride_partial = std::views::transform(i2) | std::views::stride(1);
+
+    auto transform_stride_applied      = transform_stride_partial(view);
+    auto transform_stride_applied_iter = transform_stride_applied.begin();
+    assert(*transform_stride_applied_iter == std::invoke(i2, arr[0]));
+    std::ranges::advance(transform_stride_applied_iter, 2);
+    assert(*transform_stride_applied_iter == std::invoke(i2, arr[2]));
   }
 
   {
-    using ForwardStrideView      = std::ranges::stride_view<InputView<forward_iterator<int*>>>;
-    using BidirStrideView        = std::ranges::stride_view<InputView<bidirectional_iterator<int*>>>;
-    using RandomAccessStrideView = std::ranges::stride_view<InputView<random_access_iterator<int*>>>;
-
-    static_assert(std::ranges::forward_range<ForwardStrideView>);
-    static_assert(std::ranges::bidirectional_range<BidirStrideView>);
-    static_assert(std::ranges::random_access_range<RandomAccessStrideView>);
-    // TODO: check sized_range
-  }
+    auto view                           = make_input_view(arr, arr + N);
+    const auto transform_stride_partial = std::views::transform(i2) | std::views::stride(2);
 
+    const auto transform_stride_applied = transform_stride_partial(view);
+    auto transform_stride_applied_iter  = transform_stride_applied.begin();
+    assert(*transform_stride_applied_iter == i2(arr[0]));
+  }
   // Check SFINAE friendliness
   {
     using View = InputView<bidirectional_iterator<int*>>;
     struct NotAViewableRange {};
-    struct NotARange {};
-    // Not invocable because there is no parameter.
+
+    // TODO: WORK HERE.
     static_assert(!std::is_invocable_v<decltype(std::views::stride)>);
-    // Not invocable because NotAViewableRange is, well, not a viewable range.
-    static_assert(!std::is_invocable_v<decltype(std::views::reverse), NotAViewableRange>);
-    // Is invocable because BidirView is a viewable range.
-    static_assert(std::is_invocable_v<decltype(std::views::reverse), View>);
+    static_assert(!std::is_invocable_v<decltype(std::views::stride), NotAViewableRange, int>);
+    static_assert(std::is_invocable_v<decltype(std::views::stride), View>);
 
     // Make sure that pipe operations work!
-    static_assert(CanBePiped<View, decltype(std::views::stride(std::ranges::range_difference_t<View>{}))>);
-    static_assert(CanBePiped<View&, decltype(std::views::stride(std::ranges::range_difference_t<View>{}))>);
-    static_assert(!CanBePiped<NotARange, decltype(std::views::stride(std::ranges::range_difference_t<View>{}))>);
+    static_assert(CanBePiped<View, decltype(std::views::stride(5))>);
+    static_assert(CanBePiped<View&, decltype(std::views::stride(5))>);
+    static_assert(!CanBePiped<NotAViewableRange, decltype(std::views::stride(5))>);
+    static_assert(!CanBePiped<View&, decltype(std::views::stride(NotAViewableRange{}))>);
   }
   // A final sanity check.
   { static_assert(std::same_as<decltype(std::views::stride), decltype(std::ranges::views::stride)>); }

>From a27da47faa0b4b9b76887c84aef344fb9243c7a9 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 27 Nov 2023 22:18:58 -0500
Subject: [PATCH 60/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Address (remainder) of the comments on the adaptor tests.
---
 .../range.adaptors/range.stride.view/adaptor.pass.cpp | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
index dda02680d1cedf..6d3f0bd4c3535c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -72,9 +72,9 @@ constexpr bool test() {
 
     auto transform_stride_applied      = transform_stride_partial(view);
     auto transform_stride_applied_iter = transform_stride_applied.begin();
-    assert(*transform_stride_applied_iter == std::invoke(i2, arr[0]));
+    assert(*transform_stride_applied_iter == i2(arr[0]));
     std::ranges::advance(transform_stride_applied_iter, 2);
-    assert(*transform_stride_applied_iter == std::invoke(i2, arr[2]));
+    assert(*transform_stride_applied_iter == i2(arr[2]));
   }
 
   {
@@ -87,15 +87,12 @@ constexpr bool test() {
   }
   // Check SFINAE friendliness
   {
-    using View = InputView<bidirectional_iterator<int*>>;
     struct NotAViewableRange {};
+    using View = InputView<bidirectional_iterator<int*>>;
 
-    // TODO: WORK HERE.
     static_assert(!std::is_invocable_v<decltype(std::views::stride)>);
     static_assert(!std::is_invocable_v<decltype(std::views::stride), NotAViewableRange, int>);
-    static_assert(std::is_invocable_v<decltype(std::views::stride), View>);
 
-    // Make sure that pipe operations work!
     static_assert(CanBePiped<View, decltype(std::views::stride(5))>);
     static_assert(CanBePiped<View&, decltype(std::views::stride(5))>);
     static_assert(!CanBePiped<NotAViewableRange, decltype(std::views::stride(5))>);
@@ -109,7 +106,7 @@ constexpr bool test() {
 
 int main(int, char**) {
   test();
-  static_assert(test());
+  //static_assert(test());
 
   return 0;
 }

>From 7c24bb94bacc00a05da65c307404f4eb8d24cd71 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 29 Nov 2023 09:37:31 -0500
Subject: [PATCH 61/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Complete cleanup of ctad tests.
---
 .../range.stride.view/ctad.compile.pass.cpp   | 42 +++++++++----------
 1 file changed, 19 insertions(+), 23 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
index f6f71802f861b5..c65e6a2c87d1ad 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.compile.pass.cpp
@@ -8,34 +8,30 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// std::views::stride_view
+// template <class _Range>
+// stride_view(_Range&&, range_difference_t<_Range>) -> stride_view<views::all_t<_Range>>;
 
-#include "test.h"
 #include <concepts>
 #include <ranges>
-#include <utility>
 
-constexpr bool test() {
-  int arr[]{1, 2, 3};
+struct View : std::ranges::view_base {
+  int* begin() const;
+  int* end() const;
+};
 
-  MovedCopiedTrackedBasicView<int> bv{arr, arr + 3};
-  InstrumentedBasicRange<int> br{};
+struct Range {
+  int* begin() const;
+  int* end() const;
+};
 
-  static_assert(std::same_as< decltype(std::ranges::stride_view(bv, 2)), std::ranges::stride_view<decltype(bv)> >);
-  static_assert(
-      std::same_as< decltype(std::ranges::stride_view(std::move(bv), 2)), std::ranges::stride_view<decltype(bv)> >);
-
-  static_assert(std::same_as< decltype(std::ranges::drop_view(br, 0)),
-                              std::ranges::drop_view<std::ranges::ref_view<InstrumentedBasicRange<int>>> >);
-
-  static_assert(std::same_as< decltype(std::ranges::drop_view(std::move(br), 0)),
-                              std::ranges::drop_view<std::ranges::owning_view<InstrumentedBasicRange<int>>> >);
-  return true;
-}
-
-int main(int, char**) {
-  test();
-  static_assert(test());
+void testCTAD() {
+  View v;
+  Range r;
 
-  return 0;
+  static_assert(std::same_as< decltype(std::ranges::stride_view(v, 5)), std::ranges::stride_view<View> >);
+  static_assert(std::same_as< decltype(std::ranges::stride_view(std::move(v), 5)), std::ranges::stride_view<View> >);
+  static_assert(
+      std::same_as< decltype(std::ranges::stride_view(r, 5)), std::ranges::stride_view<std::ranges::ref_view<Range>> >);
+  static_assert(std::same_as< decltype(std::ranges::stride_view(std::move(r), 5)),
+                              std::ranges::stride_view<std::ranges::owning_view<Range>> >);
 }

>From 3af0f025e5f085d467cb078558b4f6dcca90aefd Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 29 Nov 2023 09:45:44 -0500
Subject: [PATCH 62/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Clean erroneous comment in assert test of iterator::operator++.
---
 .../range.stride.view/iterator/increment.pass.cpp             | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
index 093076f21aa7f2..509d5f909c5732 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
@@ -11,9 +11,7 @@
 // UNSUPPORTED: !libcpp-hardening-mode=debug
 // XFAIL: availability-verbose_abort-missing
 
-// <ranges>
-
-// Call ....
+// constexpr stride_view::<iterator>& operator++() {
 
 #include "check_assertion.h"
 #include <ranges>

>From 9afca0e805ca1683cb3ad2f20b2cbd2bf650c5d7 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 29 Nov 2023 17:39:47 -0500
Subject: [PATCH 63/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Line up expressions in std::views::stride function object.
---
 libcxx/include/__ranges/stride_view.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 772551abadc39d..59378d2a67aa01 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -371,9 +371,9 @@ namespace __stride {
 struct __fn {
   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);
+      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);
   }
 
   template <class _Np>

>From 074dcc3daaf64bfe3cbbe3db8d9932875071becd Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 29 Nov 2023 18:21:01 -0500
Subject: [PATCH 64/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

(For real\!) complete removing unnecessary comments.
---
 .../range.adaptors/range.stride.view/ctor.assert.pass.cpp     | 2 --
 .../range.adaptors/range.stride.view/iterator/end.pass.cpp    | 4 ----
 .../range.stride.view/iterator/operator_plus_equal.pass.cpp   | 4 ----
 3 files changed, 10 deletions(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
index ced1aa5ac6776a..58e604cdcd8e25 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
@@ -11,8 +11,6 @@
 // UNSUPPORTED: !libcpp-hardening-mode=debug
 // XFAIL: availability-verbose_abort-missing
 
-// <ranges>
-
 // Call stride_view() ctor empty stride <= 0
 
 #include "check_assertion.h"
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp
index bf199f2adc22f1..30b74d3d383da6 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/end.pass.cpp
@@ -11,10 +11,6 @@
 // UNSUPPORTED: !libcpp-hardening-mode=debug
 // XFAIL: availability-verbose_abort-missing
 
-// <ranges>
-
-// Call ....
-
 #include "check_assertion.h"
 #include <ranges>
 
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
index db5373780d9e0b..13a56b4e12917e 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
@@ -11,10 +11,6 @@
 // UNSUPPORTED: !libcpp-hardening-mode=debug
 // XFAIL: availability-verbose_abort-missing
 
-// <ranges>
-
-// Call ....
-
 #include "check_assertion.h"
 #include <ranges>
 

>From 355ca039a1abbfd2d96d20adc31d843596041426 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Wed, 29 Nov 2023 21:33:44 -0500
Subject: [PATCH 65/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Upload test for stride_view::iterator == presence when base is not equalable.
---
 .../iterator/operator.pass.cpp                | 68 ++++++++++++-------
 .../range.adaptors/range.stride.view/test.h   | 20 ++++++
 2 files changed, 63 insertions(+), 25 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
index 6723c6acb60465..8bae7e110a7498 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
@@ -10,45 +10,43 @@
 
 // std::views::stride_view::iterator
 
+#include <ranges>
+
 #include "../test.h"
-#include "__concepts/constructible.h"
-#include "__iterator/concepts.h"
-#include "__ranges/access.h"
-#include "__ranges/concepts.h"
 #include "test_iterators.h"
-#include <ranges>
-#include <type_traits>
-#include <vector>
 
 template <class T>
-concept is_plus_equalable = requires(T& __t) { __t += 1; };
+concept is_plus_equalable = requires(T& t) { t += 1; };
 template <class T>
-concept is_minus_equalable = requires(T& __t) { __t -= 1; };
+concept is_minus_equalable = requires(T& t) { t -= 1; };
 
 template <class T>
-concept is_plusable = requires(T& __t) { __t + 1; };
+concept is_plusable = requires(T& t) { t + 1; };
 template <class T>
-concept is_minusable = requires(T& __t) { __t - 1; };
+concept is_minusable = requires(T& t) { t - 1; };
 
 template <class T>
-concept is_relationally_comparable = requires(T& __t) {
-  __t < __t;
-  __t > __t;
-  __t <= __t;
-  __t >= __t;
+concept is_relationally_comparable = requires(T& t) {
+  t < t;
+  t > t;
+  t <= t;
+  t >= t;
 };
 
 template <class T>
-concept is_plus_plusable_post = requires(T& __t) { __t++; };
+concept is_relationally_equalable = requires(T& t) { t == t; };
+
 template <class T>
-concept is_plus_plusable_pre = requires(T& __t) { ++__t; };
+concept is_plus_plusable_post = requires(T& t) { t++; };
 template <class T>
-concept is_minus_minusable_post = requires(T& __t) { __t--; };
+concept is_plus_plusable_pre = requires(T& t) { ++t; };
 template <class T>
-concept is_minus_minusable_pre = requires(T& __t) { --__t; };
+concept is_minus_minusable_post = requires(T& t) { t--; };
+template <class T>
+concept is_minus_minusable_pre = requires(T& t) { --t; };
 
 template <class T>
-concept can_calculate_distance_between_non_sentinel = requires(T& __t) { __t - __t; };
+concept can_calculate_distance_between_non_sentinel = requires(T& t) { t - t; };
 
 constexpr bool operator_tests() {
   {
@@ -59,7 +57,7 @@ constexpr bool operator_tests() {
     auto rav   = View(cpp17_input_iterator(arr), cpp17_input_iterator(arr + 3));
     auto str   = std::ranges::stride_view<View>(rav, 1);
 
-    auto strb = str.begin();
+    [[maybe_unused]] auto strb = str.begin();
 
     static_assert(is_plus_plusable_post<decltype(strb)>);
     static_assert(is_plus_plusable_pre<decltype(strb)>);
@@ -79,7 +77,7 @@ constexpr bool operator_tests() {
     auto rav   = View(forward_iterator(arr), forward_iterator(arr + 3));
     auto str   = std::ranges::stride_view<View>(rav, 1);
 
-    auto strb = str.begin();
+    [[maybe_unused]] auto strb = str.begin();
 
     static_assert(is_plus_plusable_post<decltype(strb)>);
     static_assert(is_plus_plusable_pre<decltype(strb)>);
@@ -99,7 +97,7 @@ constexpr bool operator_tests() {
     auto rav   = View(bidirectional_iterator(arr), bidirectional_iterator(arr + 3));
     auto str   = std::ranges::stride_view<View>(rav, 1);
 
-    auto strb = str.begin();
+    [[maybe_unused]] auto strb = str.begin();
 
     static_assert(is_plus_plusable_post<decltype(strb)>);
     static_assert(is_plus_plusable_pre<decltype(strb)>);
@@ -119,7 +117,7 @@ constexpr bool operator_tests() {
     auto rav   = View(random_access_iterator(arr), random_access_iterator(arr + 3));
     auto str   = std::ranges::stride_view<View>(rav, 1);
 
-    auto strb = str.begin();
+    [[maybe_unused]] auto strb = str.begin();
 
     static_assert(is_plus_plusable_post<decltype(strb)>);
     static_assert(is_plus_plusable_pre<decltype(strb)>);
@@ -177,6 +175,26 @@ constexpr bool operator_tests() {
     assert(stride_zoff_one - stride_ooff_two == -1);
     assert(stride_zoff_one - stride_ooff_five == -2);
   }
+
+  {
+    using EqualableView = InputView<cpp17_input_iterator<int*>>;
+    using Stride        = std::ranges::stride_view<EqualableView>;
+    using StrideIter    = std::ranges::iterator_t<Stride>;
+
+    static_assert(is_relationally_equalable<std::ranges::iterator_t<EqualableView>>);
+    static_assert(is_relationally_equalable<StrideIter>);
+  }
+
+  {
+    using UnEqualableView =
+        ViewOverNonCopyable<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>;
+    using Stride     = std::ranges::stride_view<UnEqualableView>;
+    using StrideIter = std::ranges::iterator_t<Stride>;
+
+    static_assert(!is_relationally_equalable<std::ranges::iterator_t<UnEqualableView>>);
+    static_assert(!is_relationally_equalable<StrideIter>);
+  }
+
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 634b8a34991efb..fc7f528a22196b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -181,6 +181,26 @@ struct InputView : std::ranges::view_base {
   constexpr sentinel_wrapper<T> end() const { return sentinel_wrapper<T>{end_}; }
 };
 
+// Don't move/hold the iterator itself, move/hold the base
+// of that iterator and reconstruct the iterator on demand.
+// May result in aliasing (if, e.g., Iterator is an iterator
+// over int *).
+template <class Iterator, class Sentinel>
+struct ViewOverNonCopyable : std::ranges::view_base {
+  constexpr explicit ViewOverNonCopyable(Iterator it, Sentinel sent)
+      : it_(base(std::move(it))), sent_(base(std::move(sent))) {}
+
+  ViewOverNonCopyable(ViewOverNonCopyable&&)            = default;
+  ViewOverNonCopyable& operator=(ViewOverNonCopyable&&) = default;
+
+  constexpr Iterator begin() const { return Iterator(it_); }
+  constexpr Sentinel end() const { return Sentinel(sent_); }
+
+private:
+  decltype(base(std::declval<Iterator>())) it_;
+  decltype(base(std::declval<Sentinel>())) sent_;
+};
+
 struct ForwardTracedMoveIter : ForwardIterBase<ForwardTracedMoveIter> {
   bool moved = false;
 

>From 0668c18fedf6fba1d8567f1a04a98519f332fa20 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 1 Dec 2023 10:28:43 -0500
Subject: [PATCH 66/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Cleanup (and add) iterator::operator@ tests.
---
 .../iterator/operator.pass.cpp                | 163 ++++++++++--------
 1 file changed, 93 insertions(+), 70 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
index 8bae7e110a7498..3520ae116c01c0 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
@@ -8,7 +8,20 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// std::views::stride_view::iterator
+// constexpr __iterator& operator++()
+// constexpr void operator++(int)
+// constexpr __iterator operator++(int)
+// constexpr __iterator& operator--()
+// constexpr __iterator operator--(int)
+// constexpr __iterator& operator+=(difference_type __n)
+// constexpr __iterator& operator-=(difference_type __n)
+// friend constexpr bool operator==(__iterator const& __x, default_sentinel_t)
+// friend constexpr bool operator==(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator>(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<=(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator>=(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<=>(__iterator const& __x, __iterator const& __y)
 
 #include <ranges>
 
@@ -21,9 +34,11 @@ template <class T>
 concept is_minus_equalable = requires(T& t) { t -= 1; };
 
 template <class T>
-concept is_plusable = requires(T& t) { t + 1; };
+concept is_iterator_minusable = requires(T& t) { t - t; };
 template <class T>
-concept is_minusable = requires(T& t) { t - 1; };
+concept is_difference_plusable = requires(T& t) { t + 1; };
+template <class T>
+concept is_difference_minusable = requires(T& t) { t - 1; };
 
 template <class T>
 concept is_relationally_comparable = requires(T& t) {
@@ -36,6 +51,9 @@ concept is_relationally_comparable = requires(T& t) {
 template <class T>
 concept is_relationally_equalable = requires(T& t) { t == t; };
 
+template <class T>
+concept is_three_way_comparable = requires(T& t) { t <=> t; };
+
 template <class T>
 concept is_plus_plusable_post = requires(T& t) { t++; };
 template <class T>
@@ -52,85 +70,75 @@ constexpr bool operator_tests() {
   {
     // What operators are valid for an iterator derived from a stride view
     // over an input view.
-    int arr[]  = {1, 2, 3};
-    using View = InputView<cpp17_input_iterator<int*>>;
-    auto rav   = View(cpp17_input_iterator(arr), cpp17_input_iterator(arr + 3));
-    auto str   = std::ranges::stride_view<View>(rav, 1);
-
-    [[maybe_unused]] auto strb = str.begin();
-
-    static_assert(is_plus_plusable_post<decltype(strb)>);
-    static_assert(is_plus_plusable_pre<decltype(strb)>);
-    static_assert(!is_minus_minusable_post<decltype(strb)>);
-    static_assert(!is_minus_minusable_pre<decltype(strb)>);
-    static_assert(!is_plus_equalable<decltype(strb)>);
-    static_assert(!is_minus_equalable<decltype(strb)>);
-    static_assert(!is_plusable<decltype(strb)>);
-    static_assert(!is_minusable<decltype(strb)>);
-    static_assert(!is_relationally_comparable<decltype(strb)>);
+    using View               = InputView<cpp17_input_iterator<int*>>;
+    using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<View>>;
+
+    static_assert(is_plus_plusable_post<StrideViewIterator>);
+    static_assert(is_plus_plusable_pre<StrideViewIterator>);
+    static_assert(!is_minus_minusable_post<StrideViewIterator>);
+    static_assert(!is_minus_minusable_pre<StrideViewIterator>);
+    static_assert(!is_plus_equalable<StrideViewIterator>);
+    static_assert(!is_minus_equalable<StrideViewIterator>);
+    static_assert(!is_iterator_minusable<StrideViewIterator>);
+    static_assert(!is_difference_plusable<StrideViewIterator>);
+    static_assert(!is_difference_minusable<StrideViewIterator>);
+    static_assert(!is_relationally_comparable<StrideViewIterator>);
   }
   {
     // What operators are valid for an iterator derived from a stride view
-    // over a forward  view.
-    int arr[]  = {1, 2, 3};
-    using View = InputView<forward_iterator<int*>>;
-    auto rav   = View(forward_iterator(arr), forward_iterator(arr + 3));
-    auto str   = std::ranges::stride_view<View>(rav, 1);
-
-    [[maybe_unused]] auto strb = str.begin();
-
-    static_assert(is_plus_plusable_post<decltype(strb)>);
-    static_assert(is_plus_plusable_pre<decltype(strb)>);
-    static_assert(!is_minus_minusable_post<decltype(strb)>);
-    static_assert(!is_minus_minusable_pre<decltype(strb)>);
-    static_assert(!is_plus_equalable<decltype(strb)>);
-    static_assert(!is_minus_equalable<decltype(strb)>);
-    static_assert(!is_plusable<decltype(strb)>);
-    static_assert(!is_minusable<decltype(strb)>);
-    static_assert(!is_relationally_comparable<decltype(strb)>);
+    // over a forward view.
+    using View               = InputView<forward_iterator<int*>>;
+    using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<View>>;
+
+    static_assert(is_plus_plusable_post<StrideViewIterator>);
+    static_assert(is_plus_plusable_pre<StrideViewIterator>);
+    static_assert(!is_minus_minusable_post<StrideViewIterator>);
+    static_assert(!is_minus_minusable_pre<StrideViewIterator>);
+    static_assert(!is_plus_equalable<StrideViewIterator>);
+    static_assert(!is_minus_equalable<StrideViewIterator>);
+    static_assert(!is_iterator_minusable<StrideViewIterator>);
+    static_assert(!is_difference_plusable<StrideViewIterator>);
+    static_assert(!is_difference_minusable<StrideViewIterator>);
+    static_assert(!is_relationally_comparable<StrideViewIterator>);
   }
   {
     // What operators are valid for an iterator derived from a stride view
     // over a bidirectional view.
-    int arr[]  = {1, 2, 3};
-    using View = InputView<bidirectional_iterator<int*>>;
-    auto rav   = View(bidirectional_iterator(arr), bidirectional_iterator(arr + 3));
-    auto str   = std::ranges::stride_view<View>(rav, 1);
-
-    [[maybe_unused]] auto strb = str.begin();
-
-    static_assert(is_plus_plusable_post<decltype(strb)>);
-    static_assert(is_plus_plusable_pre<decltype(strb)>);
-    static_assert(is_minus_minusable_post<decltype(strb)>);
-    static_assert(is_minus_minusable_pre<decltype(strb)>);
-    static_assert(!is_plus_equalable<decltype(strb)>);
-    static_assert(!is_minus_equalable<decltype(strb)>);
-    static_assert(!is_plusable<decltype(strb)>);
-    static_assert(!is_minusable<decltype(strb)>);
-    static_assert(!is_relationally_comparable<decltype(strb)>);
+    using View               = InputView<bidirectional_iterator<int*>>;
+    using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<View>>;
+
+    static_assert(is_plus_plusable_post<StrideViewIterator>);
+    static_assert(is_plus_plusable_pre<StrideViewIterator>);
+    static_assert(is_minus_minusable_post<StrideViewIterator>);
+    static_assert(is_minus_minusable_pre<StrideViewIterator>);
+    static_assert(!is_plus_equalable<StrideViewIterator>);
+    static_assert(!is_minus_equalable<StrideViewIterator>);
+    static_assert(!is_iterator_minusable<StrideViewIterator>);
+    static_assert(!is_difference_plusable<StrideViewIterator>);
+    static_assert(!is_difference_minusable<StrideViewIterator>);
+    static_assert(!is_relationally_comparable<StrideViewIterator>);
   }
   {
     // What operators are valid for an iterator derived from a stride view
     // over a random access view.
-    int arr[]  = {1, 2, 3};
-    using View = InputView<random_access_iterator<int*>>;
-    auto rav   = View(random_access_iterator(arr), random_access_iterator(arr + 3));
-    auto str   = std::ranges::stride_view<View>(rav, 1);
-
-    [[maybe_unused]] auto strb = str.begin();
-
-    static_assert(is_plus_plusable_post<decltype(strb)>);
-    static_assert(is_plus_plusable_pre<decltype(strb)>);
-    static_assert(is_minus_minusable_post<decltype(strb)>);
-    static_assert(is_minus_minusable_pre<decltype(strb)>);
-    static_assert(is_plus_equalable<decltype(strb)>);
-    static_assert(is_minus_equalable<decltype(strb)>);
-    static_assert(is_plusable<decltype(strb)>);
-    static_assert(is_minusable<decltype(strb)>);
-    static_assert(is_relationally_comparable<decltype(strb)>);
+    using View               = InputView<random_access_iterator<int*>>;
+    using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<View>>;
+
+    static_assert(is_plus_plusable_post<StrideViewIterator>);
+    static_assert(is_plus_plusable_pre<StrideViewIterator>);
+    static_assert(is_minus_minusable_post<StrideViewIterator>);
+    static_assert(is_minus_minusable_pre<StrideViewIterator>);
+    static_assert(is_plus_equalable<StrideViewIterator>);
+    static_assert(is_minus_equalable<StrideViewIterator>);
+    static_assert(is_iterator_minusable<StrideViewIterator>);
+    static_assert(is_difference_plusable<StrideViewIterator>);
+    static_assert(is_difference_minusable<StrideViewIterator>);
+    static_assert(is_relationally_comparable<StrideViewIterator>);
   }
-
   {
+      // Test the forward-range operator- between two iterators (i.e., no ceil).
+      // TODO
+  } {
     // Test the non-forward-range operator- between two iterators (i.e., ceil).
     int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
     auto rav_zero =
@@ -175,7 +183,6 @@ constexpr bool operator_tests() {
     assert(stride_zoff_one - stride_ooff_two == -1);
     assert(stride_zoff_one - stride_ooff_five == -2);
   }
-
   {
     using EqualableView = InputView<cpp17_input_iterator<int*>>;
     using Stride        = std::ranges::stride_view<EqualableView>;
@@ -183,8 +190,20 @@ constexpr bool operator_tests() {
 
     static_assert(is_relationally_equalable<std::ranges::iterator_t<EqualableView>>);
     static_assert(is_relationally_equalable<StrideIter>);
+
+    static_assert(!std::three_way_comparable<std::ranges::iterator_t<EqualableView>>);
+    static_assert(!std::ranges::random_access_range<EqualableView>);
+    static_assert(!is_three_way_comparable<EqualableView>);
   }
+  {
+    using ThreeWayComparableView = InputView<rvalue_iterator<int*>>;
+    using Stride                 = std::ranges::stride_view<ThreeWayComparableView>;
+    using StrideIter             = std::ranges::iterator_t<Stride>;
 
+    static_assert(std::three_way_comparable<std::ranges::iterator_t<ThreeWayComparableView>>);
+    static_assert(std::ranges::random_access_range<ThreeWayComparableView>);
+    static_assert(is_three_way_comparable<StrideIter>);
+  }
   {
     using UnEqualableView =
         ViewOverNonCopyable<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>;
@@ -193,6 +212,10 @@ constexpr bool operator_tests() {
 
     static_assert(!is_relationally_equalable<std::ranges::iterator_t<UnEqualableView>>);
     static_assert(!is_relationally_equalable<StrideIter>);
+
+    static_assert(!std::three_way_comparable<std::ranges::iterator_t<UnEqualableView>>);
+    static_assert(!std::ranges::random_access_range<UnEqualableView>);
+    static_assert(!is_three_way_comparable<UnEqualableView>);
   }
 
   return true;

>From aba2c8884897cdcfc9e224a9ead1bafbbd91b80d Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 1 Dec 2023 10:34:46 -0500
Subject: [PATCH 67/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Remove extraneous comment from libcxx assertion test on ctor.
---
 .../ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
index 58e604cdcd8e25..b1009968364338 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
@@ -18,7 +18,6 @@
 
 void stride_view_over_only_input_ranges() {
   int range[] = {1, 2, 3};
-  // Keep up to date with assertion message from the ctor.
   TEST_LIBCPP_ASSERT_FAILURE(
       [&range] { std::ranges::stride_view sv(range, 0); }(), "The value of stride must be greater than 0");
   TEST_LIBCPP_ASSERT_FAILURE(

>From a1e11df64ca92a34fd6ea6af1cc9d9272e821ce0 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Mon, 4 Dec 2023 11:45:14 -0500
Subject: [PATCH 68/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add test for iterator::operator- on forward iterators (and clean up other iterator::operator- test).
---
 .../iterator/operator.pass.cpp                | 75 ++++++++++++++-----
 .../range.adaptors/range.stride.view/test.h   | 30 ++++++++
 2 files changed, 88 insertions(+), 17 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
index 3520ae116c01c0..f0276453ec9c4b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
@@ -136,31 +136,72 @@ constexpr bool operator_tests() {
     static_assert(is_relationally_comparable<StrideViewIterator>);
   }
   {
-      // Test the forward-range operator- between two iterators (i.e., no ceil).
-      // TODO
-  } {
+    using Base = InputView<SizedForwardIterator, SizedForwardIterator>;
+    // Test the forward-range operator- between two iterators (i.e., no ceil).
+    int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    auto rav_zero    = Base(SizedForwardIterator(arr), SizedForwardIterator(arr + 10));
+    auto rav_one     = Base(SizedForwardIterator(arr + 1), SizedForwardIterator(arr + 10));
+    auto stride_zoff = std::ranges::stride_view(rav_zero, 3);
+    auto stride_ooff = std::ranges::stride_view(rav_one, 3);
+
+    auto stride_zoff_begin = stride_zoff.begin();
+    auto stride_ooff_begin = stride_ooff.begin();
+
+    auto stride_zoff_one   = stride_zoff_begin;
+    auto stride_zoff_four  = ++stride_zoff_begin;
+    auto stride_zoff_seven = ++stride_zoff_begin;
+
+    auto stride_ooff_two  = stride_ooff_begin;
+    auto stride_ooff_five = ++stride_ooff_begin;
+
+    static_assert(std::sized_sentinel_for<std::ranges::iterator_t<Base>, std::ranges::iterator_t<Base>>);
+    static_assert(can_calculate_distance_between_non_sentinel<decltype(stride_zoff_begin)>);
+    static_assert(std::forward_iterator<SizedForwardIterator>);
+
+    assert(*stride_zoff_one == 1);
+    assert(*stride_zoff_four == 4);
+    assert(*stride_zoff_seven == 7);
+
+    assert(*stride_ooff_two == 2);
+    assert(*stride_ooff_five == 5);
+    // Check positive __n with exact multiple of left's stride.
+    assert(stride_zoff_four - stride_zoff_one == 1);
+    assert(stride_zoff_seven - stride_zoff_one == 2);
+
+    // Check positive __n with non-exact multiple of left's stride.
+    assert(stride_ooff_two - stride_zoff_one == 0);
+    assert(stride_ooff_five - stride_zoff_one == 1);
+
+    // Check negative __n with exact multiple of left's stride.
+    assert(stride_zoff_one - stride_zoff_four == -1);
+    assert(stride_zoff_one - stride_zoff_seven == -2);
+
+    // Check negative __n with non-exact multiple of left's stride.
+    assert(stride_zoff_one - stride_ooff_two == 0);
+    assert(stride_zoff_one - stride_ooff_five == -1);
+  }
+
+  {
+    using Base = InputView<SizedInputIterator, SizedInputIterator>;
     // Test the non-forward-range operator- between two iterators (i.e., ceil).
     int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-    auto rav_zero =
-        InputView<SizedInputIterator, SizedInputIterator>(SizedInputIterator(arr), SizedInputIterator(arr + 10));
-    auto rav_one =
-        InputView<SizedInputIterator, SizedInputIterator>(SizedInputIterator(arr + 1), SizedInputIterator(arr + 10));
+    auto rav_zero    = Base(SizedInputIterator(arr), SizedInputIterator(arr + 10));
+    auto rav_one     = Base(SizedInputIterator(arr + 1), SizedInputIterator(arr + 10));
     auto stride_zoff = std::ranges::stride_view(rav_zero, 3);
     auto stride_ooff = std::ranges::stride_view(rav_one, 3);
 
-    auto stride_zoff_base = stride_zoff.begin();
-    auto stride_ooff_base = stride_ooff.begin();
+    auto stride_zoff_begin = stride_zoff.begin();
+    auto stride_ooff_begin = stride_ooff.begin();
 
-    auto stride_zoff_one   = stride_zoff_base;
-    auto stride_zoff_four  = ++stride_zoff_base;
-    auto stride_zoff_seven = ++stride_zoff_base;
+    auto stride_zoff_one   = stride_zoff_begin;
+    auto stride_zoff_four  = ++stride_zoff_begin;
+    auto stride_zoff_seven = ++stride_zoff_begin;
 
-    auto stride_ooff_two  = stride_ooff_base;
-    auto stride_ooff_five = ++stride_ooff_base;
+    auto stride_ooff_two  = stride_ooff_begin;
+    auto stride_ooff_five = ++stride_ooff_begin;
 
-    static_assert(std::sized_sentinel_for<decltype(std::move(stride_zoff_base).base()),
-                                          decltype(std::move(stride_zoff_base).base())>);
-    static_assert(can_calculate_distance_between_non_sentinel<decltype(stride_zoff_base)>);
+    static_assert(std::sized_sentinel_for<std::ranges::iterator_t<Base>, std::ranges::iterator_t<Base>>);
+    static_assert(can_calculate_distance_between_non_sentinel<decltype(stride_zoff_begin)>);
 
     assert(*stride_zoff_one == 1);
     assert(*stride_zoff_four == 4);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index fc7f528a22196b..86f225ef37993c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -253,4 +253,34 @@ struct SizedInputIterator {
   }
 };
 
+// TODO: Cleanup
+struct SizedForwardIterator {
+  using iterator_concept = std::forward_iterator_tag;
+  using value_type       = int;
+  using difference_type  = std::intptr_t;
+
+  int* __v_;
+
+  constexpr SizedForwardIterator() { __v_ = nullptr; }
+  constexpr SizedForwardIterator(int* v) { __v_ = v; }
+  constexpr SizedForwardIterator(const SizedInputIterator& sii) { __v_ = sii.__v_; }
+
+  constexpr int operator*() const { return *__v_; }
+  constexpr SizedForwardIterator& operator++() {
+    __v_++;
+    return *this;
+  }
+  constexpr SizedForwardIterator operator++(int) {
+    auto nv = __v_;
+    nv++;
+    return SizedForwardIterator(nv);
+  }
+  friend constexpr bool operator==(const SizedForwardIterator& left, const SizedForwardIterator& right) {
+    return left.__v_ == right.__v_;
+  }
+  friend constexpr difference_type operator-(const SizedForwardIterator& left, const SizedForwardIterator& right) {
+    return left.__v_ - right.__v_;
+  }
+};
+
 #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H

>From 070e0381b639260922f2521aa2e4819bd5af1276 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 8 Dec 2023 11:49:24 -0500
Subject: [PATCH 69/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Clean up iterator ctor (copy and default) tests.
---
 .../iterator/ctor.copy.pass.cpp               | 372 ++++++++++++++++++
 .../iterator/ctor.default.pass.cpp            | 245 ------------
 .../iterator/ctor.default.verify.cpp          |  39 ++
 3 files changed, 411 insertions(+), 245 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.copy.pass.cpp
 delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.verify.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.copy.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.copy.pass.cpp
new file mode 100644
index 00000000000000..aa4183105eca17
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.copy.pass.cpp
@@ -0,0 +1,372 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator(__iterator<!_Const> __i)
+//    requires _Const && convertible_to<ranges::iterator_t<_View>, iterator_t<_Base>> &&
+//                 convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
+
+#include <ranges>
+
+#include "../test.h"
+#include "test_iterators.h"
+
+struct NotSimpleViewIterBegin : InputIterBase<NotSimpleViewIterBegin> {};
+
+template <bool CopyConvertible, bool MoveConvertible>
+struct NotSimpleViewConstIterBegin : InputIterBase<NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>> {
+  constexpr NotSimpleViewConstIterBegin() = default;
+  constexpr NotSimpleViewConstIterBegin(NotSimpleViewConstIterBegin&&) {}
+  constexpr NotSimpleViewConstIterBegin& operator=(const NotSimpleViewConstIterBegin&) {}
+  constexpr NotSimpleViewConstIterBegin& operator=(NotSimpleViewConstIterBegin&&) {}
+
+  constexpr NotSimpleViewConstIterBegin(const NotSimpleViewConstIterBegin&) {}
+  constexpr NotSimpleViewConstIterBegin(const NotSimpleViewIterBegin&)
+    requires CopyConvertible
+  {}
+  constexpr NotSimpleViewConstIterBegin(NotSimpleViewIterBegin&&)
+    requires MoveConvertible
+  {}
+};
+
+struct NotSimpleViewIterEnd : InputIterBase<NotSimpleViewIterEnd> {};
+
+template <bool CopyConvertible, bool MoveConvertible>
+struct NotSimpleViewConstIterEnd : InputIterBase<NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>> {
+  constexpr NotSimpleViewConstIterEnd() = default;
+  constexpr NotSimpleViewConstIterEnd(NotSimpleViewConstIterEnd&&) {}
+  constexpr NotSimpleViewConstIterEnd& operator=(const NotSimpleViewConstIterEnd&) {}
+  constexpr NotSimpleViewConstIterEnd& operator=(NotSimpleViewConstIterEnd&&) {}
+
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewConstIterEnd&) {}
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewIterEnd&)
+    requires CopyConvertible
+  {}
+  constexpr NotSimpleViewConstIterEnd(NotSimpleViewIterEnd&&)
+    requires MoveConvertible
+  {}
+};
+
+constexpr bool operator==(const NotSimpleViewIterBegin&, const NotSimpleViewIterEnd&) { return true; }
+constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewIterBegin&) { return true; }
+
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterEnd&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterBegin&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewIterBegin&, const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewIterBegin&, const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&) {
+  return true;
+}
+
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterEnd&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterBegin&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&) {
+  return true;
+}
+
+/*
+ * Goal: We will need a way to get a stride_view<true>::__iterator and a
+ * stride_view<false>::__iterator because those are the two possible types
+ * of the stride_view::__iterator constructor. The template value is determined
+ * by whether the stride_view::__iterator is derivative of a stride_view over a
+ * view that is simple.
+ *
+ * So, first things first, we need to build a stride_view over a (non-)simple view.
+ * There are (at least) two ways that a view can be non-simple:
+ * 1. The iterator type for const begin is different than the iterator type for begin
+ * 2. The iterator type for const end is different that the iterator type for end
+ *
+ * So, let's create two different classes where that is the case so that we can test
+ * for those conditions individually. We parameterize with a template to decide
+ * whether to
+ * 1. enable converting constructors between the non-const and the const version.
+ * That feature is important for testing the stride_view::__iterator<true> converting
+ * constructor from a stride_view::_iterator<false> iterator.
+ * 2. enable copyability. That feature is important for testing whether the requirement
+ * the that copy constructor for the stride_view::__iterator<false> type actually moves
+ * the underlying iterator.
+ */
+template <bool CopyConvertible = false, bool MoveConvertible = true>
+struct NotSimpleViewDifferentBegin : std::ranges::view_base {
+  constexpr NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible> begin() const { return {}; }
+  constexpr NotSimpleViewIterBegin begin() { return {}; }
+
+  constexpr NotSimpleViewIterEnd end() const { return {}; }
+};
+
+template <bool CopyConvertible = false, bool MoveConvertible = true>
+struct NotSimpleViewDifferentEnd : std::ranges::view_base {
+  constexpr NotSimpleViewIterBegin begin() const { return {}; }
+  constexpr NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible> end() const { return {}; }
+  constexpr NotSimpleViewIterEnd end() { return {}; }
+};
+
+constexpr bool non_simple_view_iter_ctor_test() {
+  using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false>>;
+  using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
+  using NotSimpleStrideViewIterConst = std::ranges::iterator_t<const NotSimpleStrideView>;
+  static_assert(!std::is_same_v<NotSimpleStrideViewIterConst, NotSimpleStrideViewIter>);
+  return true;
+}
+
+constexpr bool non_const_iterator_copy_ctor() {
+  // All tests share the following general configuration.
+  //
+  // Instantiate a stride view StrideView over a non-simple view (NotSimpleViewBeingStrided) whose
+  // 1. std::ranges::iterator_t<StrideView> base's type is NotSimpleViewBeingStridedIterator
+  // 2. std::ranges::iterator_t<const StrideView> base's type is NotSimpleViewBeingStridedConstIterator
+  // 3. NotSimpleViewBeingStridedIterator is ONLY move-convertible to NotSimpleViewBeingStridedConstIterator
+  // 4. std::ranges::sentinel_t are the same whether SV is const or not.
+  // 4. the type of StrideView::end is the same whether StrideView is const or not.
+  // 5. the type of StrideView::begin is stride_view::iterator<true> when StrideView is const and
+  //    stride_view::iterator<false> when StrideView is non const.
+  // Visually, it looks like this:
+  //
+  //  NotSimpleViewBeingStrided(Const)Iterator <-----
+  //                ^                               |
+  //                |                               |
+  //                | begin (const?)                |
+  //                |                               |
+  //     NotSimpleViewBeingStrided                  |
+  //                ^                               |
+  //                |                               |
+  //                | Strides over                  |
+  //                |                               |
+  //            StrideView                          |
+  //                |                               |
+  //                | begin (const?)                |
+  //                |                               |
+  //                \/                              |
+  //       StrideView(Const)Iter                    |
+  //                |                               |
+  //                | base                          |
+  //                |                               |
+  //                ---------------------------------
+
+  {
+    // Stride over non-simple view over whose iterators are copy convertible -- should look (statically)
+    // like it is possible copy construct the stride view's iterator (the move-only requirement comes from
+    // a move of the current between the copied-from iterator to the copied-to iterator).
+    using NotSimpleViewBeingStrided              = NotSimpleViewDifferentEnd<true, false>;
+    using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are move convertible -- should look (statically)
+    // like it is possible copy construct the stride view's iterator (the move-only requirement comes from
+    // a move of the current between the copied-from iterator to the copied-to iterator).
+    using NotSimpleViewBeingStrided              = NotSimpleViewDifferentEnd<false, true>;
+    using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are not convertible -- should not be able
+    // to copy construct the stride view's iterator.
+    using NotSimpleViewBeingStrided              = NotSimpleViewDifferentEnd<false, false>;
+    using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(!std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(!std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are not convertible -- should not be able
+    // to copy construct the stride view's iterator.
+    using NotSimpleViewBeingStrided              = NotSimpleViewDifferentEnd<false, true>;
+    using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<NotSimpleViewBeingStridedIterator, NotSimpleViewBeingStridedIterator>);
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+
+    StrideView str{NotSimpleViewBeingStrided{}, 5};
+    // Confirm (5)
+    static_assert(std::is_same_v<StrideViewIter, decltype(str.begin())>);
+
+    // Now, do what we wanted the whole time: make sure that we can copy construct a
+    // stride_view::iterator<true> from a stride_view::iterator<false>. The copy
+    // constructor requires that the new __current_ StrideViewConstIter (type
+    // NotSimpleViewBeingStridedConstIterator) be constructable
+    // from the moved str.begin() __current_ (type NotSimpleViewBeingStridedConstIterator).
+    StrideViewConstIter iterator_copy{str.begin()};
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are copy convertible -- should look (statically)
+    // like it is possible copy construct the stride view's iterator (the move-only requirement comes from
+    // a move of the current between the copied-from iterator to the copied-to iterator).
+    using NotSimpleViewBeingStrided              = NotSimpleViewDifferentBegin<true, false>;
+    using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are move convertible -- should look (statically)
+    // like it is possible copy construct the stride view's iterator (the move-only requirement comes from
+    // a move of the current between the copied-from iterator to the copied-to iterator).
+    using NotSimpleViewBeingStrided              = NotSimpleViewDifferentBegin<false, true>;
+    using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are not convertible -- should not be able
+    // to copy construct the stride view's iterator.
+    using NotSimpleViewBeingStrided              = NotSimpleViewDifferentBegin<false, false>;
+    using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(!std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(!std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // The NotSimpleViewBeingStrided template parameters mean that NotSimpleViewBeingStridedIterator
+    // can be move-converted to NotSimpleViewBeingStridedConstIterator but not copy-converted.
+    using NotSimpleViewBeingStrided              = NotSimpleViewDifferentBegin<false, true>;
+    using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    // Confirm (1) and (2)
+    static_assert(std::is_same_v<NotSimpleViewBeingStridedIterator, decltype(std::declval<StrideViewIter>().base())>);
+    static_assert(
+        std::is_same_v<NotSimpleViewBeingStridedConstIterator, decltype(std::declval<StrideViewConstIter>().base())>);
+    // Confirm (3)
+    static_assert(std::convertible_to<NotSimpleViewBeingStridedIterator, NotSimpleViewBeingStridedIterator>);
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    // Confirm (4)
+    static_assert(std::is_same_v<StrideViewSentinel, StrideViewConstSentinel>);
+
+    StrideView str{NotSimpleViewBeingStrided{}, 5};
+    // Confirm (5)
+    static_assert(std::is_same_v<StrideViewIter, decltype(str.begin())>);
+
+    // Now, do what we wanted the whole time: make sure that we can copy construct a
+    // stride_view::iterator<true> from a stride_view::iterator<false>. The copy
+    // constructor requires that the new __current_ StrideViewConstIter (type
+    // NotSimpleViewBeingStridedConstIterator) be constructable
+    // from the moved str.begin() __current_ (type NotSimpleViewBeingStridedConstIterator).
+    StrideViewConstIter iterator_copy{str.begin()};
+  }
+  return true;
+}
+
+int main(int, char**) {
+  non_simple_view_iter_ctor_test();
+  static_assert(non_simple_view_iter_ctor_test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
deleted file mode 100644
index ad6a18e77d0756..00000000000000
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.pass.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// std::views::stride_view
-
-#include "../test.h"
-#include "__concepts/convertible_to.h"
-#include "__iterator/concepts.h"
-#include "__ranges/access.h"
-#include "__ranges/concepts.h"
-#include "__ranges/stride_view.h"
-#include <cassert>
-#include <ranges>
-#include <type_traits>
-#include <utility>
-
-struct NotSimpleViewIter : InputIterBase<NotSimpleViewIter> {};
-struct NotSimpleViewIterEnd : InputIterBase<NotSimpleViewIterEnd> {};
-constexpr bool operator==(const NotSimpleViewIter&, const NotSimpleViewIterEnd&) { return true; }
-constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewIter&) { return true; }
-
-template <bool Convertible, bool Copyable>
-struct NotSimpleViewConstIterEnd : InputIterBase<NotSimpleViewConstIterEnd<Convertible, Copyable>> {
-  constexpr NotSimpleViewConstIterEnd() = default;
-  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewConstIterEnd&&) {}
-  constexpr NotSimpleViewConstIterEnd& operator=(const NotSimpleViewConstIterEnd&) {}
-  constexpr NotSimpleViewConstIterEnd& operator=(const NotSimpleViewConstIterEnd&&) {}
-
-  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewConstIterEnd&)
-    requires Copyable
-  {}
-  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewIterEnd&)
-    requires Convertible
-  {}
-};
-
-template <bool Convertible, bool Copyable>
-struct NotSimpleViewConstIter : InputIterBase<NotSimpleViewConstIter<Convertible, Copyable>> {
-  constexpr NotSimpleViewConstIter() = default;
-  constexpr NotSimpleViewConstIter(const NotSimpleViewConstIter&&) {}
-  constexpr NotSimpleViewConstIter& operator=(const NotSimpleViewConstIter&&) {}
-  constexpr NotSimpleViewConstIter& operator=(const NotSimpleViewConstIter&) {}
-
-  constexpr NotSimpleViewConstIter(const NotSimpleViewConstIter&)
-    requires Copyable
-  {}
-  constexpr NotSimpleViewConstIter(const NotSimpleViewIter&)
-    requires Convertible
-  {}
-};
-
-template <bool Convertible, bool Copyable>
-constexpr bool operator==(const NotSimpleViewConstIter<Convertible, Copyable>&, const NotSimpleViewIterEnd&) {
-  return true;
-}
-template <bool Convertible, bool Copyable>
-constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIter<Convertible, Copyable>&) {
-  return true;
-}
-template <bool Convertible, bool Copyable>
-constexpr bool operator==(const NotSimpleViewConstIterEnd<Convertible, Copyable>&, const NotSimpleViewIterEnd&) {
-  return true;
-}
-template <bool Convertible, bool Copyable>
-constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIterEnd<Convertible, Copyable>&) {
-  return true;
-}
-template <bool Convertible, bool Copyable>
-constexpr bool operator==(const NotSimpleViewIter&, const NotSimpleViewConstIterEnd<Convertible, Copyable>&) {
-  return true;
-}
-template <bool Convertible, bool Copyable>
-constexpr bool operator==(const NotSimpleViewConstIterEnd<Convertible, Copyable>&, const NotSimpleViewIter&) {
-  return true;
-}
-
-/*
- * There are (at least) two ways that a view can be non-simple:
- * 1. The iterator type for const begin is different than the iterator type for begin
- * 2. The iterator type for const end is different that the iterator type for end
- *
- * So, let's create two different classes where that is the case so that we can test
- * for those conditions individually. We parameterize with a template to decide
- * whether to
- * 1. enable converting constructors between the non-const and the const version.
- * That feature is important for testing the stride_view::__iterator<true> converting
- * constructor from a stride_view::_iterator<false> iterator.
- * 2. enable copyability. That feature is important for testing whether the requirement
- * the that copy constructor for the stride_view::__iterator<false> type actually moves
- * the underlying iterator.
- */
-template <bool Convertible = false, bool Copyable = true>
-struct NotSimpleViewDifferentBegin : std::ranges::view_base {
-  constexpr NotSimpleViewConstIter<Convertible, Copyable> begin() const { return {}; }
-  constexpr NotSimpleViewIter begin() { return {}; }
-  constexpr NotSimpleViewIterEnd end() const { return {}; }
-  constexpr NotSimpleViewIterEnd end() { return {}; }
-};
-
-template <bool Convertible = false, bool Copyable = true>
-struct NotSimpleViewDifferentEnd : std::ranges::view_base {
-  constexpr NotSimpleViewIter begin() const { return {}; }
-  constexpr NotSimpleViewIter begin() { return {}; }
-  constexpr NotSimpleViewConstIterEnd<Convertible, Copyable> end() const {
-    return std::move(NotSimpleViewConstIterEnd<Convertible, Copyable>{});
-  }
-  constexpr NotSimpleViewIterEnd end() { return {}; }
-};
-
-constexpr bool non_simple_view_iter_ctor_test() {
-  using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false>>;
-  using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
-  using NotSimpleStrideViewIterConst = std::ranges::iterator_t<const NotSimpleStrideView>;
-  static_assert(!std::is_same_v<NotSimpleStrideViewIterConst, NotSimpleStrideViewIter>);
-  return true;
-}
-
-struct NonDefaultConstructibleIterator : InputIterBase<NonDefaultConstructibleIterator> {
-  NonDefaultConstructibleIterator() = delete;
-  constexpr NonDefaultConstructibleIterator(int) {}
-};
-
-struct ViewWithNonDefaultConstructibleIterator : std::ranges::view_base {
-  constexpr NonDefaultConstructibleIterator begin() const { return NonDefaultConstructibleIterator{5}; }
-  constexpr std::default_sentinel_t end() const { return {}; }
-};
-template <>
-inline constexpr bool std::ranges::enable_borrowed_range<ViewWithNonDefaultConstructibleIterator> = true;
-
-constexpr bool iterator_default_constructible() {
-  {
-    // If the type of the iterator of the range being strided is non-default
-    // constructible, then the stride view's iterator should not be default
-    // constructible, either!
-    constexpr ViewWithNonDefaultConstructibleIterator v{};
-    constexpr auto stride   = std::ranges::stride_view(v, 1);
-    using stride_iterator_t = decltype(stride.begin());
-    static_assert(!std::is_default_constructible<stride_iterator_t>());
-  }
-  {
-    // If the type of the iterator of the range being strided is default
-    // constructible, then the stride view's iterator should be default
-    // constructible, too!
-    constexpr int arr[]     = {1, 2, 3};
-    auto stride             = std::ranges::stride_view(arr, 1);
-    using stride_iterator_t = decltype(stride.begin());
-    static_assert(std::is_default_constructible<stride_iterator_t>());
-  }
-
-  return true;
-}
-
-constexpr bool non_const_iterator_copy_ctor() {
-  {
-    // Instantiate a stride view over a non-simple view whose const/non-const begin iterators are not-convertible.
-    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false, true>>;
-    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
-    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
-
-    // It should not be possible to construct a stride view iterator from a non-const stride view iterator
-    // when the strided-over type has inconvertible begin iterator types.
-    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
-    static_assert(!std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
-    static_assert(!std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
-  }
-  {
-    // Instantiate a stride view over a non-simple view whose const/non-const begin iterators are convertible.
-    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<true, true>>;
-    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
-    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
-
-    // It should be possible to construct a stride view iterator from a non-const stride view iterator
-    // when the strided-over type has convertible begin iterator types.
-    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
-    static_assert(std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
-    static_assert(std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
-  }
-
-  {
-    // Instantiate a stride view over a non-simple view whose const/non-const end iterators are not convertible.
-    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentEnd<false, true>>;
-    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
-    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
-
-    static_assert(std::ranges::__can_borrow<const NotSimpleStrideView&>);
-
-    // It should not be possible to construct a stride view iterator from a non-const stride view iterator
-    // when the strided-over type has inconvertible end iterator types.
-    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
-    static_assert(!std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
-    static_assert(!std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
-  }
-
-  {
-    // Instantiate a stride view over a non-simple view whose const/non-const end iterators are convertible.
-    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentEnd<true, true>>;
-    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
-    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
-
-    // It should not be possible to construct a stride view iterator from a non-const stride view iterator
-    // when the strided-over type has inconvertible end iterator types.
-    static_assert(std::is_copy_constructible_v<NotSimpleStrideViewConstIter>);
-    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
-    static_assert(std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
-    static_assert(std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
-  }
-
-  {
-    // Instantiate a stride view over a non-simple view whose iterators are not copyable but whose const
-    // and non-const end iterators are convertible.
-    using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<true, false>>;
-    using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
-    using NotSimpleStrideViewConstIter = std::ranges::iterator_t<const NotSimpleStrideView>;
-
-    // It should not be possible to copy construct a stride view iterator from a non-const stride view iterator
-    // when the strided-over type has non copyable end iterator type.
-    static_assert(!std::is_copy_constructible_v<NotSimpleStrideViewConstIter>);
-
-    // Given the difference between the (non-) constness of the end iterator types and the fact that
-    // they can be converted between, it should
-    // 1. not be a simple view
-    static_assert(!std::ranges::__simple_view<NotSimpleStrideView>);
-    // 2. the types should be convertible
-    static_assert(std::convertible_to<NotSimpleStrideViewIter, NotSimpleStrideViewConstIter>);
-    // 3. and a const thing should be constructible from a non const thing because they are convertible.
-    static_assert(std::is_constructible_v<NotSimpleStrideViewConstIter, NotSimpleStrideViewIter>);
-  }
-  return true;
-}
-
-int main(int, char**) {
-  non_simple_view_iter_ctor_test();
-  static_assert(non_simple_view_iter_ctor_test());
-  static_assert(iterator_default_constructible());
-  static_assert(non_const_iterator_copy_ctor());
-
-  return 0;
-}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.verify.cpp
new file mode 100644
index 00000000000000..a2842e7d269289
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.verify.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// __iterator() requires default_initializable<iterator_t<_Base>> = default;
+
+#include <ranges>
+
+#include "../test.h"
+#include "test_iterators.h"
+
+struct NonDefaultConstructibleIterator : InputIterBase<NonDefaultConstructibleIterator> {
+  NonDefaultConstructibleIterator() = delete;
+  constexpr NonDefaultConstructibleIterator(int) {}
+};
+
+struct ViewWithNonDefaultConstructibleIterator : std::ranges::view_base {
+  constexpr NonDefaultConstructibleIterator begin() const { return NonDefaultConstructibleIterator{5}; }
+  constexpr std::default_sentinel_t end() const { return {}; }
+};
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<ViewWithNonDefaultConstructibleIterator> = true;
+
+// If the type of the iterator of the range being strided is non-default
+// constructible, then the stride view's iterator should not be default
+// constructible, either!
+static_assert(!std::is_default_constructible<
+              std::ranges::iterator_t<ViewWithNonDefaultConstructibleIterator>>()); // expected-no-diagnostics
+// If the type of the iterator of the range being strided is default
+// constructible, then the stride view's iterator should be default
+// constructible, too!
+static_assert(std::is_default_constructible<std::ranges::iterator_t<
+                  std::ranges::stride_view<std::ranges::ref_view<const int[3]>>>>()); // expected-no-diagnostics

>From ebf02e78a602d9ee3441b3b14c3b36e8babdc7c5 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 8 Dec 2023 11:50:27 -0500
Subject: [PATCH 70/70] fixup! WIP: [libc++][ranges] Implement
 `ranges::stride_view`.

Add additional iterator operator (that's fun to say) tests.
---
 .../iterator/operator.pass.cpp                | 34 +++++++++++++++++++
 .../range.adaptors/range.stride.view/test.h   |  6 ++--
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
index f0276453ec9c4b..280090bf1c09d4 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
@@ -101,6 +101,40 @@ constexpr bool operator_tests() {
     static_assert(!is_difference_minusable<StrideViewIterator>);
     static_assert(!is_relationally_comparable<StrideViewIterator>);
   }
+  {
+    // What operators are valid for an iterator derived from a stride view
+    // over a sized input view.
+    using View               = InputView<SizedInputIterator>;
+    using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<View>>;
+
+    static_assert(is_plus_plusable_post<StrideViewIterator>);
+    static_assert(is_plus_plusable_pre<StrideViewIterator>);
+    static_assert(!is_minus_minusable_post<StrideViewIterator>);
+    static_assert(!is_minus_minusable_pre<StrideViewIterator>);
+    static_assert(!is_plus_equalable<StrideViewIterator>);
+    static_assert(!is_minus_equalable<StrideViewIterator>);
+    static_assert(is_iterator_minusable<StrideViewIterator>);
+    static_assert(!is_difference_plusable<StrideViewIterator>);
+    static_assert(!is_difference_minusable<StrideViewIterator>);
+    static_assert(!is_relationally_comparable<StrideViewIterator>);
+  }
+  {
+    // What operators are valid for an iterator derived from a stride view
+    // over a sized forward view.
+    using View               = InputView<SizedForwardIterator>;
+    using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<View>>;
+
+    static_assert(is_plus_plusable_post<StrideViewIterator>);
+    static_assert(is_plus_plusable_pre<StrideViewIterator>);
+    static_assert(!is_minus_minusable_post<StrideViewIterator>);
+    static_assert(!is_minus_minusable_pre<StrideViewIterator>);
+    static_assert(!is_plus_equalable<StrideViewIterator>);
+    static_assert(!is_minus_equalable<StrideViewIterator>);
+    static_assert(is_iterator_minusable<StrideViewIterator>);
+    static_assert(!is_difference_plusable<StrideViewIterator>);
+    static_assert(!is_difference_minusable<StrideViewIterator>);
+    static_assert(!is_relationally_comparable<StrideViewIterator>);
+  }
   {
     // What operators are valid for an iterator derived from a stride view
     // over a bidirectional view.
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
index 86f225ef37993c..f2a9fa4b6ca5d0 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/test.h
@@ -129,8 +129,6 @@ struct InputIterBase {
   constexpr Derived operator++(int) { return {}; }
 
   friend constexpr bool operator==(const Derived&, const Derived&) { return true; }
-  friend constexpr bool operator==(const std::default_sentinel_t&, const Derived&) { return true; }
-  friend constexpr bool operator==(const Derived&, const std::default_sentinel_t&) { return true; }
 };
 
 template <std::input_iterator T, std::sentinel_for<T> S = sentinel_wrapper<T>>
@@ -252,6 +250,8 @@ struct SizedInputIterator {
     return left.__v_ - right.__v_;
   }
 };
+static_assert(std::input_iterator<SizedInputIterator>);
+static_assert(std::sized_sentinel_for<SizedInputIterator, SizedInputIterator>);
 
 // TODO: Cleanup
 struct SizedForwardIterator {
@@ -282,5 +282,7 @@ struct SizedForwardIterator {
     return left.__v_ - right.__v_;
   }
 };
+static_assert(std::input_iterator<SizedForwardIterator>);
+static_assert(std::sized_sentinel_for<SizedForwardIterator, SizedForwardIterator>);
 
 #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H



More information about the libcxx-commits mailing list