diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -358,6 +358,8 @@ --------------------------------------------------- ----------------- ``__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 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -633,6 +633,7 @@ __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 --- /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 +_LIBCPP_HIDE_FROM_ABI constexpr _Value __div_ceil(_Value __left, _Value __right) { + _Value __r = __left / __right; + if (__left % __right) { + __r++; + } + return __r; +} + +template + requires view<_View> +class stride_view : public view_interface> { + _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); + range_difference_t<_View> __stride_ = 0; + + template + class __iterator; + template + 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 + { + 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{*this, ranges::begin(__base_)}; + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + requires ranges::range + { + return __iterator{*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{*this, ranges::end(__base_), __missing}; + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() + requires(!__simple_view<_View> && common_range<_View> && !bidirectional_range<_View>) + { + return __iterator{*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 && common_range && sized_range && forward_range) + { + auto __missing = (__stride_ - ranges::distance(__base_) % __stride_) % __stride_; + return __iterator{*this, ranges::end(__base_), __missing}; + } + _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + requires(range && common_range<_View> && !bidirectional_range<_View>) + { + return __iterator{*this, ranges::end(__base_)}; + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + requires(range) + { + return std::default_sentinel; + } +}; // class stride_view + +template +struct __stride_iterator_category {}; + +template +struct __stride_iterator_category<_View> { + using _Cat = typename iterator_traits>::iterator_category; + using iterator_category = + _If, + random_access_iterator_tag, + /* else */ _Cat >; +}; + +template + requires view<_View> +template +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_iterator_tag, + _If, + bidirectional_iterator_tag, + _If, + 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> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator __i) + requires _Const && std::convertible_to, ranges::iterator_t<_Base>> && + std::convertible_to, 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> + { + 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> + { + 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>> && 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>> + { + 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, 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, 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> + { + return ranges::iter_swap(__x.__current_, __y.__current_); + } +}; // class stride_view::__iterator + +template + requires view<_View> +template +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 const& __x, __sentinel const& __y) { + return __x.__current_ == __y.__end_; + } +}; // class stride_view::__sentinel + +template +stride_view(_Range&&) -> stride_view>; + +namespace views { +namespace __stride { +// removed this. +struct __fn { + template + [[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 + [[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 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1711,6 +1711,7 @@ 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 --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -398,6 +398,7 @@ #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 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -161,6 +161,7 @@ __cpp_lib_ranges_repeat 202207L __cpp_lib_ranges_slide 202202L __cpp_lib_ranges_starts_ends_with 202106L +__cpp_lib_ranges_stride 202207L __cpp_lib_ranges_to_container 202202L @@ -441,6 +442,7 @@ # 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 --- a/libcxx/modules/std/ranges.inc +++ b/libcxx/modules/std/ranges.inc @@ -266,6 +266,13 @@ using std::ranges::views::zip; } // namespace views + // [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; @@ -309,13 +316,6 @@ using std::ranges::views::chunk_by; } - // [range.stride], stride view - using std::ranges::stride_view; - - namespace views { - using std::ranges::views::stride; - } - 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 --- 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 @@ -260,6 +277,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 @@ -355,6 +379,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 --- 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 @@ -5043,6 +5060,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 @@ -6590,6 +6614,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 --- /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 +#include +#include + +template +concept CanBePiped = requires(View&& view, T&& t) { + { std::forward(view) | std::forward(t) }; +}; + +constexpr bool test() { + int arr[] = {1, 2, 3}; + + // Simple use cases. + { + { + BidirRange view(arr, arr + 3); + std::ranges::stride_view 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 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; + using Subrange = std::ranges::subrange; + + using ReverseIt = std::reverse_iterator; + using ReverseSubrange = std::ranges::subrange; + + { + BidirRange view(buf, buf + 3); + ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3); + std::same_as 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 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 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; + using Subrange = std::ranges::subrange; + + using ReverseIt = std::reverse_iterator; + using ReverseSubrange = std::ranges::subrange; + + { + BidirRange view(buf, buf + 3); + ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view))); + std::same_as 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 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 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> 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> 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::same_as 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, decltype(f)>; + std::same_as 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); + // Not invocable because NotAViewableRange is, well, not a viewable range. + static_assert(!std::is_invocable_v); + // Is invocable because BidirRange is a viewable range. + static_assert(std::is_invocable_v); + + // Make sure that pipe operations work! + static_assert(CanBePiped{}))>); + static_assert(CanBePiped{}))>); + static_assert( + !CanBePiped{}))>); + } + // A final sanity check. + { static_assert(std::same_as); } + + 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 --- /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 +#include + +template +concept can_call_base_on = requires(T t) { std::forward(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> const view(range, 3); + std::same_as> 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> view(range, 3); + std::same_as> 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> decltype(auto) result = std::ranges::stride_view>(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 const&>); + static_assert(!can_call_base_on&>); + static_assert(can_call_base_on&&>); + static_assert(can_call_base_on>); + } + + 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 --- /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 --- /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 --- /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 + +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>>); + static_assert(!enable_borrowed_range>>); + 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 --- /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 --- /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 +#include + +bool non_simple_view_iter_ctor_test() { + using StrideView = std::ranges::stride_view; + using StrideViewIterNonConst = std::ranges::iterator_t; + using StrideViewIterConst = std::ranges::iterator_t; + + 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; + using StrideViewIter = std::ranges::iterator_t; + + 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 --- /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 +#include + +#include "test_iterators.h" + +template +constexpr void testOne() { + using Range = std::ranges::subrange; + using StrideView = std::ranges::stride_view; + static_assert(std::ranges::common_range); + + { + // 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>(); + //testOne>(); + //testOne>(); + //testOne>(); + testOne(); + + 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 --- /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 --- /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 --- /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 +#include + +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 --- /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 +#include + +template +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 +Range(T, T) -> Range; + +template +struct BorrowedRange : public Range {}; + +template +inline constexpr bool std::ranges::enable_borrowed_range> = 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 +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(*this); } + constexpr Derived operator++(int) { return {}; } + + friend constexpr bool operator==(const ForwardIterBase&, const ForwardIterBase&) { return true; } +}; + +template +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(*this); } + constexpr Derived operator++(int) { return {}; } + + friend constexpr bool operator==(const InputIterBase&, const InputIterBase&) { return true; } +}; + +struct NotSimpleViewIterB : ForwardIterBase { + 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 { + 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 { + 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 begin() { return bidirectional_iterator{begin_}; } + constexpr bidirectional_iterator begin() const { return bidirectional_iterator{begin_}; } + constexpr bidirectional_iterator end() { return bidirectional_iterator{end_}; } + constexpr bidirectional_iterator end() const { return bidirectional_iterator{end_}; } +}; +static_assert(std::ranges::bidirectional_range); +static_assert(std::ranges::common_range); +static_assert(std::ranges::view); +static_assert(std::copyable); + +enum CopyCategory { MoveOnly, Copyable }; +template +struct BidirSentRange : std::ranges::view_base { + using sent_t = sentinel_wrapper>; + using sent_const_t = sentinel_wrapper>; + + 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 begin() { return bidirectional_iterator{begin_}; } + constexpr bidirectional_iterator begin() const { return bidirectional_iterator{begin_}; } + constexpr sent_t end() { return sent_t{bidirectional_iterator{end_}}; } + constexpr sent_const_t end() const { return sent_const_t{bidirectional_iterator{end_}}; } +}; +static_assert(std::ranges::bidirectional_range>); +static_assert(!std::ranges::common_range>); +static_assert(std::ranges::view>); +static_assert(!std::copyable>); +static_assert(std::ranges::bidirectional_range>); +static_assert(!std::ranges::common_range>); +static_assert(std::ranges::view>); +static_assert(std::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 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -832,6 +832,11 @@ "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},