| // -*- C++ -*- |
| // Iterator Wrappers for the C++ library testsuite. |
| // |
| // Copyright (C) 2004-2022 Free Software Foundation, Inc. |
| // |
| // This file is part of the GNU ISO C++ Library. This library is free |
| // software; you can redistribute it and/or modify it under the |
| // terms of the GNU General Public License as published by the |
| // Free Software Foundation; either version 3, or (at your option) |
| // any later version. |
| // |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License along |
| // with this library; see the file COPYING3. If not see |
| // <http://www.gnu.org/licenses/>. |
| // |
| |
| // This file provides the following: |
| // |
| // input_iterator_wrapper, output_iterator_wrapper |
| // forward_iterator_wrapper, bidirectional_iterator_wrapper and |
| // random_access_wrapper, which attempt to exactly perform the requirements |
| // of these types of iterators. These are constructed from the class |
| // test_container, which is given two pointers to T and an iterator type. |
| |
| #include <testsuite_hooks.h> |
| #include <bits/stl_iterator_base_types.h> |
| |
| #if __cplusplus >= 201103L |
| #include <bits/move.h> |
| #endif |
| |
| #ifndef _TESTSUITE_ITERATORS |
| #define _TESTSUITE_ITERATORS |
| |
| #ifdef DISABLE_ITERATOR_DEBUG |
| #define ITERATOR_VERIFY(x) |
| #else |
| #define ITERATOR_VERIFY(x) VERIFY(x) |
| #endif |
| |
| namespace __gnu_test |
| { |
| /** |
| * @brief Simple container for holding two pointers. |
| * |
| * Note that input_iterator_wrapper changes first to denote |
| * how the valid range of == , ++, etc. change as the iterators are used. |
| */ |
| template<typename T> |
| struct BoundsContainer |
| { |
| T* first; |
| T* last; |
| |
| BoundsContainer(T* _first, T* _last) : first(_first), last(_last) |
| { } |
| |
| std::size_t size() const { return last - first; } |
| }; |
| |
| // Simple container for holding state of a set of output iterators. |
| template<typename T> |
| struct OutputContainer : public BoundsContainer<T> |
| { |
| T* incrementedto; |
| bool* writtento; |
| |
| OutputContainer(T* _first, T* _last) |
| : BoundsContainer<T>(_first, _last), incrementedto(_first), |
| writtento(new bool[this->size()]()) |
| { } |
| |
| ~OutputContainer() |
| { delete[] writtento; } |
| }; |
| |
| // Produced by output_iterator to allow limited writing to pointer |
| template<class T> |
| class WritableObject |
| { |
| T* ptr; |
| |
| public: |
| OutputContainer<T>* SharedInfo; |
| |
| WritableObject(T* ptr_in, OutputContainer<T>* SharedInfo_in): |
| ptr(ptr_in), SharedInfo(SharedInfo_in) |
| { } |
| |
| #if __cplusplus >= 201103L |
| template<class U> |
| typename std::enable_if<std::is_assignable<T&, U>::value>::type |
| operator=(U&& new_val) const |
| { |
| ITERATOR_VERIFY(SharedInfo->writtento[ptr - SharedInfo->first] == 0); |
| SharedInfo->writtento[ptr - SharedInfo->first] = 1; |
| *ptr = std::forward<U>(new_val); |
| } |
| #else |
| template<class U> |
| void |
| operator=(const U& new_val) |
| { |
| ITERATOR_VERIFY(SharedInfo->writtento[ptr - SharedInfo->first] == 0); |
| SharedInfo->writtento[ptr - SharedInfo->first] = 1; |
| *ptr = new_val; |
| } |
| #endif |
| }; |
| |
| /** |
| * @brief output_iterator wrapper for pointer |
| * |
| * This class takes a pointer and wraps it to provide exactly |
| * the requirements of a output_iterator. It should not be |
| * instantiated directly, but generated from a test_container |
| */ |
| template<class T> |
| struct output_iterator_wrapper |
| { |
| protected: |
| output_iterator_wrapper() : ptr(0), SharedInfo(0) |
| { } |
| |
| public: |
| typedef std::output_iterator_tag iterator_category; |
| typedef T value_type; |
| typedef std::ptrdiff_t difference_type; |
| typedef T* pointer; |
| typedef T& reference; |
| |
| typedef OutputContainer<T> ContainerType; |
| T* ptr; |
| ContainerType* SharedInfo; |
| |
| output_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in) |
| : ptr(_ptr), SharedInfo(SharedInfo_in) |
| { |
| ITERATOR_VERIFY(ptr >= SharedInfo->first && ptr <= SharedInfo->last); |
| } |
| |
| #if __cplusplus >= 201103L |
| output_iterator_wrapper(const output_iterator_wrapper&) = default; |
| |
| output_iterator_wrapper& |
| operator=(const output_iterator_wrapper&) = default; |
| #endif |
| |
| WritableObject<T> |
| operator*() const |
| { |
| ITERATOR_VERIFY(ptr < SharedInfo->last); |
| ITERATOR_VERIFY(SharedInfo->writtento[ptr - SharedInfo->first] == false); |
| return WritableObject<T>(ptr, SharedInfo); |
| } |
| |
| output_iterator_wrapper& |
| operator++() |
| { |
| ITERATOR_VERIFY(SharedInfo && ptr < SharedInfo->last); |
| ITERATOR_VERIFY(ptr>=SharedInfo->incrementedto); |
| ptr++; |
| SharedInfo->incrementedto=ptr; |
| return *this; |
| } |
| |
| output_iterator_wrapper |
| operator++(int) |
| { |
| output_iterator_wrapper<T> tmp = *this; |
| ++*this; |
| return tmp; |
| } |
| |
| #if __cplusplus >= 201103L |
| template<typename U> |
| void operator,(const U&) const = delete; |
| |
| void operator&() const = delete; |
| #else |
| private: |
| template<typename U> |
| void operator,(const U&) const; |
| |
| void operator&() const; |
| #endif |
| }; |
| |
| #if __cplusplus >= 201103L |
| template<typename T, typename U> |
| void operator,(const T&, const output_iterator_wrapper<U>&) = delete; |
| #endif |
| |
| #if __cplusplus >= 201103L |
| using std::remove_cv; |
| #else |
| template<typename T> struct remove_cv { typedef T type; }; |
| template<typename T> struct remove_cv<const T> { typedef T type; }; |
| template<typename T> struct remove_cv<volatile T> { typedef T type; }; |
| template<typename T> struct remove_cv<const volatile T> { typedef T type; }; |
| #endif |
| |
| /** |
| * @brief input_iterator wrapper for pointer |
| * |
| * This class takes a pointer and wraps it to provide exactly |
| * the requirements of a input_iterator. It should not be |
| * instantiated directly, but generated from a test_container |
| */ |
| template<class T> |
| class input_iterator_wrapper |
| { |
| struct post_inc_proxy |
| { |
| struct deref_proxy |
| { |
| T* ptr; |
| operator const T&() const { return *ptr; } |
| } p; |
| |
| deref_proxy operator*() const { return p; } |
| }; |
| |
| protected: |
| input_iterator_wrapper() : ptr(0), SharedInfo(0) |
| { } |
| |
| public: |
| typedef std::input_iterator_tag iterator_category; |
| typedef typename remove_cv<T>::type value_type; |
| typedef std::ptrdiff_t difference_type; |
| typedef T* pointer; |
| typedef T& reference; |
| |
| typedef BoundsContainer<T> ContainerType; |
| T* ptr; |
| ContainerType* SharedInfo; |
| |
| input_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in) |
| : ptr(_ptr), SharedInfo(SharedInfo_in) |
| { ITERATOR_VERIFY(ptr >= SharedInfo->first && ptr <= SharedInfo->last); } |
| |
| #if __cplusplus >= 201103L |
| input_iterator_wrapper(const input_iterator_wrapper&) = default; |
| |
| input_iterator_wrapper& |
| operator=(const input_iterator_wrapper&) = default; |
| #endif |
| |
| bool |
| operator==(const input_iterator_wrapper& in) const |
| { |
| ITERATOR_VERIFY(SharedInfo && SharedInfo == in.SharedInfo); |
| ITERATOR_VERIFY(ptr>=SharedInfo->first && in.ptr>=SharedInfo->first); |
| return ptr == in.ptr; |
| } |
| |
| bool |
| operator!=(const input_iterator_wrapper& in) const |
| { |
| return !(*this == in); |
| } |
| |
| T& |
| operator*() const |
| { |
| ITERATOR_VERIFY(SharedInfo && ptr < SharedInfo->last); |
| ITERATOR_VERIFY(ptr >= SharedInfo->first); |
| return *ptr; |
| } |
| |
| T* |
| operator->() const |
| { |
| return &**this; |
| } |
| |
| input_iterator_wrapper& |
| operator++() |
| { |
| ITERATOR_VERIFY(SharedInfo && ptr < SharedInfo->last); |
| ITERATOR_VERIFY(ptr>=SharedInfo->first); |
| ptr++; |
| SharedInfo->first=ptr; |
| return *this; |
| } |
| |
| post_inc_proxy |
| operator++(int) |
| { |
| post_inc_proxy tmp = { { ptr } }; |
| ++*this; |
| return tmp; |
| } |
| |
| #if __cplusplus >= 201103L |
| template<typename U> |
| void operator,(const U&) const = delete; |
| |
| void operator&() const = delete; |
| #else |
| private: |
| template<typename U> |
| void operator,(const U&) const; |
| |
| void operator&() const; |
| #endif |
| }; |
| |
| #if __cplusplus >= 201103L |
| template<typename T, typename U> |
| void operator,(const T&, const input_iterator_wrapper<U>&) = delete; |
| #endif |
| |
| /** |
| * @brief forward_iterator wrapper for pointer |
| * |
| * This class takes a pointer and wraps it to provide exactly |
| * the requirements of a forward_iterator. It should not be |
| * instantiated directly, but generated from a test_container |
| */ |
| template<class T> |
| struct forward_iterator_wrapper : public input_iterator_wrapper<T> |
| { |
| typedef BoundsContainer<T> ContainerType; |
| typedef std::forward_iterator_tag iterator_category; |
| |
| forward_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in) |
| : input_iterator_wrapper<T>(_ptr, SharedInfo_in) |
| { } |
| |
| forward_iterator_wrapper() |
| { } |
| |
| #if __cplusplus >= 201103L |
| forward_iterator_wrapper(const forward_iterator_wrapper&) = default; |
| |
| forward_iterator_wrapper& |
| operator=(const forward_iterator_wrapper&) = default; |
| #endif |
| |
| T& |
| operator*() const |
| { |
| ITERATOR_VERIFY(this->SharedInfo && this->ptr < this->SharedInfo->last); |
| return *(this->ptr); |
| } |
| |
| T* |
| operator->() const |
| { return &**this; } |
| |
| forward_iterator_wrapper& |
| operator++() |
| { |
| ITERATOR_VERIFY(this->SharedInfo && this->ptr < this->SharedInfo->last); |
| this->ptr++; |
| return *this; |
| } |
| |
| forward_iterator_wrapper |
| operator++(int) |
| { |
| forward_iterator_wrapper<T> tmp = *this; |
| ++*this; |
| return tmp; |
| } |
| |
| #if __cplusplus >= 201402L |
| bool |
| operator==(const forward_iterator_wrapper& it) const noexcept |
| { |
| // Since C++14 value-initialized forward iterators are comparable. |
| if (this->SharedInfo == nullptr || it.SharedInfo == nullptr) |
| return this->SharedInfo == it.SharedInfo && this->ptr == it.ptr; |
| |
| const input_iterator_wrapper<T>& base_this = *this; |
| const input_iterator_wrapper<T>& base_that = it; |
| return base_this == base_that; |
| } |
| |
| bool |
| operator!=(const forward_iterator_wrapper& it) const noexcept |
| { |
| return !(*this == it); |
| } |
| #endif |
| }; |
| |
| /** |
| * @brief bidirectional_iterator wrapper for pointer |
| * |
| * This class takes a pointer and wraps it to provide exactly |
| * the requirements of a bidirectional_iterator. It should not be |
| * instantiated directly, but generated from a test_container |
| */ |
| template<class T> |
| struct bidirectional_iterator_wrapper : public forward_iterator_wrapper<T> |
| { |
| typedef BoundsContainer<T> ContainerType; |
| typedef std::bidirectional_iterator_tag iterator_category; |
| |
| bidirectional_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in) |
| : forward_iterator_wrapper<T>(_ptr, SharedInfo_in) |
| { } |
| |
| bidirectional_iterator_wrapper() |
| : forward_iterator_wrapper<T>() |
| { } |
| |
| #if __cplusplus >= 201103L |
| bidirectional_iterator_wrapper( |
| const bidirectional_iterator_wrapper&) = default; |
| |
| bidirectional_iterator_wrapper& |
| operator=(const bidirectional_iterator_wrapper&) = default; |
| #endif |
| |
| bidirectional_iterator_wrapper& |
| operator++() |
| { |
| ITERATOR_VERIFY(this->SharedInfo && this->ptr < this->SharedInfo->last); |
| this->ptr++; |
| return *this; |
| } |
| |
| bidirectional_iterator_wrapper |
| operator++(int) |
| { |
| bidirectional_iterator_wrapper<T> tmp = *this; |
| ++*this; |
| return tmp; |
| } |
| |
| bidirectional_iterator_wrapper& |
| operator--() |
| { |
| ITERATOR_VERIFY(this->SharedInfo && this->ptr > this->SharedInfo->first); |
| this->ptr--; |
| return *this; |
| } |
| |
| bidirectional_iterator_wrapper |
| operator--(int) |
| { |
| bidirectional_iterator_wrapper<T> tmp = *this; |
| --*this; |
| return tmp; |
| } |
| }; |
| |
| /** |
| * @brief random_access_iterator wrapper for pointer |
| * |
| * This class takes a pointer and wraps it to provide exactly |
| * the requirements of a random_access_iterator. It should not be |
| * instantiated directly, but generated from a test_container |
| */ |
| template<class T> |
| struct random_access_iterator_wrapper |
| : public bidirectional_iterator_wrapper<T> |
| { |
| typedef BoundsContainer<T> ContainerType; |
| typedef std::random_access_iterator_tag iterator_category; |
| |
| random_access_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in) |
| : bidirectional_iterator_wrapper<T>(_ptr, SharedInfo_in) |
| { } |
| |
| random_access_iterator_wrapper() |
| : bidirectional_iterator_wrapper<T>() |
| { } |
| |
| #if __cplusplus >= 201103L |
| random_access_iterator_wrapper( |
| const random_access_iterator_wrapper&) = default; |
| |
| random_access_iterator_wrapper& |
| operator=(const random_access_iterator_wrapper&) = default; |
| #endif |
| |
| random_access_iterator_wrapper& |
| operator++() |
| { |
| ITERATOR_VERIFY(this->SharedInfo && this->ptr < this->SharedInfo->last); |
| this->ptr++; |
| return *this; |
| } |
| |
| random_access_iterator_wrapper |
| operator++(int) |
| { |
| random_access_iterator_wrapper<T> tmp = *this; |
| ++*this; |
| return tmp; |
| } |
| |
| random_access_iterator_wrapper& |
| operator--() |
| { |
| ITERATOR_VERIFY(this->SharedInfo && this->ptr > this->SharedInfo->first); |
| this->ptr--; |
| return *this; |
| } |
| |
| random_access_iterator_wrapper |
| operator--(int) |
| { |
| random_access_iterator_wrapper<T> tmp = *this; |
| --*this; |
| return tmp; |
| } |
| |
| random_access_iterator_wrapper& |
| operator+=(std::ptrdiff_t n) |
| { |
| if(n > 0) |
| { |
| ITERATOR_VERIFY(n <= this->SharedInfo->last - this->ptr); |
| this->ptr += n; |
| } |
| else |
| { |
| ITERATOR_VERIFY(-n <= this->ptr - this->SharedInfo->first); |
| this->ptr += n; |
| } |
| return *this; |
| } |
| |
| random_access_iterator_wrapper& |
| operator-=(std::ptrdiff_t n) |
| { return *this += -n; } |
| |
| random_access_iterator_wrapper |
| operator-(std::ptrdiff_t n) const |
| { |
| random_access_iterator_wrapper<T> tmp = *this; |
| return tmp -= n; |
| } |
| |
| std::ptrdiff_t |
| operator-(const random_access_iterator_wrapper<T>& in) const |
| { |
| ITERATOR_VERIFY(this->SharedInfo == in.SharedInfo); |
| return this->ptr - in.ptr; |
| } |
| |
| T& |
| operator[](std::ptrdiff_t n) const |
| { return *(*this + n); } |
| |
| bool |
| operator<(const random_access_iterator_wrapper<T>& in) const |
| { |
| ITERATOR_VERIFY(this->SharedInfo == in.SharedInfo); |
| return this->ptr < in.ptr; |
| } |
| |
| bool |
| operator>(const random_access_iterator_wrapper<T>& in) const |
| { |
| return in < *this; |
| } |
| |
| bool |
| operator>=(const random_access_iterator_wrapper<T>& in) const |
| { |
| return !(*this < in); |
| } |
| |
| bool |
| operator<=(const random_access_iterator_wrapper<T>& in) const |
| { |
| return !(*this > in); |
| } |
| }; |
| |
| template<typename T> |
| random_access_iterator_wrapper<T> |
| operator+(random_access_iterator_wrapper<T> it, std::ptrdiff_t n) |
| { return it += n; } |
| |
| template<typename T> |
| random_access_iterator_wrapper<T> |
| operator+(std::ptrdiff_t n, random_access_iterator_wrapper<T> it) |
| { return it += n; } |
| |
| |
| /** |
| * @brief A container-type class for holding iterator wrappers |
| * test_container takes two parameters, a class T and an iterator |
| * wrapper templated by T (for example forward_iterator_wrapper<T>. |
| * It takes two pointers representing a range and presents them as |
| * a container of iterators. |
| */ |
| template <class T, template<class TT> class ItType> |
| struct test_container |
| { |
| typename ItType<T>::ContainerType bounds; |
| |
| test_container(T* _first, T* _last) : bounds(_first, _last) |
| { } |
| |
| #if __cplusplus >= 201103L |
| template<std::size_t N> |
| explicit |
| test_container(T (&arr)[N]) : test_container(arr, arr+N) |
| { } |
| #endif |
| |
| ItType<T> |
| it(int pos) |
| { |
| ITERATOR_VERIFY(pos >= 0 && (unsigned)pos <= size()); |
| return ItType<T>(bounds.first + pos, &bounds); |
| } |
| |
| ItType<T> |
| it(T* pos) |
| { |
| ITERATOR_VERIFY(pos >= bounds.first && pos <= bounds.last); |
| return ItType<T>(pos, &bounds); |
| } |
| |
| const T& |
| val(int pos) |
| { return (bounds.first)[pos]; } |
| |
| ItType<T> |
| begin() |
| { return it(bounds.first); } |
| |
| ItType<T> |
| end() |
| { return it(bounds.last); } |
| |
| std::size_t |
| size() const |
| { return bounds.size(); } |
| }; |
| |
| #if __cplusplus >= 201103L |
| template<typename T> |
| using output_container |
| = test_container<T, output_iterator_wrapper>; |
| |
| template<typename T> |
| using input_container |
| = test_container<T, input_iterator_wrapper>; |
| |
| template<typename T> |
| using forward_container |
| = test_container<T, forward_iterator_wrapper>; |
| |
| template<typename T> |
| using bidirectional_container |
| = test_container<T, bidirectional_iterator_wrapper>; |
| |
| template<typename T> |
| using random_access_container |
| = test_container<T, random_access_iterator_wrapper>; |
| #endif |
| |
| #if __cplusplus > 201703L |
| template<typename T> |
| struct contiguous_iterator_wrapper |
| : random_access_iterator_wrapper<T> |
| { |
| using random_access_iterator_wrapper<T>::random_access_iterator_wrapper; |
| |
| using iterator_concept = std::contiguous_iterator_tag; |
| |
| contiguous_iterator_wrapper& |
| operator++() |
| { |
| random_access_iterator_wrapper<T>::operator++(); |
| return *this; |
| } |
| |
| contiguous_iterator_wrapper& |
| operator--() |
| { |
| random_access_iterator_wrapper<T>::operator--(); |
| return *this; |
| } |
| |
| contiguous_iterator_wrapper |
| operator++(int) |
| { |
| auto tmp = *this; |
| ++*this; |
| return tmp; |
| } |
| |
| contiguous_iterator_wrapper |
| operator--(int) |
| { |
| auto tmp = *this; |
| --*this; |
| return tmp; |
| } |
| |
| contiguous_iterator_wrapper& |
| operator+=(std::ptrdiff_t n) |
| { |
| random_access_iterator_wrapper<T>::operator+=(n); |
| return *this; |
| } |
| |
| friend contiguous_iterator_wrapper |
| operator+(contiguous_iterator_wrapper iter, std::ptrdiff_t n) |
| { return iter += n; } |
| |
| friend contiguous_iterator_wrapper |
| operator+(std::ptrdiff_t n, contiguous_iterator_wrapper iter) |
| { return iter += n; } |
| |
| contiguous_iterator_wrapper& |
| operator-=(std::ptrdiff_t n) |
| { return *this += -n; } |
| |
| friend contiguous_iterator_wrapper |
| operator-(contiguous_iterator_wrapper iter, std::ptrdiff_t n) |
| { return iter -= n; } |
| }; |
| |
| template<typename T> |
| using contiguous_container |
| = test_container<T, contiguous_iterator_wrapper>; |
| |
| // A move-only input iterator type. |
| template<typename T> |
| struct input_iterator_wrapper_nocopy : input_iterator_wrapper<T> |
| { |
| using input_iterator_wrapper<T>::input_iterator_wrapper; |
| |
| input_iterator_wrapper_nocopy() |
| : input_iterator_wrapper<T>(nullptr, nullptr) |
| { } |
| |
| input_iterator_wrapper_nocopy(const input_iterator_wrapper_nocopy&) = delete; |
| input_iterator_wrapper_nocopy& |
| operator=(const input_iterator_wrapper_nocopy&) = delete; |
| |
| input_iterator_wrapper_nocopy(input_iterator_wrapper_nocopy&&) = default; |
| input_iterator_wrapper_nocopy& |
| operator=(input_iterator_wrapper_nocopy&&) = default; |
| |
| using input_iterator_wrapper<T>::operator++; |
| |
| input_iterator_wrapper_nocopy& |
| operator++() |
| { |
| input_iterator_wrapper<T>::operator++(); |
| return *this; |
| } |
| }; |
| |
| // A type meeting the minimum std::range requirements |
| template<typename T, template<typename> class Iter> |
| class test_range |
| { |
| // Exposes the protected default constructor of Iter<T> if needed. This |
| // is needed only when Iter is input_iterator_wrapper or |
| // output_iterator_wrapper, because legacy forward iterators and beyond |
| // are already default constructible. |
| struct iterator : Iter<T> |
| { |
| using Iter<T>::Iter; |
| |
| using Iter<T>::operator++; |
| |
| iterator& operator++() { Iter<T>::operator++(); return *this; } |
| }; |
| |
| template<typename I> |
| struct sentinel |
| { |
| T* end; |
| |
| friend bool operator==(const sentinel& s, const I& i) noexcept |
| { return s.end == i.ptr; } |
| |
| friend auto operator-(const sentinel& s, const I& i) noexcept |
| requires std::random_access_iterator<I> |
| { return s.end - i.ptr; } |
| |
| friend auto operator-(const I& i, const sentinel& s) noexcept |
| requires std::random_access_iterator<I> |
| { return i.ptr - s.end; } |
| }; |
| |
| protected: |
| auto |
| get_iterator(T* p) |
| { |
| if constexpr (std::default_initializable<Iter<T>>) |
| return Iter<T>(p, &bounds); |
| else |
| return iterator(p, &bounds); |
| } |
| |
| public: |
| test_range(T* first, T* last) : bounds(first, last) |
| { } |
| |
| template<std::size_t N> |
| explicit |
| test_range(T (&arr)[N]) : test_range(arr, arr+N) |
| { } |
| |
| auto begin() & { return get_iterator(bounds.first); } |
| |
| auto end() & |
| { |
| using I = decltype(get_iterator(bounds.last)); |
| return sentinel<I>{bounds.last}; |
| } |
| |
| typename Iter<T>::ContainerType bounds; |
| }; |
| |
| template<typename T> |
| using test_contiguous_range |
| = test_range<T, contiguous_iterator_wrapper>; |
| template<typename T> |
| using test_random_access_range |
| = test_range<T, random_access_iterator_wrapper>; |
| template<typename T> |
| using test_bidirectional_range |
| = test_range<T, bidirectional_iterator_wrapper>; |
| template<typename T> |
| using test_forward_range |
| = test_range<T, forward_iterator_wrapper>; |
| template<typename T> |
| using test_input_range |
| = test_range<T, input_iterator_wrapper>; |
| template<typename T> |
| using test_output_range |
| = test_range<T, output_iterator_wrapper>; |
| |
| // A type meeting the minimum std::sized_range requirements |
| template<typename T, template<typename> class Iter> |
| struct test_sized_range : test_range<T, Iter> |
| { |
| using test_range<T, Iter>::test_range; |
| |
| std::size_t size() const noexcept |
| { return this->bounds.size(); } |
| }; |
| |
| template<typename T> |
| using test_contiguous_sized_range |
| = test_sized_range<T, contiguous_iterator_wrapper>; |
| template<typename T> |
| using test_random_access_sized_range |
| = test_sized_range<T, random_access_iterator_wrapper>; |
| template<typename T> |
| using test_bidirectional_sized_range |
| = test_sized_range<T, bidirectional_iterator_wrapper>; |
| template<typename T> |
| using test_forward_sized_range |
| = test_sized_range<T, forward_iterator_wrapper>; |
| template<typename T> |
| using test_input_sized_range |
| = test_sized_range<T, input_iterator_wrapper>; |
| template<typename T> |
| using test_output_sized_range |
| = test_sized_range<T, output_iterator_wrapper>; |
| |
| // A type meeting the minimum std::sized_range requirements, and whose end() |
| // returns a sized sentinel. |
| template<typename T, template<typename> class Iter> |
| struct test_sized_range_sized_sent : test_sized_range<T, Iter> |
| { |
| using test_sized_range<T, Iter>::test_sized_range; |
| |
| template<typename I> |
| struct sentinel |
| { |
| T* end; |
| |
| friend bool operator==(const sentinel& s, const I& i) noexcept |
| { return s.end == i.ptr; } |
| |
| friend std::iter_difference_t<I> |
| operator-(const sentinel& s, const I& i) noexcept |
| { return s.end - i.ptr; } |
| |
| friend std::iter_difference_t<I> |
| operator-(const I& i, const sentinel& s) noexcept |
| { return i.ptr - s.end; } |
| }; |
| |
| auto end() & |
| { |
| using I = decltype(this->get_iterator(this->bounds.last)); |
| return sentinel<I>{this->bounds.last}; |
| } |
| }; |
| |
| // test_range and test_sized_range do not own their elements, so they model |
| // std::ranges::borrowed_range. This file does not define specializations of |
| // std::ranges::enable_borrowed_range, so that individual tests can decide |
| // whether or not to do so. |
| // This is also true for test_container, although only when it has forward |
| // iterators (because output_iterator_wrapper and input_iterator_wrapper are |
| // not default constructible so do not model std::input_or_output_iterator). |
| |
| |
| // Test for basic properties of C++20 16.3.3.6 [customization.point.object]. |
| template<typename T> |
| constexpr bool |
| is_customization_point_object(T& obj) noexcept |
| { |
| // A [CPO] is a function object with a literal class type. |
| static_assert( std::is_class_v<T> || std::is_union_v<T> ); |
| static_assert( __is_literal_type(T) ); |
| // The type of a [CPO], ignoring cv-qualifiers, shall model semiregular. |
| static_assert( std::semiregular<std::remove_cv_t<T>> ); |
| |
| return true; |
| } |
| |
| #endif // C++20 |
| } // namespace __gnu_test |
| #endif // _TESTSUITE_ITERATORS |