diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv index ebbc5c10916cc7..b70f0645efb6e9 100644 --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -75,7 +75,7 @@ Section,Description,Dependencies,Assignee,Complete | `ranges::next `_ | `ranges::prev `_",[iterator.concepts],Christopher Di Bella and Arthur O'Dwyer,✅ `[predef.iterators] `_," -| Updates to reverse_iterator +| `Updates to reverse_iterator `_ | `Updates to back_insert_iterator `_ | `Updates to front_insert_iterator `_ | `Updates to move_iterator `_","| [iterator.concepts] diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h index 775f2270048da2..6ce5595addb8bf 100644 --- a/libcxx/include/__iterator/iterator_traits.h +++ b/libcxx/include/__iterator/iterator_traits.h @@ -141,8 +141,9 @@ struct __has_iterator_concept #if _LIBCPP_STD_VER > 17 -// The `cpp17-*-iterator` exposition-only concepts are easily confused with the Cpp17*Iterator tables, -// so they've been banished to a namespace that makes it obvious they have a niche use-case. +// The `cpp17-*-iterator` exposition-only concepts have very similar names to the `Cpp17*Iterator` named requirements +// from `[iterator.cpp17]`. To avoid confusion between the two, the exposition-only concepts have been banished to +// a "detail" namespace indicating they have a niche use-case. namespace __iterator_traits_detail { template concept __cpp17_iterator = diff --git a/libcxx/include/__iterator/reverse_iterator.h b/libcxx/include/__iterator/reverse_iterator.h index c77f4618534b1b..bc07cf33f701cd 100644 --- a/libcxx/include/__iterator/reverse_iterator.h +++ b/libcxx/include/__iterator/reverse_iterator.h @@ -12,10 +12,18 @@ #include <__compare/compare_three_way_result.h> #include <__compare/three_way_comparable.h> +#include <__concepts/convertible_to.h> #include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> #include <__iterator/iterator.h> #include <__iterator/iterator_traits.h> +#include <__iterator/prev.h> +#include <__iterator/readable_traits.h> #include <__memory/addressof.h> +#include <__utility/move.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -41,22 +49,31 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP _Iter __t; // no longer used as of LWG #2360, not removed due to ABI break #endif +#if _LIBCPP_STD_VER > 17 + static_assert(__is_cpp17_bidirectional_iterator<_Iter>::value || bidirectional_iterator<_Iter>, + "reverse_iterator requires It to be a bidirectional iterator."); +#endif // _LIBCPP_STD_VER > 17 + protected: _Iter current; public: - typedef _Iter iterator_type; - typedef typename iterator_traits<_Iter>::difference_type difference_type; - typedef typename iterator_traits<_Iter>::reference reference; - typedef typename iterator_traits<_Iter>::pointer pointer; - typedef _If<__is_cpp17_random_access_iterator<_Iter>::value, - random_access_iterator_tag, - typename iterator_traits<_Iter>::iterator_category> iterator_category; - typedef typename iterator_traits<_Iter>::value_type value_type; + using iterator_type = _Iter; + using iterator_category = _If<__is_cpp17_random_access_iterator<_Iter>::value, + random_access_iterator_tag, + typename iterator_traits<_Iter>::iterator_category>; + using pointer = typename iterator_traits<_Iter>::pointer; #if _LIBCPP_STD_VER > 17 - typedef _If<__is_cpp17_random_access_iterator<_Iter>::value, - random_access_iterator_tag, - bidirectional_iterator_tag> iterator_concept; + using iterator_concept = _If<__is_cpp17_random_access_iterator<_Iter>::value, + random_access_iterator_tag, + bidirectional_iterator_tag>; + using value_type = iter_value_t<_Iter>; + using difference_type = iter_difference_t<_Iter>; + using reference = iter_reference_t<_Iter>; +#else + using value_type = typename iterator_traits<_Iter>::value_type; + using difference_type = typename iterator_traits<_Iter>::difference_type; + using reference = typename iterator_traits<_Iter>::reference; #endif #ifndef _LIBCPP_ABI_NO_ITERATOR_BASES @@ -114,32 +131,75 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP _Iter base() const {return current;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference operator*() const {_Iter __tmp = current; return *--__tmp;} + +#if _LIBCPP_STD_VER > 17 + _LIBCPP_INLINE_VISIBILITY + constexpr pointer operator->() const + requires is_pointer_v<_Iter> || requires(const _Iter i) { i.operator->(); } + { + if constexpr (is_pointer_v<_Iter>) { + return std::prev(current); + } else { + return std::prev(current).operator->(); + } + } +#else _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - pointer operator->() const {return _VSTD::addressof(operator*());} + pointer operator->() const { + return std::addressof(operator*()); + } +#endif // _LIBCPP_STD_VER > 17 + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reverse_iterator& operator++() {--current; return *this;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reverse_iterator operator++(int) {reverse_iterator __tmp(*this); --current; return __tmp;} + reverse_iterator operator++(int) {reverse_iterator __tmp(*this); --current; return __tmp;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reverse_iterator& operator--() {++current; return *this;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reverse_iterator operator--(int) {reverse_iterator __tmp(*this); ++current; return __tmp;} + reverse_iterator operator--(int) {reverse_iterator __tmp(*this); ++current; return __tmp;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reverse_iterator operator+ (difference_type __n) const {return reverse_iterator(current - __n);} + reverse_iterator operator+(difference_type __n) const {return reverse_iterator(current - __n);} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reverse_iterator& operator+=(difference_type __n) {current -= __n; return *this;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reverse_iterator operator- (difference_type __n) const {return reverse_iterator(current + __n);} + reverse_iterator operator-(difference_type __n) const {return reverse_iterator(current + __n);} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reverse_iterator& operator-=(difference_type __n) {current += __n; return *this;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reference operator[](difference_type __n) const {return *(*this + __n);} + reference operator[](difference_type __n) const {return *(*this + __n);} + +#if _LIBCPP_STD_VER > 17 + _LIBCPP_HIDE_FROM_ABI friend constexpr + iter_rvalue_reference_t<_Iter> iter_move(const reverse_iterator& __i) + noexcept(is_nothrow_copy_constructible_v<_Iter> && + noexcept(ranges::iter_move(--declval<_Iter&>()))) { + auto __tmp = __i.base(); + return ranges::iter_move(--__tmp); + } + + template _Iter2> + _LIBCPP_HIDE_FROM_ABI friend constexpr + void iter_swap(const reverse_iterator& __x, const reverse_iterator<_Iter2>& __y) + noexcept(is_nothrow_copy_constructible_v<_Iter> && + is_nothrow_copy_constructible_v<_Iter2> && + noexcept(ranges::iter_swap(--declval<_Iter&>(), --declval<_Iter2&>()))) { + auto __xtmp = __x.base(); + auto __ytmp = __y.base(); + ranges::iter_swap(--__xtmp, --__ytmp); + } +#endif // _LIBCPP_STD_VER > 17 }; template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 bool operator==(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER > 17 + requires requires { + { __x.base() == __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER > 17 { return __x.base() == __y.base(); } @@ -148,6 +208,11 @@ template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 bool operator<(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER > 17 + requires requires { + { __x.base() > __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER > 17 { return __x.base() > __y.base(); } @@ -156,6 +221,11 @@ template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 bool operator!=(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER > 17 + requires requires { + { __x.base() != __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER > 17 { return __x.base() != __y.base(); } @@ -164,6 +234,11 @@ template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 bool operator>(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER > 17 + requires requires { + { __x.base() < __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER > 17 { return __x.base() < __y.base(); } @@ -172,6 +247,11 @@ template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 bool operator>=(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER > 17 + requires requires { + { __x.base() <= __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER > 17 { return __x.base() <= __y.base(); } @@ -180,6 +260,11 @@ template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 bool operator<=(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER > 17 + requires requires { + { __x.base() >= __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER > 17 { return __x.base() >= __y.base(); } @@ -221,6 +306,12 @@ operator+(typename reverse_iterator<_Iter>::difference_type __n, const reverse_i return reverse_iterator<_Iter>(__x.base() - __n); } +#if _LIBCPP_STD_VER > 17 +template + requires (!sized_sentinel_for<_Iter1, _Iter2>) +inline constexpr bool disable_sized_sentinel_for, reverse_iterator<_Iter2>> = true; +#endif // _LIBCPP_STD_VER > 17 + #if _LIBCPP_STD_VER > 11 template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 diff --git a/libcxx/include/iterator b/libcxx/include/iterator index 852fa353a9c2a3..8ba4d0ccb17cfc 100644 --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -225,10 +225,17 @@ class reverse_iterator protected: Iterator current; public: - typedef Iterator iterator_type; - typedef typename iterator_traits::difference_type difference_type; - typedef typename iterator_traits::reference reference; - typedef typename iterator_traits::pointer pointer; + using iterator_type = Iterator; + using iterator_concept = see below; // since C++20 + using iterator_category = typename iterator_traits::iterator_category; // since C++17, until C++20 + using iterator_category = see below; // since C++20 + using value_type = typename iterator_traits::value_type; // since C++17, until C++20 + using value_type = iter_value_t; // since C++20 + using difference_type = typename iterator_traits::difference_type; // until C++20 + using difference_type = iter_difference_t; // since C++20 + using pointer = typename iterator_traits::pointer; + using reference = typename iterator_traits::reference; // until C++20 + using reference = iter_reference_t; // since C++20 constexpr reverse_iterator(); constexpr explicit reverse_iterator(Iterator x); @@ -236,7 +243,8 @@ public: template constexpr reverse_iterator& operator=(const reverse_iterator& u); constexpr Iterator base() const; constexpr reference operator*() const; - constexpr pointer operator->() const; + constexpr pointer operator->() const; // until C++20 + constexpr pointer operator->() const requires see below; // since C++20 constexpr reverse_iterator& operator++(); constexpr reverse_iterator operator++(int); constexpr reverse_iterator& operator--(); @@ -245,7 +253,14 @@ public: constexpr reverse_iterator& operator+=(difference_type n); constexpr reverse_iterator operator- (difference_type n) const; constexpr reverse_iterator& operator-=(difference_type n); - constexpr reference operator[](difference_type n) const; + constexpr unspecified operator[](difference_type n) const; + + friend constexpr iter_rvalue_reference_t + iter_move(const reverse_iterator& i) noexcept(see below); + template Iterator2> + friend constexpr void + iter_swap(const reverse_iterator& x, + const reverse_iterator& y) noexcept(see below); }; template @@ -254,11 +269,11 @@ operator==(const reverse_iterator& x, const reverse_iterator constexpr bool // constexpr in C++17 -operator<(const reverse_iterator& x, const reverse_iterator& y); +operator!=(const reverse_iterator& x, const reverse_iterator& y); template constexpr bool // constexpr in C++17 -operator!=(const reverse_iterator& x, const reverse_iterator& y); +operator<(const reverse_iterator& x, const reverse_iterator& y); template constexpr bool // constexpr in C++17 @@ -266,11 +281,16 @@ operator>(const reverse_iterator& x, const reverse_iterator constexpr bool // constexpr in C++17 -operator>=(const reverse_iterator& x, const reverse_iterator& y); +operator<=(const reverse_iterator& x, const reverse_iterator& y); template constexpr bool // constexpr in C++17 -operator<=(const reverse_iterator& x, const reverse_iterator& y); +operator>=(const reverse_iterator& x, const reverse_iterator& y); + +template Iterator2> + constexpr compare_three_way_result_t + operator<=>(const reverse_iterator& x, + const reverse_iterator& y); template constexpr auto @@ -285,6 +305,11 @@ operator+(typename reverse_iterator::difference_type n, template constexpr reverse_iterator make_reverse_iterator(Iterator i); // C++14, constexpr in C++17 +template + requires (!sized_sentinel_for) + inline constexpr bool disable_sized_sentinel_for, + reverse_iterator> = true; + template class back_insert_iterator : public iterator // until C++17 diff --git a/libcxx/test/libcxx/iterators/predef.iterators/reverse.iterators/bad_template_argument.verify.cpp b/libcxx/test/libcxx/iterators/predef.iterators/reverse.iterators/bad_template_argument.verify.cpp new file mode 100644 index 00000000000000..9849173d11a8db --- /dev/null +++ b/libcxx/test/libcxx/iterators/predef.iterators/reverse.iterators/bad_template_argument.verify.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// + +// reverse_iterator + +#include + +#include "test_iterators.h" + +int main(int, char**) { + using BadIter = std::reverse_iterator>; + BadIter i; //expected-error-re@*:* {{static_assert failed{{.*}} "reverse_iterator requires It to be a bidirectional iterator."}} + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp index 66ddef131b5acc..4aae0447d4efbf 100644 --- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp @@ -18,8 +18,6 @@ template constexpr bool common_reverse_iterator_checks() { static_assert(std::indirectly_writable); static_assert(std::sentinel_for); - static_assert(std::sentinel_for>); - static_assert(!std::sized_sentinel_for>); return true; } @@ -55,3 +53,10 @@ static_assert( std::indirectly_movable_storable); static_assert( std::indirectly_copyable_storable); static_assert( std::indirectly_swappable); + +static_assert( std::equality_comparable_with, std::reverse_iterator>); +static_assert(!std::equality_comparable_with, std::reverse_iterator>); +static_assert( std::totally_ordered_with, std::reverse_iterator>); +static_assert(!std::totally_ordered_with, std::reverse_iterator>); +static_assert( std::three_way_comparable_with, std::reverse_iterator>); +static_assert(!std::three_way_comparable_with, std::reverse_iterator>); diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cmp/sfinae.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cmp/sfinae.compile.pass.cpp new file mode 100644 index 00000000000000..9126a793f36582 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cmp/sfinae.compile.pass.cpp @@ -0,0 +1,196 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts + +// +// +// reverse_iterator +// +// template +// constexpr bool // constexpr in C++17 +// operator==(const reverse_iterator& x, const reverse_iterator& y); +// +// template +// constexpr bool // constexpr in C++17 +// operator!=(const reverse_iterator& x, const reverse_iterator& y); +// +// template +// constexpr bool // constexpr in C++17 +// operator<(const reverse_iterator& x, const reverse_iterator& y); +// +// template +// constexpr bool // constexpr in C++17 +// operator>(const reverse_iterator& x, const reverse_iterator& y); +// +// template +// constexpr bool // constexpr in C++17 +// operator<=(const reverse_iterator& x, const reverse_iterator& y); +// +// template +// constexpr bool // constexpr in C++17 +// operator>=(const reverse_iterator& x, const reverse_iterator& y); +// +// template Iterator2> +// constexpr compare_three_way_result_t +// operator<=>(const reverse_iterator& x, +// const reverse_iterator& y); + +#include +#include + +#include "test_macros.h" + +struct IterBase { + using iterator_category = std::bidirectional_iterator_tag; + using value_type = int; + using difference_type = ptrdiff_t; + using pointer = int*; + using reference = int&; + + reference operator*() const; + pointer operator->() const; +}; + +template concept HasEqual = requires (T t) { t == t; }; +template concept HasNotEqual = requires (T t) { t != t; }; +template concept HasLess = requires (T t) { t < t; }; +template concept HasLessOrEqual = requires (T t) { t <= t; }; +template concept HasGreater = requires (T t) { t > t; }; +template concept HasGreaterOrEqual = requires (T t) { t >= t; }; +template concept HasSpaceship = requires (T t) { t <=> t; }; + +// operator == + +struct NoEqualityCompIter : IterBase { + bool operator!=(NoEqualityCompIter) const; + bool operator<(NoEqualityCompIter) const; + bool operator>(NoEqualityCompIter) const; + bool operator<=(NoEqualityCompIter) const; + bool operator>=(NoEqualityCompIter) const; +}; + +static_assert( HasEqual>); +static_assert(!HasEqual>); +static_assert( HasNotEqual>); +static_assert( HasLess>); +static_assert( HasLessOrEqual>); +static_assert( HasGreater>); +static_assert( HasGreaterOrEqual>); + +void Foo() { + std::reverse_iterator i; + (void)i; +} + +// operator != + +struct NoInequalityCompIter : IterBase { + bool operator<(NoInequalityCompIter) const; + bool operator>(NoInequalityCompIter) const; + bool operator<=(NoInequalityCompIter) const; + bool operator>=(NoInequalityCompIter) const; +}; + +static_assert( HasNotEqual>); +static_assert(!HasNotEqual>); +static_assert(!HasEqual>); +static_assert( HasLess>); +static_assert( HasLessOrEqual>); +static_assert( HasGreater>); +static_assert( HasGreaterOrEqual>); + +// operator < + +struct NoGreaterCompIter : IterBase { + bool operator==(NoGreaterCompIter) const; + bool operator!=(NoGreaterCompIter) const; + bool operator<(NoGreaterCompIter) const; + bool operator<=(NoGreaterCompIter) const; + bool operator>=(NoGreaterCompIter) const; +}; + +static_assert( HasLess>); +static_assert(!HasLess>); +static_assert( HasEqual>); +static_assert( HasNotEqual>); +static_assert( HasLessOrEqual>); +static_assert( HasGreater>); +static_assert( HasGreaterOrEqual>); + +// operator > + +struct NoLessCompIter : IterBase { + bool operator==(NoLessCompIter) const; + bool operator!=(NoLessCompIter) const; + bool operator>(NoLessCompIter) const; + bool operator<=(NoLessCompIter) const; + bool operator>=(NoLessCompIter) const; +}; + +static_assert( HasGreater>); +static_assert(!HasGreater>); +static_assert( HasEqual>); +static_assert( HasNotEqual>); +static_assert( HasLess>); +static_assert( HasLessOrEqual>); +static_assert( HasGreaterOrEqual>); + +// operator <= + +struct NoGreaterOrEqualCompIter : IterBase { + bool operator==(NoGreaterOrEqualCompIter) const; + bool operator!=(NoGreaterOrEqualCompIter) const; + bool operator<(NoGreaterOrEqualCompIter) const; + bool operator>(NoGreaterOrEqualCompIter) const; + bool operator<=(NoGreaterOrEqualCompIter) const; +}; + +static_assert( HasLessOrEqual>); +static_assert(!HasLessOrEqual>); +static_assert( HasEqual>); +static_assert( HasNotEqual>); +static_assert( HasLess>); +static_assert( HasGreater>); +static_assert( HasGreaterOrEqual>); + +// operator >= + +struct NoLessOrEqualCompIter : IterBase { + bool operator==(NoLessOrEqualCompIter) const; + bool operator!=(NoLessOrEqualCompIter) const; + bool operator<(NoLessOrEqualCompIter) const; + bool operator>(NoLessOrEqualCompIter) const; + bool operator>=(NoLessOrEqualCompIter) const; +}; + +static_assert( HasGreaterOrEqual>); +static_assert(!HasGreaterOrEqual>); +static_assert( HasEqual>); +static_assert( HasNotEqual>); +static_assert( HasLess>); +static_assert( HasLessOrEqual>); +static_assert( HasGreater>); + +// operator <=> + +static_assert( std::three_way_comparable_with); +static_assert( HasSpaceship>); +static_assert(!std::three_way_comparable_with); +static_assert(!HasSpaceship>); +static_assert(!std::three_way_comparable_with); +static_assert(!HasSpaceship>); +static_assert(!std::three_way_comparable_with); +static_assert(!HasSpaceship>); +static_assert(!std::three_way_comparable_with); +static_assert(!HasSpaceship>); +static_assert(!std::three_way_comparable_with); +static_assert(!HasSpaceship>); +static_assert(!std::three_way_comparable_with); +static_assert(!HasSpaceship>); diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.elem/arrow.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.elem/arrow.pass.cpp index a1c40eac1569d2..bbe9c3ca5802ef 100644 --- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.elem/arrow.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.elem/arrow.pass.cpp @@ -76,43 +76,43 @@ TEST_CONSTEXPR C gC; int main(int, char**) { - A a; - test(&a+1, A()); + A a; + test(&a+1, A()); - { + { std::list l; l.push_back(B(0)); l.push_back(B(1)); l.push_back(B(2)); { - std::list::const_iterator i = l.begin(); - assert ( i->get() == 0 ); ++i; - assert ( i->get() == 1 ); ++i; - assert ( i->get() == 2 ); ++i; - assert ( i == l.end ()); + std::list::const_iterator i = l.begin(); + assert ( i->get() == 0 ); ++i; + assert ( i->get() == 1 ); ++i; + assert ( i->get() == 2 ); ++i; + assert ( i == l.end ()); } { - std::list::const_reverse_iterator ri = l.rbegin(); - assert ( ri->get() == 2 ); ++ri; - assert ( ri->get() == 1 ); ++ri; - assert ( ri->get() == 0 ); ++ri; - assert ( ri == l.rend ()); - } + std::list::const_reverse_iterator ri = l.rbegin(); + assert ( ri->get() == 2 ); ++ri; + assert ( ri->get() == 1 ); ++ri; + assert ( ri->get() == 0 ); ++ri; + assert ( ri == l.rend ()); } + } #if TEST_STD_VER > 14 - { - typedef std::reverse_iterator RI; - constexpr RI it1 = std::make_reverse_iterator(&gC+1); + { + typedef std::reverse_iterator RI; + constexpr RI it1 = std::make_reverse_iterator(&gC+1); - static_assert(it1->get() == gC.get(), ""); - } + static_assert(it1->get() == gC.get(), ""); + } #endif - { - ((void)gC); - } + { + ((void)gC); + } return 0; } diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.elem/arrow.sfinae.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.elem/arrow.sfinae.compile.pass.cpp new file mode 100644 index 00000000000000..b723176a19c45f --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.elem/arrow.sfinae.compile.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// reverse_iterator +// +// pointer operator->() const; + +#include + +#include +#include "test_iterators.h" + +template +concept HasArrow = requires(T t) { t.operator->(); }; + +struct simple_bidirectional_iterator { + using iterator_category = std::bidirectional_iterator_tag; + using value_type = int; + using difference_type = int; + using pointer = int*; + using reference = int&; + + reference operator*() const; + pointer operator->() const; + + simple_bidirectional_iterator& operator++(); + simple_bidirectional_iterator& operator--(); + simple_bidirectional_iterator operator++(int); + simple_bidirectional_iterator operator--(int); + + friend bool operator==(const simple_bidirectional_iterator&, const simple_bidirectional_iterator&); +}; +static_assert( std::bidirectional_iterator); +static_assert(!std::random_access_iterator); + +using PtrRI = std::reverse_iterator; +static_assert( HasArrow); + +using PtrLikeRI = std::reverse_iterator; +static_assert( HasArrow); + +// `bidirectional_iterator` from `test_iterators.h` doesn't define `operator->`. +using NonPtrRI = std::reverse_iterator>; +static_assert(!HasArrow); diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp new file mode 100644 index 00000000000000..acf91784ef9b46 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp @@ -0,0 +1,178 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// +// +// reverse_iterator +// +// friend constexpr iter_rvalue_reference_t +// iter_move(const reverse_iterator& i) noexcept(see below); + +#include + +#include +#include +#include +#include "test_macros.h" + +namespace adl { + +struct Iterator { + using value_type = int; + using difference_type = ptrdiff_t; + + value_type* ptr_ = nullptr; + int* iter_move_invocations_ = nullptr; + + constexpr Iterator() = default; + constexpr explicit Iterator(int* p, int& iter_moves) : ptr_(p), iter_move_invocations_(&iter_moves) {} + + constexpr value_type& operator*() const { return *ptr_; } + + Iterator& operator++() { ++ptr_; return *this; } + Iterator operator++(int) { + Iterator prev = *this; + ++ptr_; + return prev; + } + + constexpr Iterator& operator--() { --ptr_; return *this; } + constexpr Iterator operator--(int) { + Iterator prev = *this; + --ptr_; + return prev; + } + + constexpr friend value_type&& iter_move(Iterator iter) { + if (iter.iter_move_invocations_) { + ++(*iter.iter_move_invocations_); + } + return std::move(*iter); + } + + friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; } +}; + +} // namespace adl + +constexpr bool test() { + // Can use `iter_move` with a regular array. + { + constexpr int N = 3; + int a[N] = {0, 1, 2}; + + std::reverse_iterator ri(a + N); + static_assert(std::same_as); + assert(iter_move(ri) == 2); + + ++ri; + assert(iter_move(ri) == 1); + } + + // Ensure the `iter_move` customization point is being used. + { + constexpr int N = 3; + int a[N] = {0, 1, 2}; + + int iter_move_invocations = 0; + adl::Iterator i(a + N, iter_move_invocations); + std::reverse_iterator ri(i); + int x = iter_move(ri); + assert(x == 2); + assert(iter_move_invocations == 1); + } + + // Check the `noexcept` specification. + { + { + struct ThrowingCopyNoexceptDecrement { + using value_type = int; + using difference_type = ptrdiff_t; + + ThrowingCopyNoexceptDecrement(); + ThrowingCopyNoexceptDecrement(const ThrowingCopyNoexceptDecrement&); + + int& operator*() const noexcept { static int x; return x; } + + ThrowingCopyNoexceptDecrement& operator++(); + ThrowingCopyNoexceptDecrement operator++(int); + ThrowingCopyNoexceptDecrement& operator--() noexcept; + ThrowingCopyNoexceptDecrement operator--(int) noexcept; + + bool operator==(const ThrowingCopyNoexceptDecrement&) const = default; + }; + static_assert(std::bidirectional_iterator); + + static_assert(!std::is_nothrow_copy_constructible_v); + ASSERT_NOEXCEPT(std::ranges::iter_move(--std::declval())); + using RI = std::reverse_iterator; + ASSERT_NOT_NOEXCEPT(iter_move(std::declval())); + } + + { + struct NoexceptCopyThrowingDecrement { + using value_type = int; + using difference_type = ptrdiff_t; + + NoexceptCopyThrowingDecrement(); + NoexceptCopyThrowingDecrement(const NoexceptCopyThrowingDecrement&) noexcept; + + int& operator*() const { static int x; return x; } + + NoexceptCopyThrowingDecrement& operator++(); + NoexceptCopyThrowingDecrement operator++(int); + NoexceptCopyThrowingDecrement& operator--(); + NoexceptCopyThrowingDecrement operator--(int); + + bool operator==(const NoexceptCopyThrowingDecrement&) const = default; + }; + static_assert(std::bidirectional_iterator); + + static_assert( std::is_nothrow_copy_constructible_v); + ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(--std::declval())); + using RI = std::reverse_iterator; + ASSERT_NOT_NOEXCEPT(iter_move(std::declval())); + } + + { + struct NoexceptCopyAndDecrement { + using value_type = int; + using difference_type = ptrdiff_t; + + NoexceptCopyAndDecrement(); + NoexceptCopyAndDecrement(const NoexceptCopyAndDecrement&) noexcept; + + int& operator*() const noexcept { static int x; return x; } + + NoexceptCopyAndDecrement& operator++(); + NoexceptCopyAndDecrement operator++(int); + NoexceptCopyAndDecrement& operator--() noexcept; + NoexceptCopyAndDecrement operator--(int) noexcept; + + bool operator==(const NoexceptCopyAndDecrement&) const = default; + }; + static_assert(std::bidirectional_iterator); + + static_assert( std::is_nothrow_copy_constructible_v); + ASSERT_NOEXCEPT(std::ranges::iter_move(--std::declval())); + using RI = std::reverse_iterator; + ASSERT_NOEXCEPT(iter_move(std::declval())); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp new file mode 100644 index 00000000000000..3ae27368007ab3 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp @@ -0,0 +1,190 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// +// +// reverse_iterator +// +// template Iterator2> +// friend constexpr void +// iter_swap(const reverse_iterator& x, +// const reverse_iterator& y) noexcept(see below); + +#include + +#include +#include +#include +#include "test_macros.h" + +namespace adl { + +struct Iterator { + using value_type = int; + using difference_type = ptrdiff_t; + + value_type* ptr_ = nullptr; + int* iter_swap_invocations_ = nullptr; + + constexpr Iterator() = default; + constexpr explicit Iterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {} + + value_type& operator*() const { return *ptr_; } + + Iterator& operator++() { ++ptr_; return *this; } + Iterator operator++(int) { + Iterator prev = *this; + ++ptr_; + return prev; + } + + Iterator& operator--() { --ptr_; return *this; } + Iterator operator--(int) { + Iterator prev = *this; + --ptr_; + return prev; + } + + constexpr friend void iter_swap(Iterator a, Iterator) { + if (a.iter_swap_invocations_) { + ++(*a.iter_swap_invocations_); + } + } + + friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; } +}; + +} // namespace adl + +constexpr bool test() { + // Can use `iter_swap` with a regular array. + { + constexpr int N = 3; + int a[N] = {0, 1, 2}; + + std::reverse_iterator rb(a + N); + std::reverse_iterator re(a + 1); + assert(a[0] == 0); + assert(a[2] == 2); + + static_assert(std::same_as); + iter_swap(rb, re); + assert(a[0] == 2); + assert(a[2] == 0); + } + + // Ensure the `iter_swap` customization point is being used. + { + int iter_swap_invocations = 0; + adl::Iterator i1(iter_swap_invocations), i2(iter_swap_invocations); + std::reverse_iterator ri1(i1), ri2(i2); + iter_swap(i1, i2); + assert(iter_swap_invocations == 1); + + iter_swap(i2, i1); + assert(iter_swap_invocations == 2); + } + + // Check the `noexcept` specification. + { + { + struct ThrowingCopyNoexceptDecrement { + using value_type = int; + using difference_type = ptrdiff_t; + + ThrowingCopyNoexceptDecrement(); + ThrowingCopyNoexceptDecrement(const ThrowingCopyNoexceptDecrement&); + + int& operator*() const noexcept { static int x; return x; } + + ThrowingCopyNoexceptDecrement& operator++(); + ThrowingCopyNoexceptDecrement operator++(int); + ThrowingCopyNoexceptDecrement& operator--() noexcept; + ThrowingCopyNoexceptDecrement operator--(int) noexcept; + + bool operator==(const ThrowingCopyNoexceptDecrement&) const = default; + }; + static_assert(std::bidirectional_iterator); + + static_assert(!std::is_nothrow_copy_constructible_v); + static_assert( std::is_nothrow_copy_constructible_v); + ASSERT_NOEXCEPT(std::ranges::iter_swap(--std::declval(), --std::declval())); + using RI1 = std::reverse_iterator; + using RI2 = std::reverse_iterator; + ASSERT_NOT_NOEXCEPT(iter_swap(std::declval(), std::declval())); + ASSERT_NOT_NOEXCEPT(iter_swap(std::declval(), std::declval())); + } + + { + struct NoexceptCopyThrowingDecrement { + using value_type = int; + using difference_type = ptrdiff_t; + + NoexceptCopyThrowingDecrement(); + NoexceptCopyThrowingDecrement(const NoexceptCopyThrowingDecrement&) noexcept; + + int& operator*() const { static int x; return x; } + + NoexceptCopyThrowingDecrement& operator++(); + NoexceptCopyThrowingDecrement operator++(int); + NoexceptCopyThrowingDecrement& operator--(); + NoexceptCopyThrowingDecrement operator--(int); + + bool operator==(const NoexceptCopyThrowingDecrement&) const = default; + }; + static_assert(std::bidirectional_iterator); + + static_assert( std::is_nothrow_copy_constructible_v); + static_assert( std::is_nothrow_copy_constructible_v); + ASSERT_NOT_NOEXCEPT(std::ranges::iter_swap(--std::declval(), --std::declval())); + using RI1 = std::reverse_iterator; + using RI2 = std::reverse_iterator; + ASSERT_NOT_NOEXCEPT(iter_swap(std::declval(), std::declval())); + ASSERT_NOT_NOEXCEPT(iter_swap(std::declval(), std::declval())); + } + + { + struct NoexceptCopyAndDecrement { + using value_type = int; + using difference_type = ptrdiff_t; + + NoexceptCopyAndDecrement(); + NoexceptCopyAndDecrement(const NoexceptCopyAndDecrement&) noexcept; + + int& operator*() const noexcept { static int x; return x; } + + NoexceptCopyAndDecrement& operator++(); + NoexceptCopyAndDecrement operator++(int); + NoexceptCopyAndDecrement& operator--() noexcept; + NoexceptCopyAndDecrement operator--(int) noexcept; + + bool operator==(const NoexceptCopyAndDecrement&) const = default; + }; + static_assert(std::bidirectional_iterator); + + static_assert( std::is_nothrow_copy_constructible_v); + static_assert( std::is_nothrow_copy_constructible_v); + ASSERT_NOEXCEPT(std::ranges::iter_swap(--std::declval(), --std::declval())); + using RI1 = std::reverse_iterator; + using RI2 = std::reverse_iterator; + ASSERT_NOEXCEPT(iter_swap(std::declval(), std::declval())); + ASSERT_NOEXCEPT(iter_swap(std::declval(), std::declval())); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/sized_sentinel.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/sized_sentinel.compile.pass.cpp new file mode 100644 index 00000000000000..df53b8ff4de3a5 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/sized_sentinel.compile.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 +// UNSUPPORTED: libcpp-no-concepts + +// reverse_iterator + +#include + +#include "test_iterators.h" + +template concept HasMinus = requires (T t) { t - t; }; + +using sized_it = random_access_iterator; +static_assert( std::sized_sentinel_for); +static_assert( std::sized_sentinel_for, std::reverse_iterator>); +static_assert( HasMinus>); + +// Check that `sized_sentinel_for` is false for `reverse_iterator`s if it is false for the underlying iterators. +using unsized_it = bidirectional_iterator; +static_assert(!std::sized_sentinel_for); +static_assert(!std::sized_sentinel_for, std::reverse_iterator>); +static_assert(!HasMinus>); diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp new file mode 100644 index 00000000000000..419df883f1026a --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// reverse_iterator + +// Test nested types and data member: + +// template +// class reverse_iterator { +// protected: +// Iter current; +// public: +// iterator::iterator_category, +// typename iterator_traits::value_type, +// typename iterator_traits::difference_type, +// typename iterator_traits::pointer, +// typename iterator_traits::reference> { +// }; + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +template +struct find_current + : private std::reverse_iterator +{ + void test() { (void)this->current; } +}; + +template +void test() { + typedef std::reverse_iterator R; + typedef std::iterator_traits T; + find_current q; q.test(); // Just test that we can access `.current` from derived classes + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::value), ""); + static_assert((std::is_same::pointer>::value), ""); + +#if TEST_STD_VER <= 14 + typedef std::iterator iterator_base; + static_assert((std::is_base_of::value), ""); +#endif +#if TEST_STD_VER > 17 + if constexpr (std::is_same_v) { + static_assert((std::is_same::value), ""); + } else { + static_assert((std::is_same::value), ""); + } +#else + static_assert((std::is_same::value), ""); +#endif +} + +#if TEST_STD_VER > 17 + +struct FooIter { + using iterator_category = std::bidirectional_iterator_tag; + using value_type = void*; + using difference_type = void*; + using pointer = void*; + using reference = int&; + int& operator*() const; +}; +template <> +struct std::indirectly_readable_traits { + using value_type = int; +}; +template <> +struct std::incrementable_traits { + using difference_type = char; +}; + +static_assert(std::is_same_v::value_type, int>); +static_assert(std::is_same_v::difference_type, char>); + +#endif + +struct BarIter { + bool& operator*() const; +}; +template <> +struct std::iterator_traits { + using difference_type = char; + using value_type = char; + using pointer = char*; + using reference = char&; + using iterator_category = std::bidirectional_iterator_tag; +}; + +#if TEST_STD_VER > 17 + static_assert(std::is_same_v::reference, bool&>); +#else + static_assert(std::is_same::reference, char&>::value, ""); +#endif + +void test_all() { + test >(); + test >(); + test(); + +#if TEST_STD_VER > 17 + test>(); + static_assert(std::is_same_v>::iterator_concept, std::bidirectional_iterator_tag>); + static_assert(std::is_same_v>::iterator_concept, std::random_access_iterator_tag>); + static_assert(std::is_same_v>::iterator_concept, std::random_access_iterator_tag>); + static_assert(std::is_same_v::iterator_concept, std::random_access_iterator_tag>); +#endif +} diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.pass.cpp deleted file mode 100644 index 939cf87a5d464f..00000000000000 --- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.pass.cpp +++ /dev/null @@ -1,83 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// - -// reverse_iterator - -// Test nested types and data member: - -// template -// class reverse_iterator { -// protected: -// Iter current; -// public: -// iterator::iterator_category, -// typename iterator_traits::value_type, -// typename iterator_traits::difference_type, -// typename iterator_traits::pointer, -// typename iterator_traits::reference> { -// }; - -#include -#include - -#include "test_macros.h" -#include "test_iterators.h" - -template -struct find_current - : private std::reverse_iterator -{ - void test() { (void)this->current; } -}; - -template -void -test() -{ - typedef std::reverse_iterator R; - typedef std::iterator_traits T; - find_current q; q.test(); // Just test that we can access `.current` from derived classes - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::value), ""); - static_assert((std::is_same::pointer>::value), ""); - -#if TEST_STD_VER <= 14 - typedef std::iterator iterator_base; - static_assert((std::is_base_of::value), ""); -#endif -#if TEST_STD_VER > 17 - if constexpr (std::is_same_v) { - static_assert((std::is_same::value), ""); - } else { - static_assert((std::is_same::value), ""); - } -#else - static_assert((std::is_same::value), ""); -#endif -} - -int main(int, char**) -{ - test >(); - test >(); - test(); - -#if TEST_STD_VER > 17 - test>(); - static_assert(std::is_same_v>::iterator_concept, std::bidirectional_iterator_tag>); - static_assert(std::is_same_v>::iterator_concept, std::random_access_iterator_tag>); - static_assert(std::is_same_v>::iterator_concept, std::random_access_iterator_tag>); - static_assert(std::is_same_v::iterator_concept, std::random_access_iterator_tag>); -#endif - - return 0; -}