[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
This commit is contained in:
parent
07998f6d75
commit
658957c79a
|
@ -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]
|
||||
|
|
|
|
@ -141,8 +141,9 @@ public:
|
|||
|
||||
#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 =
|
||||
|
|
|
@ -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 @@ private:
|
|||
_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>::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;
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
typedef _If<__is_cpp17_random_access_iterator<_Iter>::value,
|
||||
using iterator_category = _If<__is_cpp17_random_access_iterator<_Iter>::value,
|
||||
random_access_iterator_tag,
|
||||
bidirectional_iterator_tag> iterator_concept;
|
||||
typename iterator_traits<_Iter>::iterator_category>;
|
||||
using pointer = typename iterator_traits<_Iter>::pointer;
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
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,8 +131,25 @@ public:
|
|||
_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
|
||||
|
@ -134,12 +168,38 @@ public:
|
|||
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);}
|
||||
|
||||
#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>::difference_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
|
||||
|
|
|
@ -225,10 +225,17 @@ class reverse_iterator
|
|||
protected:
|
||||
Iterator current;
|
||||
public:
|
||||
typedef Iterator iterator_type;
|
||||
typedef typename iterator_traits<Iterator>::difference_type difference_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 difference_type = typename iterator_traits<Iterator>::difference_type; // until C++20
|
||||
using difference_type = iter_difference_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+=(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<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>::difference_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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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*>>);
|
||||
|
|
|
@ -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 difference_type = ptrdiff_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>>);
|
|
@ -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 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<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>);
|
|
@ -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 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<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 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<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 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<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 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<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;
|
||||
}
|
|
@ -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 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<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 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<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 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<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 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<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;
|
||||
}
|
|
@ -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>>);
|
|
@ -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>::difference_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::difference_type, typename T::difference_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 difference_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 difference_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>::difference_type, char>);
|
||||
|
||||
#endif
|
||||
|
||||
struct BarIter {
|
||||
bool& operator*() const;
|
||||
};
|
||||
template <>
|
||||
struct std::iterator_traits<BarIter> {
|
||||
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<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
|
||||
}
|
|
@ -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>::difference_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::difference_type, typename T::difference_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;
|
||||
}
|
Loading…
Reference in New Issue