diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -352,6 +352,8 @@ --------------------------------------------------- ----------------- ``__cpp_lib_ranges_join_with`` *unimplemented* --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_repeat`` ``202207L`` + --------------------------------------------------- ----------------- ``__cpp_lib_ranges_slide`` *unimplemented* --------------------------------------------------- ----------------- ``__cpp_lib_ranges_starts_ends_with`` *unimplemented* diff --git a/libcxx/docs/ReleaseNotes/17.rst b/libcxx/docs/ReleaseNotes/17.rst --- a/libcxx/docs/ReleaseNotes/17.rst +++ b/libcxx/docs/ReleaseNotes/17.rst @@ -67,7 +67,7 @@ - P2494R2 - Relaxing range adaptors to allow for move only types - P2585R0 - Improving default container formatting - P0408R7 - Efficient Access to ``basic_stringbuf``'s Buffer - +- P2474R2 - ``views::repeat`` Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv --- a/libcxx/docs/Status/Cxx23Issues.csv +++ b/libcxx/docs/Status/Cxx23Issues.csv @@ -299,7 +299,7 @@ "`3870 `__","Remove ``voidify``","February 2023","","","" "`3871 `__","Adjust note about ``terminate``","February 2023","","","" "`3872 `__","``basic_const_iterator`` should have custom ``iter_move``","February 2023","","","" -"`3875 `__","``std::ranges::repeat_view::iterator`` may be ill-formed","February 2023","","","|ranges|" +"`3875 `__","``std::ranges::repeat_view::iterator`` may be ill-formed","February 2023","|Complete|","17.0","|ranges|" "`3876 `__","Default constructor of ``std::layout_XX::mapping`` misses precondition","February 2023","","","" "`3877 `__","Incorrect constraints on ``const``-qualified monadic overloads for ``std::expected``","February 2023","|Complete|","17.0","" "`3878 `__","import ``std;`` should guarantee initialization of standard iostreams objects","February 2023","","","" diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -77,7 +77,7 @@ "`P2460R2 `__","LWG","Relax requirements on ``wchar_t`` to match existing practices","July 2022","","" "`P2465R3 `__","LWG","Standard Library Modules ``std`` and ``std.compat``","July 2022","","" "`P2467R1 `__","LWG","Support exclusive mode for ``fstreams``","July 2022","","" -"`P2474R2 `__","LWG","``views::repeat``","July 2022","","","|ranges|" +"`P2474R2 `__","LWG","``views::repeat``","July 2022","|Complete|","17.0","|ranges|" "`P2494R2 `__","LWG","Relaxing range adaptors to allow for move only types","July 2022","|Complete|","17.0","|ranges|" "`P2499R0 `__","LWG","``string_view`` range constructor should be ``explicit``","July 2022","|Complete|","16.0","|ranges|" "`P2502R2 `__","LWG","``std::generator``: Synchronous Coroutine Generator for Ranges","July 2022","","","|ranges|" diff --git a/libcxx/docs/Status/RangesViews.csv b/libcxx/docs/Status/RangesViews.csv --- a/libcxx/docs/Status/RangesViews.csv +++ b/libcxx/docs/Status/RangesViews.csv @@ -22,7 +22,7 @@ ,,,, ,,,, ,,,, -C++23,`repeat `_,Unassigned,No patch yet,Not started +C++23,`repeat `_,Yrong,`D141699 `_,✅ C++23,`cartesian_product `_,Unassigned,No patch yet,Not started C++23,`zip `_,Hui Xie,`D122806 `_,✅ C++23,`zip_transform `_,Hui Xie,No patch yet,Not started diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -637,6 +637,7 @@ __ranges/rbegin.h __ranges/ref_view.h __ranges/rend.h + __ranges/repeat_view.h __ranges/reverse_view.h __ranges/single_view.h __ranges/size.h diff --git a/libcxx/include/__ranges/drop_view.h b/libcxx/include/__ranges/drop_view.h --- a/libcxx/include/__ranges/drop_view.h +++ b/libcxx/include/__ranges/drop_view.h @@ -30,6 +30,7 @@ #include <__ranges/iota_view.h> #include <__ranges/non_propagating_cache.h> #include <__ranges/range_adaptor.h> +#include <__ranges/repeat_view.h> #include <__ranges/size.h> #include <__ranges/subrange.h> #include <__ranges/view_interface.h> @@ -267,6 +268,32 @@ ranges::end(__rng), std::__to_unsigned_like(__dist - __clamped) );} +// clang-format off +#if _LIBCPP_STD_VER >= 23 + // [range.drop.overview]: the `repeat_view` "_RawRange models sized_range" case. + template > _Np, + class _RawRange = remove_cvref_t<_Range>, + class _Dist = range_difference_t<_Range>> + requires (__is_repeat_specialization<_RawRange> && sized_range<_RawRange>) + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const + noexcept(noexcept(views::repeat(*__range.__value_, ranges::distance(__range) - std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))))) + -> decltype( views::repeat(*__range.__value_, ranges::distance(__range) - std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n)))) + { return views::repeat(*__range.__value_, ranges::distance(__range) - std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))); } + + // [range.drop.overview]: the `repeat_view` "otherwise" case. + template > _Np, + class _RawRange = remove_cvref_t<_Range>, + class _Dist = range_difference_t<_Range>> + requires (__is_repeat_specialization<_RawRange> && !sized_range<_RawRange>) + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Range&& __range, _Np&&) const + noexcept(noexcept(_LIBCPP_AUTO_CAST(std::forward<_Range>(__range)))) + -> decltype( _LIBCPP_AUTO_CAST(std::forward<_Range>(__range))) + { return _LIBCPP_AUTO_CAST(std::forward<_Range>(__range)); } +#endif +// clang-format on // [range.drop.overview]: the "otherwise" case. template > _Np, @@ -274,6 +301,9 @@ // Note: without specifically excluding the other cases, GCC sees this overload as ambiguous with the other // overloads. requires (!(__is_empty_view<_RawRange> || +#if _LIBCPP_STD_VER >= 23 + __is_repeat_specialization<_RawRange> || +#endif (__is_subrange_specialization_with_store_size<_RawRange> && sized_range<_RawRange> && random_access_range<_RawRange>) || diff --git a/libcxx/include/__ranges/repeat_view.h b/libcxx/include/__ranges/repeat_view.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/repeat_view.h @@ -0,0 +1,260 @@ +// -*- 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_REPEAT_VIEW_H +#define _LIBCPP___RANGES_REPEAT_VIEW_H + +#include <__concepts/constructible.h> +#include <__concepts/same_as.h> +#include <__concepts/semiregular.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/unreachable_sentinel.h> +#include <__memory/addressof.h> +#include <__ranges/iota_view.h> +#include <__ranges/movable_box.h> +#include <__ranges/view_interface.h> +#include <__type_traits/is_object.h> +#include <__type_traits/make_unsigned.h> +#include <__type_traits/remove_cv.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include <__utility/piecewise_construct.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace ranges { + +template +concept __integer_like_with_usable_difference_type = + __signed_integer_like<_Tp> || (__integer_like<_Tp> && weakly_incrementable<_Tp>); + +template +struct __repeat_view_iterator_difference { + using type = _IotaDiffT<_Tp>; +}; + +template <__signed_integer_like _Tp> +struct __repeat_view_iterator_difference<_Tp> { + using type = _Tp; +}; + +template +using __repeat_view_iterator_difference_t = typename __repeat_view_iterator_difference<_Tp>::type; + +namespace views::__drop { +struct __fn; +} // namespace views::__drop + +namespace views::__take { +struct __fn; +} // namespace views::__take + +template + requires(is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> && + (__integer_like_with_usable_difference_type<_Bound> || same_as<_Bound, unreachable_sentinel_t>)) +class repeat_view : public view_interface> { + friend struct views::__take::__fn; + friend struct views::__drop::__fn; + class __iterator; + +public: + _LIBCPP_HIDE_FROM_ABI repeat_view() + requires default_initializable<_Tp> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit repeat_view(const _Tp& __value, _Bound __bound_sentinel = _Bound()) + requires copy_constructible<_Tp> + : __value_(in_place, __value), __bound_(__bound_sentinel) { + if constexpr (!same_as<_Bound, unreachable_sentinel_t>) + _LIBCPP_ASSERT(__bound_ >= 0, "The value of bound must be greater than or equal to 0"); + } + + _LIBCPP_HIDE_FROM_ABI constexpr explicit repeat_view(_Tp&& __value, _Bound __bound_sentinel = _Bound()) + : __value_(in_place, std::move(__value)), __bound_(__bound_sentinel) { + if constexpr (!same_as<_Bound, unreachable_sentinel_t>) + _LIBCPP_ASSERT(__bound_ >= 0, "The value of bound must be greater than or equal to 0"); + } + + template + requires(constructible_from<_Tp, _TpArgs...> && constructible_from<_Bound, _BoundArgs...>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit repeat_view( + piecewise_construct_t, tuple<_TpArgs...> __value_args, tuple<_BoundArgs...> __bound_args = tuple<>{}) + : __value_(in_place, std::make_from_tuple<_Tp>(std::move(__value_args))), + __bound_(std::make_from_tuple<_Bound>(std::move(__bound_args))) { + if constexpr (!same_as<_Bound, unreachable_sentinel_t>) + _LIBCPP_ASSERT( + __bound_ >= 0, "The behavior is undefined if Bound is not unreachable_sentinel_t and bound is negative"); + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() const { return __iterator(std::addressof(*__value_)); } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator end() const + requires(!same_as<_Bound, unreachable_sentinel_t>) + { + return __iterator(std::addressof(*__value_), __bound_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr unreachable_sentinel_t end() const noexcept { return unreachable_sentinel; } + + _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + requires(!same_as<_Bound, unreachable_sentinel_t>) + { + return std::__to_unsigned_like(__bound_); + } + +private: + __movable_box<_Tp> __value_; + _LIBCPP_NO_UNIQUE_ADDRESS _Bound __bound_ = _Bound(); +}; + +template +repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>; + +// [range.repeat.iterator] +template + requires(is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> && + (__integer_like_with_usable_difference_type<_Bound> || same_as<_Bound, unreachable_sentinel_t>)) +class repeat_view<_Tp, _Bound>::__iterator { + friend class repeat_view; + + using _IndexT = conditional_t, ptrdiff_t, _Bound>; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(const _Tp* __value, _IndexT __bound_sentinel = _IndexT()) + : __value_(__value), __current_(__bound_sentinel) {} + +public: + using iterator_concept = random_access_iterator_tag; + using iterator_category = random_access_iterator_tag; + using value_type = _Tp; + using difference_type = __repeat_view_iterator_difference_t<_IndexT>; + + _LIBCPP_HIDE_FROM_ABI __iterator() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const noexcept { return *__value_; } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { + ++__current_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { + auto __tmp = *this; + ++*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--() { + if constexpr (!same_as<_Bound, unreachable_sentinel_t>) + _LIBCPP_ASSERT(__current_ > 0, "The value of bound must be greater than or equal to 0"); + --__current_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int) { + auto __tmp = *this; + --*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n) { + if constexpr (!same_as<_Bound, unreachable_sentinel_t>) + _LIBCPP_ASSERT(__current_ + __n >= 0, "The value of bound must be greater than or equal to 0"); + __current_ += __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n) { + if constexpr (!same_as<_Bound, unreachable_sentinel_t>) + _LIBCPP_ASSERT(__current_ - __n >= 0, "The value of bound must be greater than or equal to 0"); + __current_ -= __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](difference_type __n) const noexcept { return *(*this + __n); } + + _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 auto operator<=>(const __iterator& __x, const __iterator& __y) { + return __x.__current_ <=> __y.__current_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i, difference_type __n) { + __i += __n; + return __i; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, __iterator __i) { + __i += __n; + return __i; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, difference_type __n) { + __i -= __n; + return __i; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y) { + return static_cast(__x.__current_) - static_cast(__y.__current_); + } + +private: + const _Tp* __value_ = nullptr; + _IndexT __current_ = _IndexT(); +}; + +// clang-format off +namespace views { +namespace __repeat { +struct __fn { + template + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __value) const + noexcept(noexcept(ranges::repeat_view(std::forward<_Tp>(__value)))) + -> decltype( ranges::repeat_view(std::forward<_Tp>(__value))) + { return ranges::repeat_view(std::forward<_Tp>(__value)); } + + + template + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __value, _Bound&& __bound_sentinel) const + noexcept(noexcept(ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel)))) + -> decltype( ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel))) + { return ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel)); } +}; +} // namespace __repeat +// clang-format on + +inline namespace __cpo { +inline constexpr auto repeat = __repeat::__fn{}; +} // namespace __cpo +} // namespace views + +template +inline constexpr bool __is_repeat_specialization = false; + +template +inline constexpr bool __is_repeat_specialization> = true; + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_REPEAT_VIEW_H diff --git a/libcxx/include/__ranges/take_view.h b/libcxx/include/__ranges/take_view.h --- a/libcxx/include/__ranges/take_view.h +++ b/libcxx/include/__ranges/take_view.h @@ -31,6 +31,7 @@ #include <__ranges/enable_borrowed_range.h> #include <__ranges/iota_view.h> #include <__ranges/range_adaptor.h> +#include <__ranges/repeat_view.h> #include <__ranges/size.h> #include <__ranges/subrange.h> #include <__ranges/view_interface.h> @@ -301,6 +302,31 @@ *ranges::begin(__rng), *ranges::begin(__rng) + std::min<_Dist>(ranges::distance(__rng), std::forward<_Np>(__n)) ); } +// clang-format off +#if _LIBCPP_STD_VER >= 23 + // [range.take.overview]: the `repeat_view` "_RawRange models sized_range" case. + template > _Np, + class _RawRange = remove_cvref_t<_Range>, + class _Dist = range_difference_t<_Range>> + requires(__is_repeat_specialization<_RawRange> && sized_range<_RawRange>) + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const + noexcept(noexcept(views::repeat(*__range.__value_, std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))))) + -> decltype( views::repeat(*__range.__value_, std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n)))) + { return views::repeat(*__range.__value_, std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))); } + + // [range.take.overview]: the `repeat_view` "otherwise" case. + template > _Np, + class _RawRange = remove_cvref_t<_Range>, + class _Dist = range_difference_t<_Range>> + requires(__is_repeat_specialization<_RawRange> && !sized_range<_RawRange>) + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const + noexcept(noexcept(views::repeat(*__range.__value_, static_cast<_Dist>(__n)))) + -> decltype( views::repeat(*__range.__value_, static_cast<_Dist>(__n))) + { return views::repeat(*__range.__value_, static_cast<_Dist>(__n)); } +#endif +// clang-format on // [range.take.overview]: the "otherwise" case. template > _Np, @@ -308,6 +334,9 @@ // Note: without specifically excluding the other cases, GCC sees this overload as ambiguous with the other // overloads. requires (!(__is_empty_view<_RawRange> || +#if _LIBCPP_STD_VER >= 23 + __is_repeat_specialization<_RawRange> || +#endif (__is_iota_specialization<_RawRange> && sized_range<_RawRange> && random_access_range<_RawRange>) || diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1481,6 +1481,7 @@ module rbegin { private header "__ranges/rbegin.h" } module ref_view { private header "__ranges/ref_view.h" } module rend { private header "__ranges/rend.h" } + module repeat_view { private header "__ranges/repeat_view.h" } module reverse_view { private header "__ranges/reverse_view.h" } module single_view { private header "__ranges/single_view.h" } module size { diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -252,6 +252,19 @@ template inline constexpr bool enable_borrowed_range> = true; + // [range.repeat], repeat view + template + concept integer-like-with-usable-difference-type = // exposition only + is-signed-integer-like || (is-integer-like && weakly_incrementable); + + template + requires (is_object_v && same_as> && + (integer-like-with-usable-difference-type || + same_as)) + class repeat_view; + + namespace views { inline constexpr unspecified repeat = unspecified; } + // [range.join], join view template requires view && input_range> @@ -370,6 +383,7 @@ #include <__ranges/rbegin.h> #include <__ranges/ref_view.h> #include <__ranges/rend.h> +#include <__ranges/repeat_view.h> #include <__ranges/reverse_view.h> #include <__ranges/single_view.h> #include <__ranges/size.h> diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -158,6 +158,7 @@ __cpp_lib_ranges_chunk_by 202202L __cpp_lib_ranges_iota 202202L __cpp_lib_ranges_join_with 202202L +__cpp_lib_ranges_repeat 202207L __cpp_lib_ranges_slide 202202L __cpp_lib_ranges_starts_ends_with 202106L __cpp_lib_ranges_to_container 202202L @@ -436,6 +437,7 @@ // # define __cpp_lib_ranges_chunk_by 202202L // # define __cpp_lib_ranges_iota 202202L // # define __cpp_lib_ranges_join_with 202202L +# define __cpp_lib_ranges_repeat 202207L // # define __cpp_lib_ranges_slide 202202L // # define __cpp_lib_ranges_starts_ends_with 202106L // # define __cpp_lib_ranges_to_container 202202L diff --git a/libcxx/modules/std/ranges.cppm b/libcxx/modules/std/ranges.cppm --- a/libcxx/modules/std/ranges.cppm +++ b/libcxx/modules/std/ranges.cppm @@ -119,13 +119,12 @@ } // namespace views // [range.repeat], repeat view -#if 0 using std::ranges::repeat_view; namespace views { using std::ranges::views::repeat; } // namespace views -#endif + #ifndef _LIBCPP_HAS_NO_LOCALIZATION // [range.istream], istream view using std::ranges::basic_istream_view; diff --git a/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp b/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode +// REQUIRES: has-unix-headers +// XFAIL: availability-verbose_abort-missing + +// template +// requires constructible_from && +// constructible_from +// constexpr explicit repeat_view(piecewise_construct_t, +// tuple value_args, tuple bound_args = tuple<>{}); + +#include +#include + +#include "check_assertion.h" + +// clang-format off +int main(int, char**) { + using Repeat = std::ranges::repeat_view; + TEST_LIBCPP_ASSERT_FAILURE(Repeat(std::piecewise_construct, std::tuple{1}, std::tuple{-1}), "The behavior is undefined if Bound is not unreachable_sentinel_t and bound is negative"); + + return 0; +} +// clang-format on diff --git a/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp b/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode +// REQUIRES: has-unix-headers +// XFAIL: availability-verbose_abort-missing + +// constexpr explicit repeat_view(W&& value, Bound bound = Bound()); +// constexpr explicit repeat_view(const W& value, Bound bound = Bound()); + +#include + +#include "check_assertion.h" + +// clang-format off +int main(int, char**) { + TEST_LIBCPP_ASSERT_FAILURE(std::ranges::repeat_view(0, -1), "The value of bound must be greater than or equal to 0"); + const int val = 0; + TEST_LIBCPP_ASSERT_FAILURE(std::ranges::repeat_view(val, -1), "The value of bound must be greater than or equal to 0"); + + return 0; +} +// clang-format on diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp @@ -21,6 +21,7 @@ __cpp_lib_ranges_chunk 202202L [C++23] __cpp_lib_ranges_chunk_by 202202L [C++23] __cpp_lib_ranges_join_with 202202L [C++23] + __cpp_lib_ranges_repeat 202207L [C++23] __cpp_lib_ranges_slide 202202L [C++23] __cpp_lib_ranges_zip 202110L [C++23] */ @@ -50,6 +51,10 @@ # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should not be defined before c++23" # endif @@ -80,6 +85,10 @@ # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should not be defined before c++23" # endif @@ -110,6 +119,10 @@ # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should not be defined before c++23" # endif @@ -143,6 +156,10 @@ # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should not be defined before c++23" # endif @@ -206,6 +223,13 @@ # endif # endif +# ifndef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should be defined in c++23" +# endif +# if __cpp_lib_ranges_repeat != 202207L +# error "__cpp_lib_ranges_repeat should have the value 202207L in c++23" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should be defined in c++23" @@ -287,6 +311,13 @@ # endif # endif +# ifndef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should be defined in c++26" +# endif +# if __cpp_lib_ranges_repeat != 202207L +# error "__cpp_lib_ranges_repeat should have the value 202207L in c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should be defined in c++26" diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -146,6 +146,7 @@ __cpp_lib_ranges_chunk_by 202202L [C++23] __cpp_lib_ranges_iota 202202L [C++23] __cpp_lib_ranges_join_with 202202L [C++23] + __cpp_lib_ranges_repeat 202207L [C++23] __cpp_lib_ranges_slide 202202L [C++23] __cpp_lib_ranges_starts_ends_with 202106L [C++23] __cpp_lib_ranges_to_container 202202L [C++23] @@ -707,6 +708,10 @@ # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should not be defined before c++23" # endif @@ -1461,6 +1466,10 @@ # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should not be defined before c++23" # endif @@ -2386,6 +2395,10 @@ # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should not be defined before c++23" # endif @@ -3581,6 +3594,10 @@ # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should not be defined before c++23" # endif @@ -4992,6 +5009,13 @@ # endif # endif +# ifndef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should be defined in c++23" +# endif +# if __cpp_lib_ranges_repeat != 202207L +# error "__cpp_lib_ranges_repeat should have the value 202207L in c++23" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should be defined in c++23" @@ -6544,6 +6568,13 @@ # endif # endif +# ifndef __cpp_lib_ranges_repeat +# error "__cpp_lib_ranges_repeat should be defined in c++26" +# endif +# if __cpp_lib_ranges_repeat != 202207L +# error "__cpp_lib_ranges_repeat should have the value 202207L in c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_slide # error "__cpp_lib_ranges_slide should be defined in c++26" diff --git a/libcxx/test/std/ranges/range.adaptors/range.drop/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.drop/adaptor.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.drop/adaptor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.drop/adaptor.pass.cpp @@ -220,6 +220,27 @@ test_small_range(std::views::iota(1, 8)); } +#if TEST_STD_VER >= 23 + // `views::drop(repeat_view, n)` returns a `repeat_view` when `repeat_view` models `sized_range`. + { + auto repeat = std::ranges::repeat_view(1, 8); + using Result = std::ranges::repeat_view; + std::same_as decltype(auto) result = repeat | std::views::drop(3); + static_assert(std::ranges::sized_range); + assert(result.size() == 5); + assert(*result.begin() == 1); + } + + // `views::drop(repeat_view, n)` returns a `repeat_view` when `repeat_view` doesn't model `sized_range`. + { + auto repeat = std::ranges::repeat_view(1); + using Result = std::ranges::repeat_view; + std::same_as decltype(auto) result = repeat | std::views::drop(3); + static_assert(!std::ranges::sized_range); + static_assert(std::same_as); + } +#endif + // Test that it's possible to call `std::views::drop` with any single argument as long as the resulting closure is // never invoked. There is no good use case for it, but it's valid. { diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp @@ -179,6 +179,27 @@ assert(result.size() == 3); } +#if TEST_STD_VER >= 23 + // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` models `sized_range`. + { + auto repeat = std::ranges::repeat_view(1, 8); + using Result = std::ranges::repeat_view; + std::same_as decltype(auto) result = repeat | std::views::take(3); + static_assert(std::ranges::sized_range); + assert(result.size() == 3); + assert(*result.begin() == 1); + } + + // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` doesn't model `sized_range`. + { + auto repeat = std::ranges::repeat_view(1); + using Result = std::ranges::repeat_view>; + std::same_as decltype(auto) result = repeat | std::views::take(3); + assert(result.size() == 3); + assert(*result.begin() == 1); + } +#endif + // When the size of the input range `s` is shorter than `n`, only `s` elements are taken. { test_small_range(std::span(buf)); diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/begin.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/begin.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/begin.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr iterator begin() const; + +#include +#include +#include + +constexpr bool test() { + // Test unbound && non-const view + { + std::ranges::repeat_view rv(0); + std::same_as> decltype(auto) iter = rv.begin(); + assert(*iter == 0); + } + + // Test unbound && const view + { + const std::ranges::repeat_view rv(0); + std::same_as> decltype(auto) iter = rv.begin(); + assert(*iter == 0); + } + + // Test bound && non-const view + { + std::ranges::repeat_view rv(1024, 10); + std::same_as> decltype(auto) iter = rv.begin(); + assert(*iter == 1024); + } + + // Test bound && const view + { + const std::ranges::repeat_view rv(1024, 10); + std::same_as> decltype(auto) iter = rv.begin(); + assert(*iter == 1024); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctad.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctad.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// repeat_view(T, Bound) -> repeat_view; + +#include +#include +#include + +struct Empty {}; + +// clang-format off +static_assert(std::same_as>); +static_assert(std::same_as())), std::ranges::repeat_view>); +static_assert(std::same_as())), std::ranges::repeat_view>); +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.factories/range.repeat.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.default.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// repeat_view() requires default_initializable = default; + +#include +#include +#include + +struct DefaultInt42 { + int value = 42; +}; + +struct Int { + Int(int) {} +}; + +static_assert(std::default_initializable>); +static_assert(!std::default_initializable>); + +constexpr bool test() { + std::ranges::repeat_view rv; + assert((*rv.begin()).value == 42); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp @@ -0,0 +1,130 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// requires constructible_from && +// constructible_from +// constexpr explicit repeat_view(piecewise_construct_t, +// tuple value_args, tuple bound_args = tuple<>{}); + +#include +#include +#include +#include +#include + +struct C {}; + +struct B { + int v; +}; + +struct A { + int x = 111; + int y = 222; + + constexpr A() = default; + constexpr A(B b) : x(b.v), y(b.v + 1) {} + constexpr A(int _x, int _y) : x(_x), y(_y) {} +}; + +static_assert(std::constructible_from, + std::piecewise_construct_t, + std::tuple, + std::tuple>); +static_assert(std::constructible_from, + std::piecewise_construct_t, + std::tuple, + std::tuple>); +static_assert(std::constructible_from, + std::piecewise_construct_t, + std::tuple<>, + std::tuple>); +static_assert(std::constructible_from, + std::piecewise_construct_t, + std::tuple, + std::tuple>); +static_assert(std::constructible_from, + std::piecewise_construct_t, + std::tuple, + std::tuple>); +static_assert(std::constructible_from, + std::piecewise_construct_t, + std::tuple<>, + std::tuple>); +static_assert(!std::constructible_from, + std::piecewise_construct_t, + std::tuple, + std::tuple>); +static_assert(!std::constructible_from, + std::piecewise_construct_t, + std::tuple, + std::tuple>); +static_assert(!std::constructible_from, + std::piecewise_construct_t, + std::tuple, + std::tuple>); +static_assert(!std::constructible_from, + std::piecewise_construct_t, + std::tuple, + std::tuple>); +static_assert( + !std::constructible_from, std::piecewise_construct_t, std::tuple, std::tuple>); + +constexpr bool test() { + { + std::ranges::repeat_view rv(std::piecewise_construct, std::tuple{}, std::tuple{3}); + assert(rv.size() == 3); + assert(rv[0].x == 111); + assert(rv[0].y == 222); + assert(rv.begin() + 3 == rv.end()); + } + { + std::ranges::repeat_view rv(std::piecewise_construct, std::tuple{}, std::tuple{std::unreachable_sentinel}); + assert(rv[0].x == 111); + assert(rv[0].y == 222); + assert(rv.begin() + 300 != rv.end()); + } + { + std::ranges::repeat_view rv(std::piecewise_construct, std::tuple{1, 2}, std::tuple{3}); + assert(rv.size() == 3); + assert(rv[0].x == 1); + assert(rv[0].y == 2); + assert(rv.begin() + 3 == rv.end()); + } + { + std::ranges::repeat_view rv(std::piecewise_construct, std::tuple{1, 2}, std::tuple{std::unreachable_sentinel}); + assert(rv[0].x == 1); + assert(rv[0].y == 2); + assert(rv.begin() + 300 != rv.end()); + } + { + std::ranges::repeat_view rv(std::piecewise_construct, std::tuple{B{11}}, std::tuple{3}); + assert(rv.size() == 3); + assert(rv[0].x == 11); + assert(rv[0].y == 12); + assert(rv.begin() + 3 == rv.end()); + } + { + std::ranges::repeat_view rv(std::piecewise_construct, std::tuple{B{10}}, std::tuple{std::unreachable_sentinel}); + assert(rv[0].x == 10); + assert(rv[0].y == 11); + assert(rv.begin() + 300 != rv.end()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr explicit repeat_view(const T& value, Bound bound = Bound()) requires copy_constructible; +// constexpr explicit repeat_view(T&& value, Bound bound = Bound()); + +#include +#include +#include +#include + +#include "MoveOnly.h" + +struct Empty {}; + +// Test explicit +static_assert(std::is_constructible_v, const Empty&>); +static_assert(std::is_constructible_v, Empty&&>); +static_assert(std::is_constructible_v, const Empty&>); +static_assert(std::is_constructible_v, Empty&&>); + +static_assert(!std::is_convertible_v>); +static_assert(!std::is_convertible_v>); +static_assert(!std::is_convertible_v>); +static_assert(!std::is_convertible_v>); + +static_assert(!std::is_constructible_v, const MoveOnly&>); +static_assert(std::is_constructible_v, MoveOnly&&>); + +constexpr bool test() { + // Move && unbound && default argument + { + std::ranges::repeat_view rv(Empty{}); + assert(rv.begin() + 10 != rv.end()); + } + + // Move && unbound && user-provided argument + { + std::ranges::repeat_view rv(Empty{}, std::unreachable_sentinel); + assert(rv.begin() + 10 != rv.end()); + } + + // Move && bound && default argument + { + std::ranges::repeat_view rv(Empty{}); + assert(rv.begin() == rv.end()); + } + + // Move && bound && user-provided argument + { + std::ranges::repeat_view rv(Empty{}, 10); + assert(rv.begin() + 10 == rv.end()); + } + + // Copy && unbound && default argument + { + Empty e; + std::ranges::repeat_view rv(e); + assert(rv.begin() + 10 != rv.end()); + } + + // Copy && unbound && user-provided argument + { + Empty e; + std::ranges::repeat_view rv(e, std::unreachable_sentinel); + assert(rv.begin() + 10 != rv.end()); + } + + // Copy && bound && default argument + { + Empty e; + std::ranges::repeat_view rv(e); + assert(rv.begin() == rv.end()); + } + + // Copy && bound && user-provided argument + { + Empty e; + std::ranges::repeat_view rv(e, 10); + assert(rv.begin() + 10 == rv.end()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/end.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/end.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/end.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr unreachable_sentinel_t end() const noexcept; +// constexpr iterator end() const requires (!same_as); + +#include +#include +#include +#include + +constexpr bool test() { + // bound + { + std::ranges::repeat_view rv(0, 10); + assert(rv.begin() + 10 == rv.end()); + std::same_as> decltype(auto) iter = rv.end(); + static_assert(std::same_as); + for (const auto& i : rv) { + assert(i == 0); + } + } + + // unbound + { + std::ranges::repeat_view rv(0); + assert(rv.begin() + 10 != rv.end()); + static_assert(std::same_as); + static_assert(noexcept(rv.end())); + for (const auto& i : rv | std::views::take(10)) { + assert(i == 0); + } + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/compare.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/compare.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/compare.pass.cpp @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// repeat_view::::operator{==,<=>} + +#include +#include +#include + +constexpr bool test() { + // Test unbound + { + using R = std::ranges::repeat_view; + static_assert(std::three_way_comparable>); + + std::ranges::repeat_view r(42); + auto iter1 = r.begin(); + auto iter2 = iter1 + 1; + + static_assert(std::same_as); + + assert(iter1 == iter1); + assert(!(iter1 == iter2)); + assert(iter2 == iter2); + + assert(!(iter1 < iter1)); + assert(iter1 < iter2); + assert(!(iter2 < iter1)); + assert(iter1 <= iter1); + assert(iter1 <= iter2); + assert(!(iter2 <= iter1)); + assert(!(iter1 > iter1)); + assert(!(iter1 > iter2)); + assert(iter2 > iter1); + assert(iter1 >= iter1); + assert(!(iter1 >= iter2)); + assert(iter2 >= iter1); + assert(iter1 == iter1); + assert(!(iter1 == iter2)); + assert(iter2 == iter2); + assert(!(iter1 != iter1)); + assert(iter1 != iter2); + assert(!(iter2 != iter2)); + + assert((iter1 <=> iter2) == std::strong_ordering::less); + assert((iter1 <=> iter1) == std::strong_ordering::equal); + assert((iter2 <=> iter1) == std::strong_ordering::greater); + + static_assert(std::same_as iter2), std::strong_ordering>); + } + + // Test bound + { + using R = std::ranges::repeat_view; + static_assert(std::three_way_comparable>); + + std::ranges::repeat_view r(42, 10); + auto iter1 = r.begin(); + auto iter2 = iter1 + 1; + + static_assert(std::same_as); + + assert(iter1 == iter1); + assert(!(iter1 == iter2)); + assert(iter2 == iter2); + + assert(!(iter1 < iter1)); + assert(iter1 < iter2); + assert(!(iter2 < iter1)); + assert(iter1 <= iter1); + assert(iter1 <= iter2); + assert(!(iter2 <= iter1)); + assert(!(iter1 > iter1)); + assert(!(iter1 > iter2)); + assert(iter2 > iter1); + assert(iter1 >= iter1); + assert(!(iter1 >= iter2)); + assert(iter2 >= iter1); + assert(iter1 == iter1); + assert(!(iter1 == iter2)); + assert(iter2 == iter2); + assert(!(iter1 != iter1)); + assert(iter1 != iter2); + assert(!(iter2 != iter2)); + + assert((iter1 <=> iter2) == std::strong_ordering::less); + assert((iter1 <=> iter1) == std::strong_ordering::equal); + assert((iter2 <=> iter1) == std::strong_ordering::greater); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/ctor.default.pass.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// iterator() = default; + +#include +#include + +constexpr bool test() { + using Iter = std::ranges::iterator_t>; + static_assert(std::is_default_constructible_v); + [[maybe_unused]] Iter iter; + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/decrement.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/decrement.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr iterator& operator--(); +// constexpr iterator operator--(int); + +#include +#include + +constexpr bool test() { + using Iter = std::ranges::iterator_t>; + std::ranges::repeat_view rv(10); + auto iter = rv.begin() + 10; + + assert(iter-- == rv.begin() + 10); + assert(--iter == rv.begin() + 8); + + static_assert(std::same_as); + static_assert(std::same_as); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/increment.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/increment.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr iterator& operator++(); +// constexpr void operator++(int); + +#include +#include +#include + +constexpr bool test() { + using Iter = std::ranges::iterator_t>; + std::ranges::repeat_view rv(10); + using Iter = std::ranges::iterator_t>; + auto iter = rv.begin(); + + assert(iter++ == rv.begin()); + assert(++iter == rv.begin() + 2); + + static_assert(std::same_as); + static_assert(std::same_as); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/member_typedefs.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/member_typedefs.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/member_typedefs.compile.pass.cpp @@ -0,0 +1,112 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// Test iterator category and iterator concepts. + +// using index-type = conditional_t, ptrdiff_t, Bound>; +// using iterator_concept = random_access_iterator_tag; +// using iterator_category = random_access_iterator_tag; +// using value_type = T; +// using difference_type = see below: +// If is-signed-integer-like is true, the member typedef-name difference_type denotes +// index-type. Otherwise, it denotes IOTA-DIFF-T(index-type). + +#include +#include +#include +#include +#include + +constexpr bool test() { + // unbound + { + using Iter = std::ranges::iterator_t>; + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::is_signed_v); + } + + // bound + { + { + using Iter = std::ranges::iterator_t>; + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::is_signed_v); + static_assert(sizeof(Iter::difference_type) == sizeof(std::int8_t)); + } + + { + using Iter = std::ranges::iterator_t>; + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::is_signed_v); + static_assert(sizeof(Iter::difference_type) > sizeof(std::uint8_t)); + } + + { + using Iter = std::ranges::iterator_t>; + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::is_signed_v); + static_assert(sizeof(Iter::difference_type) == sizeof(std::int16_t)); + } + + { + using Iter = std::ranges::iterator_t>; + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::is_signed_v); + static_assert(sizeof(Iter::difference_type) > sizeof(std::uint16_t)); + } + + { + using Iter = std::ranges::iterator_t>; + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::is_signed_v); + static_assert(sizeof(Iter::difference_type) == sizeof(std::int32_t)); + } + + { + using Iter = std::ranges::iterator_t>; + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::is_signed_v); + static_assert(sizeof(Iter::difference_type) > sizeof(std::uint32_t)); + } + + { + using Iter = std::ranges::iterator_t>; + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::is_signed_v); + static_assert(sizeof(Iter::difference_type) == sizeof(std::int64_t)); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// friend constexpr iterator operator-(iterator i, difference_type n); +// friend constexpr difference_type operator-(const iterator& x, const iterator& y); + +#include +#include +#include +#include + +constexpr bool test() { + // - difference_type + { + using Iter = std::ranges::iterator_t>; + std::ranges::repeat_view v(0); + Iter iter = v.begin() + 10; + assert(iter - 5 == v.begin() + 5); + static_assert(std::same_as); + } + + // - + { + // unbound + { + std::ranges::repeat_view v(0); + auto iter1 = v.begin() + 10; + auto iter2 = v.begin() + 5; + assert(iter1 - iter2 == 5); + static_assert(std::same_as); + } + + // bound && signed bound sentinel + { + std::ranges::repeat_view v(0, 20); + auto iter1 = v.begin() + 10; + auto iter2 = v.begin() + 5; + assert(iter1 - iter2 == 5); + static_assert(std::same_as); + } + + // bound && unsigned bound sentinel + { + std::ranges::repeat_view v(0, 20); + auto iter1 = v.begin() + 10; + auto iter2 = v.begin() + 5; + assert(iter1 - iter2 == 5); + static_assert(sizeof(decltype(iter1 - iter2)) > sizeof(unsigned)); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus_eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus_eq.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus_eq.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr iterator& operator-=(difference_type n); + +#include +#include +#include + +constexpr bool test() { + using Iter = std::ranges::iterator_t>; + std::ranges::repeat_view v(10); + auto iter = v.begin() + 10; + iter -= 5; + assert(iter == v.begin() + 5); + + static_assert(std::same_as); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// friend constexpr iterator operator+(iterator i, difference_type n); +// friend constexpr iterator operator+(difference_type n, iterator i); + +#include +#include +#include + +constexpr bool test() { + std::ranges::repeat_view v(10); + using Iter = std::ranges::iterator_t>; + auto iter = v.begin(); + assert(iter + 5 == v.begin() + 5); + assert(5 + iter == v.begin() + 5); + assert(2 + iter == v.begin() + 2); + assert(3 + iter == v.begin() + 3); + + static_assert(std::same_as); + static_assert(std::same_as); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus_eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus_eq.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus_eq.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr iterator& operator+=(difference_type n); + +#include +#include +#include + +constexpr bool test() { + std::ranges::repeat_view v(10); + using Iter = std::ranges::iterator_t>; + auto iter1 = v.begin() + 10; + auto iter2 = v.begin() + 10; + assert(iter1 == iter2); + iter1 += 5; + assert(iter1 != iter2); + assert(iter1 == iter2 + 5); + + static_assert(std::same_as); + assert(std::addressof(iter2) == std::addressof(iter2 += 5)); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/star.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/star.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/star.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr const W & operator*() const noexcept; + +#include +#include +#include + +constexpr bool test() { + // unbound + { + std::ranges::repeat_view v(31); + auto iter = v.begin(); + + const int& val = *iter; + for (int i = 0; i < 100; ++i, ++iter) { + assert(*iter == 31); + assert(&*iter == &val); + } + + static_assert(noexcept(*iter)); + static_assert(std::same_as); + } + + // bound && one element + { + std::ranges::repeat_view v(31, 1); + auto iter = v.begin(); + assert(*iter == 31); + static_assert(noexcept(*iter)); + static_assert(std::same_as); + } + + // bound && several elements + { + std::ranges::repeat_view v(31, 100); + auto iter = v.begin(); + + const int& val = *iter; + for (int i = 0; i < 100; ++i, ++iter) { + assert(*iter == 31); + assert(&*iter == &val); + } + } + + // bound && foreach + { + for (const auto& val : std::views::repeat(31, 100)) + assert(val == 31); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/subscript.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/subscript.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr const W & operator[](difference_type n) const noexcept; + +#include +#include +#include +#include + +constexpr bool test() { + // unbound + { + std::ranges::repeat_view v(31); + auto iter = v.begin(); + assert(std::ranges::all_of(std::views::iota(0, 100), [&v](int i) { return v[i] == 31; })); + + static_assert(noexcept(iter[0])); + static_assert(std::same_as); + } + + // bound + { + std::ranges::repeat_view v(32); + auto iter = v.begin(); + assert(std::ranges::all_of(v, [](int i) { return i == 32; })); + static_assert(noexcept(iter[0])); + static_assert(std::same_as); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/size.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/size.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/size.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr auto size() const requires (!same_as); + +#include +#include +#include +#include +#include + +template +concept has_size = requires(T&& view) { + { std::forward(view).size() }; +}; + +static_assert(has_size>); +static_assert(!has_size>); +static_assert(!has_size>); + +constexpr bool test() { + { + std::ranges::repeat_view rv(10, 20); + assert(rv.size() == 20); + } + + { + std::ranges::repeat_view rv(10, std::numeric_limits::max()); + assert(rv.size() == std::numeric_limits::max()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/views_repeat.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/views_repeat.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/views_repeat.pass.cpp @@ -0,0 +1,122 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// views::repeat(T &&) requires constructible_from, T>; + +// templaye +// views::repeat(T &&, Bound &&) requires constructible_from, T, Bound>; + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" + +struct NonCopyable { + NonCopyable(NonCopyable&) = delete; +}; + +struct NonDefaultCtor { + NonDefaultCtor(int) {} +}; + +struct Empty {}; + +struct LessThan3 { + constexpr bool operator()(int i) const { return i < 3; } +}; + +struct EqualTo33 { + constexpr bool operator()(int i) const { return i == 33; } +}; + +struct Add3 { + constexpr int operator()(int i) const { return i + 3; } +}; + +// Tp is_object +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); + +// _Bound is semiregular, integer like or std::unreachable_sentinel_t +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +// Tp is copy_constructible +static_assert(!std::is_invocable_v); + +// Tp is move_constructible +static_assert(std::is_invocable_v); + +constexpr bool test() { + assert(*std::views::repeat(33).begin() == 33); + assert(*std::views::repeat(33, 10).begin() == 33); + static_assert(std::same_as>); + static_assert(std::same_as>); + static_assert(std::same_as); + + // unbound && drop_view + { + auto r = std::views::repeat(33) | std::views::drop(3); + static_assert(!std::ranges::sized_range); + assert(*r.begin() == 33); + } + + // bound && drop_view + { + auto r = std::views::repeat(33, 8) | std::views::drop(3); + static_assert(std::ranges::sized_range); + assert(*r.begin() == 33); + assert(r.size() == 5); + } + + // unbound && take_view + { + auto r = std::views::repeat(33) | std::views::take(3); + static_assert(std::ranges::sized_range); + assert(*r.begin() == 33); + assert(r.size() == 3); + } + + // bound && take_view + { + auto r = std::views::repeat(33, 8) | std::views::take(3); + static_assert(std::ranges::sized_range); + assert(*r.begin() == 33); + assert(r.size() == 3); + } + + // bound && transform_view + { + auto r = std::views::repeat(33, 8) | std::views::transform(Add3{}); + assert(*r.begin() == 36); + assert(r.size() == 8); + } + + // unbound && transform_view + { + auto r = std::views::repeat(33) | std::views::transform(Add3{}); + assert(*r.begin() == 36); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -816,6 +816,11 @@ "headers": ["ranges"], "unimplemented": True, }, + { + "name": "__cpp_lib_ranges_repeat", + "values": { "c++23": 202207}, + "headers": ["ranges"], + }, { "name": "__cpp_lib_ranges_slide", "values": {"c++23": 202202},