diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 108702e71dec7..bafe97444c1a1 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -370,7 +370,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_ranges_as_rvalue`` ``202207L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_ranges_chunk`` *unimplemented* + ``__cpp_lib_ranges_chunk`` ``202202L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_ranges_chunk_by`` ``202202L`` ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst index f7a8e5b04f1ea..5aff2fddb5177 100644 --- a/libcxx/docs/ReleaseNotes/23.rst +++ b/libcxx/docs/ReleaseNotes/23.rst @@ -55,6 +55,7 @@ Implemented Papers - P3369R0: constexpr for ``uninitialized_default_construct`` (`Github `__) - P3508R0: Wording for "constexpr for specialized memory algorithms" (`Github `__) - P4206R0: Revert string support in ``std::constant_wrapper`` (`Github `__) +- P2442R1: Windowing range adaptors: ``views::chunk`` and ``views::slide`` (`Github `__) (Implemented ``views::chunk`` only) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 0c608bd2bc1da..88e51baa1dd03 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -48,7 +48,7 @@ "`P2387R3 `__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","`#105183 `__","" "`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Complete|","23","`#105184 `__","" "`P2441R2 `__","``views::join_with``","2022-02 (Virtual)","|Complete|","21","`#105185 `__","" -"`P2442R1 `__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","","`#105187 `__","" +"`P2442R1 `__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","|Partial|","","`#105187 `__","Only ``views::chunk`` is implemented." "`P2443R1 `__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","`#105188 `__","" "","","","","","","" "`P0009R18 `__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18","`#105189 `__","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index fcea3b7601182..4b87e48c70ca2 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -728,6 +728,7 @@ set(files __ranges/all.h __ranges/as_rvalue_view.h __ranges/chunk_by_view.h + __ranges/chunk_view.h __ranges/common_view.h __ranges/concat_view.h __ranges/concepts.h @@ -940,6 +941,7 @@ set(files __utility/convert_to_integral.h __utility/declval.h __utility/default_three_way_comparator.h + __utility/div_ceil.h __utility/element_count.h __utility/empty.h __utility/exception_guard.h diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h new file mode 100644 index 0000000000000..a6686cc1e90df --- /dev/null +++ b/libcxx/include/__ranges/chunk_view.h @@ -0,0 +1,559 @@ +// -*- 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_CHUNK_VIEW_H +#define _LIBCPP___RANGES_CHUNK_VIEW_H + +#include <__algorithm/ranges_min.h> +#include <__assert> +#include <__concepts/constructible.h> +#include <__concepts/convertible_to.h> +#include <__config> +#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 <__memory/addressof.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/take_view.h> +#include <__ranges/view_interface.h> +#include <__type_traits/conditional.h> +#include <__type_traits/decay.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/make_unsigned.h> +#include <__utility/div_ceil.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace ranges { + +template + requires input_range<_View> +class chunk_view : public view_interface> { + _LIBCPP_NO_UNIQUE_ADDRESS _View __base_; + range_difference_t<_View> __n_; + range_difference_t<_View> __remainder_; + _LIBCPP_NO_UNIQUE_ADDRESS __non_propagating_cache> __current_; + + class __outer_iterator; + class __inner_iterator; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr explicit chunk_view(_View __base, range_difference_t<_View> __n) + : __base_(std::move(__base)), __n_(__n), __remainder_(0) { + _LIBCPP_ASSERT_PEDANTIC(__n > 0, "Trying to construct a chunk_view with chunk size <= 0"); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + requires copy_constructible<_View> + { + return __base_; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator begin() { + __current_.__emplace(ranges::begin(__base_)); + __remainder_ = __n_; + return __outer_iterator(*this); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr default_sentinel_t end() const noexcept { + return std::default_sentinel; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() + requires sized_range<_View> + { + return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __n_)); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + requires sized_range + { + return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __n_)); + } +}; + +template + requires input_range<_View> +class chunk_view<_View>::__outer_iterator { + friend chunk_view; + + chunk_view* __parent_; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __outer_iterator(chunk_view& __parent) + : __parent_(std::addressof(__parent)) {} + +public: + class value_type; + using iterator_concept = input_iterator_tag; + using difference_type = range_difference_t<_View>; + + _LIBCPP_HIDE_FROM_ABI __outer_iterator(__outer_iterator&&) = default; + + _LIBCPP_HIDE_FROM_ABI __outer_iterator& operator=(__outer_iterator&&) = default; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const { + _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to dereference past-the-end chunk_view iterator"); + return value_type(*__parent_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator& operator++() { + _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to increment past-the-end chunk_view iterator"); + ranges::advance(*__parent_->__current_, __parent_->__remainder_, ranges::end(__parent_->__base_)); + __parent_->__remainder_ = __parent_->__n_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const __outer_iterator& __i, default_sentinel_t) { + return *__i.__parent_->__current_ == ranges::end(__i.__parent_->__base_) && __i.__parent_->__remainder_ != 0; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(default_sentinel_t, const __outer_iterator& __i) + requires sized_sentinel_for, iterator_t<_View>> + { + const auto __dist = ranges::end(__i.__parent_->__base_) - *__i.__parent_->__current_; + if (__dist < __i.__parent_->__remainder_) + return __dist == 0 ? 0 : 1; + return std::__div_ceil(__dist - __i.__parent_->__remainder_, __i.__parent_->__n_) + 1; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(const __outer_iterator& __i, default_sentinel_t __s) + requires sized_sentinel_for, iterator_t<_View>> + { + return -(__s - __i); + } +}; + +template + requires input_range<_View> +class chunk_view<_View>::__outer_iterator::value_type : public view_interface { + friend __outer_iterator; + + chunk_view* __parent_; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit value_type(chunk_view& __parent) : __parent_(std::addressof(__parent)) {} + +public: + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __inner_iterator begin() const noexcept { + return __inner_iterator(*__parent_); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr default_sentinel_t end() const noexcept { return default_sentinel; } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + requires sized_sentinel_for, iterator_t<_View>> + { + return std::__to_unsigned_like( + ranges::min(__parent_->__remainder_, ranges::end(__parent_->__base_) - *__parent_->__current_)); + } +}; + +template + requires input_range<_View> +class chunk_view<_View>::__inner_iterator { + friend chunk_view; + + chunk_view* __parent_; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __inner_iterator(chunk_view& __parent) noexcept + : __parent_(std::addressof(__parent)) {} + +public: + using iterator_concept = input_iterator_tag; + using difference_type = range_difference_t<_View>; + using value_type = range_value_t<_View>; + + _LIBCPP_HIDE_FROM_ABI __inner_iterator(__inner_iterator&&) = default; + + _LIBCPP_HIDE_FROM_ABI __inner_iterator& operator=(__inner_iterator&&) = default; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_View> base() const& { return *__parent_->__current_; } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_reference_t<_View> operator*() const { + _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to dereference past-the-end chunk_view iterator"); + return **__parent_->__current_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __inner_iterator& operator++() { + _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to increment past-the-end chunk_view iterator"); + ++*__parent_->__current_; + if (*__parent_->__current_ == ranges::end(__parent_->__base_)) + __parent_->__remainder_ = 0; + else + --__parent_->__remainder_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const __inner_iterator& __i, default_sentinel_t) { + return __i.__parent_->__remainder_ == 0; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(default_sentinel_t, const __inner_iterator& __i) + requires sized_sentinel_for, iterator_t<_View>> + { + return ranges::min(__i.__parent_->__remainder_, ranges::end(__i.__parent_->__base_) - *__i.__parent_->__current_); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(const __inner_iterator& __i, default_sentinel_t __s) + requires sized_sentinel_for, iterator_t<_View>> + { + return -(__s - __i); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_rvalue_reference_t<_View> + iter_move(const __inner_iterator& __i) noexcept(noexcept(ranges::iter_move(*__i.__parent_->__current_))) { + return ranges::iter_move(*__i.__parent_->__current_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void + iter_swap(const __inner_iterator& __x, const __inner_iterator& __y) noexcept( + noexcept((ranges::iter_swap(*__x.__parent_->__current_, *__y.__parent_->__current_)))) + requires indirectly_swappable> + { + return ranges::iter_swap(*__x.__parent_->__current_, *__y.__parent_->__current_); + } +}; + +template + requires forward_range<_View> +class chunk_view<_View> : public view_interface> { + _LIBCPP_NO_UNIQUE_ADDRESS _View __base_; + range_difference_t<_View> __n_; + + template + class __iterator; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr explicit chunk_view(_View __base, range_difference_t<_View> __n) + : __base_(std::move(__base)), __n_(__n) { + _LIBCPP_ASSERT_PEDANTIC(__n > 0, "Trying to construct a chunk_view with chunk size <= 0"); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + requires copy_constructible<_View> + { + return __base_; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() + requires(!__simple_view<_View>) + { + return __iterator(this, ranges::begin(__base_)); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + requires forward_range + { + return __iterator(this, ranges::begin(__base_)); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() + requires(!__simple_view<_View>) + { + if constexpr (common_range<_View> && sized_range<_View>) { + auto __missing = (__n_ - ranges::distance(__base_) % __n_) % __n_; + return __iterator(this, ranges::end(__base_), __missing); + } else if constexpr (common_range<_View> && !bidirectional_range<_View>) + return __iterator(this, ranges::end(__base_)); + else + return default_sentinel; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + requires forward_range + { + if constexpr (common_range && sized_range) { + auto __missing = (__n_ - ranges::distance(__base_) % __n_) % __n_; + return __iterator(this, ranges::end(__base_), __missing); + } else if constexpr (common_range && !bidirectional_range) + return __iterator(this, ranges::end(__base_)); + else + return default_sentinel; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() + requires sized_range<_View> + { + return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __n_)); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + requires sized_range + { + return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __n_)); + } +}; + +template + requires forward_range<_View> +template +class chunk_view<_View>::__iterator { + friend chunk_view; + + using _Parent _LIBCPP_NODEBUG = __maybe_const<_Const, chunk_view>; + using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; + + iterator_t<_Base> __current_ = iterator_t<_Base>(); + sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + range_difference_t<_Base> __n_ = 0; + range_difference_t<_Base> __missing_ = 0; + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator( + _Parent* __parent, iterator_t<_Base> __current, range_difference_t<_Base> __missing = 0) + : __current_(__current), __end_(ranges::end(__parent->__base_)), __n_(__parent->__n_), __missing_(__missing) {} + + static consteval auto __get_iterator_concept() { + if constexpr (random_access_range<_Base>) + return random_access_iterator_tag{}; + else if constexpr (bidirectional_range<_Base>) + return bidirectional_iterator_tag{}; + else + return forward_iterator_tag{}; + } + +public: + using iterator_category = input_iterator_tag; + using iterator_concept = decltype(__iterator::__get_iterator_concept()); + using value_type = decltype(views::take(subrange(__current_, __end_), __n_)); + using difference_type = range_difference_t<_Base>; + + _LIBCPP_HIDE_FROM_ABI __iterator() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator __i) + requires _Const && convertible_to, iterator_t<_Base>> && + convertible_to, sentinel_t<_Base>> + : __current_(std::move(__i.__current_)), + __end_(std::move(__i.__end_)), + __n_(__i.__n_), + __missing_(__i.__missing_) {} + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() const { return __current_; } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const { + _LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Trying to dereference past-the-end chunk_view iterator"); + return views::take(subrange(__current_, __end_), __n_); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator[](difference_type __pos) const + requires random_access_range<_Base> + { + return *(*this + __pos); + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { + _LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Trying to increment past-the-end chunk_view iterator"); + __missing_ = ranges::advance(__current_, __n_, __end_); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { + auto __tmp = *this; + ++*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--() + requires bidirectional_range<_Base> + { + ranges::advance(__current_, __missing_ - __n_); + __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 __x) + requires random_access_range<_Base> + { + if (__x > 0) { + _LIBCPP_ASSERT_PEDANTIC(ranges::distance(__current_, __end_) > __n_ * (__x - 1), + "Trying to advance chunk_view iterator out of range"); + ranges::advance(__current_, __n_ * (__x - 1)); + __missing_ = ranges::advance(__current_, __n_, __end_); + } else if (__x < 0) { + ranges::advance(__current_, __n_ * __x + __missing_); + __missing_ = 0; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __x) + requires random_access_range<_Base> + { + return *this += -__x; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) { + return __x.__current_ == __y.__current_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, default_sentinel_t) { + return __x.__current_ == __x.__end_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __x.__current_ < __y.__current_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __y < __x; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return !(__y < __x); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return !(__x < __y); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> && three_way_comparable> + { + return __x.__current_ <=> __y.__current_; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator + operator+(const __iterator& __i, difference_type __pos) + requires random_access_range<_Base> + { + auto __r = __i; + __r += __pos; + return __r; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator + operator+(difference_type __pos, const __iterator& __i) + requires random_access_range<_Base> + { + auto __r = __i; + __r += __pos; + return __r; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator + operator-(const __iterator& __i, difference_type __pos) + requires random_access_range<_Base> + { + auto __r = __i; + __r -= __pos; + return __r; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(const __iterator& __i, const __iterator& __j) + requires sized_sentinel_for, iterator_t<_Base>> + { + return (__i.__current_ - __j.__current_ + __i.__missing_ - __j.__missing_) / __i.__n_; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(default_sentinel_t, const __iterator& __i) + requires sized_sentinel_for, iterator_t<_Base>> + { + return std::__div_ceil(__i.__end_ - __i.__current_, __i.__n_); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(const __iterator& __i, default_sentinel_t __s) + requires sized_sentinel_for, iterator_t<_Base>> + { + return -(__s - __i); + } +}; + +template +chunk_view(_Range&&, range_difference_t<_Range>) -> chunk_view>; + +template +inline constexpr bool enable_borrowed_range> = forward_range<_View> && enable_borrowed_range<_View>; + +namespace views { +namespace __chunk { +struct __fn { + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto + operator()(_Range&& __range, range_difference_t<_Range> __n) noexcept( + noexcept(/*-----*/ chunk_view(std::forward<_Range>(__range), std::forward>(__n)))) + -> decltype(/*--*/ chunk_view(std::forward<_Range>(__range), std::forward>(__n))) { + return /*---------*/ chunk_view(std::forward<_Range>(__range), std::forward>(__n)); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto + operator()(_DifferenceType __n) noexcept(is_nothrow_constructible_v, _DifferenceType>) { + return __pipeable(std::__bind_back(__fn{}, std::forward<_DifferenceType>(__n))); + } +}; + +} // namespace __chunk + +inline namespace __cpo { +inline constexpr auto chunk = __chunk::__fn{}; + +} // namespace __cpo +} // namespace views + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_CHUNK_VIEW_H diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h index 780bb25743c15..a8b485cbe33e5 100644 --- a/libcxx/include/__ranges/stride_view.h +++ b/libcxx/include/__ranges/stride_view.h @@ -32,6 +32,7 @@ #include <__ranges/range_adaptor.h> #include <__ranges/view_interface.h> #include <__type_traits/make_unsigned.h> +#include <__utility/div_ceil.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -46,15 +47,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD 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> { @@ -121,13 +113,13 @@ class stride_view : public view_interface> { [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_View> { - return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_)); + return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __stride_)); } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range { - return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_)); + return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __stride_)); } }; // class stride_view @@ -340,16 +332,16 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<__maybe } auto __n = __x.__current_ - __y.__current_; if (__n < 0) { - return -ranges::__div_ceil(-__n, __x.__stride_); + return -std::__div_ceil(-__n, __x.__stride_); } - return ranges::__div_ceil(__n, __x.__stride_); + return std::__div_ceil(__n, __x.__stride_); } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(default_sentinel_t, __iterator const& __x) requires sized_sentinel_for, iterator_t<_Base>> { - return ranges::__div_ceil(__x.__end_ - __x.__current_, __x.__stride_); + return std::__div_ceil(__x.__end_ - __x.__current_, __x.__stride_); } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(__iterator const& __x, default_sentinel_t __y) diff --git a/libcxx/include/__utility/div_ceil.h b/libcxx/include/__utility/div_ceil.h new file mode 100644 index 0000000000000..21e9bcb30d1a1 --- /dev/null +++ b/libcxx/include/__utility/div_ceil.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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___UTILITY_DIV_CEIL_H +#define _LIBCPP___UTILITY_DIV_CEIL_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +// __div_ceil computes the ceiling of the division of two integers. It is mainly used by +// range adaptors like chunk_view and stride_view. + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto __div_ceil(_Integral __num, _Integral __denom) { + _Integral __r = __num / __denom; + if (__num % __denom) + ++__r; + return __r; +} + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_DIV_CEIL_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index e3b9e5ac09cb3..a5058ac4eeb23 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1902,6 +1902,10 @@ module std { header "__ranges/chunk_by_view.h" export std.functional.bind_back } + module chunk_view { + header "__ranges/chunk_view.h" + export std.functional.bind_back + } module common_view { header "__ranges/common_view.h" } module concat_view { header "__ranges/concat_view.h" } module concepts { header "__ranges/concepts.h" } @@ -2212,6 +2216,7 @@ module std { module constant_wrapper { header "__utility/constant_wrapper.h" } module convert_to_integral { header "__utility/convert_to_integral.h" } module default_three_way_comparator { header "__utility/default_three_way_comparator.h" } + module div_ceil { header "__utility/div_ceil.h" } module element_count { header "__utility/element_count.h" } module exception_guard { header "__utility/exception_guard.h" } module exchange { header "__utility/exchange.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges index d82a41942327b..a95cf2e895f17 100644 --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -418,6 +418,17 @@ namespace std::ranges { namespace views { inline constexpr unspecified chunk_by = unspecified; } // C++23 + // [range.chunk] + template + requires input_range + class chunk_view; // C++23 + + template + requires forward_range + class chunk_view; // C++23 + + namespace views { inline constexpr unspecified chunk = unspecified; } // C++23 + // [range.stride.view], stride view template requires view @@ -514,6 +525,7 @@ namespace std { # include <__ranges/adjacent_view.h> # include <__ranges/as_rvalue_view.h> # include <__ranges/chunk_by_view.h> +# include <__ranges/chunk_view.h> # include <__ranges/enumerate_view.h> # include <__ranges/from_range.h> # include <__ranges/join_with_view.h> diff --git a/libcxx/include/version b/libcxx/include/version index 9160c51835d6f..e959df0899b55 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -528,7 +528,7 @@ __cpp_lib_void_t 201411L # define __cpp_lib_ranges 202406L // # define __cpp_lib_ranges_as_const 202207L # define __cpp_lib_ranges_as_rvalue 202207L -// # define __cpp_lib_ranges_chunk 202202L +# define __cpp_lib_ranges_chunk 202202L # define __cpp_lib_ranges_chunk_by 202202L # define __cpp_lib_ranges_contains 202207L # define __cpp_lib_ranges_enumerate 202302L diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc index 876942bdffbf5..0afa170ae2f88 100644 --- a/libcxx/modules/std/ranges.inc +++ b/libcxx/modules/std/ranges.inc @@ -323,18 +323,17 @@ export namespace std { using std::ranges::views::adjacent_transform; using std::ranges::views::pairwise_transform; } // namespace views +#endif -#endif // _LIBCPP_STD_VER >= 23 - -#if 0 +#if _LIBCPP_STD_VER >= 23 using std::ranges::chunk_view; - using std::ranges::chunk_view; - namespace views { using std::ranges::views::chunk; - } + } // namespace views +#endif +#if 0 using std::ranges::slide_view; namespace views { diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp new file mode 100644 index 0000000000000..477f89be5f070 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 +// REQUIRES: has-unix-headers +// REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// Construct a chunk_view with chunk size <= 0 + +#include +#include + +#include "check_assertion.h" +#include "types.h" + +int main() { + std::vector vector = {1, 2, 3}; + + // Test constructor when V models only input_range. + { + TEST_LIBCPP_ASSERT_FAILURE( + input_span(vector.data(), 3) | std::views::chunk(0), "Trying to construct a chunk_view with chunk size <= 0"); + TEST_LIBCPP_ASSERT_FAILURE( + input_span(vector.data(), 3) | std::views::chunk(-1), "Trying to construct a chunk_view with chunk size <= 0"); + } + + // Test constructor when V models forward_range. + { + TEST_LIBCPP_ASSERT_FAILURE(vector | std::views::chunk(0), "Trying to construct a chunk_view with chunk size <= 0"); + TEST_LIBCPP_ASSERT_FAILURE(vector | std::views::chunk(-1), "Trying to construct a chunk_view with chunk size <= 0"); + } +} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp new file mode 100644 index 0000000000000..5d32daf4c178a --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// This test ensures that we use `[[no_unique_address]]` in `chunk_view`. + +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_range.h" + +// When V models only input_range + +struct input_view { + cpp20_input_iterator begin() const; + sentinel_wrapper> end() const; +}; +template <> +inline constexpr bool std::ranges::enable_view = true; +static_assert(std::ranges::input_range && !std::ranges::forward_range); + +using CV1 = std::ranges::chunk_view; +// Expected CV1 (when V models only input_range) layout: +// [[no_unique_address]] _View __base_ // size: 0 +// [[no_unique_address]] range_difference_t<_View> __n_ // size: sizeof(ptrdiff_t) +// [[no_unique_address]] range_difference_t<_View> __remainder_ // size: sizeof(ptrdiff_t) +// [[no_unique_address]] __non_propagating_cache> __current_ // size: sizeof(__non_propagating_cache>), align: std::ptrdiff_t +static_assert(alignof(std::ranges::__non_propagating_cache>) == alignof(std::ptrdiff_t)); +static_assert(sizeof(CV1) == /*sizeof(__base_) == 0 + */ sizeof(std::ptrdiff_t) * 2 + + sizeof(std::ranges::__non_propagating_cache>)); + +// When V models forward_range + +struct forward_view { + int* begin() const; + int* end() const; +}; +template <> +inline constexpr bool std::ranges::enable_view = true; +static_assert(std::ranges::forward_range); + +using CV2 = std::ranges::chunk_view; +// Expected CV2 (when V models forward_range) layout: +// [[no_unique_address]] _View __base_ // size: 0 +// [[no_unique_address]] range_difference_t<_View> // size: sizeof(ptrdiff_t) +static_assert(sizeof(CV2) == /*sizeof(__base_) == 0 + */ sizeof(std::ptrdiff_t)); diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp new file mode 100644 index 0000000000000..94df3795a40e0 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// Test that functions are marked [[nodiscard]]. + +#include +#include + +#include "types.h" + +void test() { + char range[6] = {'x', 'x', 'y', 'y', 'z', 'z'}; + auto view = range | std::views::chunk(2); + auto it = view.begin(); + int input_range[] = {1, 2, 3, 4, 5, 6}; + auto input_view = input_span(input_range, 6) | std::views::chunk(2); + auto outer = input_view.begin(); + auto value = *outer; + auto inner = value.begin(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + view.base(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(view).base(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::move(std::as_const(view)).base(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::move(view).base(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + view.begin(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(view).begin(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::ranges::iter_move(view.begin()); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::ranges::iter_move(std::as_const(view).begin()); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + view.end(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(view).end(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::ranges::iter_move(view.end()); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::ranges::iter_move(std::as_const(view).end()); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + view.size(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::as_const(view).size(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + *view.begin(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + *std::as_const(view).begin(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + it.base(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + it[0]; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + it + 1; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + 1 + it; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + it - 1; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + view.end() - it; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::default_sentinel - it; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + it - std::default_sentinel; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + input_view.size(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + *outer; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::default_sentinel - outer; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + outer - std::default_sentinel; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + value.begin(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + value.end(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + value.size(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + inner.base(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + *inner; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::default_sentinel - inner; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + inner - std::default_sentinel; + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::ranges::iter_move(inner); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::views::chunk(3); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::views::chunk(range, 3); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + range | std::views::chunk(3); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::views::reverse | std::views::chunk(3); +} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp new file mode 100644 index 0000000000000..9b91d94841b91 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 +// REQUIRES: has-unix-headers +// REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// Trying to advance chunk_view iterator out of range + +#include +#include +#include + +#include "check_assertion.h" + +int main() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8}; + auto chunked = vector | std::views::chunk(3); + + // Test advance past-the-end iterator when V models forward_range + { + /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.begin(); + TEST_LIBCPP_ASSERT_FAILURE(it += 4, "Trying to advance chunk_view iterator out of range"); + } +} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp new file mode 100644 index 0000000000000..3640b04192bf4 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 +// REQUIRES: has-unix-headers +// REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// Trying to dereference past-the-end chunk_view iterator + +#include +#include +#include + +#include "check_assertion.h" +#include "../types.h" + +int main() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8}; + auto chunked = vector | std::views::chunk(3); + auto input_chunked = input_span(vector.data(), 8) | std::views::chunk(3); + + // Test dereference iterator when V models only input_range + { + /*chunk_view::__outer_iterator*/ std::input_iterator auto outer_it = input_chunked.begin(); + ++outer_it; + ++outer_it; + ++outer_it; + TEST_LIBCPP_ASSERT_FAILURE(*outer_it, "Trying to dereference past-the-end chunk_view iterator"); + + /*chunk_view::__inner_iterator*/ std::input_iterator auto inner_it = (*input_chunked.begin()).begin(); + ++inner_it; + ++inner_it; + ++inner_it; + TEST_LIBCPP_ASSERT_FAILURE(*inner_it, "Trying to dereference past-the-end chunk_view iterator"); + } + + // Test dereference iterator when V models forward_range + { + /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.begin(); + ++it; + ++it; + ++it; + TEST_LIBCPP_ASSERT_FAILURE(*it, "Trying to dereference past-the-end chunk_view iterator"); + } +} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp new file mode 100644 index 0000000000000..61c096f74158e --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 +// REQUIRES: has-unix-headers +// REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// + +// Trying to increment past-the-end chunk_view iterator + +#include +#include +#include + +#include "check_assertion.h" +#include "../types.h" + +int main() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8}; + auto chunked = vector | std::views::chunk(3); + auto input_chunked = input_span(vector.data(), 8) | std::views::chunk(3); + + // Test increment past-the-end iterator when V models only input_range + { + /*chunk_view::__outer_iterator*/ std::input_iterator auto outer_it = input_chunked.begin(); + ++outer_it; + ++outer_it; + ++outer_it; + TEST_LIBCPP_ASSERT_FAILURE(++outer_it, "Trying to increment past-the-end chunk_view iterator"); + + /*chunk_view::__inner_iterator*/ std::input_iterator auto inner_it = (*input_chunked.begin()).begin(); + ++inner_it; + ++inner_it; + ++inner_it; + TEST_LIBCPP_ASSERT_FAILURE(++inner_it, "Trying to increment past-the-end chunk_view iterator"); + } + + // Test increment past-the-end iterator when V models forward_range + { + /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.begin(); + ++it; + ++it; + ++it; + TEST_LIBCPP_ASSERT_FAILURE(++it, "Trying to increment past-the-end chunk_view iterator"); + } +} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h new file mode 100644 index 0000000000000..4852ec29204bb --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H +#define TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H + +#include +#include +#include +#include +#include + +// input_span + +template +struct input_span : std::span { + struct iterator : std::span::iterator { + using iterator_concept = std::input_iterator_tag; + constexpr iterator() = default; + constexpr iterator(std::span::iterator i) : std::span::iterator(i) {} + constexpr auto operator*() const { return std::span::iterator::operator*(); } + friend constexpr auto operator+(iterator, std::span::difference_type) = delete; + friend constexpr auto operator+(std::span::difference_type, iterator) = delete; + friend constexpr auto operator-(iterator, std::span::difference_type) = delete; + friend constexpr auto operator-(std::span::difference_type, iterator) = delete; + friend constexpr iterator& operator++(iterator& self) { + ++static_cast::iterator&>(self); + return self; + } + friend constexpr void operator++(iterator& self, int) { ++self; } + friend constexpr iterator& operator--(iterator&) = delete; + friend constexpr void operator--(iterator&, int) = delete; + }; + + using std::span::span; + constexpr iterator begin() { return iterator(std::span::begin()); } + constexpr iterator end() { return iterator(std::span::end()); } +}; + +template +input_span(T*, std::ptrdiff_t) -> input_span; + +template +inline constexpr bool std::ranges::enable_view> = true; + +static_assert(std::ranges::input_range> && !std::ranges::forward_range> && + std::ranges::view>); + +#endif 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 670b0e664721a..aff6534830b26 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 @@ -302,17 +302,11 @@ # error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_chunk -# error "__cpp_lib_ranges_chunk should be defined in c++23" -# endif -# if __cpp_lib_ranges_chunk != 202202L -# error "__cpp_lib_ranges_chunk should have the value 202202L in c++23" -# endif -# else -# ifdef __cpp_lib_ranges_chunk -# error "__cpp_lib_ranges_chunk should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_chunk +# error "__cpp_lib_ranges_chunk should be defined in c++23" +# endif +# if __cpp_lib_ranges_chunk != 202202L +# error "__cpp_lib_ranges_chunk should have the value 202202L in c++23" # endif # ifndef __cpp_lib_ranges_chunk_by @@ -427,17 +421,11 @@ # error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_chunk -# error "__cpp_lib_ranges_chunk should be defined in c++26" -# endif -# if __cpp_lib_ranges_chunk != 202202L -# error "__cpp_lib_ranges_chunk should have the value 202202L in c++26" -# endif -# else -# ifdef __cpp_lib_ranges_chunk -# error "__cpp_lib_ranges_chunk should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_chunk +# error "__cpp_lib_ranges_chunk should be defined in c++26" +# endif +# if __cpp_lib_ranges_chunk != 202202L +# error "__cpp_lib_ranges_chunk should have the value 202202L in c++26" # endif # ifndef __cpp_lib_ranges_chunk_by 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 3af3d6694c6bf..7c41e28034e96 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 @@ -5774,17 +5774,11 @@ # error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_chunk -# error "__cpp_lib_ranges_chunk should be defined in c++23" -# endif -# if __cpp_lib_ranges_chunk != 202202L -# error "__cpp_lib_ranges_chunk should have the value 202202L in c++23" -# endif -# else -# ifdef __cpp_lib_ranges_chunk -# error "__cpp_lib_ranges_chunk should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_chunk +# error "__cpp_lib_ranges_chunk should be defined in c++23" +# endif +# if __cpp_lib_ranges_chunk != 202202L +# error "__cpp_lib_ranges_chunk should have the value 202202L in c++23" # endif # ifndef __cpp_lib_ranges_chunk_by @@ -7713,17 +7707,11 @@ # error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ranges_chunk -# error "__cpp_lib_ranges_chunk should be defined in c++26" -# endif -# if __cpp_lib_ranges_chunk != 202202L -# error "__cpp_lib_ranges_chunk should have the value 202202L in c++26" -# endif -# else -# ifdef __cpp_lib_ranges_chunk -# error "__cpp_lib_ranges_chunk should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ranges_chunk +# error "__cpp_lib_ranges_chunk should be defined in c++26" +# endif +# if __cpp_lib_ranges_chunk != 202202L +# error "__cpp_lib_ranges_chunk should have the value 202202L in c++26" # endif # ifndef __cpp_lib_ranges_chunk_by diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/adaptor.pass.cpp new file mode 100644 index 0000000000000..657e16383256b --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/adaptor.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// std::views::chunk + +#include +#include +#include +#include +#include +#include + +constexpr bool test() { + std::array array = {1, 2, 3, 4, 5, 6, 7, 8}; + std::ranges::ref_view> view = array | std::views::all; + + // Test `views::chunk(view, n)` + { + std::same_as>>> decltype(auto) chunked = + std::views::chunk(view, 2); + assert(std::ranges::equal(*chunked.begin(), std::array{1, 2})); + std::same_as>>> decltype(auto) const_chunked = + std::views::chunk(std::as_const(view), 2); + assert(std::ranges::equal(*const_chunked.begin(), std::array{1, 2})); + } + + // Test `views::chunk(n)(range)` + { + static_assert(noexcept(std::views::chunk(2))); + /*__pipable*/ auto adaptor = std::views::chunk(3); + std::same_as>>> decltype(auto) chunked = + adaptor(view); + assert(std::ranges::equal(*chunked.begin(), std::array{1, 2, 3})); + std::same_as>>> decltype(auto) const_chunked = + adaptor(std::as_const(view)); + assert(std::ranges::equal(*const_chunked.begin(), std::array{1, 2, 3})); + } + + // Test `view | views::chunk` + { + std::same_as>>> decltype(auto) chunked = + view | std::views::chunk(4); + assert(std::ranges::equal(*chunked.begin(), std::array{1, 2, 3, 4})); + std::same_as>>> decltype(auto) const_chunked = + std::as_const(view) | std::views::chunk(4); + assert(std::ranges::equal(*const_chunked.begin(), std::array{1, 2, 3, 4})); + } + + // Test `views::chunk | adaptor` + { + /*__pipable*/ auto adaptors = std::views::chunk(5) | std::views::join; + std::ranges::input_range auto rejoined = view | adaptors; + assert(std::ranges::equal(rejoined, view)); + std::ranges::input_range auto const_rejoined = std::as_const(view) | adaptors; + assert(std::ranges::equal(const_rejoined, view)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp new file mode 100644 index 0000000000000..4dca324a23695 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// constexpr V base() const& requires copy_constructible; +// constexpr V base() &&; + +#include +#include +#include +#include +#include +#include + +constexpr bool test() { + std::array array = {1, 2, 3, 4, 5, 6, 7, 8}; + std::ranges::chunk_view>> chunked = array | std::views::chunk(3); + std::ranges::chunk_view>> const_chunked = + std::as_const(array) | std::views::chunk(4); + + // Test `chunk_view.base() const&` + { + std::same_as&> decltype(auto) base = chunked.base().base(); + assert(std::addressof(base) == std::addressof(array)); + + std::same_as&> decltype(auto) const_base = const_chunked.base().base(); + assert(std::addressof(const_base) == std::addressof(array)); + } + + // Test `chunk_view.base() &&` + { + std::same_as>> decltype(auto) moved = std::move(chunked).base(); + assert(std::addressof(moved.base()) == std::addressof(array)); + + std::same_as>> decltype(auto) const_moved = + std::move(const_chunked).base(); + assert(std::addressof(const_moved.base()) == std::addressof(array)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp new file mode 100644 index 0000000000000..29588a57fbcab --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// constexpr __outer_iterator begin(); + +// V models forward_range: +// constexpr auto begin() requires (!__simple_view); +// constexpr auto begin() const requires forward_range; + +#include +#include +#include +#include +#include +#include + +#include "test_range.h" +#include "types.h" + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8}; + std::ranges::chunk_view>> chunked = vector | std::views::chunk(3); + std::ranges::chunk_view>> const_chunked = + std::as_const(vector) | std::views::chunk(3); + std::ranges::chunk_view> input_chunked = input_span(vector.data(), 8) | std::views::chunk(3); + + // Test `chunk_view.begin()` when V models only input_range + { + /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin(); + assert(std::ranges::equal(*it, std::vector{1, 2, 3})); + assert(std::ranges::equal(*++it, std::vector{4, 5, 6})); + assert(std::ranges::equal(*++it, std::vector{7, 8})); + assert(++it == input_chunked.end()); + } + + // Test `chunk_view.begin()` when V models forward_range + { + /*chunk_view::__iterator*/ std::forward_iterator auto it = chunked.begin(); + assert(std::ranges::equal(*it, std::vector{1, 2, 3})); + assert(std::ranges::equal(*++it, std::vector{4, 5, 6})); + assert(std::ranges::equal(*++it, std::vector{7, 8})); + assert(++it == chunked.end()); + /*chunk_view::__iterator*/ std::forward_iterator auto const_it = const_chunked.begin(); + assert(std::ranges::equal(*const_it, std::vector{1, 2, 3})); + assert(std::ranges::equal(*++const_it, std::vector{4, 5, 6})); + assert(std::ranges::equal(*++const_it, std::vector{7, 8})); + assert(++const_it == const_chunked.end()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/borrowing.compile.pass.cpp new file mode 100644 index 0000000000000..1eb4a34f87217 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/borrowing.compile.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// template +// inline constexpr bool enable_borrowed_range> = +// forward_range && enable_borrowed_range; + +#include + +#include "test_range.h" +#include "types.h" + +// When V models only `input_range`. +static_assert(!std::ranges::enable_borrowed_range>>); + +// When V models at least `forward_range`. +static_assert(std::ranges::enable_borrowed_range>); +static_assert(!std::ranges::enable_borrowed_range>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/concept.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/concept.compile.pass.cpp new file mode 100644 index 0000000000000..61b89d4c09c32 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/concept.compile.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// template +// requires input_range +// class chunk_view; +// +// template +// requires forward_range +// class chunk_view<_View>; + +#include +#include + +#include "almost_satisfies_types.h" +#include "test_range.h" +#include "types.h" + +template <> +inline constexpr bool std::ranges::enable_view = true; + +// Test two separate properties: +// 1. Whether `chunk_view` can be formed. +// 2. Whether a well-formed `chunk_view` can be constructed. +template +concept CanFormChunkView = requires { typename std::ranges::chunk_view; }; + +template +concept CanConstructChunkView = CanFormChunkView && requires(View view, std::ranges::range_difference_t n) { + std::ranges::chunk_view(std::move(view), n); +}; + +// Test constraints when the template argument is not a view +static_assert(!std::ranges::view>); +static_assert(std::ranges::input_range>); +static_assert(!CanFormChunkView>); + +// Test constraints when the template argument is not an input_range +static_assert(!std::ranges::input_range); +static_assert(std::ranges::view); +static_assert(!CanFormChunkView); + +// Test constraints when the template argument is an input_range and a view +static_assert(std::ranges::input_range>); +static_assert(std::ranges::view>); +static_assert(CanFormChunkView> && CanConstructChunkView>); + +// Test constraints when the template argument is a forward_range and a view +static_assert(std::ranges::forward_range); +static_assert(std::ranges::view); +static_assert(CanFormChunkView && CanConstructChunkView); + +// chunk_view itself models view +static_assert(std::ranges::view>>); +static_assert(std::ranges::view>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctad.compile.pass.cpp new file mode 100644 index 0000000000000..9bf2baba58c78 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctad.compile.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// template +// chunk_view(R&&, range_difference_t) -> chunk_view>; + +#include + +struct view : std::ranges::view_base { + int* begin() const; + int* end() const; +}; + +struct range { + int* begin() const; + int* end() const; +}; + +struct borrowed_range { + int* begin() const; + int* end() const; +}; + +template <> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +void test_ctad() { + view v; + range r; + borrowed_range br; + + // clang-format off + static_assert(std::same_as>); + static_assert(std::same_as>); + static_assert(std::same_as>>); + static_assert(std::same_as>>); + static_assert(std::same_as>>); + static_assert(std::same_as>>); + // clang-format on +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp new file mode 100644 index 0000000000000..c0d210aa45dc3 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// constexpr explicit chunk_view(_View __base, range_difference_t<_View> __n); + +#include +#include +#include +#include +#include + +#include "test_convertible.h" +#include "test_range.h" +#include "types.h" + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8}; + + // Test `chunk_view(_View, range_difference_t<_View>)` when V models only `input_range` + { + static_assert(!test_convertible>, input_span, std::ptrdiff_t>()); + + std::ranges::chunk_view> chunked(input_span(vector.data(), 8), 3); + assert(std::ranges::equal(*chunked.begin(), std::vector{1, 2, 3})); + } + + // Test `chunk_view(_View, range_difference_t<_View>)` when V models `forward_range` + { + static_assert(!test_convertible>>, + std::ranges::ref_view>, + std::ptrdiff_t>()); + + std::ranges::chunk_view>> chunked(std::ranges::ref_view(vector), 3); + assert(std::ranges::equal(*chunked.begin(), std::vector{1, 2, 3})); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp new file mode 100644 index 0000000000000..2f37ac5f73524 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// constexpr default_sentinel_t end(); + +// V moduels forward_range: +// constexpr auto end() requires (!__simple_view); +// constexpr auto end() const requires forward_range; + +#include +#include +#include +#include +#include +#include +#include + +#include "test_range.h" +#include "types.h" + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8}; + std::ranges::chunk_view>> chunked = vector | std::views::chunk(3); + std::ranges::chunk_view>> const_chunked = + std::as_const(vector) | std::views::chunk(3); + std::ranges::chunk_view> input_chunked = input_span(vector.data(), 8) | std::views::chunk(3); + + // Test `chunk_view.end()` when V models only input_range + { + static_assert(noexcept(input_chunked.end())); + [[maybe_unused]] std::same_as auto it = input_chunked.end(); + } + + // Test `chunk_view.end()` when V models forward_range + { + /*chunk_view::__iterator*/ std::forward_iterator auto it = chunked.end(); + assert(std::ranges::equal(*--it, std::vector{7, 8})); + assert(std::ranges::equal(*--it, std::vector{4, 5, 6})); + assert(std::ranges::equal(*--it, std::vector{1, 2, 3})); + assert(it == chunked.begin()); + /*chunk_view::__iterator*/ std::forward_iterator auto const_it = const_chunked.end(); + assert(std::ranges::equal(*--const_it, std::vector{7, 8})); + assert(std::ranges::equal(*--const_it, std::vector{4, 5, 6})); + assert(std::ranges::equal(*--const_it, std::vector{1, 2, 3})); + assert(const_it == const_chunked.begin()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/general.pass.cpp new file mode 100644 index 0000000000000..89891bc093080 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/general.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// General tests for chunk_view. This file does not test anything specifically. + +#include +#include +#include +#include + +#include "test_range.h" + +constexpr bool test() { + std::string_view str = "Cheese with chicken chunk by chunk on truck with my trick"; + // clang-format off + auto str2 = str + | std::views::chunk(4) + | std::views::join + | std::views::chunk(314159) + | std::views::take(1) + | std::views::join + | std::views::lazy_split(' ') + | std::views::chunk(2) + | std::views::transform([] (auto&& subview) + { + return subview | std::views::join_with(' '); + }) + | std::views::join_with(' '); + // clang-format on + assert(std::ranges::equal(str, str2)); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp new file mode 100644 index 0000000000000..c6fc5d026699e --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// friend constexpr difference_type operator-(default_sentinel_t y, const inner_iterator& x) +// requires sized_sentinel_for, iterator_t>; +// friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t y) +// requires sized_sentinel_for, iterator_t>; + +#include +#include +#include +#include + +#include "../types.h" + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + std::ranges::chunk_view> input_chunked = input_span(vector) | std::views::chunk(3); + + // Test `friend constexpr difference_type operator-(default_sentinel_t, const inner_iterator& x)` + { + assert(std::default_sentinel - (*input_chunked.begin()).begin() == 3); + } + + // Test `friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t)` + { + assert((*input_chunked.begin()).begin() - std::default_sentinel == -3); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp new file mode 100644 index 0000000000000..76816ea99ab9c --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// constexpr const iterator_t base() const&; + +#include +#include +#include +#include + +#include "../types.h" + +constexpr bool test() { + int buffer[] = {1, 2, 3, 4}; + + std::ranges::chunk_view> chunked(input_span(buffer, 4), 2); + auto outer = chunked.begin(); + auto inner = (*outer).begin(); + + std::same_as>> decltype(auto) base = inner.base(); + assert(*base == 1); + + ++inner; + assert(*inner.base() == 2); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp new file mode 100644 index 0000000000000..81333cd787e6e --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t); + +#include +#include +#include +#include + +#include "../types.h" + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + std::ranges::chunk_view> input_chunked = input_span(vector) | std::views::chunk(3); + + // Test `friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t)` + { + /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin(); + std::ranges::advance(it, 2); + assert(it != std::default_sentinel); + ++it; + assert(it == std::default_sentinel); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp new file mode 100644 index 0000000000000..072e0bd524481 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// inner_iterator(inner_iterator&&) = default; +// inner_iterator& operator=(inner_iterator&&) = default; + +#include +#include + +#include "../types.h" + +using InnerIterator = std::ranges::iterator_t>>>; + +static_assert(!std::default_initializable); +static_assert(!std::copy_constructible); +static_assert(!std::assignable_from); +static_assert(std::move_constructible); +static_assert(std::assignable_from); diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp new file mode 100644 index 0000000000000..41c58c02cbd72 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// constexpr range_reference_v inner_iterator::operator*() const; + +#include +#include +#include +#include + +#include "../types.h" + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + std::ranges::chunk_view> input_chunked = input_span(vector) | std::views::chunk(3); + + // Test `constexpr range_reference_v inner_iterator::operator*() const` + { + /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin(); + std::same_as decltype(auto) v = *it; + assert(v == 1); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp new file mode 100644 index 0000000000000..082e9ad7c08ea --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// constexpr inner_iterator& operator++(); +// constexpr void operator++(int); + +#include +#include +#include +#include +#include + +#include "../types.h" + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8}; + std::ranges::chunk_view> input_chunked = input_span(vector) | std::views::chunk(2); + + // Test `constexpr inner_iterator& operator++();` + { + /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin(); + assert(*++it == 2); + } + + // Test `constexpr inner_iterator& operator++();` + { + /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin(); + static_assert(std::same_as); + it++; + assert(*it == 2); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp new file mode 100644 index 0000000000000..d7d6dd9cce2ae --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// friend constexpr range_rvalue_reference_t iter_move(const inner_iterator& i) +// noexcept(noexcept(ranges::iter_move(i.parent_->current_.value()))); + +#include +#include +#include + +#include "test_iterators.h" +#include "test_range.h" + +constexpr bool test() { + using InnerIterator = + std::ranges::iterator_t>>>; + + static_assert(std::ranges::input_range>); + static_assert(!std::ranges::forward_range>); + + static_assert(std::same_as())), int&&>); + static_assert(std::same_as())), + std::ranges::range_rvalue_reference_t>>); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp new file mode 100644 index 0000000000000..6efa479e56c2e --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// friend constexpr void iter_swap(const inner_iterator& x, const inner_iterator& y) +// noexcept(noexcept(ranges::iter_swap(x.parent_->current_.value(), y.parent_->current_.value()))) +// requires indirectly_swappable>; + +#include +#include + +#include "../types.h" + +constexpr bool test() { + int a[] = {1, 2, 3, 4}; + int b[] = {5, 6, 7, 8}; + + // Each chunk_view owns its own `current_` cache, so use two independent views to observe a real swap. + std::ranges::chunk_view> chunked_a(input_span(a, 4), 2); + std::ranges::chunk_view> chunked_b(input_span(b, 4), 2); + + auto inner_a = (*chunked_a.begin()).begin(); + auto inner_b = (*chunked_b.begin()).begin(); + + assert(a[0] == 1); + assert(b[0] == 5); + + std::ranges::iter_swap(inner_a, inner_b); + + assert(a[0] == 5); + assert(b[0] == 1); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp new file mode 100644 index 0000000000000..288388843b919 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models only input_range: +// class inner_iterator; + +// using inner_iterator::iterator_concept = input_iterator_tag; +// using inner_iterator::difference_type = range_difference_t; +// using inner_iterator::value_type = range_value_t; + +#include +#include +#include + +#include "../types.h" + +using InnerIterator = std::ranges::iterator_t>>>; + +static_assert(std::same_as); +static_assert(std::same_as>>); +static_assert(std::same_as>>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp new file mode 100644 index 0000000000000..89fd953e4306a --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models forward_range: +// friend constexpr iterator operator+(const iterator& i, difference_type n) +// requires random_access_range; +// friend constexpr iterator operator+(difference_type n, const iterator& i) +// requires random_access_range; +// friend constexpr iterator operator-(const iterator& i, difference_type n) +// requires random_access_range; +// friend constexpr difference_type operator-(const iterator& x, const iterator& y) +// requires sized_sentinel_for, iterator_t>; +// friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x) +// requires sized_sentinel_for, iterator_t>; +// friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y) +// requires sized_sentinel_for, iterator_t>; + +#include +#include +#include +#include +#include + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + std::ranges::chunk_view>> chunked = vector | std::views::chunk(3); + + // Test `friend constexpr iterator operator+(const iterator& i, difference_type n)` + { + assert(chunked.begin() + 4 == chunked.end()); + } + + // Test `friend constexpr iterator operator+(difference_type n, const iterator& i)` + { + assert(4 + chunked.begin() == chunked.end()); + } + + // Test `friend constexpr iterator operator-(const iterator& i, difference_type n)` + { + assert(chunked.end() - 4 == chunked.begin()); + } + + // Test `friend constexpr difference_type operator-(const iterator& x, const iterator& y)` + { + assert(chunked.end() - chunked.begin() == 4); + } + + // Test `friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x)` + { + assert(std::default_sentinel - chunked.begin() == 4); + } + + // Test `friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)` + { + assert(chunked.begin() - std::default_sentinel == -4); + } + + // Test `operator+=`/`operator-=` moving back and forth across a partial final chunk, when the range is + // not evenly divisible by the chunk size. + { + std::ranges::chunk_view>> uneven_chunked = vector | std::views::chunk(5); + + auto it = uneven_chunked.begin(); + assert(std::ranges::equal(*it, std::vector{1, 2, 3, 4, 5})); + + it += 2; + assert(std::ranges::equal(*it, std::vector{11, 12})); + + it -= 1; + assert(std::ranges::equal(*it, std::vector{6, 7, 8, 9, 10})); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp new file mode 100644 index 0000000000000..7f150b218eb2a --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models forward_range: +// constexpr iterator_t base() const; + +#include +#include +#include +#include + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6}; + + std::ranges::chunk_view>> chunked = vector | std::views::chunk(2); + auto it = chunked.begin(); + + std::same_as::iterator> decltype(auto) base = it.base(); + assert(base == vector.begin()); + + ++it; + assert(it.base() == vector.begin() + 2); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp new file mode 100644 index 0000000000000..9b9a42dd1034a --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models forward_range +// friend constexpr bool operator==(const iterator& x, const iterator& y); +// friend constexpr bool operator==(const iterator& x, default_sentinel_t); +// friend constexpr bool operator<(const iterator& x, const iterator& y) +// requires random_access_range; +// friend constexpr bool operator>(const iterator& x, const iterator& y) +// requires random_access_range; +// friend constexpr bool operator<=(const iterator& x, const iterator& y) +// requires random_access_range; +// friend constexpr bool operator>=(const iterator& x, const iterator& y) +// requires random_access_range; +// friend constexpr auto operator<=>(const iterator& x, const iterator& y) +// requires random_access_range && +// three_way_comparable>; + +#include +#include +#include +#include +#include + +#include "test_range.h" + +// The relational operators (<, >, <=, >=, <=>) are only available when `Base` models `random_access_range`. +template +concept HasChunkIteratorRelationalOperators = requires(std::ranges::iterator_t> it) { + it < it; + it > it; + it <= it; + it >= it; +}; + +static_assert(!HasChunkIteratorRelationalOperators>); +static_assert(!HasChunkIteratorRelationalOperators>); +static_assert(HasChunkIteratorRelationalOperators>); + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + std::ranges::chunk_view>> chunked = vector | std::views::chunk(3); + + // Test `friend constexpr bool operator==(const iterator& x, const iterator& y)` + { + assert(chunked.begin() == chunked.begin()); + assert(chunked.end() == chunked.end()); + assert(chunked.begin() != chunked.end()); + } + + // Test `friend constexpr bool operator==(const iterator& x, default_sentinel)` + { + assert(chunked.end() == std::default_sentinel); + assert(chunked.begin() != std::default_sentinel); + } + + // Test `friend constexpr bool operator<(const iterator& x, const iterator& y)` + { + assert(chunked.begin() < chunked.end()); + assert(!(chunked.end() < chunked.begin())); + assert(!(chunked.begin() < chunked.begin())); + } + + // Test `friend constexpr bool operator>(const iterator& x, const iterator& y)` + { + assert(chunked.end() > chunked.begin()); + assert(!(chunked.begin() > chunked.end())); + assert(!(chunked.begin() > chunked.begin())); + } + + // Test `friend constexpr bool operator<=(const iterator& x, const iterator& y)` + { + assert(chunked.begin() <= chunked.begin()); + assert(chunked.begin() <= chunked.end()); + assert(!(chunked.end() <= chunked.begin())); + } + + // Test `friend constexpr bool operator>=(const iterator& x, const iterator& y)` + { + assert(chunked.end() >= chunked.end()); + assert(chunked.end() >= chunked.begin()); + assert(!(chunked.begin() >= chunked.end())); + } + + // Test `friend constexpr auto operator<=>(const iterator& x, const iterator& y)` + { + assert((chunked.begin() <=> chunked.begin()) == std::strong_ordering::equal); + assert((chunked.begin() <=> chunked.end()) == std::strong_ordering::less); + assert((chunked.end() <=> chunked.begin()) == std::strong_ordering::greater); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp new file mode 100644 index 0000000000000..bdf96841bda73 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models forward_range: +// constexpr iterator(iterator i) +// requires Const && convertible_to, iterator_t> && +// convertible_to, sentinel_t>; + +#include +#include + +#include "test_iterators.h" +#include "test_range.h" + +using ChunkView = std::ranges::chunk_view>; +using Iterator = std::ranges::iterator_t; +using ConstIterator = std::ranges::iterator_t; + +// `test_view`'s const and non-const `begin()` return different iterator types, so the converting +// constructor is actually exercised here (unlike a simple_view, where both would collapse into one type). +static_assert(!std::same_as); +static_assert(std::convertible_to); +static_assert(!std::convertible_to); diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/decrement.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/decrement.pass.cpp new file mode 100644 index 0000000000000..397b32e73080a --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/decrement.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// constexpr iterator& operator--() +// requires bidirectional_range; +// constexpr iterator operator--(int) +// requires bidirectional_range; +// constexpr iterator& operator-=(difference_type) +// requires random_access_range; + +#include +#include +#include +#include +#include + +#include "test_range.h" + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8}; + std::ranges::chunk_view>> chunked = vector | std::views::chunk(2); + + // Test `constexpr iterator& operator--();` + { + /*chunk_view::__outer_iterator*/ std::bidirectional_iterator auto it = chunked.end(); + assert(std::ranges::equal(*--it, std::vector{7, 8})); + } + + // Test `constexpr iterator operator--(int)` + { + /*chunk_view::__outer_iterator*/ std::bidirectional_iterator auto it = chunked.end(); + it--; + assert(std::ranges::equal(*it, std::vector{7, 8})); + } + + // Test `constexpr iterator& operator-=(difference_type)` + { + /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.end(); + it -= 3; + assert(std::ranges::equal(*it, std::vector{3, 4})); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp new file mode 100644 index 0000000000000..4404ac907e6c7 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models forward_range: +// constexpr value_type iterator::operator*() const; + +#include +#include +#include +#include + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + std::ranges::chunk_view>> chunked = vector | std::views::chunk(3); + + // Test `constexpr value_type iterator::operator*() const` + { + std::same_as decltype(auto) v = *(*chunked.begin()).begin(); + assert(v == 1); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp new file mode 100644 index 0000000000000..36bc19c5dee65 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models forward_range: +// constexpr iterator& operator++(); +// constexpr iterator operator++(int); +// constexpr iterator& operator+=(difference_type) +// requires random_access_range; + +#include +#include +#include +#include +#include + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8}; + std::ranges::chunk_view>> chunked = vector | std::views::chunk(2); + + // Test `constexpr iterator& operator++();` + { + /*chunk_view::__iterator*/ std::forward_iterator auto it = chunked.begin(); + assert(std::ranges::equal(*++it, std::vector{3, 4})); + } + + // Test `constexpr iterator operator++(int)` + { + /*chunk_view::__iterator*/ std::forward_iterator auto it = chunked.begin(); + it++; + assert(std::ranges::equal(*it, std::vector{3, 4})); + } + + // Test `constexpr iterator& operator+=(difference_type)` + { + /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.begin(); + it += 3; + assert(std::ranges::equal(*it, std::vector{7, 8})); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/subscript.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/subscript.pass.cpp new file mode 100644 index 0000000000000..9b45fc6d779bf --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/subscript.pass.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models forward_range +// constexpr value_type iterator::operator[](difference_type n) const +// requires random_access_range; + +#include +#include +#include +#include +#include + +#include "test_range.h" + +constexpr bool test() { + std::vector vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + std::ranges::chunk_view>> chunked = vector | std::views::chunk(3); + + // Test `constexpr value_type iterator::operator[](difference_type n) const` + { + assert(std::ranges::equal(chunked.begin()[1], std::vector{4, 5, 6})); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp new file mode 100644 index 0000000000000..06b41656abc8e --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// + +// V models forward_range: +// class iterator; + +// using iterator::iterator_category = input_iterator_tag; +// using iterator::iterator_concept = see below; +// using iterator::value_type = decltype(views::take(subrange(current_, end_), n_)); +// using iterator::difference_type = range_difference_t; + +#include +#include +#include + +#include "test_iterators.h" +#include "test_range.h" + +template