[libcxx-commits] [libcxx] 658957c - [libc++][ranges] Implement changes to reverse_iterator from One Ranges Proposal.
Konstantin Varlamov via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Mar 17 19:58:54 PDT 2022
Author: Konstantin Varlamov
Date: 2022-03-17T19:58:03-07:00
New Revision: 658957c79afa77d306a9869ac669116e5e00109d
URL: https://github.com/llvm/llvm-project/commit/658957c79afa77d306a9869ac669116e5e00109d
DIFF: https://github.com/llvm/llvm-project/commit/658957c79afa77d306a9869ac669116e5e00109d.diff
LOG: [libc++][ranges] Implement changes to reverse_iterator from One Ranges Proposal.
Changes in [P0896](https://wg21.link/p0896):
- add `disable_sized_sentinel_for`;
- add `iter_move` and `iter_swap`;
- add a `requires` clause to the `operator->`;
- add `iterator_concept`;
- check that the `Iterator` template parameter is a bidirectional
iterator;
- add constraints to all comparison operators;
- change the definitions of `iterator_category`, `value_type`,
`difference_type` and `reference` (changes to `iterator_category` were
already implemented).
Also add a few forgotten things to the `reverse_iterator` synopsis
(notably the spaceship operator).
Differential Revision: https://reviews.llvm.org/D120180
Added:
libcxx/test/libcxx/iterators/predef.iterators/reverse.iterators/bad_template_argument.verify.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cmp/sfinae.compile.pass.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.elem/arrow.sfinae.compile.pass.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/sized_sentinel.compile.pass.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp
Modified:
libcxx/docs/Status/RangesPaper.csv
libcxx/include/__iterator/iterator_traits.h
libcxx/include/__iterator/reverse_iterator.h
libcxx/include/iterator
libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.elem/arrow.pass.cpp
Removed:
libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.pass.cpp
################################################################################
diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index ebbc5c10916cc..b70f0645efb6e 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -75,7 +75,7 @@ Section,Description,Dependencies,Assignee,Complete
| `ranges::next <https://llvm.org/D102563>`_
| `ranges::prev <https://llvm.org/D102564>`_",[iterator.concepts],Christopher Di Bella and Arthur O'Dwyer,✅
`[predef.iterators] <https://wg21.link/predef.iterators>`_,"
-| Updates to reverse_iterator
+| `Updates to reverse_iterator <https://llvm.org/D120180>`_
| `Updates to back_insert_iterator <https://llvm.org/D103273>`_
| `Updates to front_insert_iterator <https://llvm.org/D103273>`_
| `Updates to move_iterator <https://llvm.org/D117656>`_","| [iterator.concepts]
diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h
index 775f2270048da..6ce5595addb8b 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<class _Ip>
concept __cpp17_iterator =
diff --git a/libcxx/include/__iterator/reverse_iterator.h b/libcxx/include/__iterator/reverse_iterator.h
index c77f4618534b1..bc07cf33f701c 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 <type_traits>
#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<It> 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>::
diff erence_type
diff erence_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
diff erence_type = iter_
diff erence_t<_Iter>;
+ using reference = iter_reference_t<_Iter>;
+#else
+ using value_type = typename iterator_traits<_Iter>::value_type;
+ using
diff erence_type = typename iterator_traits<_Iter>::
diff erence_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+ (
diff erence_type __n) const {return reverse_iterator(current - __n);}
+ reverse_iterator operator+(
diff erence_type __n) const {return reverse_iterator(current - __n);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
reverse_iterator& operator+=(
diff erence_type __n) {current -= __n; return *this;}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
- reverse_iterator operator- (
diff erence_type __n) const {return reverse_iterator(current + __n);}
+ reverse_iterator operator-(
diff erence_type __n) const {return reverse_iterator(current + __n);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
reverse_iterator& operator-=(
diff erence_type __n) {current += __n; return *this;}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
- reference operator[](
diff erence_type __n) const {return *(*this + __n);}
+ reference operator[](
diff erence_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 <indirectly_swappable<_Iter> _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 <class _Iter1, class _Iter2>
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<bool>;
+ }
+#endif // _LIBCPP_STD_VER > 17
{
return __x.base() == __y.base();
}
@@ -148,6 +208,11 @@ template <class _Iter1, class _Iter2>
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<bool>;
+ }
+#endif // _LIBCPP_STD_VER > 17
{
return __x.base() > __y.base();
}
@@ -156,6 +221,11 @@ template <class _Iter1, class _Iter2>
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<bool>;
+ }
+#endif // _LIBCPP_STD_VER > 17
{
return __x.base() != __y.base();
}
@@ -164,6 +234,11 @@ template <class _Iter1, class _Iter2>
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<bool>;
+ }
+#endif // _LIBCPP_STD_VER > 17
{
return __x.base() < __y.base();
}
@@ -172,6 +247,11 @@ template <class _Iter1, class _Iter2>
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<bool>;
+ }
+#endif // _LIBCPP_STD_VER > 17
{
return __x.base() <= __y.base();
}
@@ -180,6 +260,11 @@ template <class _Iter1, class _Iter2>
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<bool>;
+ }
+#endif // _LIBCPP_STD_VER > 17
{
return __x.base() >= __y.base();
}
@@ -221,6 +306,12 @@ operator+(typename reverse_iterator<_Iter>::
diff erence_type __n, const reverse_i
return reverse_iterator<_Iter>(__x.base() - __n);
}
+#if _LIBCPP_STD_VER > 17
+template <class _Iter1, class _Iter2>
+ requires (!sized_sentinel_for<_Iter1, _Iter2>)
+inline constexpr bool disable_sized_sentinel_for<reverse_iterator<_Iter1>, reverse_iterator<_Iter2>> = true;
+#endif // _LIBCPP_STD_VER > 17
+
#if _LIBCPP_STD_VER > 11
template <class _Iter>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
diff --git a/libcxx/include/iterator b/libcxx/include/iterator
index 852fa353a9c2a..8ba4d0ccb17cf 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<Iterator>::
diff erence_type
diff erence_type;
- typedef typename iterator_traits<Iterator>::reference reference;
- typedef typename iterator_traits<Iterator>::pointer pointer;
+ using iterator_type = Iterator;
+ using iterator_concept = see below; // since C++20
+ using iterator_category = typename iterator_traits<Iterator>::iterator_category; // since C++17, until C++20
+ using iterator_category = see below; // since C++20
+ using value_type = typename iterator_traits<Iterator>::value_type; // since C++17, until C++20
+ using value_type = iter_value_t<Iterator>; // since C++20
+ using
diff erence_type = typename iterator_traits<Iterator>::
diff erence_type; // until C++20
+ using
diff erence_type = iter_
diff erence_t<Iterator>; // since C++20
+ using pointer = typename iterator_traits<Iterator>::pointer;
+ using reference = typename iterator_traits<Iterator>::reference; // until C++20
+ using reference = iter_reference_t<Iterator>; // since C++20
constexpr reverse_iterator();
constexpr explicit reverse_iterator(Iterator x);
@@ -236,7 +243,8 @@ public:
template <class U> constexpr reverse_iterator& operator=(const reverse_iterator<U>& 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+=(
diff erence_type n);
constexpr reverse_iterator operator- (
diff erence_type n) const;
constexpr reverse_iterator& operator-=(
diff erence_type n);
- constexpr reference operator[](
diff erence_type n) const;
+ constexpr unspecified operator[](
diff erence_type n) const;
+
+ friend constexpr iter_rvalue_reference_t<Iterator>
+ iter_move(const reverse_iterator& i) noexcept(see below);
+ template<indirectly_swappable<Iterator> Iterator2>
+ friend constexpr void
+ iter_swap(const reverse_iterator& x,
+ const reverse_iterator<Iterator2>& y) noexcept(see below);
};
template <class Iterator1, class Iterator2>
@@ -254,11 +269,11 @@ operator==(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator
template <class Iterator1, class Iterator2>
constexpr bool // constexpr in C++17
-operator<(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+operator!=(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
template <class Iterator1, class Iterator2>
constexpr bool // constexpr in C++17
-operator!=(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+operator<(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
template <class Iterator1, class Iterator2>
constexpr bool // constexpr in C++17
@@ -266,11 +281,16 @@ operator>(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2
template <class Iterator1, class Iterator2>
constexpr bool // constexpr in C++17
-operator>=(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+operator<=(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
template <class Iterator1, class Iterator2>
constexpr bool // constexpr in C++17
-operator<=(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+operator>=(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+
+template<class Iterator1, three_way_comparable_with<Iterator1> Iterator2>
+ constexpr compare_three_way_result_t<Iterator1, Iterator2>
+ operator<=>(const reverse_iterator<Iterator1>& x,
+ const reverse_iterator<Iterator2>& y);
template <class Iterator1, class Iterator2>
constexpr auto
@@ -285,6 +305,11 @@ operator+(typename reverse_iterator<Iterator>::
diff erence_type n,
template <class Iterator>
constexpr reverse_iterator<Iterator> make_reverse_iterator(Iterator i); // C++14, constexpr in C++17
+template<class Iterator1, class Iterator2>
+ requires (!sized_sentinel_for<Iterator1, Iterator2>)
+ inline constexpr bool disable_sized_sentinel_for<reverse_iterator<Iterator1>,
+ reverse_iterator<Iterator2>> = true;
+
template <class Container>
class back_insert_iterator
: public iterator<output_iterator_tag, void, void, void, void> // 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 0000000000000..9849173d11a8d
--- /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
+
+// <iterator>
+
+// reverse_iterator
+
+#include <iterator>
+
+#include "test_iterators.h"
+
+int main(int, char**) {
+ using BadIter = std::reverse_iterator<forward_iterator<int*>>;
+ BadIter i; //expected-error-re@*:* {{static_assert failed{{.*}} "reverse_iterator<It> 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 66ddef131b5ac..4aae0447d4efb 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<class I1>
constexpr bool common_reverse_iterator_checks() {
static_assert(std::indirectly_writable<I1, int>);
static_assert(std::sentinel_for<I1, I1>);
- static_assert(std::sentinel_for<I1, std::reverse_iterator<float*>>);
- static_assert(!std::sized_sentinel_for<I1, std::reverse_iterator<float*>>);
return true;
}
@@ -55,3 +53,10 @@ static_assert( std::indirectly_movable_storable<reverse_contiguous_iterator, rev
static_assert( std::indirectly_copyable<reverse_contiguous_iterator, reverse_contiguous_iterator>);
static_assert( std::indirectly_copyable_storable<reverse_contiguous_iterator, reverse_contiguous_iterator>);
static_assert( std::indirectly_swappable<reverse_contiguous_iterator, reverse_contiguous_iterator>);
+
+static_assert( std::equality_comparable_with<std::reverse_iterator<int*>, std::reverse_iterator<const int*>>);
+static_assert(!std::equality_comparable_with<std::reverse_iterator<int*>, std::reverse_iterator<char*>>);
+static_assert( std::totally_ordered_with<std::reverse_iterator<int*>, std::reverse_iterator<const int*>>);
+static_assert(!std::totally_ordered_with<std::reverse_iterator<int*>, std::reverse_iterator<char*>>);
+static_assert( std::three_way_comparable_with<std::reverse_iterator<int*>, std::reverse_iterator<const int*>>);
+static_assert(!std::three_way_comparable_with<std::reverse_iterator<int*>, std::reverse_iterator<char*>>);
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 0000000000000..9126a793f3658
--- /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
+
+// <iterator>
+//
+// reverse_iterator
+//
+// template <class Iterator1, class Iterator2>
+// constexpr bool // constexpr in C++17
+// operator==(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+//
+// template <class Iterator1, class Iterator2>
+// constexpr bool // constexpr in C++17
+// operator!=(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+//
+// template <class Iterator1, class Iterator2>
+// constexpr bool // constexpr in C++17
+// operator<(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+//
+// template <class Iterator1, class Iterator2>
+// constexpr bool // constexpr in C++17
+// operator>(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+//
+// template <class Iterator1, class Iterator2>
+// constexpr bool // constexpr in C++17
+// operator<=(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+//
+// template <class Iterator1, class Iterator2>
+// constexpr bool // constexpr in C++17
+// operator>=(const reverse_iterator<Iterator1>& x, const reverse_iterator<Iterator2>& y);
+//
+// template<class Iterator1, three_way_comparable_with<Iterator1> Iterator2>
+// constexpr compare_three_way_result_t<Iterator1, Iterator2>
+// operator<=>(const reverse_iterator<Iterator1>& x,
+// const reverse_iterator<Iterator2>& y);
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+
+struct IterBase {
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = int;
+ using
diff erence_type = ptr
diff _t;
+ using pointer = int*;
+ using reference = int&;
+
+ reference operator*() const;
+ pointer operator->() const;
+};
+
+template<class T> concept HasEqual = requires (T t) { t == t; };
+template<class T> concept HasNotEqual = requires (T t) { t != t; };
+template<class T> concept HasLess = requires (T t) { t < t; };
+template<class T> concept HasLessOrEqual = requires (T t) { t <= t; };
+template<class T> concept HasGreater = requires (T t) { t > t; };
+template<class T> concept HasGreaterOrEqual = requires (T t) { t >= t; };
+template<class T> 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<std::reverse_iterator<int*>>);
+static_assert(!HasEqual<std::reverse_iterator<NoEqualityCompIter>>);
+static_assert( HasNotEqual<std::reverse_iterator<NoEqualityCompIter>>);
+static_assert( HasLess<std::reverse_iterator<NoEqualityCompIter>>);
+static_assert( HasLessOrEqual<std::reverse_iterator<NoEqualityCompIter>>);
+static_assert( HasGreater<std::reverse_iterator<NoEqualityCompIter>>);
+static_assert( HasGreaterOrEqual<std::reverse_iterator<NoEqualityCompIter>>);
+
+void Foo() {
+ std::reverse_iterator<NoEqualityCompIter> 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<std::reverse_iterator<int*>>);
+static_assert(!HasNotEqual<std::reverse_iterator<NoInequalityCompIter>>);
+static_assert(!HasEqual<std::reverse_iterator<NoInequalityCompIter>>);
+static_assert( HasLess<std::reverse_iterator<NoInequalityCompIter>>);
+static_assert( HasLessOrEqual<std::reverse_iterator<NoInequalityCompIter>>);
+static_assert( HasGreater<std::reverse_iterator<NoInequalityCompIter>>);
+static_assert( HasGreaterOrEqual<std::reverse_iterator<NoInequalityCompIter>>);
+
+// 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<std::reverse_iterator<int*>>);
+static_assert(!HasLess<std::reverse_iterator<NoGreaterCompIter>>);
+static_assert( HasEqual<std::reverse_iterator<NoGreaterCompIter>>);
+static_assert( HasNotEqual<std::reverse_iterator<NoGreaterCompIter>>);
+static_assert( HasLessOrEqual<std::reverse_iterator<NoGreaterCompIter>>);
+static_assert( HasGreater<std::reverse_iterator<NoGreaterCompIter>>);
+static_assert( HasGreaterOrEqual<std::reverse_iterator<NoGreaterCompIter>>);
+
+// 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<std::reverse_iterator<int*>>);
+static_assert(!HasGreater<std::reverse_iterator<NoLessCompIter>>);
+static_assert( HasEqual<std::reverse_iterator<NoLessCompIter>>);
+static_assert( HasNotEqual<std::reverse_iterator<NoLessCompIter>>);
+static_assert( HasLess<std::reverse_iterator<NoLessCompIter>>);
+static_assert( HasLessOrEqual<std::reverse_iterator<NoLessCompIter>>);
+static_assert( HasGreaterOrEqual<std::reverse_iterator<NoLessCompIter>>);
+
+// 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<std::reverse_iterator<int*>>);
+static_assert(!HasLessOrEqual<std::reverse_iterator<NoGreaterOrEqualCompIter>>);
+static_assert( HasEqual<std::reverse_iterator<NoGreaterOrEqualCompIter>>);
+static_assert( HasNotEqual<std::reverse_iterator<NoGreaterOrEqualCompIter>>);
+static_assert( HasLess<std::reverse_iterator<NoGreaterOrEqualCompIter>>);
+static_assert( HasGreater<std::reverse_iterator<NoGreaterOrEqualCompIter>>);
+static_assert( HasGreaterOrEqual<std::reverse_iterator<NoGreaterOrEqualCompIter>>);
+
+// 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<std::reverse_iterator<int*>>);
+static_assert(!HasGreaterOrEqual<std::reverse_iterator<NoLessOrEqualCompIter>>);
+static_assert( HasEqual<std::reverse_iterator<NoLessOrEqualCompIter>>);
+static_assert( HasNotEqual<std::reverse_iterator<NoLessOrEqualCompIter>>);
+static_assert( HasLess<std::reverse_iterator<NoLessOrEqualCompIter>>);
+static_assert( HasLessOrEqual<std::reverse_iterator<NoLessOrEqualCompIter>>);
+static_assert( HasGreater<std::reverse_iterator<NoLessOrEqualCompIter>>);
+
+// operator <=>
+
+static_assert( std::three_way_comparable_with<int*, int*>);
+static_assert( HasSpaceship<std::reverse_iterator<int*>>);
+static_assert(!std::three_way_comparable_with<NoEqualityCompIter, NoEqualityCompIter>);
+static_assert(!HasSpaceship<std::reverse_iterator<NoEqualityCompIter>>);
+static_assert(!std::three_way_comparable_with<NoInequalityCompIter, NoInequalityCompIter>);
+static_assert(!HasSpaceship<std::reverse_iterator<NoInequalityCompIter>>);
+static_assert(!std::three_way_comparable_with<NoGreaterCompIter, NoGreaterCompIter>);
+static_assert(!HasSpaceship<std::reverse_iterator<NoGreaterCompIter>>);
+static_assert(!std::three_way_comparable_with<NoLessCompIter, NoLessCompIter>);
+static_assert(!HasSpaceship<std::reverse_iterator<NoLessCompIter>>);
+static_assert(!std::three_way_comparable_with<NoGreaterOrEqualCompIter, NoGreaterOrEqualCompIter>);
+static_assert(!HasSpaceship<std::reverse_iterator<NoGreaterOrEqualCompIter>>);
+static_assert(!std::three_way_comparable_with<NoLessOrEqualCompIter, NoLessOrEqualCompIter>);
+static_assert(!HasSpaceship<std::reverse_iterator<NoLessOrEqualCompIter>>);
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 a1c40eac1569d..bbe9c3ca5802e 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<B> l;
l.push_back(B(0));
l.push_back(B(1));
l.push_back(B(2));
{
- std::list<B>::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<B>::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<B>::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<B>::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<const C *> RI;
- constexpr RI it1 = std::make_reverse_iterator(&gC+1);
+ {
+ typedef std::reverse_iterator<const C *> 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 0000000000000..b723176a19c45
--- /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
+
+// <iterator>
+//
+// reverse_iterator
+//
+// pointer operator->() const;
+
+#include <iterator>
+
+#include <type_traits>
+#include "test_iterators.h"
+
+template <class T>
+concept HasArrow = requires(T t) { t.operator->(); };
+
+struct simple_bidirectional_iterator {
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = int;
+ using
diff erence_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<simple_bidirectional_iterator>);
+static_assert(!std::random_access_iterator<simple_bidirectional_iterator>);
+
+using PtrRI = std::reverse_iterator<int*>;
+static_assert( HasArrow<PtrRI>);
+
+using PtrLikeRI = std::reverse_iterator<simple_bidirectional_iterator>;
+static_assert( HasArrow<PtrLikeRI>);
+
+// `bidirectional_iterator` from `test_iterators.h` doesn't define `operator->`.
+using NonPtrRI = std::reverse_iterator<bidirectional_iterator<int*>>;
+static_assert(!HasArrow<NonPtrRI>);
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 0000000000000..acf91784ef9b4
--- /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
+
+// <iterator>
+//
+// reverse_iterator
+//
+// friend constexpr iter_rvalue_reference_t<Iterator>
+// iter_move(const reverse_iterator& i) noexcept(see below);
+
+#include <iterator>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include "test_macros.h"
+
+namespace adl {
+
+struct Iterator {
+ using value_type = int;
+ using
diff erence_type = ptr
diff _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<int*> ri(a + N);
+ static_assert(std::same_as<decltype(iter_move(ri)), int&&>);
+ 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<adl::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
diff erence_type = ptr
diff _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<ThrowingCopyNoexceptDecrement>);
+
+ static_assert(!std::is_nothrow_copy_constructible_v<ThrowingCopyNoexceptDecrement>);
+ ASSERT_NOEXCEPT(std::ranges::iter_move(--std::declval<ThrowingCopyNoexceptDecrement&>()));
+ using RI = std::reverse_iterator<ThrowingCopyNoexceptDecrement>;
+ ASSERT_NOT_NOEXCEPT(iter_move(std::declval<RI>()));
+ }
+
+ {
+ struct NoexceptCopyThrowingDecrement {
+ using value_type = int;
+ using
diff erence_type = ptr
diff _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<NoexceptCopyThrowingDecrement>);
+
+ static_assert( std::is_nothrow_copy_constructible_v<NoexceptCopyThrowingDecrement>);
+ ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(--std::declval<NoexceptCopyThrowingDecrement&>()));
+ using RI = std::reverse_iterator<NoexceptCopyThrowingDecrement>;
+ ASSERT_NOT_NOEXCEPT(iter_move(std::declval<RI>()));
+ }
+
+ {
+ struct NoexceptCopyAndDecrement {
+ using value_type = int;
+ using
diff erence_type = ptr
diff _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<NoexceptCopyAndDecrement>);
+
+ static_assert( std::is_nothrow_copy_constructible_v<NoexceptCopyAndDecrement>);
+ ASSERT_NOEXCEPT(std::ranges::iter_move(--std::declval<NoexceptCopyAndDecrement&>()));
+ using RI = std::reverse_iterator<NoexceptCopyAndDecrement>;
+ ASSERT_NOEXCEPT(iter_move(std::declval<RI>()));
+ }
+ }
+
+ 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 0000000000000..3ae27368007ab
--- /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
+
+// <iterator>
+//
+// reverse_iterator
+//
+// template<indirectly_swappable<Iterator> Iterator2>
+// friend constexpr void
+// iter_swap(const reverse_iterator& x,
+// const reverse_iterator<Iterator2>& y) noexcept(see below);
+
+#include <iterator>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include "test_macros.h"
+
+namespace adl {
+
+struct Iterator {
+ using value_type = int;
+ using
diff erence_type = ptr
diff _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<decltype(iter_swap(rb, re)), void>);
+ 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<adl::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
diff erence_type = ptr
diff _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<ThrowingCopyNoexceptDecrement>);
+
+ static_assert(!std::is_nothrow_copy_constructible_v<ThrowingCopyNoexceptDecrement>);
+ static_assert( std::is_nothrow_copy_constructible_v<int*>);
+ ASSERT_NOEXCEPT(std::ranges::iter_swap(--std::declval<ThrowingCopyNoexceptDecrement&>(), --std::declval<int*&>()));
+ using RI1 = std::reverse_iterator<ThrowingCopyNoexceptDecrement>;
+ using RI2 = std::reverse_iterator<int*>;
+ ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<RI1>(), std::declval<RI2>()));
+ ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<RI2>(), std::declval<RI1>()));
+ }
+
+ {
+ struct NoexceptCopyThrowingDecrement {
+ using value_type = int;
+ using
diff erence_type = ptr
diff _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<NoexceptCopyThrowingDecrement>);
+
+ static_assert( std::is_nothrow_copy_constructible_v<NoexceptCopyThrowingDecrement>);
+ static_assert( std::is_nothrow_copy_constructible_v<int*>);
+ ASSERT_NOT_NOEXCEPT(std::ranges::iter_swap(--std::declval<NoexceptCopyThrowingDecrement&>(), --std::declval<int*&>()));
+ using RI1 = std::reverse_iterator<NoexceptCopyThrowingDecrement>;
+ using RI2 = std::reverse_iterator<int*>;
+ ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<RI1>(), std::declval<RI2>()));
+ ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<RI2>(), std::declval<RI1>()));
+ }
+
+ {
+ struct NoexceptCopyAndDecrement {
+ using value_type = int;
+ using
diff erence_type = ptr
diff _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<NoexceptCopyAndDecrement>);
+
+ static_assert( std::is_nothrow_copy_constructible_v<NoexceptCopyAndDecrement>);
+ static_assert( std::is_nothrow_copy_constructible_v<int*>);
+ ASSERT_NOEXCEPT(std::ranges::iter_swap(--std::declval<NoexceptCopyAndDecrement&>(), --std::declval<int*&>()));
+ using RI1 = std::reverse_iterator<NoexceptCopyAndDecrement>;
+ using RI2 = std::reverse_iterator<int*>;
+ ASSERT_NOEXCEPT(iter_swap(std::declval<RI1>(), std::declval<RI2>()));
+ ASSERT_NOEXCEPT(iter_swap(std::declval<RI2>(), std::declval<RI1>()));
+ }
+ }
+
+ 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 0000000000000..df53b8ff4de3a
--- /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 <iterator>
+
+#include "test_iterators.h"
+
+template<class T> concept HasMinus = requires (T t) { t - t; };
+
+using sized_it = random_access_iterator<int*>;
+static_assert( std::sized_sentinel_for<sized_it, sized_it>);
+static_assert( std::sized_sentinel_for<std::reverse_iterator<sized_it>, std::reverse_iterator<sized_it>>);
+static_assert( HasMinus<std::reverse_iterator<sized_it>>);
+
+// Check that `sized_sentinel_for` is false for `reverse_iterator`s if it is false for the underlying iterators.
+using unsized_it = bidirectional_iterator<int*>;
+static_assert(!std::sized_sentinel_for<unsized_it, unsized_it>);
+static_assert(!std::sized_sentinel_for<std::reverse_iterator<unsized_it>, std::reverse_iterator<unsized_it>>);
+static_assert(!HasMinus<std::reverse_iterator<unsized_it>>);
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 0000000000000..419df883f1026
--- /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
+//
+//===----------------------------------------------------------------------===//
+
+// <iterator>
+
+// reverse_iterator
+
+// Test nested types and data member:
+
+// template <BidirectionalIterator Iter>
+// class reverse_iterator {
+// protected:
+// Iter current;
+// public:
+// iterator<typename iterator_traits<Iterator>::iterator_category,
+// typename iterator_traits<Iterator>::value_type,
+// typename iterator_traits<Iterator>::
diff erence_type,
+// typename iterator_traits<Iterator>::pointer,
+// typename iterator_traits<Iterator>::reference> {
+// };
+
+#include <iterator>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+template <class It>
+struct find_current
+ : private std::reverse_iterator<It>
+{
+ void test() { (void)this->current; }
+};
+
+template <class It>
+void test() {
+ typedef std::reverse_iterator<It> R;
+ typedef std::iterator_traits<It> T;
+ find_current<It> q; q.test(); // Just test that we can access `.current` from derived classes
+ static_assert((std::is_same<typename R::iterator_type, It>::value), "");
+ static_assert((std::is_same<typename R::value_type, typename T::value_type>::value), "");
+ static_assert((std::is_same<typename R::
diff erence_type, typename T::
diff erence_type>::value), "");
+ static_assert((std::is_same<typename R::reference, typename T::reference>::value), "");
+ static_assert((std::is_same<typename R::pointer, typename std::iterator_traits<It>::pointer>::value), "");
+
+#if TEST_STD_VER <= 14
+ typedef std::iterator<typename T::iterator_category, typename T::value_type> iterator_base;
+ static_assert((std::is_base_of<iterator_base, R>::value), "");
+#endif
+#if TEST_STD_VER > 17
+ if constexpr (std::is_same_v<typename T::iterator_category, std::contiguous_iterator_tag>) {
+ static_assert((std::is_same<typename R::iterator_category, std::random_access_iterator_tag>::value), "");
+ } else {
+ static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
+ }
+#else
+ static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
+#endif
+}
+
+#if TEST_STD_VER > 17
+
+struct FooIter {
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = void*;
+ using
diff erence_type = void*;
+ using pointer = void*;
+ using reference = int&;
+ int& operator*() const;
+};
+template <>
+struct std::indirectly_readable_traits<FooIter> {
+ using value_type = int;
+};
+template <>
+struct std::incrementable_traits<FooIter> {
+ using
diff erence_type = char;
+};
+
+static_assert(std::is_same_v<typename std::reverse_iterator<FooIter>::value_type, int>);
+static_assert(std::is_same_v<typename std::reverse_iterator<FooIter>::
diff erence_type, char>);
+
+#endif
+
+struct BarIter {
+ bool& operator*() const;
+};
+template <>
+struct std::iterator_traits<BarIter> {
+ using
diff erence_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<typename std::reverse_iterator<BarIter>::reference, bool&>);
+#else
+ static_assert(std::is_same<typename std::reverse_iterator<BarIter>::reference, char&>::value, "");
+#endif
+
+void test_all() {
+ test<bidirectional_iterator<char*> >();
+ test<random_access_iterator<char*> >();
+ test<char*>();
+
+#if TEST_STD_VER > 17
+ test<contiguous_iterator<char*>>();
+ static_assert(std::is_same_v<typename std::reverse_iterator<bidirectional_iterator<char*>>::iterator_concept, std::bidirectional_iterator_tag>);
+ static_assert(std::is_same_v<typename std::reverse_iterator<random_access_iterator<char*>>::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::is_same_v<typename std::reverse_iterator<contiguous_iterator<char*>>::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::is_same_v<typename std::reverse_iterator<char*>::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 939cf87a5d464..0000000000000
--- 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
-//
-//===----------------------------------------------------------------------===//
-
-// <iterator>
-
-// reverse_iterator
-
-// Test nested types and data member:
-
-// template <BidirectionalIterator Iter>
-// class reverse_iterator {
-// protected:
-// Iter current;
-// public:
-// iterator<typename iterator_traits<Iterator>::iterator_category,
-// typename iterator_traits<Iterator>::value_type,
-// typename iterator_traits<Iterator>::
diff erence_type,
-// typename iterator_traits<Iterator>::pointer,
-// typename iterator_traits<Iterator>::reference> {
-// };
-
-#include <iterator>
-#include <type_traits>
-
-#include "test_macros.h"
-#include "test_iterators.h"
-
-template <class It>
-struct find_current
- : private std::reverse_iterator<It>
-{
- void test() { (void)this->current; }
-};
-
-template <class It>
-void
-test()
-{
- typedef std::reverse_iterator<It> R;
- typedef std::iterator_traits<It> T;
- find_current<It> q; q.test(); // Just test that we can access `.current` from derived classes
- static_assert((std::is_same<typename R::iterator_type, It>::value), "");
- static_assert((std::is_same<typename R::value_type, typename T::value_type>::value), "");
- static_assert((std::is_same<typename R::
diff erence_type, typename T::
diff erence_type>::value), "");
- static_assert((std::is_same<typename R::reference, typename T::reference>::value), "");
- static_assert((std::is_same<typename R::pointer, typename std::iterator_traits<It>::pointer>::value), "");
-
-#if TEST_STD_VER <= 14
- typedef std::iterator<typename T::iterator_category, typename T::value_type> iterator_base;
- static_assert((std::is_base_of<iterator_base, R>::value), "");
-#endif
-#if TEST_STD_VER > 17
- if constexpr (std::is_same_v<typename T::iterator_category, std::contiguous_iterator_tag>) {
- static_assert((std::is_same<typename R::iterator_category, std::random_access_iterator_tag>::value), "");
- } else {
- static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
- }
-#else
- static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
-#endif
-}
-
-int main(int, char**)
-{
- test<bidirectional_iterator<char*> >();
- test<random_access_iterator<char*> >();
- test<char*>();
-
-#if TEST_STD_VER > 17
- test<contiguous_iterator<char*>>();
- static_assert(std::is_same_v<typename std::reverse_iterator<bidirectional_iterator<char*>>::iterator_concept, std::bidirectional_iterator_tag>);
- static_assert(std::is_same_v<typename std::reverse_iterator<random_access_iterator<char*>>::iterator_concept, std::random_access_iterator_tag>);
- static_assert(std::is_same_v<typename std::reverse_iterator<contiguous_iterator<char*>>::iterator_concept, std::random_access_iterator_tag>);
- static_assert(std::is_same_v<typename std::reverse_iterator<char*>::iterator_concept, std::random_access_iterator_tag>);
-#endif
-
- return 0;
-}
More information about the libcxx-commits
mailing list