[libcxx-commits] [libcxx] [libc++][ranges] Implement `ranges::stride_view`. (PR #65200)
Will Hawkins via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Nov 15 20:56:47 PST 2023
https://github.com/hawkinsw updated https://github.com/llvm/llvm-project/pull/65200
>From ae8384162bf10554170c9ee1afee1bfc3871198f 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/52] 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 42bf6eb46212d07..f4ad45aefced490 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -358,6 +358,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 889d7fedbf2965f..cf39fbc894209e0 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -640,6 +640,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 000000000000000..880c8ce2950e470
--- /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 17ebe48f329963d..12188fce72d6644 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1718,6 +1718,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 f71a92f8a660b06..d00ccb22698df01 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 ec0cb0813492383..6e1e9f41d34f172 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -161,6 +161,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>
@@ -443,6 +444,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 a883103d812588b..0f418971c700da7 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 582e0c7dfe5e65d..ce73f5955649ddf 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
@@ -23,6 +23,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]
*/
@@ -60,6 +61,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
@@ -98,6 +103,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
@@ -136,6 +145,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
@@ -177,6 +190,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
@@ -254,6 +271,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
@@ -343,6 +367,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 0c1b8fa997ffd85..74dbe722d11b277 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
@@ -149,6 +149,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]
@@ -721,6 +722,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
@@ -1479,6 +1484,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
@@ -2408,6 +2417,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
@@ -3607,6 +3620,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
@@ -5031,6 +5048,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
@@ -6566,6 +6590,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 000000000000000..8ad758a953426dd
--- /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 000000000000000..badfd532453158c
--- /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 000000000000000..68556f32f875b12
--- /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 000000000000000..68556f32f875b12
--- /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 000000000000000..646a9423f4523c7
--- /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 000000000000000..68556f32f875b12
--- /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 000000000000000..cfc38b32926805a
--- /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 000000000000000..7f2711adc5179db
--- /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 000000000000000..68556f32f875b12
--- /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 000000000000000..68556f32f875b12
--- /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 000000000000000..981395f9e2c3290
--- /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 000000000000000..4d13f05d48c01ba
--- /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 98cf995ec223651..2503663e5a0bb90 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -829,6 +829,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 2b6eac60ecef48d4606d9ed18dd29402015bd072 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/52] 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 68556f32f875b12..7831d792d64e770 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 b69f434f67d5edd118a523c39943c6d92687b811 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/52] 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 8ad758a953426dd..0de98ba259517fc 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 badfd532453158c..6b22b7e89c01581 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 646a9423f4523c7..7c28842fe65f699 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 cfc38b32926805a..d0f466d3adeaef0 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 4d13f05d48c01ba..d9931cb6e63202f 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 7ca42bd0e2836f5d82390e031c99e147636238d4 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/52] 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 0de98ba259517fc..ba0efe36b98243f 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 d9931cb6e63202f..d06ef2c3b923c8a 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 e3eebc3bd9f624c1754e68bdf9a52adfe3ab9720 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/52] 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 880c8ce2950e470..f85247c825d815a 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 1fea37833908536c5f8c53d5c1f4dc22bf1c7ad1 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/52] 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 000000000000000..09cb8c20ea31857
--- /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 c56310305eaa06744d544c75b6ae1f921d08da0f 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/52] 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 f85247c825d815a..ff3b36073efa182 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 8a16b0f8c8cf23254b2eab31b262a2a7f19059f5 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/52] 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 ff3b36073efa182..fc1fb89b3ba0ed1 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 019b15700f639176144ecf010662f92f90e46531 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/52] 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 fc1fb89b3ba0ed1..9bf30e6c2815b9e 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 12188fce72d6644..af7e415355eb58d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1718,7 +1718,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 0f418971c700da7..85384202e4758ce 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 000000000000000..80092fc6738703a
--- /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 dc618e2347ce5b3c88bcb639fd972c1c3b8f3b1d 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/52] 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 9bf30e6c2815b9e..e2ef0cdc30ee541 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 d0f466d3adeaef0..a4a6ba56727663f 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 d06ef2c3b923c8a..e6640cd892e9d6a 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 d31f2456be2a11c5b54279f85a574df632e01aa3 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/52] 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 85384202e4758ce..7066c26011f14a8 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 27610afdd23db083705a167e23d5e2d774319343 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/52] 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 e2ef0cdc30ee541..47ecf3c58506674 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 000000000000000..126a7af66093e73
--- /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 a4a6ba56727663f..acd26c35a5db2b5 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 5467ff9f9807299cbc0f34ebd773d61cd721acba 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/52] 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 000000000000000..89c55d434745dcf
--- /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 43af5fb7fe60eb1e621eaa88cab5dea27f150793 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/52] 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 47ecf3c58506674..4ccd7051a4c2324 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 126a7af66093e73..000000000000000
--- 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 dd87fbd60b3cc3699663d993288ee4a2d45d062c 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/52] 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 68556f32f875b12..000000000000000
--- 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 68556f32f875b12..000000000000000
--- 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 7860ebbef9d153ad8cb7d6572ef6ba95ea9d80a7 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/52] 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 6b22b7e89c01581..4d06840ff7f8f3b 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 7831d792d64e770..ab8768502b1d061 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 3043dbf5b32596f327d6eed341ad2f005010da05 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/52] 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 89c55d434745dcf..54336576584802d 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 96e163dac45794ef55178cb76831734c296592ff 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/52] 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 000000000000000..ad23f7284fdd95d
--- /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 e6640cd892e9d6a..87c57d19d337c47 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 fa659eda28025d02333881a4197d77bc5bbb3859 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/52] 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 ad23f7284fdd95d..395ab4a55b9b8fd 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 09cb8c20ea31857..6891b5e62a187ad 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 87c57d19d337c47..a0d5540c53f0f54 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 65ed04ed6716b93a9d09893d8e1123fee2401114 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/52] 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 4d06840ff7f8f3b..062262ffde577cf 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 ab8768502b1d061..4cceca699d21580 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 6891b5e62a187ad..a205386fa0a9d1a 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 7c28842fe65f699..4add46949a6aec4 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 a0d5540c53f0f54..71120fb35774107 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 4d458afb87b6a234bef0028d7348bdca67b018d5 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/52] 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 ba0efe36b98243f..60ed5587933a064 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 1810cacd259008ee5f5491ed8e1672f1e6609018 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/52] 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 981395f9e2c3290..c270c77f6f9f324 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 71120fb35774107..8eb7423e03f6510 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 82f11c266de81d1ed20c02a030fbe9dd24e401a1 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/52] 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 4ccd7051a4c2324..0239a6c595df83d 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 000000000000000..3216a9ab85e84bd
--- /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 8eb7423e03f6510..6bef25b8618882b 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 09d1059720486f1ab002cb615e7861fcdebd10e5 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/52] 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 3216a9ab85e84bd..b6b871bd6910692 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 481574d730e4d85e9b1ad98fb9d755d4f96df8e4 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/52] 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 0239a6c595df83d..ba05c34553fcf58 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 000000000000000..0100dd1708b0da2
--- /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 78a23481cd7ac19669192d01ba938d85de6661c4 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/52] 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 7f2711adc5179db..ff5196d26476ce3 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 46fc18c29a6e97fe23130eb386f70346feecd26c 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/52] 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 acd26c35a5db2b5..02c261db280171c 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 6bef25b8618882b..3bf7d7b8a4f0058 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 f74aff5ac7fee46cbce6b3a8e23d48f37f624915 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/52] 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 ba05c34553fcf58..b699868c0234a95 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 863d5e5f14635b98179cc1eb12a57e54d5efc303 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/52] 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 b699868c0234a95..f923e7f3795faa9 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 94c7abf5a182d8bd6a41faa8b1caeb91e5117ecf 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/52] 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 3bf7d7b8a4f0058..b2ea7098d75bc06 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 e4e8d80c433fb91baa102ada681bc909caae9b3a 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/52] 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 60ed5587933a064..02e57c8865709be 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 a205386fa0a9d1a..30256ac12b77e45 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 b6b871bd6910692..6a9b1df59961bdb 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 02c261db280171c..567c9b1af0be0f9 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 80092fc6738703a..154f747f49bd7f4 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 1106f2dd698efca174cc8c77b38e3c9b78b02e0b 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/52] 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 f923e7f3795faa9..93eb4a473717806 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 7ba33e87fdd5fa029bcb5a48b65745867d18e9f7 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/52] 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 567c9b1af0be0f9..d782413375e4d45 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 b2ea7098d75bc06..993b595093f04ab 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 b649c2f0396a43c38a9923445e0e31c777d630fc 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/52] 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 93eb4a473717806..add002687a869ab 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 63bfd04f9549f9a8db69f689d7410e6691e2b2a8 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/52] 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 0100dd1708b0da2..667b74e4c3d516c 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 5c8b475d981f89c8d0549139249cf286fcd604c7 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/52] 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 d782413375e4d45..b27c686ccaf1022 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 993b595093f04ab..967c75c9cf00223 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 722fcecc3b622714902d08a104c991d249aa25e1 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/52] 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 b27c686ccaf1022..5a954fc73ef3e94 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 55eddf451e0629ccccbda3d3f3ddb127d3c63315 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/52] 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 add002687a869ab..ecf6065e20b7011 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 4ac8b6fe464235a7ca2ce4ba4c6abd220026b54a 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/52] 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 5a954fc73ef3e94..56620b758ad6b0c 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 68fdf821deb4a70241c532ace5fd8e4e7a9b9048 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/52] 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 000000000000000..3fbc312b9f307a1
--- /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 d55969cf5849befc2d09f627e7bbe40dc8e36ba7 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/52] 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 3fbc312b9f307a1..579bcea2d7186de 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 bb2902e61af16569d87542c5eaaf3d332a97299e 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/52] 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 ecf6065e20b7011..ea8cfc730d48329 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 000000000000000..16516574070a04f
--- /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 ad69a48e5001e27bdcdaf049c5a65ef9452b007b 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/52] 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 ea8cfc730d48329..c2f7a9d35135dd9 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 c2890dc2037fc054223f6167e3b2045664e2daad 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/52] 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 c2f7a9d35135dd9..8be633b65d914cd 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 000000000000000..caec0a2de71c63f
--- /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 fa2c0ab600be7af7d564f33501fdf44b4fd9e9cc 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/52] 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 8be633b65d914cd..c7f9a4922f7d0a2 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 000000000000000..b3672765e891a53
--- /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 096fa2de526ecdb30900deb38ad37be7a330843f 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/52] 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 967c75c9cf00223..957cab30446978c 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 a9d03709ec24bcbc261601b92f7799b302a40788 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/52] 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 b3672765e891a53..2b2f17b9feed6eb 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 a789087d467ed4180853c8b46754c12807ed72bf 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/52] 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 c7f9a4922f7d0a2..772551abadc39d4 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 870e6001986f668ca44408107859c7ee77746f10 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/52] 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 02e57c8865709be..50a349cd6207df5 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 30256ac12b77e45..8d3cbcd1463cfa3 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 6a9b1df59961bdb..270d5cd0caaffad 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 2b2f17b9feed6eb..5118b35db820457 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 154f747f49bd7f4..25ffcce838bd441 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 957cab30446978c..4bda90fcf0e288a 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 f2e1b4a9f69926e5255670b99559e5f334c09fd1 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/52] 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 25ffcce838bd441..9b84817be4abb1f 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 34c5b7b114f33e75f0a420a59a6e49c2dec0f50f 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/52] 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 8d3cbcd1463cfa3..a34d3cbb3863f62 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 4bda90fcf0e288a..159de0f78f58376 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_; }
More information about the libcxx-commits
mailing list