diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -348,6 +348,8 @@ --------------------------------------------------- ----------------- ``__cpp_lib_ranges_chunk_by`` ``202202L`` --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_enumerate`` ``202302L`` + --------------------------------------------------- ----------------- ``__cpp_lib_ranges_iota`` *unimplemented* --------------------------------------------------- ----------------- ``__cpp_lib_ranges_join_with`` *unimplemented* 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 @@ -105,7 +105,7 @@ "","","","","","","" "`P0290R4 `__","LWG", "``apply()`` for ``synchronized_value``","February 2023","","","|concurrency TS|" "`P2770R0 `__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","","","|ranges|" -"`P2164R9 `__","LWG", "``views::enumerate``","February 2023","","","|ranges|" +"`P2164R9 `__","LWG", "``views::enumerate``","February 2023","|Complete|","18.0","|ranges|" "`P2711R1 `__","LWG", "Making multi-param constructors of ``views`` ``explicit``","February 2023","|Partial| [#note-P2711R1]_","","|ranges|" "`P2609R3 `__","LWG", "Relaxing Ranges Just A Smidge","February 2023","","","|ranges|" "`P2713R1 `__","LWG", "Escaping improvements in ``std::format``","February 2023","","","|format|" diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -8,8 +8,8 @@ "`3903 `__","span destructor is redundantly noexcept","Varna June 2023","|Complete|","7.0","" "`3904 `__","``lazy_split_view::outer-iterator``'s const-converting constructor isn't setting ``trailing_empty_``","Varna June 2023","","","|ranges|" "`3905 `__","Type of ``std::fexcept_t``","Varna June 2023","|Complete|","3.4","" -"`3912 `__","``enumerate_view::iterator::operator-`` should be ``noexcept``","Varna June 2023","","","|ranges|" -"`3914 `__","Inconsistent template-head of ``ranges::enumerate_view``","Varna June 2023","","","|ranges|" +"`3912 `__","``enumerate_view::iterator::operator-`` should be ``noexcept``","Varna June 2023","|Complete|","18.0","|ranges|" +"`3914 `__","Inconsistent template-head of ``ranges::enumerate_view``","Varna June 2023","|Complete|","18.0","|ranges|" "`3915 `__","Redundant paragraph about expression variations","Varna June 2023","","","|ranges|" "`3925 `__","Concept ``formattable``'s definition is incorrect","Varna June 2023","|Complete|","17.0","|format|" "`3927 `__","Unclear preconditions for ``operator[]`` for sequence containers","Varna June 2023","|Nothing To Do|","","" 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 @@ -35,4 +35,4 @@ C++23,`as_const `_,Unassigned,No patch yet,Not started C++23,`as_rvalue `_,Nikolas Klauser,`D137637 `_,✅ C++23,`stride `_,Hristo Hristov and Will Hawkins,`D156924 `_,In Progress -C++23,`enumerate `_,Hristo Hristov,`D157193 `_,In Progress +C++23,`enumerate `_,Hristo Hristov,`D157193 `_,✅ diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -619,6 +619,7 @@ __ranges/empty_view.h __ranges/enable_borrowed_range.h __ranges/enable_view.h + __ranges/enumerate_view.h __ranges/filter_view.h __ranges/from_range.h __ranges/iota_view.h diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/enumerate_view.h @@ -0,0 +1,333 @@ +// -*- 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_ENUMERATE_VIEW_H +#define _LIBCPP___RANGES_ENUMERATE_VIEW_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iter_move.h> +#include <__iterator/iterator_traits.h> +#include <__ranges/access.h> +#include <__ranges/all.h> +#include <__ranges/concepts.h> +#include <__ranges/enable_borrowed_range.h> +#include <__ranges/range_adaptor.h> +#include <__ranges/size.h> +#include <__ranges/view_interface.h> +#include <__type_traits/maybe_const.h> +#include <__utility/forward.h> +#include <__utility/move.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 { + +// [concept.object] + +template +concept __range_with_movable_references = + ranges::input_range<_Rp> && std::move_constructible> && + std::move_constructible>; + +// [range.enumerate.view] + +template + requires __range_with_movable_references<_View> +class enumerate_view : public view_interface> { + _View __base_ = _View(); + + // [range.enumerate.iterator] + template + class __iterator; + + // [range.enumerate.sentinel] + template + class __sentinel; + + template + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __get_current(const __iterator<_AnyConst>& __iter) { + return (__iter.__current_); + } + +public: + _LIBCPP_HIDE_FROM_ABI constexpr enumerate_view() + requires(default_initializable<_View>) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr explicit enumerate_view(_View __base) : __base_(std::move(__base)){}; + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() + requires(!__simple_view<_View>) + { + return __iterator(ranges::begin(__base_), 0); + } + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + requires __range_with_movable_references + { + return __iterator(ranges::begin(__base_), 0); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() + requires(!__simple_view<_View>) + { + if constexpr (common_range<_View> && sized_range<_View>) + return __iterator(ranges::end(__base_), ranges::distance(__base_)); + else + return __sentinel(ranges::end(__base_)); + } + _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + requires __range_with_movable_references + { + if constexpr (common_range && sized_range) + return __iterator(ranges::end(__base_), ranges::distance(__base_)); + else + return __sentinel(ranges::end(__base_)); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto size() + requires sized_range<_View> + { + return ranges::size(__base_); + } + _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + requires sized_range + { + return ranges::size(__base_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + requires copy_constructible<_View> + { + return __base_; + } + _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } +}; + +template +enumerate_view(_Range&&) -> enumerate_view>; + +// [range.enumerate.iterator] + +template + requires __range_with_movable_references<_View> +template +class enumerate_view<_View>::__iterator { + using _Base = __maybe_const<_Const, _View>; + + 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 if constexpr (forward_range<_Base>) { + return forward_iterator_tag{}; + } else { + return input_iterator_tag{}; + } + } + + friend class enumerate_view<_View>; + +public: + using iterator_category = input_iterator_tag; + using iterator_concept = decltype(__get_iterator_concept()); + using difference_type = range_difference_t<_Base>; + using value_type = tuple>; + +private: + using __reference_type = tuple>; + iterator_t<_Base> __current_ = iterator_t<_Base>(); + difference_type __pos_ = 0; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(iterator_t<_Base> __current, difference_type __pos) + : __current_(std::move(__current)), __pos_(__pos) {} + +public: + _LIBCPP_HIDE_FROM_ABI __iterator() + requires(default_initializable>) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator __i) + requires _Const && convertible_to, iterator_t<_Base>> + : __current_(std::move(__i.__current_)), __pos_(__i.__pos_) {} + + _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_Base>& base() const& noexcept { return __current_; } + _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); } + + _LIBCPP_HIDE_FROM_ABI constexpr difference_type index() const noexcept { return __pos_; } + + _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { return __reference_type(__pos_, *__current_); } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { + ++__current_; + ++__pos_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { return ++*this; } + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) + requires forward_range<_Base> + { + auto __temp = *this; + ++*this; + return __temp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--() + requires bidirectional_range<_Base> + { + --__current_; + --__pos_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int) + requires bidirectional_range<_Base> + { + auto __temp = *this; + --*this; + return *__temp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n) + requires random_access_range<_Base> + { + __current_ += __n; + __pos_ += __n; + return *this; + } + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n) + requires random_access_range<_Base> + { + __current_ -= __n; + __pos_ -= __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const + requires random_access_range<_Base> + { + return __reference_type(__pos_ + __n, __current_[__n]); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) noexcept { + return __x.__pos_ == __y.__pos_; + } + _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering + operator<=>(const __iterator& __x, const __iterator& __y) noexcept { + return __x.__pos_ <=> __y.__pos_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n) + requires random_access_range<_Base> + { + auto __temp = __i; + __temp += __n; + return __temp; + } + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i) + requires random_access_range<_Base> + { + return __i + __n; + } + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n) + requires random_access_range<_Base> + { + auto __temp = __i; + __temp -= __n; + return __temp; + } + _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(const __iterator& __x, const __iterator& __y) noexcept { + return __x.__pos_ - __y.__pos_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept( + noexcept(ranges::iter_move(__i.__current_)) && is_nothrow_move_constructible_v>) { + return tuple>(__i.__pos_, ranges::iter_move(__i.__current_)); + } +}; + +// [range.enumerate.sentinel] + +template + requires __range_with_movable_references<_View> +template +class enumerate_view<_View>::__sentinel { + using _Base = __maybe_const<_Const, _View>; + sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {} + + friend class enumerate_view<_View>; + +public: + _LIBCPP_HIDE_FROM_ABI __sentinel() = default; + _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel __other) + requires _Const && convertible_to, sentinel_t<_Base>> + : __end_(std::move(__other.__end_)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; } + + template + requires sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) { + return __get_current(__x) == __y.__end_; + } + + template + requires sized_sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> + _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> + operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) { + return __get_current(__x) - __y.__end_; + } + + template + requires sized_sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> + _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> + operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) { + return __x.__end_ - __get_current(__y); + } +}; + +template +constexpr bool enable_borrowed_range> = enable_borrowed_range<_View>; + +namespace views { +namespace __enumerate { + +struct __fn : __range_adaptor_closure<__fn> { + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const + noexcept(noexcept(/**/ enumerate_view(std::forward<_Range>(__range)))) + -> decltype(/*--*/ enumerate_view(std::forward<_Range>(__range))) { + return /*-------------*/ enumerate_view(std::forward<_Range>(__range)); + } +}; + +} // namespace __enumerate + +inline namespace __cpo { + +inline constexpr auto enumerate = __enumerate::__fn{}; + +} // namespace __cpo +} // namespace views +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_ENUMERATE_VIEW_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1680,6 +1680,7 @@ module std_private_ranges_empty_view [system] { header "__ranges/empty_view.h" } module std_private_ranges_enable_borrowed_range [system] { header "__ranges/enable_borrowed_range.h" } module std_private_ranges_enable_view [system] { header "__ranges/enable_view.h" } +module std_private_ranges_enumerate_view [system] { header "__ranges/enumerate_view.h" } module std_private_ranges_filter_view [system] { header "__ranges/filter_view.h" export std_private_ranges_range_adaptor diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -314,6 +314,17 @@ namespace views { template inline constexpr unspecified istream = unspecified; } + // [range.enumerate], enumerate view + template + requires see below + class enumerate_view; // since C++23 + + template + constexpr bool enable_borrowed_range> = // since C++23 + enable_borrowed_range; + + namespace views { inline constexpr unspecified enumerate = unspecified; } // since C++23 + // [range.zip], zip view template requires (view && ...) && (sizeof...(Views) > 0) @@ -393,6 +404,7 @@ #include <__ranges/empty_view.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> +#include <__ranges/enumerate_view.h> #include <__ranges/filter_view.h> #include <__ranges/from_range.h> #include <__ranges/iota_view.h> diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -156,6 +156,7 @@ __cpp_lib_ranges_as_rvalue 202207L __cpp_lib_ranges_chunk 202202L __cpp_lib_ranges_chunk_by 202202L +__cpp_lib_ranges_enumerate 202302L __cpp_lib_ranges_iota 202202L __cpp_lib_ranges_join_with 202202L __cpp_lib_ranges_repeat 202207L @@ -436,6 +437,7 @@ # define __cpp_lib_ranges_as_rvalue 202207L // # define __cpp_lib_ranges_chunk 202202L # define __cpp_lib_ranges_chunk_by 202202L +# define __cpp_lib_ranges_enumerate 202302L // # define __cpp_lib_ranges_iota 202202L // # define __cpp_lib_ranges_join_with 202202L # define __cpp_lib_ranges_repeat 202207L diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc --- a/libcxx/modules/std/ranges.inc +++ b/libcxx/modules/std/ranges.inc @@ -320,9 +320,8 @@ namespace views { using std::ranges::views::chunk_by; } -#endif // _LIBCPP_STD_VER >= 23 -#if 0 +# if 0 // [range.stride], stride view using std::ranges::stride_view; @@ -335,7 +334,15 @@ namespace views { using std::ranges::views::cartesian_product; } -#endif +# endif + + // [range.enumerate] + using std::ranges::enumerate_view; + + namespace views { + using std::ranges::views::enumerate; + } +#endif // _LIBCPP_STD_VER >= 23 } // namespace ranges namespace views = ranges::views; diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp @@ -20,6 +20,7 @@ __cpp_lib_ranges_as_rvalue 202207L [C++23] __cpp_lib_ranges_chunk 202202L [C++23] __cpp_lib_ranges_chunk_by 202202L [C++23] + __cpp_lib_ranges_enumerate 202302L [C++23] __cpp_lib_ranges_join_with 202202L [C++23] __cpp_lib_ranges_repeat 202207L [C++23] __cpp_lib_ranges_slide 202202L [C++23] @@ -48,6 +49,10 @@ # error "__cpp_lib_ranges_chunk_by should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_join_with # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif @@ -86,6 +91,10 @@ # error "__cpp_lib_ranges_chunk_by should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_join_with # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif @@ -124,6 +133,10 @@ # error "__cpp_lib_ranges_chunk_by should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_join_with # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif @@ -165,6 +178,10 @@ # error "__cpp_lib_ranges_chunk_by should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_join_with # error "__cpp_lib_ranges_join_with should not be defined before c++23" # endif @@ -221,6 +238,13 @@ # error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++23" # endif +# ifndef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should be defined in c++23" +# endif +# if __cpp_lib_ranges_enumerate != 202302L +# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++23" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_join_with # error "__cpp_lib_ranges_join_with should be defined in c++23" @@ -310,6 +334,13 @@ # error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++26" # endif +# ifndef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should be defined in c++26" +# endif +# if __cpp_lib_ranges_enumerate != 202302L +# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_join_with # error "__cpp_lib_ranges_join_with 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 @@ -144,6 +144,7 @@ __cpp_lib_ranges_as_rvalue 202207L [C++23] __cpp_lib_ranges_chunk 202202L [C++23] __cpp_lib_ranges_chunk_by 202202L [C++23] + __cpp_lib_ranges_enumerate 202302L [C++23] __cpp_lib_ranges_iota 202202L [C++23] __cpp_lib_ranges_join_with 202202L [C++23] __cpp_lib_ranges_repeat 202207L [C++23] @@ -701,6 +702,10 @@ # error "__cpp_lib_ranges_chunk_by should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_iota # error "__cpp_lib_ranges_iota should not be defined before c++23" # endif @@ -1459,6 +1464,10 @@ # error "__cpp_lib_ranges_chunk_by should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_iota # error "__cpp_lib_ranges_iota should not be defined before c++23" # endif @@ -2388,6 +2397,10 @@ # error "__cpp_lib_ranges_chunk_by should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_iota # error "__cpp_lib_ranges_iota should not be defined before c++23" # endif @@ -3587,6 +3600,10 @@ # error "__cpp_lib_ranges_chunk_by should not be defined before c++23" # endif +# ifdef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should not be defined before c++23" +# endif + # ifdef __cpp_lib_ranges_iota # error "__cpp_lib_ranges_iota should not be defined before c++23" # endif @@ -4978,6 +4995,13 @@ # error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++23" # endif +# ifndef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should be defined in c++23" +# endif +# if __cpp_lib_ranges_enumerate != 202302L +# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++23" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_iota # error "__cpp_lib_ranges_iota should be defined in c++23" @@ -6519,6 +6543,13 @@ # error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++26" # endif +# ifndef __cpp_lib_ranges_enumerate +# error "__cpp_lib_ranges_enumerate should be defined in c++26" +# endif +# if __cpp_lib_ranges_enumerate != 202302L +# error "__cpp_lib_ranges_enumerate should have the value 202302L in c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_ranges_iota # error "__cpp_lib_ranges_iota should be defined in c++26" diff --git a/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp b/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp --- a/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp +++ b/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp @@ -76,4 +76,5 @@ #if TEST_STD_VER >= 23 static_assert(!CanFindADLFunc>); +static_assert(!CanFindADLFunc>); #endif diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/adaptor.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// std::views::enumerate; + +#include +#include +#include +#include + +#include "types.h" + +// Concepts + +template +concept CanBePiped = requires(View&& view, T&& t) { + { std::forward(view) | std::forward(t) }; +}; + +// Helpers + +template +using ExpectedViewElement = std::tuple::difference_type, T>; + +template +constexpr void compareViews(View v, std::initializer_list> list) { + assert(std::ranges::equal(v, list)); +} + +// Test SFINAE friendliness + +static_assert(CanBePiped); + +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +static_assert(std::is_same_v); + +constexpr bool test() { + // Test `views::enumerate_view(v)` + { + int buff[] = {0, 1, 2, 3}; + + using Result = std::ranges::enumerate_view; + RangeView const range(buff, buff + 4); + + std::same_as decltype(auto) result = std::views::enumerate(range); + compareViews(result, {{0, 0}, {1, 1}, {2, 2}, {3, 3}}); + } + { + std::string_view sv{"babazmt"}; + using Result = std::ranges::enumerate_view; + + std::same_as decltype(auto) result = std::views::enumerate(sv); + compareViews(result, {{0, 'b'}, {1, 'a'}, {2, 'b'}, {3, 'a'}, {4, 'z'}, {5, 'm'}, {6, 't'}}); + } + + // Test `adaptor | views::enumerate` + { + int buff[] = {0, 1, 2, 3}; + + using Result = std::ranges::enumerate_view; + RangeView const range(buff, buff + 4); + + std::same_as decltype(auto) result = range | std::views::enumerate; + compareViews(result, {{0, 0}, {1, 1}, {2, 2}, {3, 3}}); + } + { + std::string_view sv{"babazmt"}; + using Result = std::ranges::enumerate_view; + + std::same_as decltype(auto) result = sv | std::views::enumerate; + compareViews(result, {{0, 'b'}, {1, 'a'}, {2, 'b'}, {3, 'a'}, {4, 'z'}, {5, 'm'}, {6, 't'}}); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/base.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// constexpr V base() const & requires copy_constructible; +// constexpr V base() &&; + +#include +#include + +#include "types.h" + +constexpr bool test() { + // Check the const& overload + { + int buff[] = {0, 1, 2, 3}; + + RangeView range(buff, buff + 4); + + std::ranges::enumerate_view view{range}; + std::same_as decltype(auto) result = view.base(); + assert(result.wasCopyInitialized); + assert(range.begin() == result.begin()); + assert(range.end() == result.end()); + } + { + int buff[] = {0, 1, 2, 3}; + + RangeView const range(buff, buff + 4); + + std::ranges::enumerate_view const view{range}; + std::same_as decltype(auto) result = view.base(); + assert(result.wasCopyInitialized); + assert(range.begin() == result.begin()); + assert(range.end() == result.end()); + } + + // Check the && overload + { + int buff[] = {0, 1, 2, 3}; + + RangeView const range(buff, buff + 4); + + std::ranges::enumerate_view view{range}; + std::same_as decltype(auto) result = std::move(view).base(); + assert(result.wasMoveInitialized); + assert(range.begin() == result.begin()); + assert(range.end() == result.end()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/begin.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// constexpr auto begin() requires (!simple-view); +// constexpr auto begin() const requires range-with-movable-references; + +#include +#include +#include + +#include "test_iterators.h" +#include "types.h" + +constexpr bool test() { + int buff[] = {1, 2, 3, 4, 5, 6, 7, 8}; + + // Check the return type of `.begin()` + { + RangeView range(buff, buff + 1); + + std::ranges::enumerate_view view(range); + using Iterator = std::ranges::iterator_t; + static_assert(std::same_as); + } + + // begin() over an empty range + { + RangeView range(buff, buff); + + std::ranges::enumerate_view view(range); + auto it = view.begin(); + assert(base(it.base()) == buff); + assert(it == view.end()); + } + + // begin() over an 1-element range + { + RangeView range(buff, buff + 1); + + std::ranges::enumerate_view view(range); + auto it = view.begin(); + assert(base(it.base()) == buff); + } + + // begin() over an N-element range + { + RangeView range(buff, buff + 8); + + std::ranges::enumerate_view view(range); + auto it = view.begin(); + assert(base(it.base()) == buff); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctad.compile.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class enumerate_view + +// template +// enumerate_view(R&&) -> enumerate_view>; + +#include +#include + +#include "test_iterators.h" +#include "types.h" + +constexpr bool test() { + { + MinimalDefaultConstructedView jv; + std::ranges::enumerate_view view(jv); + static_assert(std::is_same_v>); + } + + // Test with a range that isn't a view, to make sure we properly use views::all_t in the implementation. + { + NotAViewRange range; + std::ranges::enumerate_view view(range); + static_assert(std::is_same_v>>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.base.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.base.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 + +// + +// class enumerate_view + +// constexpr explicit enumerate_view(V base); + +#include + +#include +#include +#include + +constexpr int buff[] = {0, 1}; + +struct DefaultConstructibleView : std::ranges::view_base { + constexpr DefaultConstructibleView() : begin_(buff), end_(buff + 1) {} + constexpr int const* begin() const { return begin_; } + constexpr int const* end() const { return end_; } + + int const* begin_; + int const* end_; +}; + +template +struct DefaultInitializableView : std::ranges::view_base { + constexpr explicit DefaultInitializableView() + requires DefaultInitializable + = default; + + int* begin() const; + int* end() const; +}; + +struct NoDefaultView : std::ranges::view_base { + NoDefaultView() = delete; + + int* begin() const; + int* end() const; +}; + +// SFINAE + +static_assert(!std::is_default_constructible_v>); +static_assert(std::is_default_constructible_v>>); +static_assert(!std::is_default_constructible_v>>); + +constexpr bool test() { + using EnumerateView = std::ranges::enumerate_view; + + { + EnumerateView view; + + assert((*view.begin() == std::tuple::difference_type, int>{0, 0})); + assert((*view.end() == std::tuple::difference_type, int>{1, 1})); + + auto [bi, bv] = *view.begin(); + assert(bi == 0); + assert(bv == 0); + + auto [ei, ev] = *view.end(); + assert(ei == 1); + assert(ev == 1); + } + + { + EnumerateView view = {}; + + assert((*view.begin() == std::tuple::difference_type, int>{0, 0})); + assert((*view.end() == std::tuple::difference_type, int>{1, 1})); + + auto [bi, bv] = *view.begin(); + assert(bi == 0); + assert(bv == 0); + + auto [ei, ev] = *view.end(); + assert(ei == 1); + assert(ev == 1); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/ctor.default.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// constexpr enumerate_view() requires default_initializable; + +#include + +#include +#include +#include + +constexpr int buff[] = {0, 1}; + +struct DefaultConstructibleView : std::ranges::view_base { + constexpr DefaultConstructibleView() : begin_(buff), end_(buff + 1) {} + constexpr int const* begin() const { return begin_; } + constexpr int const* end() const { return end_; } + + int const* begin_; + int const* end_; +}; + +template +struct DefaultInitializableView : std::ranges::view_base { + constexpr explicit DefaultInitializableView() + requires DefaultInitializable + = default; + + int* begin() const; + int* end() const; +}; + +struct NoDefaultView : std::ranges::view_base { + NoDefaultView() = delete; + + int* begin() const; + int* end() const; +}; + +// SFINAE + +static_assert(!std::is_default_constructible_v>); +static_assert(std::is_default_constructible_v>>); +static_assert(!std::is_default_constructible_v>>); + +constexpr bool test() { + using EnumerateView = std::ranges::enumerate_view; + + { + EnumerateView view; + + assert((*view.begin() == std::tuple::difference_type, int>{0, 0})); + assert((*view.end() == std::tuple::difference_type, int>{1, 1})); + + auto [bi, bv] = *view.begin(); + assert(bi == 0); + assert(bv == 0); + + auto [ei, ev] = *view.end(); + assert(ei == 1); + assert(ev == 1); + } + { + EnumerateView view = {}; + + assert((*view.begin() == std::tuple::difference_type, int>{0, 0})); + assert((*view.end() == std::tuple::difference_type, int>{1, 1})); + + auto [bi, bv] = *view.begin(); + assert(bi == 0); + assert(bv == 0); + + auto [ei, ev] = *view.end(); + assert(ei == 1); + assert(ev == 1); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/enable_borrowed_range.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/enable_borrowed_range.compile.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// template +// constexpr bool enable_borrowed_range>; + +#include +#include + +struct NonBorrowedRange : std::ranges::view_base { + int* begin(); + int* end(); +}; + +struct BorrowedRange : std::ranges::view_base { + int* begin(); + int* end(); +}; + +template <> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +static_assert(!std::ranges::borrowed_range>); +static_assert(std::ranges::borrowed_range>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/end.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// constexpr auto end() requires (!simple-view); +// constexpr auto end() const requires range-with-movable-references; + +#include +#include +#include + +#include "test_iterators.h" +#include "types.h" + +constexpr bool test() { + int buff[] = {1, 2, 3, 4, 5, 6, 7, 8}; + + // Check the return type of `.end()` + { + RangeView range(buff, buff + 1); + + std::ranges::enumerate_view view(range); + using Iterator = std::ranges::iterator_t; + static_assert(std::same_as); + } + + // end() over an empty range + { + RangeView range(buff, buff); + + std::ranges::enumerate_view view(range); + auto it = view.end(); + assert(base(it.base()) == buff); + assert(it == view.end()); + } + + // end() over an 1-element range + { + RangeView range(buff, buff + 1); + + std::ranges::enumerate_view view(range); + auto it = view.end(); + assert(base(it.base()) == buff + 1); + } + + // end() over an N-element range + { + RangeView range(buff, buff + 8); + + std::ranges::enumerate_view view(range); + auto it = view.end(); + assert(base(it.base()) == buff + 8); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/arithmetic.pass.cpp @@ -0,0 +1,127 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// constexpr iterator& operator+=(difference_type x) +// requires random_access_range; +// constexpr iterator& operator-=(difference_type x) +// requires random_access_range; + +// friend constexpr iterator operator+(const iterator& x, difference_type y) +// requires random_access_range; +// friend constexpr iterator operator+(difference_type x, const iterator& y) +// requires random_access_range; +// friend constexpr iterator operator-(const iterator& x, difference_type y) +// requires random_access_range; +// friend constexpr difference_type operator-(const iterator& x, const iterator& y); + +#include + +#include "test_iterators.h" + +// Concepts + +template +concept CanPlus = requires(T t, U u) { t + u; }; + +template +concept CanPlusEqual = requires(T t, U u) { t += u; }; + +template +concept CanMinus = requires(T t, U u) { t - u; }; + +template +concept CanMinusEqual = requires(T t, U u) { t -= u; }; + +template +using EnumerateIter = std::ranges::iterator_t>; + +using RandomAccessRange = std::ranges::subrange; + +// SFINAE. + +static_assert(std::ranges::random_access_range); +static_assert( + std::sized_sentinel_for, std::ranges::iterator_t>); + +static_assert(CanPlus, int>); +static_assert(CanPlus>); +static_assert(CanPlusEqual, int>); +static_assert(CanMinus, int>); +static_assert(CanMinus, EnumerateIter>); +static_assert(CanMinusEqual, int>); + +using BidirectionalRange = std::ranges::subrange>; +static_assert(!std::ranges::random_access_range); +static_assert( + !std::sized_sentinel_for, std::ranges::iterator_t>); + +static_assert(!CanPlus, int>); +static_assert(!CanPlus>); +static_assert(!CanPlusEqual, int>); +static_assert(!CanMinus, int>); +static_assert(!CanMinusEqual, int>); + +constexpr bool test() { + int ts[] = {1, 2, 3, 4, 5}; + + RandomAccessRange r{ts, ts + 5}; + auto ev = r | std::views::enumerate; + + // operator+(x, n), operator+(n,x) and operator+= + { + auto it1 = ev.begin(); + + auto it2 = it1 + 3; + assert(it2.base() == &ts[3]); + + auto it3 = 3 + it1; + assert(it3.base() == &ts[3]); + + it1 += 3; + assert(it1 == it2); + assert(it1.base() == &ts[3]); + } + + // operator-(x, n) and operator-= + { + auto it1 = ev.end(); + + auto it2 = it1 - 4; + assert(it2.base() == &ts[1]); + + it1 -= 4; + assert(it1 == it2); + assert(it1.base() == &ts[1]); + } + + // operator-(x, y) + { + assert((ev.end() - ev.begin()) == 5); + + auto it1 = ev.begin() + 2; + auto it2 = ev.end() - 2; + assert((it1 - it2) == -1); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/base.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// constexpr const iterator_t& base() const & noexcept; +// constexpr iterator_t base() &&; + +#include + +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +template +constexpr void testBase() { + using Sentinel = sentinel_wrapper; + using View = MinimalView; + using EnumerateView = std::ranges::enumerate_view; + using EnumerateIterator = std::ranges::iterator_t; + + auto make_enumerate_view = [](auto begin, auto end) { + View view{Iterator(begin), Sentinel(Iterator(end))}; + + return EnumerateView(std::move(view)); + }; + + std::array array{0, 1, 2, 3, 84}; + const auto view = make_enumerate_view(array.begin(), array.end()); + + // Test the const& version + { + EnumerateIterator const it = view.begin(); + std::same_as decltype(auto) result = it.base(); + ASSERT_NOEXCEPT(it.base()); + assert(base(result) == array.begin()); + } + + // Test the && version + { + EnumerateIterator it = view.begin(); + std::same_as decltype(auto) result = std::move(it).base(); + assert(base(result) == array.begin()); + } +} + +constexpr bool test() { + testBase>(); + testBase>(); + testBase>(); + testBase>(); + testBase>(); + testBase>(); + testBase(); + testBase(); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/compare.three_way.pass.cpp @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// friend constexpr strong_ordering operator<=>(const iterator& x, const iterator& y) noexcept; + +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +constexpr void compareOperatorTest(const auto& iter1, const auto& 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)); +} + +constexpr bool test() { + int buff[] = {0, 1, 2, 3}; + { + using View = std::ranges::enumerate_view; + RangeView const range(buff, buff + 4); + + std::same_as decltype(auto) ev = std::views::enumerate(range); + + auto it1 = ev.begin(); + auto it2 = it1 + 1; + + compareOperatorTest(it1, it2); + + assert((it1 <=> it2) == std::strong_ordering::less); + assert((it1 <=> it1) == std::strong_ordering::equal); + assert((it2 <=> it2) == std::strong_ordering::equal); + assert((it2 <=> it1) == std::strong_ordering::greater); + } + + // Test an old-school iterator with no operator<=> + { + using Iterator = random_access_iterator; + static_assert(!std::three_way_comparable); + using Subrange = std::ranges::subrange; + static_assert(!std::three_way_comparable>); + using EnumerateView = std::ranges::enumerate_view; + static_assert(std::three_way_comparable>); + + auto ev = Subrange{Iterator{buff}, Iterator{buff + 3}} | std::views::enumerate; + auto it1 = ev.begin(); + auto it2 = it1 + 1; + + compareOperatorTest(it1, it2); + + assert((it1 <=> it2) == std::strong_ordering::less); + assert((it1 <=> it1) == std::strong_ordering::equal); + assert((it2 <=> it2) == std::strong_ordering::equal); + assert((it2 <=> it1) == 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.enumerate/iterator/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.convert.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// constexpr iterator(iterator i) +// requires Const && convertible_to, iterator_t>; + +#include + +#include +#include +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +template > +constexpr void test() { + using View = MinimalView; + using EnumerateView = std::ranges::enumerate_view; + using EnumerateIterator = std::ranges::iterator_t; + using EnumerateConstIterator = std::ranges::iterator_t; + + auto make_enumerate_view = [](auto begin, auto end) { + View view{Iterator(begin), Sentinel(Iterator(end))}; + + return EnumerateView(std::move(view)); + }; + + static_assert(std::is_convertible_v); + + std::array array{0, 84, 2, 3, 4}; + auto view = make_enumerate_view(array.begin(), array.end()); + { + std::same_as decltype(auto) it = view.begin(); + std::same_as decltype(auto) itResult = it.base(); + assert(base(base(itResult)) == array.begin()); + + auto [index, value] = *(++it); + assert(index == 1); + assert(value == 84); + } + { + std::same_as decltype(auto) it = view.begin(); + std::same_as decltype(auto) itResult = it.base(); + assert(base(base(itResult)) == array.begin()); + + auto [index, value] = *(++it); + assert(index == 1); + assert(value == 84); + } +} + +constexpr bool tests() { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test(); + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/ctor.default.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// iterator() requires default_initializable>; + +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +template +constexpr void test_default_constructible() { + using View = MinimalView>; + using EnumerateView = std::ranges::enumerate_view; + using EnumerateIterator = std::ranges::iterator_t; + + EnumerateIterator it1; + EnumerateIterator it2{}; + + assert(it1 == it2); + + static_assert(noexcept(EnumerateIterator()) == IsNoexcept); +} + +template +constexpr void test_not_default_constructible() { + // Make sure the iterator is *not* default constructible when the underlying iterator isn't. + using Sentinel = sentinel_wrapper; + using View = MinimalView; + using EnumerateView = std::ranges::enumerate_view; + using EnumerateIterator = std::ranges::iterator_t; + + static_assert(!std::is_default_constructible_v); +} + +constexpr bool tests() { + // clang-format off + test_not_default_constructible>(); + test_not_default_constructible>(); + test_default_constructible, /* noexcept */ false>(); + test_default_constructible, /* noexcept */ false>(); + test_default_constructible, /* noexcept */ false>(); + test_default_constructible, /* noexcept */ false>(); + test_default_constructible(); + // clang-format on + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/deref.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// constexpr auto operator*() const; + +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "../types.h" + +template > +constexpr void test() { + using View = MinimalView; + using EnumerateView = std::ranges::enumerate_view; + using EnumerateIterator = std::ranges::iterator_t; + + using Result = std::tuple>>; + + auto make_enumerate_view = [](auto begin, auto end) { + View view{Iterator(begin), Sentinel(Iterator(end))}; + return EnumerateView(std::move(view)); + }; + + std::array array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + EnumerateView view = make_enumerate_view(array.begin(), array.end()); + + auto it = view.begin(); + for (std::size_t index = 0; index < array.size(); ++index) { + std::same_as decltype(auto) result = *it; + + auto [resultIndex, resultValue] = result; + assert(std::cmp_equal(index, resultIndex)); + assert(array[index] == resultValue); + + ++it; + } + + assert(it == view.end()); +} + +constexpr bool tests() { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test(); + + test, int const>(); + test, int const>(); + test, int const>(); + test, int const>(); + test, int const>(); + test, int const>(); + test(); + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/equal.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// friend constexpr bool operator==(const iterator& x, const iterator& y) noexcept; + +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +constexpr bool test() { + int buff[] = {0, 1, 2, 3, 5}; + { + using View = std::ranges::enumerate_view; + RangeView const range(buff, buff + 5); + + std::same_as decltype(auto) ev = std::views::enumerate(range); + + auto it1 = ev.begin(); + auto it2 = it1 + 5; + + assert(it1 == it1); + ASSERT_NOEXCEPT(it1 == it1); + assert(it1 != it2); + ASSERT_NOEXCEPT(it1 != it2); + assert(it2 != it1); + ASSERT_NOEXCEPT(it2 != it1); + assert(it2 == ev.end()); + assert(ev.end() == it2); + + for (std::size_t index = 0; index != 5; ++index) { + ++it1; + } + + assert(it1 == it2); + assert(it2 == it1); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/index.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// constexpr difference_type index() const noexcept; + +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "../types.h" + +template > +constexpr void test() { + using View = MinimalView; + using EnumerateView = std::ranges::enumerate_view; + + auto make_enumerate_view = [](auto begin, auto end) { + View view{Iterator(begin), Sentinel(Iterator(end))}; + return EnumerateView(std::move(view)); + }; + + std::array array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + EnumerateView view = make_enumerate_view(array.begin(), array.end()); + + auto it = view.begin(); + ASSERT_NOEXCEPT(it.index()); + static_assert(std::same_as); + for (std::size_t index = 0; index < array.size(); ++index) { + assert(std::cmp_equal(index, it.index())); + + ++it; + } + + assert(it == view.end()); +} + +constexpr bool tests() { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test(); + + test, int const>(); + test, int const>(); + test, int const>(); + test, int const>(); + test, int const>(); + test, int const>(); + test(); + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/iter_move.pass.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// friend constexpr auto iter_move(const iterator& i) +// noexcept(noexcept(ranges::iter_move(i.current_)) && +// is_nothrow_move_constructible_v>); + +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" +#include "../types.h" + +template +constexpr void test() { + using Sentinel = sentinel_wrapper; + using View = MinimalView; + using EnumerateView = std::ranges::enumerate_view; + using EnumerateIterator = std::ranges::iterator_t; + + auto make_enumerate_view = [](auto begin, auto end) { + View view{Iterator(begin), Sentinel(Iterator(end))}; + + return EnumerateView(std::move(view)); + }; + + std::array array{0, 1, 2, 3, 4}; + EnumerateView view = make_enumerate_view(array.begin(), array.end()); + EnumerateIterator const it = view.begin(); + + auto&& result = iter_move(it); + + static_assert(std::is_same_v::difference_type, int&&>&&>); + static_assert(std::is_same_v&&>); + + assert(get<0>(result) == 0); + assert(&get<1>(result) == array.begin()); + + static_assert(noexcept(iter_move(it)) == HasNoexceptIterMove); +} + +constexpr bool tests() { + // clang-format off + test, /* noexcept */ false>(); + test, /* noexcept */ false>(); + test, /* noexcept */ false>(); + test, /* noexcept */ false>(); + test, /* noexcept */ false>(); + test, /* noexcept */ false>(); + test(); + test, /* noexcept */ true>(); + test, /* noexcept */ false>(); + // clang-format on + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/subscript.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// constexpr auto operator[](difference_type n) const +// requires random_access_range; + +#include +#include +#include +#include + +#include "test_iterators.h" + +template +concept HasSubscriptOperator = requires(T t, U u) { t[u]; }; + +template +using EnumerateIterator = std::ranges::iterator_t>; + +using RandomAccessRange = std::ranges::subrange; +static_assert(std::ranges::random_access_range); + +static_assert(HasSubscriptOperator, int>); + +using BidirectionalRange = std::ranges::subrange>; +static_assert(!std::ranges::random_access_range); + +static_assert(!HasSubscriptOperator, int>); + +constexpr bool test() { + // Reference + { + std::array ts = {0, 1, 2, 3, 84}; + auto view = ts | std::views::enumerate; + auto it = view.begin(); + + for (std::size_t index = 0; index != ts.size(); ++index) { + assert(it[index] == *(it + index)); + } + + static_assert(std::is_same_v>); + } + + // Value + { + auto view = std::views::iota(0, 5) | std::views::enumerate; + auto it = view.begin(); + + for (std::size_t index = 0; index != 5; ++index) { + assert(it[index] == *(it + index)); + } + + static_assert(std::is_same_v>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/iterator/types.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 + +// + +// class enumerate_view + +// class enumerate_view::iterator + +// std::enumerate_view::::difference_type; +// std::enumerate_view::::value_type; +// std::enumerate_view::::iterator_category; +// std::enumerate_view::::iterator_concept; + +#include + +#include +#include "test_iterators.h" +#include "../types.h" + +template +concept HasIteratorCategory = requires { typename T::iterator_category; }; + +template +using EnumerateViewFor = std::ranges::enumerate_view< MinimalView>>; + +template +using EnumerateIteratorFor = std::ranges::iterator_t>; + +struct ForwardIteratorWithInputCategory { + using difference_type = int; + using value_type = int; + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::forward_iterator_tag; + ForwardIteratorWithInputCategory(); + ForwardIteratorWithInputCategory& operator++(); + ForwardIteratorWithInputCategory operator++(int); + int& operator*() const; + friend bool operator==(ForwardIteratorWithInputCategory, ForwardIteratorWithInputCategory); +}; +static_assert(std::forward_iterator); + +constexpr bool test() { + // Check that value_type is range_value_t and difference_type is range_difference_t + { + auto test = [] { + using EnumerateView = EnumerateViewFor; + using EnumerateIterator = EnumerateIteratorFor; + static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); + }; + test.operator()>(); + test.operator()>(); + test.operator()>(); + test.operator()>(); + test.operator()>(); + test.operator()>(); + test.operator()(); + } + // Check iterator_concept for various categories of ranges + { + static_assert( + std::is_same_v>::iterator_concept, std::input_iterator_tag>); + static_assert( + std::is_same_v>::iterator_concept, std::input_iterator_tag>); + static_assert(std::is_same_v::iterator_concept, + std::forward_iterator_tag>); + static_assert( + std::is_same_v>::iterator_concept, std::forward_iterator_tag>); + static_assert(std::is_same_v>::iterator_concept, + std::bidirectional_iterator_tag>); + static_assert(std::is_same_v>::iterator_concept, + std::random_access_iterator_tag>); + static_assert(std::is_same_v>::iterator_concept, + std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_concept, std::random_access_iterator_tag>); + } + + // Check iterator_category for various categories of ranges + { + static_assert(HasIteratorCategory>>); + static_assert(HasIteratorCategory>>); + static_assert(std::is_same_v::iterator_category, + std::input_iterator_tag>); + static_assert( + std::is_same_v>::iterator_category, std::input_iterator_tag>); + static_assert( + std::is_same_v>::iterator_category, std::input_iterator_tag>); + static_assert( + std::is_same_v>::iterator_category, std::input_iterator_tag>); + static_assert( + std::is_same_v>::iterator_category, std::input_iterator_tag>); + static_assert(std::is_same_v::iterator_category, std::input_iterator_tag>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/base.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class enumerate_view + +// class enumerate_view::sentinel + +// constexpr sentinel_t base() const; + +#include + +#include +#include +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +template > +constexpr void test() { + using View = MinimalView; + using EnumerateView = std::ranges::enumerate_view; + using EnumerateSentinel = std::ranges::sentinel_t; + + auto make_enumerate_view = [](auto begin, auto end) { + View view{Iterator(begin), Sentinel(Iterator(end))}; + + return EnumerateView(std::move(view)); + }; + + std::array array{0, 1, 2, 3, 84}; + auto view = make_enumerate_view(array.begin(), array.end()); + + EnumerateSentinel const s = view.end(); + std::same_as decltype(auto) result = s.base(); + assert(base(base(result)) == array.end()); +} + +constexpr bool tests() { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test(); + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class enumerate_view + +// class enumerate_view::sentinel + +// constexpr sentinel(sentinel other) +// requires Const && convertible_to, sentinel_t>; + +#include + +#include +#include +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +template > +constexpr void test() { + using View = MinimalView; + using EnumerateView = std::ranges::enumerate_view; + using EnumerateSentinel = std::ranges::sentinel_t; + using EnumerateConstSentinel = std::ranges::sentinel_t; + + auto make_enumerate_view = [](auto begin, auto end) { + View view{Iterator(begin), Sentinel(Iterator(end))}; + + return EnumerateView(std::move(view)); + }; + + static_assert(std::is_convertible_v); + + std::array array{0, 1, 2, 3, 84}; + auto view = make_enumerate_view(array.begin(), array.end()); + + std::same_as decltype(auto) s = view.end(); + std::same_as decltype(auto) sResult = s.base(); + assert(base(base(sResult)) == array.end()); + + // Test assignment + EnumerateConstSentinel cs = s; + std::same_as decltype(auto) csResult = cs.base(); + assert(base(base(csResult)) == array.end()); +} + +constexpr bool tests() { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test(); + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.default.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class enumerate_view + +// class enumerate_view::sentinel + +// sentinel() = default; + +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +template +constexpr void test() { + using Sentinel = sentinel_wrapper; + using View = MinimalView; + using EnumerateView = std::ranges::enumerate_view; + using EnumerateSentinel = std::ranges::sentinel_t; + + EnumerateSentinel s1; + EnumerateSentinel s2{}; + + assert(base(base(s1.base())) == base(base(s2.base()))); + + static_assert(noexcept(EnumerateSentinel())); +} + +constexpr bool tests() { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test(); + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class enumerate_view + +// class enumerate_view::sentinel + +// template +// requires sentinel_for, iterator_t>> +// friend constexpr bool operator==(const iterator& x, const sentinel& y); + +#include + +#include +#include +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +template > +constexpr void test() { + using View = MinimalView; + + std::array array{0, 1, 2, 3, 84}; + + View v(Iterator(array.begin()), Sentinel(Iterator(array.end()))); + std::ranges::enumerate_view view(std::move(v)); + + auto const it = view.begin(); + auto const s = view.end(); + + std::same_as decltype(auto) eqResult = (it == s); + assert(!eqResult); + std::same_as decltype(auto) neqResult = (it != s); + assert(neqResult); +} + +constexpr bool tests() { + test>(); + test>(); + test>(); + test>(); + test>(); + test>(); + test(); + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/minus.pass.cpp @@ -0,0 +1,250 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class enumerate_view + +// class enumerate_view::sentinel + +// template +// requires sized_sentinel_for, iterator_t>> +// friend constexpr range_difference_t> +// operator-(const iterator& x, const sentinel& y); + +// template +// requires sized_sentinel_for, iterator_t>> +// friend constexpr range_difference_t> +// operator-(const sentinel& x, const iterator& y); + +#include +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +template +struct Iter { + int* it_; + + using value_type = int; + using difference_type = std::ptrdiff_t; + using iterator_concept = std::input_iterator_tag; + + constexpr decltype(auto) operator*() const { return *it_; } + constexpr Iter& operator++() { + ++it_; + return *this; + } + constexpr void operator++(int) { ++it_; } +}; + +template +struct Sent { + int* end_; + + constexpr bool operator==(const Iter& i) const { return i.it_ == end_; } +}; + +template +struct SizedSent { + int* end_; + + constexpr bool operator==(const Iter& i) const { return i.it_ == end_; } + + friend constexpr auto operator-(const SizedSent& st, const Iter& it) { return st.end_ - it.it_; } + + friend constexpr auto operator-(const Iter& it, const SizedSent& st) { return it.it_ - st.end_; } +}; + +template +struct CrossSizedSent { + int* end_; + + template + constexpr bool operator==(const Iter& i) const { + return i.it_ == end_; + } + + template + friend constexpr auto operator-(const CrossSizedSent& st, const Iter& it) { + return st.end_ - it.it_; + } + + template + friend constexpr auto operator-(const Iter& it, const CrossSizedSent& st) { + return it.it_ - st.end_; + } +}; + +template