diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -281,7 +281,7 @@ "`3373 `__","``{to,from}_chars_result``\ and ``format_to_n_result``\ need the ""we really mean what we say"" wording","Prague","|Complete|","14.0","|format|" "`3374 `__","P0653 + P1006 should have made the other ``std::to_address``\ overload ``constexpr``\ ","Prague","|Complete|","12.0" "`3375 `__","``decay``\ in ``viewable_range``\ should be ``remove_cvref``\ ","Prague","|Complete|","15.0","|ranges|" -"`3377 `__","``elements_view::iterator``\ befriends a specialization of itself","Prague","","","|ranges|" +"`3377 `__","``elements_view::iterator``\ befriends a specialization of itself","Prague","|Nothing To Do|","","|ranges|" "`3379 `__","""``safe``\ "" in several library names is misleading","Prague","|Complete|","15.0","|ranges|" "`3380 `__","``common_type``\ and comparison categories","Prague","|Complete|","15.0","|spaceship|" "`3381 `__","``begin``\ and ``data``\ must agree for ``contiguous_range``\ ","Prague","|Nothing To Do|","","|ranges|" diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -108,7 +108,7 @@ "`P0784R7 `__","CWG","More constexpr containers","Cologne","|Complete|","12.0" "`P0980R1 `__","LWG","Making std::string constexpr","Cologne","|Complete|","15.0" "`P1004R2 `__","LWG","Making std::vector constexpr","Cologne","|Complete|","15.0" -"`P1035R7 `__","LWG","Input Range Adaptors, Todo: elements_view","Cologne","|In Progress|","" +"`P1035R7 `__","LWG","Input Range Adaptors","Cologne","|Complete|","16.0" "`P1065R2 `__","LWG","Constexpr INVOKE","Cologne","|Complete|","12.0" "`P1135R6 `__","LWG","The C++20 Synchronization Library","Cologne","|Complete|","11.0" "`P1207R4 `__","LWG","Movability of Single-pass Iterators","Cologne","|Complete|","15.0" @@ -183,7 +183,7 @@ "`P1981R0 `__","LWG","Rename leap to leap_second","Prague","* *","" "`P1982R0 `__","LWG","Rename link to time_zone_link","Prague","* *","" "`P1983R0 `__","LWG","Wording for GB301, US296, US292, US291, and US283","Prague","|Complete|","15.0" -"`P1994R1 `__","LWG","elements_view needs its own sentinel","Prague","* *","" +"`P1994R1 `__","LWG","elements_view needs its own sentinel","Prague","Complete","16.0" "`P2002R1 `__","CWG","Defaulted comparison specification cleanups","Prague","* *","" "`P2045R1 `__","LWG","Missing Mandates for the standard library","Prague","* *","" "`P2085R0 `__","CWG","Consistent defaulted comparisons","Prague","* *","" diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -22,7 +22,7 @@ "`3403 `__","Domain of ``ranges::ssize(E)`` doesn't ``match ranges::size(E)``","November 2020","","","|ranges|" "`3404 `__","Finish removing subrange's conversions from pair-like","November 2020","","","|ranges|" "`3405 `__","``common_view``'s converting constructor is bad, too","November 2020","|Complete|","14.0","|ranges|" -"`3406 `__","``elements_view::begin()`` and ``elements_view::end()`` have incompatible constraints","November 2020","","","|ranges|" +"`3406 `__","``elements_view::begin()`` and ``elements_view::end()`` have incompatible constraints","November 2020","|Complete|","16.0","|ranges|" "`3419 `__","[algorithms.requirements]/15 doesn't reserve as many rights as it intends to","November 2020","|Nothing To Do|","" "`3420 `__","cpp17-iterator should check that the type looks like an iterator first","November 2020","|Complete|","14.0","|ranges|" "`3421 `__","Imperfect ADL emulation for boolean-testable","November 2020","|Nothing To Do|","","|ranges|" @@ -53,11 +53,11 @@ "`3391 `__","Problems with ``counted_iterator``/``move_iterator::base() const &``","February 2021","","","|ranges|" "`3433 `__","``subrange::advance(n)`` has UB when ``n < 0``","February 2021","|Complete|","14.0","|ranges|" "`3490 `__","``ranges::drop_while_view::begin()`` is missing a precondition","February 2021","|Nothing To Do|","","|ranges|" -"`3492 `__","Minimal improvements to ``elements_view::iterator``","February 2021","","","|ranges|" +"`3492 `__","Minimal improvements to ``elements_view::iterator``","February 2021","|Complete|","16.0","|ranges|" "`3494 `__","Allow ranges to be conditionally borrowed","February 2021","Superseded by `P2017R1 `__","","|ranges|" "`3495 `__","``constexpr launder`` makes pointers to inactive members of unions usable","February 2021","|Nothing To Do|","" "`3500 `__","``join_view::iterator::operator->()`` is bogus","February 2021","|Complete|","14.0","|ranges|" -"`3502 `__","``elements_view`` should not be allowed to return dangling reference","February 2021","","","|ranges|" +"`3502 `__","``elements_view`` should not be allowed to return dangling reference","February 2021","|Complete|","16.0","|ranges|" "`3505 `__","``split_view::outer-iterator::operator++`` misspecified","February 2021","","","|ranges|" "","","","","" `2774 `__,"``std::function`` construction vs assignment","June 2021","","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -482,6 +482,7 @@ __ranges/data.h __ranges/drop_view.h __ranges/drop_while_view.h + __ranges/elements_view.h __ranges/empty.h __ranges/empty_view.h __ranges/enable_borrowed_range.h diff --git a/libcxx/include/__ranges/elements_view.h b/libcxx/include/__ranges/elements_view.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/elements_view.h @@ -0,0 +1,407 @@ +// -*- 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_ELEMENTS_VIEW_H +#define _LIBCPP___RANGES_ELEMENTS_VIEW_H + +#include <__compare/three_way_comparable.h> +#include <__concepts/constructible.h> +#include <__concepts/convertible_to.h> +#include <__concepts/derived_from.h> +#include <__concepts/equality_comparable.h> +#include <__config> +#include <__fwd/get.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__ranges/all.h> +#include <__ranges/access.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 <__tuple/tuple_element.h> +#include <__tuple/tuple_like.h> +#include <__tuple/tuple_size.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/maybe_const.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_cvref.h> +#include <__type_traits/remove_reference.h> +#include <__utility/declval.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 >= 20 + +namespace ranges { + +template +concept __has_tuple_element = __tuple_like<_Tp>::value && _Np < tuple_size<_Tp>::value; + +template +concept __returnable_element = is_reference_v<_Tp> || move_constructible>; + +template + requires view<_View> && __has_tuple_element, _Np> && + __has_tuple_element>, _Np> && + __returnable_element, _Np> +class elements_view : public view_interface> { +public: + _LIBCPP_HIDE_FROM_ABI elements_view() + requires default_initializable<_View> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit elements_view(_View __base) : __base_(std::move(__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_); } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() + requires(!__simple_view<_View>) + { + return __iterator(ranges::begin(__base_)); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + requires range + { + return __iterator(ranges::begin(__base_)); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() + requires(!__simple_view<_View> && !common_range<_View>) + { + return __sentinel{ranges::end(__base_)}; + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() + requires(!__simple_view<_View> && common_range<_View>) + { + return __iterator{ranges::end(__base_)}; + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + requires range + { + return __sentinel{ranges::end(__base_)}; + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + requires common_range + { + return __iterator{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_); + } + +private: + template + class __iterator; + + template + class __sentinel; + + _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); +}; + +template +struct __elements_view_iterator_category_base {}; + +template +struct __elements_view_iterator_category_base<_Base, _Np> { + static consteval auto __get_iterator_category() { + using _Result = decltype(std::get<_Np>(*std::declval>())); + using _Cat = typename iterator_traits>::iterator_category; + + if constexpr (!is_lvalue_reference_v<_Result>) { + return input_iterator_tag{}; + } else if constexpr (derived_from<_Cat, random_access_iterator_tag>) { + return random_access_iterator_tag{}; + } else { + return _Cat{}; + } + } + + using iterator_category = decltype(__get_iterator_category()); +}; + +template + requires view<_View> && __has_tuple_element, _Np> && + __has_tuple_element>, _Np> && + __returnable_element, _Np> +template +class elements_view<_View, _Np>::__iterator + : public __elements_view_iterator_category_base<__maybe_const<_Const, _View>, _Np> { + template + friend class elements_view<_View, _Np>::__sentinel; + + using _Base = __maybe_const<_Const, _View>; + + iterator_t<_Base> __current_ = iterator_t<_Base>(); + + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __get_element(const iterator_t<_Base>& __i) { + if constexpr (is_reference_v>) { + return std::get<_Np>(*__i); + } else { + using _Ele = remove_cv_t>>; + return static_cast<_Ele>(std::get<_Np>(*__i)); + } + } + + 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{}; + } + } + +public: + using iterator_concept = decltype(__get_iterator_concept()); + using value_type = remove_cvref_t>>; + using difference_type = range_difference_t<_Base>; + + _LIBCPP_HIDE_FROM_ABI __iterator() + requires default_initializable> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(iterator_t<_Base> __current) : __current_(std::move(__current)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator __i) + requires _Const && convertible_to, iterator_t<_Base>> + : __current_(std::move(__i.__current_)) {} + + _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 decltype(auto) operator*() const { return __get_element(__current_); } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { + ++__current_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++__current_; } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) + requires forward_range<_Base> + { + auto temp = *this; + ++__current_; + return temp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--() + requires bidirectional_range<_Base> + { + --__current_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int) + requires bidirectional_range<_Base> + { + auto temp = *this; + --__current_; + return temp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n) + requires random_access_range<_Base> + { + __current_ += __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n) + requires random_access_range<_Base> + { + __current_ -= __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const + requires random_access_range<_Base> + { + return __get_element(__current_ + __n); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) + requires equality_comparable> + { + return __x.__current_ == __y.__current_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __x.__current_ < __y.__current_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __y < __x; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return !(__y < __x); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return !(__x < __y); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> && three_way_comparable> + { + return __x.__current_ <=> __y.__current_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __x, difference_type __y) + requires random_access_range<_Base> + { + return __iterator{__x} += __y; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __y + __x; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __x, difference_type __y) + requires random_access_range<_Base> + { + return __iterator{__x} -= __y; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y) + requires sized_sentinel_for, iterator_t<_Base>> + { + return __x.current_ - __y.current_; + } +}; + +template + requires view<_View> && __has_tuple_element, _Np> && + __has_tuple_element>, _Np> && + __returnable_element, _Np> +template +class elements_view<_View, _Np>::__sentinel { +private: + using _Base = __maybe_const<_Const, _View>; + sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + + template + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) + __get_current(const elements_view<_View, _Np>::__iterator<_AnyConst>& __iter) { + return (__iter.__current_); + } + +public: + _LIBCPP_HIDE_FROM_ABI __sentinel() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {} + + _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 +inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Tp>; + +template +using keys_view = elements_view<_Tp, 0>; +template +using values_view = elements_view<_Tp, 1>; + +namespace views { +namespace __elements { + +template +struct __fn : __range_adaptor_closure<__fn<_Np>> { + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const + /**/ noexcept(noexcept(elements_view, _Np>(std::forward<_Range>(__range)))) + /*------*/ -> decltype(elements_view, _Np>(std::forward<_Range>(__range))) { + /*-------------*/ return elements_view, _Np>(std::forward<_Range>(__range)); + } +}; +} // namespace __elements + +inline namespace __cpo { +template +inline constexpr auto elements = __elements::__fn<_Np>{}; +inline constexpr auto keys = elements<0>; +inline constexpr auto values = elements<1>; +} // namespace __cpo +} // namespace views +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_ELEMENTS_VIEW_H diff --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h --- a/libcxx/include/__ranges/subrange.h +++ b/libcxx/include/__ranges/subrange.h @@ -28,6 +28,7 @@ #include <__ranges/size.h> #include <__ranges/view_interface.h> #include <__tuple/tuple_element.h> +#include <__tuple/tuple_like.h> #include <__tuple/tuple_size.h> #include <__utility/move.h> #include @@ -287,6 +288,11 @@ using type = _Sp; }; +// [tuple.like] + +template +struct __tuple_like> : true_type {}; + #endif // _LIBCPP_STD_VER > 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__tuple/tuple_like.h b/libcxx/include/__tuple/tuple_like.h --- a/libcxx/include/__tuple/tuple_like.h +++ b/libcxx/include/__tuple/tuple_like.h @@ -14,7 +14,9 @@ #include <__fwd/pair.h> #include <__fwd/tuple.h> #include <__tuple/tuple_types.h> -#include <__type_traits/integral_constant.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_same.h> +#include <__type_traits/remove_cvref.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -23,11 +25,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template struct __tuple_like : false_type {}; +template struct __tuple_like : false_type {}; -template struct __tuple_like : public __tuple_like<_Tp> {}; -template struct __tuple_like : public __tuple_like<_Tp> {}; -template struct __tuple_like : public __tuple_like<_Tp> {}; +template +struct __tuple_like<_Tp, __enable_if_t>::value>> + : public __tuple_like<__remove_cvref_t<_Tp>> {}; #ifndef _LIBCPP_CXX03_LANG template struct __tuple_like > : true_type {}; @@ -39,6 +41,10 @@ template struct __tuple_like<__tuple_types<_Tp...> > : true_type {}; +// `subrange` specialization is defined in __ranges/subrange.h, +// because the forward declaration of `subrange` would introduce +// too many dependencies due to its complex requirements of the type. + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___TUPLE_TUPLE_LIKE_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 @@ -1121,6 +1121,7 @@ module data { private header "__ranges/data.h" } module drop_view { private header "__ranges/drop_view.h" } module drop_while_view { private header "__ranges/drop_while_view.h" } + module elements_view { private header "__ranges/elements_view.h" } module empty { private header "__ranges/empty.h" } module empty_view { private header "__ranges/empty_view.h" } module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -115,6 +115,27 @@ template using borrowed_subrange_t = see below; + // [range.elements], elements view + template + requires see below + class elements_view; + + template + inline constexpr bool enable_borrowed_range> = + enable_borrowed_range; + + template + using keys_view = elements_view; + template + using values_view = elements_view; + + namespace views { + template + inline constexpr unspecified elements = unspecified; + inline constexpr auto keys = elements<0>; + inline constexpr auto values = elements<1>; + } + // [range.empty], empty view template requires is_object_v @@ -316,6 +337,7 @@ #include <__ranges/data.h> #include <__ranges/drop_view.h> #include <__ranges/drop_while_view.h> +#include <__ranges/elements_view.h> #include <__ranges/empty.h> #include <__ranges/empty_view.h> #include <__ranges/enable_borrowed_range.h> diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -513,8 +513,9 @@ #include <__ranges/data.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/data.h'}} #include <__ranges/drop_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/drop_view.h'}} #include <__ranges/drop_while_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/drop_while_view.h'}} +#include <__ranges/elements_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/empty.h'}} #include <__ranges/empty.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/empty.h'}} -#include <__ranges/empty_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/empty_view.h'}} +#include <__ranges/empty_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/elements_view.h'}} #include <__ranges/enable_borrowed_range.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_borrowed_range.h'}} #include <__ranges/enable_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_view.h'}} #include <__ranges/filter_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/filter_view.h'}} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/adaptor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/adaptor.pass.cpp @@ -0,0 +1,157 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::views::elements +// std::views::keys +// std::views::values + +#include +#include +#include +#include +#include + +template +struct View : std::ranges::view_base { + T* begin() const; + T* end() const; +}; + +static_assert(!std::is_invocable_v))>); +static_assert(!std::is_invocable_v)), View>); +static_assert(std::is_invocable_v)), View>>); +static_assert(std::is_invocable_v)), View>>); +static_assert(!std::is_invocable_v)), View>>); + +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_invocable_v); +static_assert(!std::is_invocable_v>); +static_assert(std::is_invocable_v>>); +static_assert(!std::is_invocable_v>>); + +template +concept CanBePiped = + requires(View&& view, T&& t) { + { std::forward(view) | std::forward(t) }; + }; + +static_assert(!CanBePiped, decltype((std::views::elements<0>))>); +static_assert(CanBePiped>, decltype((std::views::elements<0>))>); +static_assert(CanBePiped>, decltype((std::views::elements<0>))>); +static_assert(!CanBePiped>, decltype((std::views::elements<5>))>); + +static_assert(!CanBePiped, decltype((std::views::keys))>); +static_assert(CanBePiped>, decltype((std::views::keys))>); +static_assert(CanBePiped>, decltype((std::views::keys))>); + +static_assert(!CanBePiped, decltype((std::views::values))>); +static_assert(CanBePiped>, decltype((std::views::values))>); +static_assert(!CanBePiped>, decltype((std::views::values))>); + +constexpr bool test() { + std::pair buff[] = {{1, 2}, {3, 4}, {5, 6}}; + + // Test `views::elements(v)` + { + using Result = std::ranges::elements_view[3]>, 0>; + std::same_as decltype(auto) result = std::views::elements<0>(buff); + auto expected = {1, 3, 5}; + assert(std::ranges::equal(result, expected)); + } + + // Test `views::keys(v)` + { + using Result = std::ranges::elements_view[3]>, 0>; + std::same_as decltype(auto) result = std::views::keys(buff); + auto expected = {1, 3, 5}; + assert(std::ranges::equal(result, expected)); + } + + // Test `views::values(v)` + { + using Result = std::ranges::elements_view[3]>, 1>; + std::same_as decltype(auto) result = std::views::values(buff); + auto expected = {2, 4, 6}; + assert(std::ranges::equal(result, expected)); + } + + // Test `v | views::elements` + { + using Result = std::ranges::elements_view[3]>, 1>; + std::same_as decltype(auto) result = buff | std::views::elements<1>; + auto expected = {2, 4, 6}; + assert(std::ranges::equal(result, expected)); + } + + // Test `v | views::keys` + { + using Result = std::ranges::elements_view[3]>, 0>; + std::same_as decltype(auto) result = buff | std::views::keys; + auto expected = {1, 3, 5}; + assert(std::ranges::equal(result, expected)); + } + + // Test `v | views::values` + { + using Result = std::ranges::elements_view[3]>, 1>; + std::same_as decltype(auto) result = buff | std::views::values; + auto expected = {2, 4, 6}; + assert(std::ranges::equal(result, expected)); + } + + // Test views::elements<0> | views::elements<0> + { + std::pair, std::tuple> nested[] = {{{1}, {2}}, {{3}, {4}}, {{5}, {6}}}; + using Result = std::ranges::elements_view< + std::ranges::elements_view, std::tuple>[3]>, 0>, + 0>; + auto const partial = std::views::elements<0> | std::views::elements<0>; + std::same_as decltype(auto) result = nested | partial; + auto expected = {1, 3, 5}; + assert(std::ranges::equal(result, expected)); + } + + // Test views::keys | views::keys + { + std::pair, std::tuple> nested[] = {{{1}, {2}}, {{3}, {4}}, {{5}, {6}}}; + using Result = std::ranges::elements_view< + std::ranges::elements_view, std::tuple>[3]>, 0>, + 0>; + auto const partial = std::views::keys | std::views::keys; + std::same_as decltype(auto) result = nested | partial; + auto expected = {1, 3, 5}; + assert(std::ranges::equal(result, expected)); + } + + // Test views::values | views::values + { + std::pair, std::tuple> nested[] = {{{1}, {2, 2}}, {{3}, {4, 4}}, {{5}, {6, 6}}}; + using Result = std::ranges::elements_view< + std::ranges::elements_view, std::tuple>[3]>, 1>, + 1>; + auto const partial = std::views::values | std::views::values; + std::same_as decltype(auto) result = nested | partial; + auto expected = {2, 4, 6}; + assert(std::ranges::equal(result, expected)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/base.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/base.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// constexpr V base() const & requires copy_constructible { return base_; } +// constexpr V base() && { return std::move(base_); } + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" + +struct View : std::ranges::view_base { + int i; + std::tuple* begin() const; + std::tuple* end() const; +}; + +struct MoveOnlyView : View { + MoveOnly mo; +}; + +template +concept HasBase = requires(T&& t) { std::forward(t).base(); }; + +static_assert(HasBase const&>); +static_assert(HasBase&&>); + +static_assert(!HasBase const&>); +static_assert(HasBase&&>); + +constexpr bool test() { + // const & + { + const std::ranges::elements_view ev{View{{}, 5}}; + std::same_as decltype(auto) v = ev.base(); + assert(v.i == 5); + } + + // & + { + std::ranges::elements_view ev{View{{}, 5}}; + std::same_as decltype(auto) v = ev.base(); + assert(v.i == 5); + } + + // && + { + std::ranges::elements_view ev{View{{}, 5}}; + std::same_as decltype(auto) v = std::move(ev).base(); + assert(v.i == 5); + } + + // const && + { + const std::ranges::elements_view ev{View{{}, 5}}; + std::same_as decltype(auto) v = std::move(ev).base(); + assert(v.i == 5); + } + + // move only + { + std::ranges::elements_view ev{MoveOnlyView{{}, 5}}; + std::same_as decltype(auto) v = std::move(ev).base(); + assert(v.mo.get() == 5); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/begin.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/begin.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// constexpr auto begin() requires (!simple-view) +// constexpr auto begin() const requires range + +#include +#include +#include +#include +#include + +#include "types.h" + +template +concept HasConstBegin = requires(const T ct) { ct.begin(); }; + +template +concept HasBegin = requires(T t) { t.begin(); }; + +template +concept HasConstAndNonConstBegin = + HasConstBegin && + // because const begin and non-const begin returns different types (iterator, iterator) + requires(T t, const T ct) { requires !std::same_as; }; + +template +concept HasOnlyNonConstBegin = HasBegin && !HasConstBegin; + +template +concept HasOnlyConstBegin = HasConstBegin && !HasConstAndNonConstBegin; + +struct NoConstBeginView : TupleBufferView { + using TupleBufferView::TupleBufferView; + constexpr std::tuple* begin() { return buffer_; } + constexpr std::tuple* end() { return buffer_ + size_; } +}; + +// simple-view +static_assert(HasOnlyConstBegin>); + +// !simple-view && range +static_assert(HasConstAndNonConstBegin>); + +// !range +static_assert(HasOnlyNonConstBegin>); + +constexpr bool test() { + std::tuple buffer[] = {{1}, {2}}; + { + // underlying iterator should be pointing to the first element + auto ev = std::views::elements<0>(buffer); + auto iter = ev.begin(); + assert(&(*iter) == &std::get<0>(buffer[0])); + } + + { + // underlying range models simple-view + auto v = std::views::elements<0>(SimpleCommon{buffer}); + static_assert(std::is_same_v); + assert(v.begin() == std::as_const(v).begin()); + auto&& r = *std::as_const(v).begin(); + assert(&r == &std::get<0>(buffer[0])); + } + + { + // underlying const R is not a range + auto v = std::views::elements<0>(NoConstBeginView{buffer}); + auto&& r = *v.begin(); + assert(&r == &std::get<0>(buffer[0])); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/ctor.default.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 + +// elements_view() requires default_initializable = default; + +#include +#include +#include +#include + +template +struct View : std::ranges::view_base { + int i = 42; + constexpr explicit View() + requires DefaultInitializable + = default; + std::tuple* begin() const; + std::tuple* end() const; +}; + + +// clang-format off +static_assert( std::is_default_constructible_v, 0>>); +static_assert(!std::is_default_constructible_v, 0>>); +// clang-format on + +constexpr bool test() { + { + std::ranges::elements_view, 0> ev = {}; + assert(ev.base().i == 42); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/ctor.view.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/ctor.view.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/ctor.view.pass.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// constexpr explicit elements_view(V base); + +#include +#include +#include +#include + +#include "MoveOnly.h" + +struct View : std::ranges::view_base { + MoveOnly mo; + std::tuple* begin() const; + std::tuple* end() const; +}; + +// Test Explicit +static_assert(std::is_constructible_v, View>); +static_assert(!std::is_constructible_v>); + +constexpr bool test() { + { + std::ranges::elements_view ev{View{{}, MoveOnly{5}}}; + assert(std::move(ev).base().mo.get() == 5); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/end.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/end.pass.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// constexpr auto end() requires (!simple-view && !common_range) +// constexpr auto end() requires (!simple-view && common_range) +// constexpr auto end() const requires range +// constexpr auto end() const requires common_range + +#include +#include +#include +#include + +#include "types.h" + +// | simple | common | v.end() | as_const(v) +// | | | | .end() +// |--------|--------|------------------|--------------- +// | Y | Y | iterator | iterator +// | Y | N | sentinel | sentinel +// | N | Y | iterator | iterator +// | N | N | sentinel | sentinel + +// !range +template +concept HasEnd = requires(T t) { t.end(); }; + +template +concept HasConstEnd = requires(const T ct) { ct.end(); }; + +struct NoConstEndView : TupleBufferView { + using TupleBufferView::TupleBufferView; + constexpr std::tuple* begin() { return buffer_; } + constexpr std::tuple* end() { return buffer_ + size_; } +}; + +static_assert(HasEnd>); +static_assert(!HasConstEnd>); + +constexpr bool test() { + std::tuple buffer[] = {{1}, {2}, {3}}; + + // simple-view && common_view + { + SimpleCommon v{buffer}; + auto ev = std::views::elements<0>(v); + + auto it = ev.begin(); + decltype(auto) st = ev.end(); + assert(st == it + 3); + + auto const_it = std::as_const(ev).begin(); + decltype(auto) const_st = std::as_const(ev).end(); + assert(const_st == const_it + 3); + + // Both iterator + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + + // simple-view && !common_view + { + SimpleNonCommon v{buffer}; + auto ev = std::views::elements<0>(v); + + auto it = ev.begin(); + decltype(auto) st = ev.end(); + assert(st == it + 3); + + auto const_it = std::as_const(ev).begin(); + decltype(auto) const_st = std::as_const(ev).end(); + assert(const_st == const_it + 3); + + // Both iterator + static_assert(std::same_as); + static_assert(!std::same_as); + static_assert(!std::same_as); + } + + // !simple-view && common_view + { + NonSimpleCommon v{buffer}; + auto ev = std::views::elements<0>(v); + + auto it = ev.begin(); + decltype(auto) st = ev.end(); + assert(st == it + 3); + + auto const_it = std::as_const(ev).begin(); + decltype(auto) const_st = std::as_const(ev).end(); + assert(const_st == const_it + 3); + + // iterator and iterator + static_assert(!std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + + // !simple-view && !common_view + { + NonSimpleNonCommon v{buffer}; + auto ev = std::views::elements<0>(v); + + auto it = ev.begin(); + decltype(auto) st = ev.end(); + assert(st == it + 3); + + auto const_it = std::as_const(ev).begin(); + decltype(auto) const_st = std::as_const(ev).end(); + assert(const_st == const_it + 3); + + // sentinel and sentinel + static_assert(!std::same_as); + static_assert(!std::same_as); + static_assert(!std::same_as); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/general.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/general.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// Some basic examples of how elements_view might be used in the wild. This is a general +// collection of sample algorithms and functions that try to mock general usage of +// this view. + +#include +#include +#include +#include +#include +#include + +#include + +int main(int, char**) { + using namespace std::string_view_literals; + auto historical_figures = + std::map{std::pair{"Lovelace"sv, 1815}, {"Turing"sv, 1912}, {"Babbage"sv, 1791}, {"Hamilton"sv, 1936}}; + + auto names = historical_figures | std::views::elements<0>; + auto expectedNames = {"Babbage"sv, "Hamilton"sv, "Lovelace"sv, "Turing"sv}; + std::ranges::equal(names, expectedNames); + + auto birth_years = historical_figures | std::views::elements<1>; + auto expectedYears = {1791, 1936, 1815, 1912}; + std::ranges::equal(birth_years, expectedYears); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/range.concept.compile.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 + +// concept checking +// +// template +// concept has-tuple-element = +// tuple-like && N < tuple_size_v; +// +// template +// concept returnable-element = +// is_reference_v || move_constructible>; +// +// template +// requires view && has-tuple-element, N> && +// has-tuple-element>, N> && +// returnable-element, N> +// class elements_view; + +#include +#include +#include +#include + +#include "test_iterators.h" + +template +using Range = std::ranges::subrange>; + +template +concept HasElementsView = requires { typename std::ranges::elements_view; }; + +static_assert(HasElementsView*>, 0>); +static_assert(HasElementsView*>, 1>); +static_assert(HasElementsView*>, 2>); +static_assert(HasElementsView*>, 3>); + +// !view +static_assert(!HasElementsView, 1>, 0>); + +// !input_range +static_assert(!HasElementsView*>>, 0>); + +// !tuple-like +static_assert(!HasElementsView, 1>); + +// !(N > tuple_size_v) +static_assert(!HasElementsView*>, 2>); + +// ! (is_reference_v || move_constructible>) +struct NonMovable { + NonMovable(int) {} + NonMovable(NonMovable&&) = delete; +}; + +using NonMovableGenerator = + decltype(std::views::iota(0, 1) | std::views::transform([](int) { + return std::pair{1, 1}; + })); + +static_assert(!HasElementsView); +static_assert( HasElementsView); diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/size.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/size.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 + +// constexpr auto size() requires sized_range +// constexpr auto size() const requires sized_range + + +#include +#include +#include +#include + +#include "types.h" + +template +concept HasSize = requires(T t) { t.size(); }; + +static_assert(HasSize>); +static_assert(HasSize>); + +struct NonSized : std::ranges::view_base { + using iterator = forward_iterator*>; + constexpr iterator begin() const; + constexpr iterator end() const; +}; +static_assert(!std::ranges::sized_range); +static_assert(!std::ranges::sized_range); + +static_assert(!HasSize>); +static_assert(!HasSize>); + +struct SizedNonConst : TupleBufferView { + using TupleBufferView::TupleBufferView; + + using iterator = forward_iterator*>; + constexpr auto begin() const { return iterator{buffer_}; } + constexpr auto end() const { return iterator{buffer_ + size_}; } + constexpr std::size_t size() { return size_; } +}; + +static_assert(HasSize>); +static_assert(!HasSize>); + +constexpr bool test() { + std::tuple buffer[] = {{1}, {2}, {3}}; + + // non-const and const are sized + { + auto ev = std::views::elements<0>(buffer); + assert(ev.size() == 3); + assert(std::as_const(ev).size() == 3); + } + + { + // const-view non-sized range + auto ev = std::views::elements<0>(SizedNonConst{buffer}); + assert(ev.size() == 3); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/types.h b/libcxx/test/std/ranges/range.adaptors/range.elements/types.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/types.h @@ -0,0 +1,460 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ELEMENTS_TYPES_H +#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ELEMENTS_TYPES_H + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +template +struct BufferView : std::ranges::view_base { + T* buffer_; + std::size_t size_; + + template + constexpr BufferView(T (&b)[N]) : buffer_(b), size_(N) {} +}; + +using TupleBufferView = BufferView>; + +template +struct Common : TupleBufferView { + using TupleBufferView::TupleBufferView; + + constexpr std::tuple* begin() + requires(!Simple) + { + return buffer_; + } + constexpr const std::tuple* begin() const { return buffer_; } + constexpr std::tuple* end() + requires(!Simple) + { + return buffer_ + size_; + } + constexpr const std::tuple* end() const { return buffer_ + size_; } +}; +using SimpleCommon = Common; +using NonSimpleCommon = Common; + +using SimpleCommonRandomAccessSized = SimpleCommon; +using NonSimpleCommonRandomAccessSized = NonSimpleCommon; + +static_assert(std::ranges::common_range>); +static_assert(std::ranges::random_access_range); +static_assert(std::ranges::sized_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); +#if 0 +template +struct CommonNonRandom : TupleBufferView { + using TupleBufferView::TupleBufferView; + using const_iterator = forward_iterator; + using iterator = forward_iterator; + constexpr iterator begin() + requires(!Simple) { + return iterator(buffer_); + } + constexpr const_iterator begin() const { return const_iterator(buffer_); } + constexpr iterator end() + requires(!Simple) { + return iterator(buffer_ + size_); + } + constexpr const_iterator end() const { return const_iterator(buffer_ + size_); } +}; + +using SimpleCommonNonRandom = CommonNonRandom; +using NonSimpleCommonNonRandom = CommonNonRandom; + +static_assert(std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::sized_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); +#endif + +template +struct NonCommon : TupleBufferView { + using TupleBufferView::TupleBufferView; + constexpr std::tuple* begin() + requires(!Simple) { + return buffer_; + } + constexpr const std::tuple* begin() const { return buffer_; } + constexpr sentinel_wrapper*> end() + requires(!Simple) { + return sentinel_wrapper*>(buffer_ + size_); + } + constexpr sentinel_wrapper*> end() const { return sentinel_wrapper*>(buffer_ + size_); } +}; + +using SimpleNonCommon = NonCommon; +using NonSimpleNonCommon = NonCommon; + +static_assert(!std::ranges::common_range); +static_assert(std::ranges::random_access_range); +static_assert(!std::ranges::sized_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +#if 0 +template +struct NonCommonSized : TupleBufferView { + using TupleBufferView::TupleBufferView; + constexpr int* begin() + requires(!Simple) { + return buffer_; + } + constexpr const int* begin() const { return buffer_; } + constexpr sentinel_wrapper end() + requires(!Simple) { + return sentinel_wrapper(buffer_ + size_); + } + constexpr sentinel_wrapper end() const { return sentinel_wrapper(buffer_ + size_); } + constexpr std::size_t size() const { return size_; } +}; + +using SimpleNonCommonSized = NonCommonSized; +using SimpleNonCommonRandomAcessSized = SimpleNonCommonSized; +using NonSimpleNonCommonSized = NonCommonSized; +using NonSimpleNonCommonRandomAcessSized = NonSimpleNonCommonSized; + +static_assert(!std::ranges::common_range); +static_assert(std::ranges::random_access_range); +static_assert(std::ranges::sized_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +template +struct NonCommonNonRandom : TupleBufferView { + using TupleBufferView::TupleBufferView; + + using const_iterator = forward_iterator; + using iterator = forward_iterator; + + constexpr iterator begin() + requires(!Simple) { + return iterator(buffer_); + } + constexpr const_iterator begin() const { return const_iterator(buffer_); } + constexpr sentinel_wrapper end() + requires(!Simple) { + return sentinel_wrapper(iterator(buffer_ + size_)); + } + constexpr sentinel_wrapper end() const { + return sentinel_wrapper(const_iterator(buffer_ + size_)); + } +}; + +using SimpleNonCommonNonRandom = NonCommonNonRandom; +using NonSimpleNonCommonNonRandom = NonCommonNonRandom; + +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::sized_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +template +struct BasicView : TupleBufferView { + using TupleBufferView::TupleBufferView; + + constexpr NonConstIter begin() + requires(!std::is_same_v) { + return NonConstIter(buffer_); + } + constexpr Iter begin() const { return Iter(buffer_); } + + constexpr NonConstSent end() + requires(!std::is_same_v) { + if constexpr (std::is_same_v) { + return NonConstIter(buffer_ + size_); + } else { + return NonConstSent(NonConstIter(buffer_ + size_)); + } + } + + constexpr Sent end() const { + if constexpr (std::is_same_v) { + return Iter(buffer_ + size_); + } else { + return Sent(Iter(buffer_ + size_)); + } + } +}; + +template +struct forward_sized_iterator { + Base it_ = nullptr; + + using iterator_category = std::forward_iterator_tag; + using value_type = int; + using difference_type = intptr_t; + using pointer = Base; + using reference = decltype(*Base{}); + + forward_sized_iterator() = default; + constexpr forward_sized_iterator(Base it) : it_(it) {} + + constexpr reference operator*() const { return *it_; } + + constexpr forward_sized_iterator& operator++() { + ++it_; + return *this; + } + constexpr forward_sized_iterator operator++(int) { return forward_sized_iterator(it_++); } + + friend constexpr bool operator==(const forward_sized_iterator&, const forward_sized_iterator&) = default; + + friend constexpr difference_type operator-(const forward_sized_iterator& x, const forward_sized_iterator& y) { + return x.it_ - y.it_; + } +}; +static_assert(std::forward_iterator>); +static_assert(std::sized_sentinel_for, forward_sized_iterator<>>); + +using ForwardSizedView = BasicView>; +static_assert(std::ranges::forward_range); +static_assert(std::ranges::sized_range); +static_assert(std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + +using NonSimpleForwardSizedView = BasicView, forward_sized_iterator, + forward_sized_iterator, forward_sized_iterator>; +static_assert(std::ranges::forward_range); +static_assert(std::ranges::sized_range); +static_assert(std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +using ForwardSizedNonCommon = BasicView, sized_sentinel>>; +static_assert(std::ranges::forward_range); +static_assert(std::ranges::sized_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + +using NonSimpleForwardSizedNonCommon = + BasicView, sized_sentinel>, + forward_sized_iterator, sized_sentinel>>; +static_assert(std::ranges::forward_range); +static_assert(std::ranges::sized_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +struct SizedRandomAccessView : TupleBufferView { + using TupleBufferView::TupleBufferView; + using iterator = random_access_iterator; + + constexpr auto begin() const { return iterator(buffer_); } + constexpr auto end() const { return sized_sentinel(iterator(buffer_ + size_)); } + + constexpr decltype(auto) operator[](std::size_t n) const { return *(begin() + n); } +}; +static_assert(std::ranges::view); +static_assert(std::ranges::random_access_range); +static_assert(std::ranges::sized_range); + +using NonSizedRandomAccessView = + BasicView, sentinel_wrapper>>; +static_assert(!std::ranges::contiguous_range); +static_assert(std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::sized_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + +using NonSimpleNonSizedRandomAccessView = + BasicView, sentinel_wrapper>, + random_access_iterator, sentinel_wrapper> >; +static_assert(!std::ranges::contiguous_range); +static_assert(std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::sized_range); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +using ContiguousCommonView = BasicView; +static_assert(std::ranges::contiguous_range); +static_assert(std::ranges::common_range); +static_assert(std::ranges::sized_range); + +using ContiguousNonCommonView = BasicView>; +static_assert(std::ranges::contiguous_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::sized_range); + +using ContiguousNonCommonSized = BasicView>; + +static_assert(std::ranges::contiguous_range); +static_assert(!std::ranges::common_range); +static_assert(std::ranges::sized_range); + +template +struct common_input_iterator { + Base it_; + + using value_type = int; + using difference_type = std::intptr_t; + using iterator_concept = std::input_iterator_tag; + + constexpr common_input_iterator() = default; + constexpr explicit common_input_iterator(Base it) : it_(it) {} + + constexpr common_input_iterator& operator++() { + ++it_; + return *this; + } + constexpr void operator++(int) { ++it_; } + + constexpr int& operator*() const { return *it_; } + + friend constexpr bool operator==(common_input_iterator const&, common_input_iterator const&) = default; +}; + +using InputCommonView = BasicView>; +static_assert(std::ranges::input_range); +static_assert(!std::ranges::forward_range); +static_assert(std::ranges::common_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + +using NonSimpleInputCommonView = BasicView, common_input_iterator, + common_input_iterator, common_input_iterator>; +static_assert(std::ranges::input_range); +static_assert(!std::ranges::forward_range); +static_assert(std::ranges::common_range); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +using InputNonCommonView = BasicView, sentinel_wrapper>>; +static_assert(std::ranges::input_range); +static_assert(!std::ranges::forward_range); +static_assert(!std::ranges::common_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + +using NonSimpleInputNonCommonView = + BasicView, sentinel_wrapper>, + common_input_iterator, sentinel_wrapper>>; +static_assert(std::ranges::input_range); +static_assert(!std::ranges::forward_range); +static_assert(!std::ranges::common_range); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +using BidiCommonView = BasicView>; +static_assert(!std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(std::ranges::common_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + +using NonSimpleBidiCommonView = BasicView, bidirectional_iterator, + bidirectional_iterator, bidirectional_iterator>; +static_assert(!std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(std::ranges::common_range); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +struct SizedBidiCommon : BidiCommonView { + using BidiCommonView::BidiCommonView; + std::size_t size() const { return base(end()) - base(begin()); } +}; +static_assert(std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(std::ranges::common_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + +struct NonSimpleSizedBidiCommon : NonSimpleBidiCommonView { + using NonSimpleBidiCommonView::NonSimpleBidiCommonView; + std::size_t size() const { return base(end()) - base(begin()); } +}; +static_assert(std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(std::ranges::common_range); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +using BidiNonCommonView = BasicView, sentinel_wrapper>>; +static_assert(!std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + +using NonSimpleBidiNonCommonView = + BasicView, sentinel_wrapper>, + bidirectional_iterator, sentinel_wrapper>>; +static_assert(!std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +using SizedBidiNonCommonView = BasicView, sized_sentinel>>; +static_assert(std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + +using NonSimpleSizedBidiNonCommonView = + BasicView, sized_sentinel>, + bidirectional_iterator, sized_sentinel>>; +static_assert(std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + +namespace adltest{ +struct iter_move_swap_iterator { + + std::reference_wrapper iter_move_called_times; + std::reference_wrapper iter_swap_called_times; + int i = 0; + + using iterator_category = std::input_iterator_tag; + using value_type = int; + using difference_type = intptr_t; + + constexpr int operator*() const { return i; } + + constexpr iter_move_swap_iterator& operator++() { + ++i; + return *this; + } + constexpr void operator++(int) { ++i; } + + friend constexpr bool operator==(const iter_move_swap_iterator& x, std::default_sentinel_t) { return x.i == 5; } + + friend constexpr int iter_move(iter_move_swap_iterator const& it) { + ++it.iter_move_called_times; + return it.i; + } + friend constexpr void iter_swap(iter_move_swap_iterator const& x, iter_move_swap_iterator const& y) { + ++x.iter_swap_called_times; + ++y.iter_swap_called_times; + } +}; + +struct IterMoveSwapRange { + int iter_move_called_times = 0; + int iter_swap_called_times = 0; + constexpr auto begin() { return iter_move_swap_iterator{iter_move_called_times, iter_swap_called_times}; } + constexpr auto end() const { return std::default_sentinel; } +}; +} // namespace adltest + +#endif +#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ELEMENTS_TYPES_H