| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SUPPORT_TEST_ITERATORS_H |
| #define SUPPORT_TEST_ITERATORS_H |
| |
| #include <cassert> |
| #include <iterator> |
| #include <stdexcept> |
| #include <utility> |
| |
| #include "test_macros.h" |
| |
| template <class It> |
| class output_iterator |
| { |
| It it_; |
| |
| template <class U> friend class output_iterator; |
| public: |
| typedef std::output_iterator_tag iterator_category; |
| typedef void value_type; |
| typedef typename std::iterator_traits<It>::difference_type difference_type; |
| typedef It pointer; |
| typedef typename std::iterator_traits<It>::reference reference; |
| |
| TEST_CONSTEXPR_CXX14 It base() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 output_iterator() {} |
| explicit TEST_CONSTEXPR_CXX14 output_iterator(It it) : it_(it) {} |
| template <class U> |
| TEST_CONSTEXPR_CXX14 output_iterator(const output_iterator<U>& u) :it_(u.it_) {} |
| |
| TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} |
| |
| TEST_CONSTEXPR_CXX14 output_iterator& operator++() {++it_; return *this;} |
| TEST_CONSTEXPR_CXX14 output_iterator operator++(int) |
| {output_iterator tmp(*this); ++(*this); return tmp;} |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| }; |
| |
| // This is the Cpp17InputIterator requirement as described in Table 87 ([input.iterators]), |
| // formerly known as InputIterator prior to C++20. |
| template <class It, class ItTraits = It> |
| class cpp17_input_iterator |
| { |
| typedef std::iterator_traits<ItTraits> Traits; |
| It it_; |
| |
| template <class U, class T> friend class cpp17_input_iterator; |
| public: |
| typedef std::input_iterator_tag iterator_category; |
| typedef typename Traits::value_type value_type; |
| typedef typename Traits::difference_type difference_type; |
| typedef It pointer; |
| typedef typename Traits::reference reference; |
| |
| TEST_CONSTEXPR_CXX14 It base() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 cpp17_input_iterator() : it_() {} |
| explicit TEST_CONSTEXPR_CXX14 cpp17_input_iterator(It it) : it_(it) {} |
| template <class U, class T> |
| TEST_CONSTEXPR_CXX14 cpp17_input_iterator(const cpp17_input_iterator<U, T>& u) :it_(u.it_) {} |
| |
| TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} |
| TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 cpp17_input_iterator& operator++() {++it_; return *this;} |
| TEST_CONSTEXPR_CXX14 cpp17_input_iterator operator++(int) |
| {cpp17_input_iterator tmp(*this); ++(*this); return tmp;} |
| |
| friend TEST_CONSTEXPR_CXX14 bool operator==(const cpp17_input_iterator& x, const cpp17_input_iterator& y) |
| {return x.it_ == y.it_;} |
| friend TEST_CONSTEXPR_CXX14 bool operator!=(const cpp17_input_iterator& x, const cpp17_input_iterator& y) |
| {return !(x == y);} |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| }; |
| |
| template <class T, class TV, class U, class UV> |
| bool operator==(const cpp17_input_iterator<T, TV>& x, const cpp17_input_iterator<U, UV>& y) |
| { |
| return x.base() == y.base(); |
| } |
| |
| template <class T, class TV, class U, class UV> |
| bool operator!=(const cpp17_input_iterator<T, TV>& x, const cpp17_input_iterator<U, UV>& y) |
| { |
| return !(x == y); |
| } |
| |
| template <class It> |
| class forward_iterator |
| { |
| It it_; |
| |
| template <class U> friend class forward_iterator; |
| public: |
| typedef std::forward_iterator_tag iterator_category; |
| typedef typename std::iterator_traits<It>::value_type value_type; |
| typedef typename std::iterator_traits<It>::difference_type difference_type; |
| typedef It pointer; |
| typedef typename std::iterator_traits<It>::reference reference; |
| |
| TEST_CONSTEXPR_CXX14 It base() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 forward_iterator() : it_() {} |
| explicit TEST_CONSTEXPR_CXX14 forward_iterator(It it) : it_(it) {} |
| template <class U> |
| TEST_CONSTEXPR_CXX14 forward_iterator(const forward_iterator<U>& u) :it_(u.it_) {} |
| |
| TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} |
| TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 forward_iterator& operator++() {++it_; return *this;} |
| TEST_CONSTEXPR_CXX14 forward_iterator operator++(int) |
| {forward_iterator tmp(*this); ++(*this); return tmp;} |
| |
| friend TEST_CONSTEXPR_CXX14 bool operator==(const forward_iterator& x, const forward_iterator& y) |
| {return x.it_ == y.it_;} |
| friend TEST_CONSTEXPR_CXX14 bool operator!=(const forward_iterator& x, const forward_iterator& y) |
| {return !(x == y);} |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| }; |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator==(const forward_iterator<T>& x, const forward_iterator<U>& y) |
| { |
| return x.base() == y.base(); |
| } |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator!=(const forward_iterator<T>& x, const forward_iterator<U>& y) |
| { |
| return !(x == y); |
| } |
| |
| template <class It> |
| class non_default_constructible_iterator |
| { |
| It it_; |
| |
| template <class U> friend class non_default_constructible_iterator; |
| public: |
| typedef std::input_iterator_tag iterator_category; |
| typedef typename std::iterator_traits<It>::value_type value_type; |
| typedef typename std::iterator_traits<It>::difference_type difference_type; |
| typedef It pointer; |
| typedef typename std::iterator_traits<It>::reference reference; |
| |
| TEST_CONSTEXPR_CXX14 It base() const {return it_;} |
| |
| non_default_constructible_iterator() = delete; |
| |
| explicit TEST_CONSTEXPR_CXX14 non_default_constructible_iterator(It it) : it_(it) {} |
| template <class U> |
| TEST_CONSTEXPR_CXX14 non_default_constructible_iterator(const non_default_constructible_iterator<U>& u) :it_(u.it_) {} |
| |
| TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} |
| TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 non_default_constructible_iterator& operator++() {++it_; return *this;} |
| TEST_CONSTEXPR_CXX14 non_default_constructible_iterator operator++(int) |
| {non_default_constructible_iterator tmp(*this); ++(*this); return tmp;} |
| |
| friend TEST_CONSTEXPR_CXX14 bool operator==(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y) |
| {return x.it_ == y.it_;} |
| friend TEST_CONSTEXPR_CXX14 bool operator!=(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y) |
| {return !(x == y);} |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| }; |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator==(const non_default_constructible_iterator<T>& x, const non_default_constructible_iterator<U>& y) |
| { |
| return x.base() == y.base(); |
| } |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator!=(const non_default_constructible_iterator<T>& x, const non_default_constructible_iterator<U>& y) |
| { |
| return !(x == y); |
| } |
| |
| template <class It> |
| class bidirectional_iterator |
| { |
| It it_; |
| |
| template <class U> friend class bidirectional_iterator; |
| public: |
| typedef std::bidirectional_iterator_tag iterator_category; |
| typedef typename std::iterator_traits<It>::value_type value_type; |
| typedef typename std::iterator_traits<It>::difference_type difference_type; |
| typedef It pointer; |
| typedef typename std::iterator_traits<It>::reference reference; |
| |
| TEST_CONSTEXPR_CXX14 It base() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 bidirectional_iterator() : it_() {} |
| explicit TEST_CONSTEXPR_CXX14 bidirectional_iterator(It it) : it_(it) {} |
| template <class U> |
| TEST_CONSTEXPR_CXX14 bidirectional_iterator(const bidirectional_iterator<U>& u) :it_(u.it_) {} |
| |
| TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} |
| TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator++() {++it_; return *this;} |
| TEST_CONSTEXPR_CXX14 bidirectional_iterator operator++(int) |
| {bidirectional_iterator tmp(*this); ++(*this); return tmp;} |
| |
| TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator--() {--it_; return *this;} |
| TEST_CONSTEXPR_CXX14 bidirectional_iterator operator--(int) |
| {bidirectional_iterator tmp(*this); --(*this); return tmp;} |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| }; |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator==(const bidirectional_iterator<T>& x, const bidirectional_iterator<U>& y) |
| { |
| return x.base() == y.base(); |
| } |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator!=(const bidirectional_iterator<T>& x, const bidirectional_iterator<U>& y) |
| { |
| return !(x == y); |
| } |
| |
| template <class It> |
| class random_access_iterator |
| { |
| It it_; |
| |
| template <class U> friend class random_access_iterator; |
| public: |
| typedef std::random_access_iterator_tag iterator_category; |
| typedef typename std::iterator_traits<It>::value_type value_type; |
| typedef typename std::iterator_traits<It>::difference_type difference_type; |
| typedef It pointer; |
| typedef typename std::iterator_traits<It>::reference reference; |
| |
| TEST_CONSTEXPR_CXX14 It base() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 random_access_iterator() : it_() {} |
| explicit TEST_CONSTEXPR_CXX14 random_access_iterator(It it) : it_(it) {} |
| template <class U> |
| TEST_CONSTEXPR_CXX14 random_access_iterator(const random_access_iterator<U>& u) :it_(u.it_) {} |
| |
| TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} |
| TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 random_access_iterator& operator++() {++it_; return *this;} |
| TEST_CONSTEXPR_CXX14 random_access_iterator operator++(int) |
| {random_access_iterator tmp(*this); ++(*this); return tmp;} |
| |
| TEST_CONSTEXPR_CXX14 random_access_iterator& operator--() {--it_; return *this;} |
| TEST_CONSTEXPR_CXX14 random_access_iterator operator--(int) |
| {random_access_iterator tmp(*this); --(*this); return tmp;} |
| |
| TEST_CONSTEXPR_CXX14 random_access_iterator& operator+=(difference_type n) {it_ += n; return *this;} |
| TEST_CONSTEXPR_CXX14 random_access_iterator operator+(difference_type n) const |
| {random_access_iterator tmp(*this); tmp += n; return tmp;} |
| friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(difference_type n, random_access_iterator x) |
| {x += n; return x;} |
| TEST_CONSTEXPR_CXX14 random_access_iterator& operator-=(difference_type n) {return *this += -n;} |
| TEST_CONSTEXPR_CXX14 random_access_iterator operator-(difference_type n) const |
| {random_access_iterator tmp(*this); tmp -= n; return tmp;} |
| |
| TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return it_[n];} |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| }; |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator==(const random_access_iterator<T>& x, const random_access_iterator<U>& y) |
| { |
| return x.base() == y.base(); |
| } |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator!=(const random_access_iterator<T>& x, const random_access_iterator<U>& y) |
| { |
| return !(x == y); |
| } |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator<(const random_access_iterator<T>& x, const random_access_iterator<U>& y) |
| { |
| return x.base() < y.base(); |
| } |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator<=(const random_access_iterator<T>& x, const random_access_iterator<U>& y) |
| { |
| return !(y < x); |
| } |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator>(const random_access_iterator<T>& x, const random_access_iterator<U>& y) |
| { |
| return y < x; |
| } |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| bool operator>=(const random_access_iterator<T>& x, const random_access_iterator<U>& y) |
| { |
| return !(x < y); |
| } |
| |
| template <class T, class U> |
| TEST_CONSTEXPR_CXX14 |
| typename std::iterator_traits<T>::difference_type |
| operator-(const random_access_iterator<T>& x, const random_access_iterator<U>& y) |
| { |
| return x.base() - y.base(); |
| } |
| |
| #if TEST_STD_VER > 17 |
| template <class It> |
| class contiguous_iterator |
| { |
| static_assert(std::is_pointer_v<It>, "Things probably break in this case"); |
| |
| It it_; |
| |
| template <class U> friend class contiguous_iterator; |
| public: |
| typedef std::contiguous_iterator_tag iterator_category; |
| typedef typename std::iterator_traits<It>::value_type value_type; |
| typedef typename std::iterator_traits<It>::difference_type difference_type; |
| typedef It pointer; |
| typedef typename std::iterator_traits<It>::reference reference; |
| typedef typename std::remove_pointer<It>::type element_type; |
| |
| TEST_CONSTEXPR_CXX14 It base() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 contiguous_iterator() : it_() {} |
| explicit TEST_CONSTEXPR_CXX14 contiguous_iterator(It it) : it_(it) {} |
| template <class U> |
| TEST_CONSTEXPR_CXX14 contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_) {} |
| |
| TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} |
| TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;} |
| |
| TEST_CONSTEXPR_CXX14 contiguous_iterator& operator++() {++it_; return *this;} |
| TEST_CONSTEXPR_CXX14 contiguous_iterator operator++(int) |
| {contiguous_iterator tmp(*this); ++(*this); return tmp;} |
| |
| TEST_CONSTEXPR_CXX14 contiguous_iterator& operator--() {--it_; return *this;} |
| TEST_CONSTEXPR_CXX14 contiguous_iterator operator--(int) |
| {contiguous_iterator tmp(*this); --(*this); return tmp;} |
| |
| TEST_CONSTEXPR_CXX14 contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;} |
| TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(difference_type n) const |
| {contiguous_iterator tmp(*this); tmp += n; return tmp;} |
| friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(difference_type n, contiguous_iterator x) |
| {x += n; return x;} |
| TEST_CONSTEXPR_CXX14 contiguous_iterator& operator-=(difference_type n) {return *this += -n;} |
| TEST_CONSTEXPR_CXX14 contiguous_iterator operator-(difference_type n) const |
| {contiguous_iterator tmp(*this); tmp -= n; return tmp;} |
| |
| TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return it_[n];} |
| |
| friend TEST_CONSTEXPR_CXX14 |
| difference_type operator-(const contiguous_iterator& x, const contiguous_iterator& y) { |
| return x.base() - y.base(); |
| } |
| |
| friend TEST_CONSTEXPR_CXX14 |
| difference_type operator<(const contiguous_iterator& x, const contiguous_iterator& y) { |
| return x.base() < y.base(); |
| } |
| friend TEST_CONSTEXPR_CXX14 |
| difference_type operator>(const contiguous_iterator& x, const contiguous_iterator& y) { |
| return x.base() > y.base(); |
| } |
| friend TEST_CONSTEXPR_CXX14 |
| difference_type operator<=(const contiguous_iterator& x, const contiguous_iterator& y) { |
| return x.base() <= y.base(); |
| } |
| friend TEST_CONSTEXPR_CXX14 |
| difference_type operator>=(const contiguous_iterator& x, const contiguous_iterator& y) { |
| return x.base() >= y.base(); |
| } |
| friend TEST_CONSTEXPR_CXX14 |
| difference_type operator==(const contiguous_iterator& x, const contiguous_iterator& y) { |
| return x.base() == y.base(); |
| } |
| friend TEST_CONSTEXPR_CXX14 |
| difference_type operator!=(const contiguous_iterator& x, const contiguous_iterator& y) { |
| return x.base() != y.base(); |
| } |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| }; |
| #endif |
| |
| template <class Iter> |
| TEST_CONSTEXPR_CXX14 Iter base(output_iterator<Iter> i) { return i.base(); } |
| |
| template <class Iter> |
| TEST_CONSTEXPR_CXX14 Iter base(cpp17_input_iterator<Iter> i) { return i.base(); } |
| |
| template <class Iter> |
| TEST_CONSTEXPR_CXX14 Iter base(forward_iterator<Iter> i) { return i.base(); } |
| |
| template <class Iter> |
| TEST_CONSTEXPR_CXX14 Iter base(bidirectional_iterator<Iter> i) { return i.base(); } |
| |
| template <class Iter> |
| TEST_CONSTEXPR_CXX14 Iter base(random_access_iterator<Iter> i) { return i.base(); } |
| |
| #if TEST_STD_VER > 17 |
| template <class Iter> |
| TEST_CONSTEXPR_CXX14 Iter base(contiguous_iterator<Iter> i) { return i.base(); } |
| #endif |
| |
| template <class Iter> // everything else |
| TEST_CONSTEXPR_CXX14 Iter base(Iter i) { return i; } |
| |
| template <typename T> |
| struct ThrowingIterator { |
| typedef std::bidirectional_iterator_tag iterator_category; |
| typedef ptrdiff_t difference_type; |
| typedef const T value_type; |
| typedef const T * pointer; |
| typedef const T & reference; |
| |
| enum ThrowingAction { TAIncrement, TADecrement, TADereference, TAAssignment, TAComparison }; |
| |
| ThrowingIterator() |
| : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference), index_(0) {} |
| explicit ThrowingIterator(const T *first, const T *last, int index = 0, ThrowingAction action = TADereference) |
| : begin_(first), end_(last), current_(first), action_(action), index_(index) {} |
| ThrowingIterator(const ThrowingIterator &rhs) |
| : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_), action_(rhs.action_), index_(rhs.index_) {} |
| |
| ThrowingIterator& operator=(const ThrowingIterator& rhs) { |
| if (action_ == TAAssignment && --index_ < 0) { |
| #ifndef TEST_HAS_NO_EXCEPTIONS |
| throw std::runtime_error("throw from iterator assignment"); |
| #else |
| assert(false); |
| #endif |
| } |
| begin_ = rhs.begin_; |
| end_ = rhs.end_; |
| current_ = rhs.current_; |
| action_ = rhs.action_; |
| index_ = rhs.index_; |
| return *this; |
| } |
| |
| reference operator*() const { |
| if (action_ == TADereference && --index_ < 0) { |
| #ifndef TEST_HAS_NO_EXCEPTIONS |
| throw std::runtime_error("throw from iterator dereference"); |
| #else |
| assert(false); |
| #endif |
| } |
| return *current_; |
| } |
| |
| ThrowingIterator& operator++() { |
| if (action_ == TAIncrement && --index_ < 0) { |
| #ifndef TEST_HAS_NO_EXCEPTIONS |
| throw std::runtime_error("throw from iterator increment"); |
| #else |
| assert(false); |
| #endif |
| } |
| ++current_; |
| return *this; |
| } |
| |
| ThrowingIterator operator++(int) { |
| ThrowingIterator temp = *this; |
| ++(*this); |
| return temp; |
| } |
| |
| ThrowingIterator& operator--() { |
| if (action_ == TADecrement && --index_ < 0) { |
| #ifndef TEST_HAS_NO_EXCEPTIONS |
| throw std::runtime_error("throw from iterator decrement"); |
| #else |
| assert(false); |
| #endif |
| } |
| --current_; |
| return *this; |
| } |
| |
| ThrowingIterator operator--(int) { |
| ThrowingIterator temp = *this; |
| --(*this); |
| return temp; |
| } |
| |
| friend bool operator==(const ThrowingIterator& a, const ThrowingIterator& b) { |
| if (a.action_ == TAComparison && --a.index_ < 0) { |
| #ifndef TEST_HAS_NO_EXCEPTIONS |
| throw std::runtime_error("throw from iterator comparison"); |
| #else |
| assert(false); |
| #endif |
| } |
| bool atEndL = a.current_ == a.end_; |
| bool atEndR = b.current_ == b.end_; |
| if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not. |
| if (atEndL) return true; // both are at the end (or empty) |
| return a.current_ == b.current_; |
| } |
| |
| friend bool operator!=(const ThrowingIterator& a, const ThrowingIterator& b) { |
| return !(a == b); |
| } |
| |
| template <class T2> |
| void operator,(T2 const &) = delete; |
| |
| private: |
| const T* begin_; |
| const T* end_; |
| const T* current_; |
| ThrowingAction action_; |
| mutable int index_; |
| }; |
| |
| template <typename T> |
| struct NonThrowingIterator { |
| typedef std::bidirectional_iterator_tag iterator_category; |
| typedef ptrdiff_t difference_type; |
| typedef const T value_type; |
| typedef const T * pointer; |
| typedef const T & reference; |
| |
| NonThrowingIterator() |
| : begin_(nullptr), end_(nullptr), current_(nullptr) {} |
| explicit NonThrowingIterator(const T *first, const T *last) |
| : begin_(first), end_(last), current_(first) {} |
| NonThrowingIterator(const NonThrowingIterator& rhs) |
| : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_) {} |
| |
| NonThrowingIterator& operator=(const NonThrowingIterator& rhs) TEST_NOEXCEPT { |
| begin_ = rhs.begin_; |
| end_ = rhs.end_; |
| current_ = rhs.current_; |
| return *this; |
| } |
| |
| reference operator*() const TEST_NOEXCEPT { |
| return *current_; |
| } |
| |
| NonThrowingIterator& operator++() TEST_NOEXCEPT { |
| ++current_; |
| return *this; |
| } |
| |
| NonThrowingIterator operator++(int) TEST_NOEXCEPT { |
| NonThrowingIterator temp = *this; |
| ++(*this); |
| return temp; |
| } |
| |
| NonThrowingIterator & operator--() TEST_NOEXCEPT { |
| --current_; |
| return *this; |
| } |
| |
| NonThrowingIterator operator--(int) TEST_NOEXCEPT { |
| NonThrowingIterator temp = *this; |
| --(*this); |
| return temp; |
| } |
| |
| friend bool operator==(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT { |
| bool atEndL = a.current_ == a.end_; |
| bool atEndR = b.current_ == b.end_; |
| if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not. |
| if (atEndL) return true; // both are at the end (or empty) |
| return a.current_ == b.current_; |
| } |
| |
| friend bool operator!=(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT { |
| return !(a == b); |
| } |
| |
| template <class T2> |
| void operator,(T2 const &) = delete; |
| |
| private: |
| const T *begin_; |
| const T *end_; |
| const T *current_; |
| }; |
| |
| #ifdef TEST_SUPPORTS_RANGES |
| |
| template <class I> |
| struct cpp20_input_iterator { |
| using value_type = std::iter_value_t<I>; |
| using difference_type = std::iter_difference_t<I>; |
| using iterator_concept = std::input_iterator_tag; |
| |
| cpp20_input_iterator() = delete; |
| |
| cpp20_input_iterator(cpp20_input_iterator&&) = default; |
| cpp20_input_iterator& operator=(cpp20_input_iterator&&) = default; |
| |
| cpp20_input_iterator(cpp20_input_iterator const&) = delete; |
| cpp20_input_iterator& operator=(cpp20_input_iterator const&) = delete; |
| |
| explicit constexpr cpp20_input_iterator(I base) : base_(std::move(base)) {} |
| |
| constexpr decltype(auto) operator*() const { return *base_; } |
| |
| constexpr cpp20_input_iterator& operator++() { |
| ++base_; |
| return *this; |
| } |
| |
| constexpr void operator++(int) { ++base_; } |
| |
| constexpr const I& base() const& { return base_; } |
| |
| constexpr I base() && { return std::move(base_); } |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| |
| private: |
| I base_ = I(); |
| }; |
| |
| template <std::input_or_output_iterator I> |
| struct iterator_concept { |
| using type = std::output_iterator_tag; |
| }; |
| |
| template <std::input_iterator I> |
| struct iterator_concept<I> { |
| using type = std::input_iterator_tag; |
| }; |
| |
| template <std::forward_iterator I> |
| struct iterator_concept<I> { |
| using type = std::forward_iterator_tag; |
| }; |
| |
| template <std::bidirectional_iterator I> |
| struct iterator_concept<I> { |
| using type = std::bidirectional_iterator_tag; |
| }; |
| |
| template <std::random_access_iterator I> |
| struct iterator_concept<I> { |
| using type = std::random_access_iterator_tag; |
| }; |
| |
| template<std::contiguous_iterator I> |
| struct iterator_concept<I> { |
| using type = std::contiguous_iterator_tag; |
| }; |
| |
| template <std::input_or_output_iterator I> |
| using iterator_concept_t = typename iterator_concept<I>::type; |
| |
| template<std::input_or_output_iterator> |
| struct iter_value_or_void { using type = void; }; |
| |
| template<std::input_iterator I> |
| struct iter_value_or_void<I> { |
| using type = std::iter_value_t<I>; |
| }; |
| |
| // Iterator adaptor that counts the number of times the iterator has had a successor/predecessor |
| // operation called. Has two recorders: |
| // * `stride_count`, which records the total number of calls to an op++, op--, op+=, or op-=. |
| // * `stride_displacement`, which records the displacement of the calls. This means that both |
| // op++/op+= will increase the displacement counter by 1, and op--/op-= will decrease the |
| // displacement counter by 1. |
| template <std::input_or_output_iterator I> |
| class stride_counting_iterator { |
| public: |
| using value_type = typename iter_value_or_void<I>::type; |
| using difference_type = std::iter_difference_t<I>; |
| using iterator_concept = iterator_concept_t<I>; |
| |
| stride_counting_iterator() = default; |
| |
| constexpr explicit stride_counting_iterator(I current) : base_(std::move(current)) {} |
| |
| constexpr const I& base() const& { return base_; } |
| |
| constexpr I base() && { return std::move(base_); } |
| |
| constexpr difference_type stride_count() const { return stride_count_; } |
| |
| constexpr difference_type stride_displacement() const { return stride_displacement_; } |
| |
| constexpr decltype(auto) operator*() const { return *base_; } |
| |
| constexpr decltype(auto) operator[](difference_type const n) const { return base_[n]; } |
| |
| constexpr stride_counting_iterator& operator++() { |
| ++base_; |
| ++stride_count_; |
| ++stride_displacement_; |
| return *this; |
| } |
| |
| constexpr void operator++(int) { ++*this; } |
| |
| constexpr stride_counting_iterator operator++(int) |
| requires std::forward_iterator<I> |
| { |
| auto temp = *this; |
| ++*this; |
| return temp; |
| } |
| |
| constexpr stride_counting_iterator& operator--() |
| requires std::bidirectional_iterator<I> |
| { |
| --base_; |
| ++stride_count_; |
| --stride_displacement_; |
| return *this; |
| } |
| |
| constexpr stride_counting_iterator operator--(int) |
| requires std::bidirectional_iterator<I> |
| { |
| auto temp = *this; |
| --*this; |
| return temp; |
| } |
| |
| constexpr stride_counting_iterator& operator+=(difference_type const n) |
| requires std::random_access_iterator<I> |
| { |
| base_ += n; |
| ++stride_count_; |
| ++stride_displacement_; |
| return *this; |
| } |
| |
| constexpr stride_counting_iterator& operator-=(difference_type const n) |
| requires std::random_access_iterator<I> |
| { |
| base_ -= n; |
| ++stride_count_; |
| --stride_displacement_; |
| return *this; |
| } |
| |
| friend constexpr stride_counting_iterator operator+(stride_counting_iterator i, difference_type const n) |
| requires std::random_access_iterator<I> |
| { |
| return i += n; |
| } |
| |
| friend constexpr stride_counting_iterator operator+(difference_type const n, stride_counting_iterator i) |
| requires std::random_access_iterator<I> |
| { |
| return i += n; |
| } |
| |
| friend constexpr stride_counting_iterator operator-(stride_counting_iterator i, difference_type const n) |
| requires std::random_access_iterator<I> |
| { |
| return i -= n; |
| } |
| |
| friend constexpr difference_type operator-(stride_counting_iterator const& x, stride_counting_iterator const& y) |
| requires std::sized_sentinel_for<I, I> |
| { |
| return x.base() - y.base(); |
| } |
| |
| constexpr bool operator==(stride_counting_iterator const& other) const |
| requires std::sentinel_for<I, I> |
| { |
| return base_ == other.base_; |
| } |
| |
| template <std::sentinel_for<I> S> |
| constexpr bool operator==(S const last) const |
| { |
| return base_ == last; |
| } |
| |
| friend constexpr bool operator<(stride_counting_iterator const& x, stride_counting_iterator const& y) |
| requires std::random_access_iterator<I> |
| { |
| return x.base_ < y.base_; |
| } |
| |
| friend constexpr bool operator>(stride_counting_iterator const& x, stride_counting_iterator const& y) |
| requires std::random_access_iterator<I> |
| { |
| return y < x; |
| } |
| |
| friend constexpr bool operator<=(stride_counting_iterator const& x, stride_counting_iterator const& y) |
| requires std::random_access_iterator<I> |
| { |
| return !(y < x); |
| } |
| |
| friend constexpr bool operator>=(stride_counting_iterator const& x, stride_counting_iterator const& y) |
| requires std::random_access_iterator<I> |
| { |
| return !(x < y); |
| } |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| |
| private: |
| I base_; |
| difference_type stride_count_ = 0; |
| difference_type stride_displacement_ = 0; |
| }; |
| |
| template<class T, class U> |
| concept sentinel_for_base = requires(U const& u) { |
| u.base(); |
| requires std::input_or_output_iterator<std::remove_cvref_t<decltype(u.base())>>; |
| requires std::equality_comparable_with<T, decltype(u.base())>; |
| }; |
| |
| template <std::input_or_output_iterator I> |
| class sentinel_wrapper { |
| public: |
| sentinel_wrapper() = default; |
| constexpr explicit sentinel_wrapper(I base) : base_(std::move(base)) {} |
| |
| constexpr bool operator==(const I& other) const requires std::equality_comparable<I> { |
| return base_ == other; |
| } |
| |
| constexpr const I& base() const& { return base_; } |
| constexpr I base() && { return std::move(base_); } |
| |
| template<std::input_or_output_iterator I2> |
| requires sentinel_for_base<I, I2> |
| constexpr bool operator==(const I2& other) const { |
| return base_ == other.base(); |
| } |
| |
| private: |
| I base_ = I(); |
| }; |
| |
| template <std::input_or_output_iterator I> |
| class sized_sentinel { |
| public: |
| sized_sentinel() = default; |
| constexpr explicit sized_sentinel(I base) : base_(std::move(base)) {} |
| |
| constexpr bool operator==(const I& other) const requires std::equality_comparable<I> { |
| return base_ == other; |
| } |
| |
| constexpr const I& base() const& { return base_; } |
| constexpr I base() && { return std::move(base_); } |
| |
| template<std::input_or_output_iterator I2> |
| requires sentinel_for_base<I, I2> |
| constexpr bool operator==(const I2& other) const { |
| return base_ == other.base(); |
| } |
| |
| private: |
| I base_ = I(); |
| }; |
| |
| template <std::input_or_output_iterator I> |
| constexpr auto operator-(sized_sentinel<I> sent, std::input_or_output_iterator auto iter) { |
| return sent.base() - iter; |
| } |
| |
| template <std::input_or_output_iterator I> |
| constexpr auto operator-(std::input_or_output_iterator auto iter, sized_sentinel<I> sent) { |
| return iter - sent.base(); |
| } |
| |
| template <class It> |
| class three_way_contiguous_iterator |
| { |
| static_assert(std::is_pointer_v<It>, "Things probably break in this case"); |
| |
| It it_; |
| |
| template <class U> friend class three_way_contiguous_iterator; |
| public: |
| typedef std::contiguous_iterator_tag iterator_category; |
| typedef typename std::iterator_traits<It>::value_type value_type; |
| typedef typename std::iterator_traits<It>::difference_type difference_type; |
| typedef It pointer; |
| typedef typename std::iterator_traits<It>::reference reference; |
| typedef typename std::remove_pointer<It>::type element_type; |
| |
| constexpr It base() const {return it_;} |
| |
| constexpr three_way_contiguous_iterator() : it_() {} |
| constexpr explicit three_way_contiguous_iterator(It it) : it_(it) {} |
| template <class U> |
| constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator<U>& u) : it_(u.it_) {} |
| |
| constexpr reference operator*() const {return *it_;} |
| constexpr pointer operator->() const {return it_;} |
| |
| constexpr three_way_contiguous_iterator& operator++() {++it_; return *this;} |
| constexpr three_way_contiguous_iterator operator++(int) {auto tmp = *this; ++(*this); return tmp;} |
| |
| constexpr three_way_contiguous_iterator& operator--() {--it_; return *this;} |
| constexpr three_way_contiguous_iterator operator--(int) {auto tmp = *this; --(*this); return tmp;} |
| |
| constexpr three_way_contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;} |
| constexpr auto operator+(difference_type n) const {auto tmp = *this; tmp += n; return tmp;} |
| friend constexpr auto operator+(difference_type n, three_way_contiguous_iterator x) {x += n; return x;} |
| constexpr three_way_contiguous_iterator& operator-=(difference_type n) {return *this += -n;} |
| constexpr auto operator-(difference_type n) const {auto tmp = *this; tmp -= n; return tmp;} |
| |
| constexpr reference operator[](difference_type n) const {return it_[n];} |
| |
| template <class T> |
| void operator,(T const &) = delete; |
| |
| friend constexpr |
| difference_type operator-(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) { |
| return x.base() - y.base(); |
| } |
| |
| friend auto operator<=>(const three_way_contiguous_iterator&, const three_way_contiguous_iterator&) = default; |
| }; |
| |
| #endif // TEST_STD_VER > 17 && defined(__cpp_lib_concepts) |
| |
| #endif // SUPPORT_TEST_ITERATORS_H |