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`` *unimplemented* --------------------------------------------------- ----------------- + ``__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 @@ -107,7 +107,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","|Nothing To Do|","","|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,No patch yet,In Progress -C++23,`enumerate `_,Hristo Hristov,No patch yet,In Progress +C++23,`enumerate `_,Hristo Hristov,No patch yet,✅ diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -647,6 +647,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/concepts.h b/libcxx/include/__ranges/concepts.h --- a/libcxx/include/__ranges/concepts.h +++ b/libcxx/include/__ranges/concepts.h @@ -141,6 +141,17 @@ (is_lvalue_reference_v<_Tp> || (movable> && !__is_std_initializer_list>)))); +# if _LIBCPP_STD_VER >= 23 + + // [concept.object] + + template + concept __range_with_movable_references = + ranges::input_range<_Rp> && std::move_constructible> && + std::move_constructible>; // exposition only + +# endif // _LIBCPP_STD_VER >= 23 + } // namespace ranges #endif // _LIBCPP_STD_VER >= 20 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,331 @@ +// -*- 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 { + +// [range.enumerate.view] + +template + requires __range_with_movable_references<_View> +class enumerate_view : public view_interface> { + _View __base_ = _View(); // exposition only + + // [range.enumerate.iterator], class template enumerate_view::iterator + template + class __iterator; // exposition only + + // [range.enumerate.sentinel], class template enumerate_view::sentinel + template + class __sentinel; // exposition only + +public: + 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>; // exposition only + + 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>; // exposition only + iterator_t<_Base> __current_ = iterator_t<_Base>(); // exposition only + difference_type __pos_ = 0; // exposition only + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(iterator_t<_Base> __current, difference_type __pos) + : __current_(std::move(__current)), __pos_(std::move(__pos)) {} // exposition only + +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_(std::move(__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>; // exposition only + sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + _LIBCPP_HIDE_FROM_ABI // exposition only + constexpr explicit __sentinel(sentinel_t<_Base> __end) + : __end_(std::move(__end)) {} // exposition only + + 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 enumerate_view<_View>::__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 enumerate_view<_View>::__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_ - enumerate_view<_View>::__get_current(__y); + } +}; + +template +constexpr bool enable_borrowed_range> = enable_borrowed_range<_View>; // freestanding + +namespace views { +namespace __enumerate { + +// clang-format off +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)); + } +}; +// clang-format on + +} // 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 @@ -1712,6 +1712,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; // freestanding, since C++23 + + template + constexpr bool enable_borrowed_range> = // freestanding, since C++23 + enable_borrowed_range; + + namespace views { inline constexpr unspecified enumerate = unspecified; } // freestanding, since C++23 + // [range.zip], zip view template requires (view && ...) && (sizeof...(Views) > 0) @@ -385,6 +396,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 @@ -435,6 +436,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.cppm b/libcxx/modules/std/ranges.cppm --- a/libcxx/modules/std/ranges.cppm +++ b/libcxx/modules/std/ranges.cppm @@ -326,6 +326,13 @@ using std::ranges::views::cartesian_product; } #endif + + // [range.enumerate] + using std::ranges::enumerate_view; + + namespace views { + using std::ranges::views::enumerate; + } } // 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 @@ -227,6 +244,13 @@ # endif # 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" @@ -322,6 +346,13 @@ # endif # 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] @@ -700,6 +701,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 @@ -1458,6 +1463,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 @@ -2387,6 +2396,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 @@ -3586,6 +3599,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 @@ -4983,6 +5000,13 @@ # endif # 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" @@ -6536,6 +6560,13 @@ # endif # 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/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,100 @@ +//===----------------------------------------------------------------------===// +// +// 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 "types.h" + +// Concepts + +template +concept CanBePiped = requires(View&& view, T&& t) { + { std::forward(view) | std::forward(t) }; +}; + +// Helpers + +template +constexpr void compareViews(View v, std::initializer_list> list) { + auto b1 = v.begin(); + auto e1 = v.end(); + auto b2 = list.begin(); + auto e2 = list.end(); + for (; b1 != e1 && b2 != e2; ++b1, ++b2) { + assert(*b1 == *b2); + } + assert(b1 == e1); + assert(b2 == e2); +} + +// 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; + Range 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; + Range 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,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 + +// constexpr V base() const & requires copy_constructible { return base_; } +// constexpr V base() && { return std::move(base_); } + +#include +#include + +#include "types.h" + +constexpr bool test() { + // Check the const& overload + { + int buff[] = {0, 1, 2, 3}; + + Range 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}; + + Range 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,71 @@ +//===----------------------------------------------------------------------===// +// +// 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) +// { return iterator(ranges::begin(base_), 0); } +// constexpr auto begin() const requires range-with-movable-references +// { return iterator(ranges::begin(base_), 0); } + +#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()` + { + Range range(buff, buff + 1); + + std::ranges::enumerate_view view(range); + using Iterator = std::ranges::iterator_t; + ASSERT_SAME_TYPE(Iterator, decltype(view.begin())); + } + // begin() over an empty range + { + Range range(buff, buff); + + std::ranges::enumerate_view view(range); + auto it = view.begin(); + assert(base(it.base()) == buff); + assert(it == view.end()); + } + // begin() over a 1-element range + { + Range range(buff, buff + 1); + + std::ranges::enumerate_view view(range); + auto it = view.begin(); + assert(base(it.base()) == buff); + } + // begin() over a N-element range + { + Range 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,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 + +// + +// class enumerate_view + +// template +// enumerate_view(R&&) -> enumerate_view>; + +#include +#include + +#include "test_iterators.h" +#include "types.h" + +constexpr bool test() { + { + JustAView 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,95 @@ +//===----------------------------------------------------------------------===// +// +// 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() { + { + std::ranges::enumerate_view view; + + assert((*view.begin() == std::tuple{0, 0})); + assert((*view.end() == std::tuple{1, 1})); + + auto [bi, bv] = *view.begin(); + assert(bi == 0); + assert(bv == 0); + + auto [ei, ev] = *view.end(); + assert(ei == 1); + assert(ev == 1); + } + { + std::ranges::enumerate_view view = {}; + + assert((*view.begin() == std::tuple{0, 0})); + assert((*view.end() == std::tuple{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,95 @@ +//===----------------------------------------------------------------------===// +// +// 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 = default; + +#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() { + { + std::ranges::enumerate_view view; + + assert((*view.begin() == std::tuple{0, 0})); + assert((*view.end() == std::tuple{1, 1})); + + auto [bi, bv] = *view.begin(); + assert(bi == 0); + assert(bv == 0); + + auto [ei, ev] = *view.end(); + assert(ei == 1); + assert(ev == 1); + } + { + std::ranges::enumerate_view view = {}; + + assert((*view.begin() == std::tuple{0, 0})); + assert((*view.end() == std::tuple{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,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 + +// + +// class enumerate_view + +// template +// constexpr bool enable_borrowed_range> = // freestanding +// 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,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 + +// constexpr auto end() requires (!simple-view) { +// if constexpr (common_range && sized_range) +// return iterator(ranges::end(base_), ranges::distance(base_)); +// else +// return sentinel(ranges::end(base_)); +// } +// 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_)); +// } + +#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()` + { + Range range(buff, buff + 1); + + std::ranges::enumerate_view view(range); + using Iterator = std::ranges::iterator_t; + ASSERT_SAME_TYPE(Iterator, decltype(view.end())); + } + // begin() over an empty range + { + Range range(buff, buff); + + std::ranges::enumerate_view view(range); + auto it = view.begin(); + assert(base(it.base()) == buff); + assert(it == view.end()); + } + // begin() over a 1-element range + { + Range range(buff, buff + 1); + + std::ranges::enumerate_view view(range); + auto it = view.end(); + assert(base(it.base()) == buff + 1); + } + // begin() over a N-element range + { + Range 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,123 @@ +//===----------------------------------------------------------------------===// +// +// 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 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[0], &ts[0] + 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,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 + +// 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; + 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}; + auto view = make_enumerate_view(array.begin(), array.end()); + + // Test the const& version + { + EnumerateIterator const iter(view); + Iterator const& result = iter.base(); + ASSERT_SAME_TYPE(Iterator const&, decltype(iter.base())); + ASSERT_NOEXCEPT(iter.base()); + assert(base(result) == array.begin()); + } + + // Test the && version + { + EnumerateIterator iter(view); + Iterator result = std::move(iter).base(); + ASSERT_SAME_TYPE(Iterator, decltype(std::move(iter).base())); + assert(base(result) == array.begin()); + } +} + +constexpr bool tests() { + // test>(); + // 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/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,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 + +// + +// class enumerate_view + +// friend constexpr strong_ordering operator<=>(const iterator& x, const iterator& y) noexcept; + +#include +#include + +#include "test_iterators.h" + +constexpr bool test() { return true; } + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.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,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class enumerate_view + +// constexpr iterator(iterator i) +// requires Const && convertible_to, iterator_t>; + +#include +#include + +#include "test_iterators.h" + +constexpr bool test() { return true; } + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.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,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 + +// iterator() requires default_initializable> = default; + +#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 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 + +// constexpr auto operator*() const { +// return reference-type(pos_, *current_); +// } + +#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,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 + +// + +// class enumerate_view + +// friend constexpr bool operator==(const iterator& x, const iterator& y) noexcept; + +#include +#include + +#include "test_iterators.h" + +constexpr bool test() { return true; } + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.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,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 + +// + +// class enumerate_view + +// constexpr difference_type index() const noexcept; + +#include +#include + +#include "test_iterators.h" + +constexpr bool test() { return true; } + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.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,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 + +// 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_)); +// } + +#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); + 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 + +// constexpr auto operator[](difference_type n) const +// requires random_access_range +// { return reference-type(pos_ + n, current_[n]); } + +#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 + { + int ts[] = {0, 1, 2, 3, 84}; + auto ev = ts | std::views::enumerate; + auto it = ev.begin(); + + assert(std::get<0>(it[0]) == std::get<0>(*it)); + assert(std::get<1>(it[0]) == std::get<1>(*it)); + assert(std::get<0>(it[2]) == std::get<0>(*(it + 2))); + assert(std::get<1>(it[2]) == std::get<1>(*(it + 2))); + assert(std::get<0>(it[4]) == std::get<0>(*(it + 4))); + assert(std::get<1>(it[4]) == std::get<1>(*(it + 4))); + + static_assert(std::is_same_v>); + } + + // Value + { + auto view = std::views::iota(0, 5) | std::views::enumerate; + auto it = view.begin(); + assert(it[0] == *it); + assert(it[2] == *(it + 2)); + assert(it[4] == *(it + 4)); + + 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/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,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class enumerate_view + +// 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,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 + +// + +// class enumerate_view + +// constexpr sentinel(sentinel other) +// requires Const && convertible_to, sentinel_t>; + +#include +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +struct Sentinel { + int i; + constexpr Sentinel() = default; + constexpr Sentinel(int ii) : i(ii) {} + friend constexpr bool operator==(int*, const Sentinel&) { return true; } +}; + +struct ConstSentinel { + int i; + constexpr ConstSentinel() = default; + constexpr ConstSentinel(int ii) : i(ii) {} + constexpr ConstSentinel(const Sentinel& s) : i(s.i) {} + friend constexpr bool operator==(int*, const ConstSentinel&) { return true; } +}; + +struct ConstSentinelRange : std::ranges::view_base { + int i; + constexpr ConstSentinelRange() = default; + constexpr ConstSentinelRange(int ii) : i(ii) {} + int* begin() const; + Sentinel end(); + ConstSentinel end() const; +}; + +struct NonConvertConstSentinel { + int i; + constexpr NonConvertConstSentinel() = default; + constexpr NonConvertConstSentinel(int ii) : i(ii) {} + friend constexpr bool operator==(int*, const NonConvertConstSentinel&) { return true; } +}; + +struct NonConvertConstSentinelRange : std::ranges::view_base { + int* begin() const; + Sentinel end(); + NonConvertConstSentinel end() const; +}; + +// Test Constraint +static_assert(std::is_constructible_v>, + std::ranges::sentinel_t>>); + +// !Const +static_assert(!std::is_constructible_v>, + std::ranges::sentinel_t>>); + +// !convertible_to, sentinel_t> +static_assert( + !std::is_constructible_v< std::ranges::sentinel_t>, + std::ranges::sentinel_t>>); + +// template > +constexpr void test() { + using EnumerateView = std::ranges::enumerate_view; + using EnumerateSentinel = std::ranges::sentinel_t; + using ConstEnumerateSentinel = std::ranges::sentinel_t; + static_assert(!std::same_as); + + // EnumerateSentinel s1{EnumerateView{84}}; + // ConstEnumerateSentinel s2 = s1; + + // assert(s2.base().i == 84); +} + +constexpr bool tests() { + test(); + // 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,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 + +// + +// class enumerate_view + +// iterator() requires default_initializable> = default; + +#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; + + 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,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// class enumerate_view + +// 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,226 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// 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 "test_iterators.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 +struct BufferView : std::ranges::view_base { + T* buffer_; + std::size_t size_; + + template + constexpr BufferView(T (&b)[N]) : buffer_(b), size_(N) {} + + template + constexpr BufferView(std::array& arr) : buffer_(arr.data()), size_(N) {} +}; + +template