From: Jonathan Wakely Date: Mon, 25 Nov 2019 19:02:03 +0000 (+0000) Subject: libstdc++: Add move_sentinel, common_iterator and counted_iterator X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7def9bd7cd9637ec31496febc217ca039de11746;p=gcc.git libstdc++: Add move_sentinel, common_iterator and counted_iterator This implements most of the remaining C++20 additions to the header. * include/bits/iterator_concepts.h (ranges::iter_swap): Fix parameter types of poison pill overload. Use remove_reference_t when checking constraints. * include/bits/stl_iterator.h (move_sentinel): Define for C++20. (move_iterator): Adjust definitions of nested types for C++20. Add hidden friends for move_sentinel operations, iter_move and iter_swap. (common_iterator, counted_iterator): Define for C++20. * testsuite/24_iterators/move_iterator/cust.cc: New test. * testsuite/24_iterators/move_iterator/sentinel.cc: New test. * testsuite/24_iterators/common_iterator/1.cc: New test. * testsuite/24_iterators/counted_iterator/1.cc: New test. From-SVN: r278698 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 09202af787f..4ea06a37a1f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,17 @@ 2019-11-25 Jonathan Wakely + * include/bits/iterator_concepts.h (ranges::iter_swap): Fix parameter + types of poison pill overload. Use remove_reference_t when checking + constraints. + * include/bits/stl_iterator.h (move_sentinel): Define for C++20. + (move_iterator): Adjust definitions of nested types for C++20. Add + hidden friends for move_sentinel operations, iter_move and iter_swap. + (common_iterator, counted_iterator): Define for C++20. + * testsuite/24_iterators/move_iterator/cust.cc: New test. + * testsuite/24_iterators/move_iterator/sentinel.cc: New test. + * testsuite/24_iterators/common_iterator/1.cc: New test. + * testsuite/24_iterators/counted_iterator/1.cc: New test. + PR libstdc++/91786 * include/bits/fs_path.h (filesystem_error): Move definition before the use in u8path. diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index 3843ba5d57f..97aed72e255 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -700,7 +700,7 @@ namespace ranges namespace __cust_iswap { template - void iter_swap(_It1&, _It2&) = delete; + void iter_swap(_It1, _It2) = delete; template concept __adl_iswap @@ -744,7 +744,8 @@ namespace ranges public: template requires __adl_iswap<_Tp, _Up> - || (readable<_Tp> && readable<_Up> + || (readable> + && readable> && swappable_with, iter_reference_t<_Up>>) || (indirectly_movable_storable<_Tp, _Up> && indirectly_movable_storable<_Up, _Tp>) diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index a707621c9ed..89cca64438c 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -73,6 +73,11 @@ # define __cpp_lib_array_constexpr 201803 #endif +#if __cplusplus > 201703L +# include +# include +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -1055,12 +1060,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __it.base(); } #if __cplusplus >= 201103L - /** * @addtogroup iterators * @{ */ +#if __cplusplus > 201703L && __cpp_lib_concepts + template + class move_sentinel + { + public: + constexpr + move_sentinel() + noexcept(is_nothrow_default_constructible_v<_Sent>) + : _M_last() { } + + constexpr explicit + move_sentinel(_Sent __s) + noexcept(is_nothrow_move_constructible_v<_Sent>) + : _M_last(std::move(__s)) { } + + template requires convertible_to + constexpr + move_sentinel(const move_sentinel<_S2>& __s) + noexcept(is_nothrow_constructible_v<_Sent, const _S2&>) + : _M_last(__s.base()) + { } + + template requires assignable_from<_Sent&, const _S2&> + constexpr move_sentinel& + operator=(const move_sentinel<_S2>& __s) + noexcept(is_nothrow_assignable_v<_Sent, const _S2&>) + { + _M_last = __s.base(); + return *this; + } + + constexpr _Sent + base() const + noexcept(is_nothrow_copy_constructible_v<_Sent>) + { return _M_last; } + + private: + _Sent _M_last; + }; + + namespace __detail + { + // Weaken iterator_category _Cat to _Limit if it is derived from that, + // otherwise use _Otherwise. + template + using __clamp_iter_cat + = conditional_t, _Limit, _Otherwise>; + } +#endif // C++20 + // 24.4.3 Move iterators /** * Class template move_iterator is an iterator adapter with the same @@ -1073,14 +1127,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template class move_iterator { - protected: _Iterator _M_current; - typedef iterator_traits<_Iterator> __traits_type; - typedef typename __traits_type::reference __base_ref; + using __traits_type = iterator_traits<_Iterator>; +#if __cplusplus > 201703L && __cpp_lib_concepts + using __base_cat = typename __traits_type::iterator_category; +#else + using __base_ref = typename __traits_type::reference; +#endif public: - typedef _Iterator iterator_type; + using iterator_type = _Iterator; + +#if __cplusplus > 201703L && __cpp_lib_concepts + using iterator_concept = input_iterator_tag; + using iterator_category + = __detail::__clamp_iter_cat<__base_cat, random_access_iterator_tag>; + using value_type = iter_value_t<_Iterator>; + using difference_type = iter_difference_t<_Iterator>; + using pointer = _Iterator; + using reference = iter_rvalue_reference_t<_Iterator>; +#else typedef typename __traits_type::iterator_category iterator_category; typedef typename __traits_type::value_type value_type; typedef typename __traits_type::difference_type difference_type; @@ -1091,6 +1158,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef typename conditional::value, typename remove_reference<__base_ref>::type&&, __base_ref>::type reference; +#endif _GLIBCXX17_CONSTEXPR move_iterator() @@ -1172,6 +1240,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX17_CONSTEXPR reference operator[](difference_type __n) const { return std::move(_M_current[__n]); } + +#if __cplusplus > 201703L && __cpp_lib_concepts + template _Sent> + friend constexpr bool + operator==(const move_iterator& __x, const move_sentinel<_Sent>& __y) + { return __x.base() == __y.base(); } + + template _Sent> + friend constexpr iter_difference_t<_Iterator> + operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y) + { return __x.base() - __y.base(); } + + template _Sent> + friend constexpr iter_difference_t<_Iterator> + operator-(const move_iterator& __x, const move_sentinel<_Sent>& __y) + { return __x.base() - __y.base(); } + + friend constexpr iter_rvalue_reference_t<_Iterator> + iter_move(const move_iterator& __i) + noexcept(noexcept(ranges::iter_move(__i._M_current))) + { return ranges::iter_move(__i._M_current); } + + template _Iter2> + friend constexpr void + iter_swap(const move_iterator& __x, const move_iterator<_Iter2>& __y) + noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current))) + { return ranges::iter_swap(__x._M_current, __y._M_current); } +#endif // C++20 }; // Note: See __normal_iterator operators note from Gaby to understand @@ -1285,6 +1381,592 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __make_move_if_noexcept_iterator(_Tp* __i) { return _ReturnType(__i); } +#if __cplusplus > 201703L && __cpp_lib_concepts + // [iterators.common] Common iterators + + namespace __detail + { + template + class _Common_iter_proxy + { + iter_value_t<_It> _M_keep; + + _Common_iter_proxy(iter_reference_t<_It>&& __x) + : _M_keep(std::move(__x)) { } + + template + friend class common_iterator; + + public: + const iter_value_t<_It>* + operator->() const + { return std::__addressof(_M_keep); } + }; + + template + concept __common_iter_has_arrow = readable + && (requires(const _It& __it) { __it.operator->(); } + || is_reference_v> + || constructible_from, iter_reference_t<_It>>); + + } // namespace __detail + + /// An iterator/sentinel adaptor for representing a non-common range. + template _Sent> + requires (!same_as<_It, _Sent>) + class common_iterator + { + template + static constexpr bool + _S_noexcept1() + { + if constexpr (is_trivially_default_constructible_v<_Tp>) + return is_nothrow_assignable_v<_Tp, _Up>; + else + return is_nothrow_constructible_v<_Tp, _Up>; + } + + template + static constexpr bool + _S_noexcept() + { return _S_noexcept1<_It, _It2>() && _S_noexcept1<_Sent, _Sent2>(); } + + public: + constexpr + common_iterator() + noexcept(is_nothrow_default_constructible_v<_It>) + : _M_it(), _M_index(0) + { } + + constexpr + common_iterator(_It __i) + noexcept(is_nothrow_move_constructible_v<_It>) + : _M_it(std::move(__i)), _M_index(0) + { } + + constexpr + common_iterator(_Sent __s) + noexcept(is_nothrow_move_constructible_v<_Sent>) + : _M_sent(std::move(__s)), _M_index(1) + { } + + template + requires convertible_to + && convertible_to + constexpr + common_iterator(const common_iterator<_It2, _Sent2>& __x) + noexcept(_S_noexcept()) + : _M_valueless(), _M_index(__x._M_index) + { + if (_M_index == 0) + { + if constexpr (is_trivially_default_constructible_v<_It>) + _M_it = std::move(__x._M_it); + else + ::new((void*)std::__addressof(_M_it)) _It(__x._M_it); + } + else if (_M_index == 1) + { + if constexpr (is_trivially_default_constructible_v<_Sent>) + _M_sent = std::move(__x._M_sent); + else + ::new((void*)std::__addressof(_M_sent)) _Sent(__x._M_sent); + } + } + + constexpr + common_iterator(const common_iterator& __x) + noexcept(_S_noexcept()) + : _M_valueless(), _M_index(__x._M_index) + { + if (_M_index == 0) + { + if constexpr (is_trivially_default_constructible_v<_It>) + _M_it = std::move(__x._M_it); + else + ::new((void*)std::__addressof(_M_it)) _It(__x._M_it); + } + else if (_M_index == 1) + { + if constexpr (is_trivially_default_constructible_v<_Sent>) + _M_sent = std::move(__x._M_sent); + else + ::new((void*)std::__addressof(_M_sent)) _Sent(__x._M_sent); + } + } + + common_iterator& + operator=(const common_iterator& __x) + noexcept(is_nothrow_copy_assignable_v<_It> + && is_nothrow_copy_assignable_v<_Sent> + && is_nothrow_copy_constructible_v<_It> + && is_nothrow_copy_constructible_v<_Sent>) + { + return this->operator=<_It, _Sent>(__x); + } + + template + requires convertible_to + && convertible_to + && assignable_from<_It&, const _It2&> + && assignable_from<_Sent&, const _Sent2&> + common_iterator& + operator=(const common_iterator<_It2, _Sent2>& __x) + noexcept(is_nothrow_constructible_v<_It, const _It2&> + && is_nothrow_constructible_v<_Sent, const _Sent2&> + && is_nothrow_assignable_v<_It, const _It2&> + && is_nothrow_assignable_v<_Sent, const _Sent2&>) + { + switch(_M_index << 2 | __x._M_index) + { + case 0b0000: + _M_it = __x._M_it; + break; + case 0b0101: + _M_sent = __x._M_sent; + break; + case 0b0001: + _M_it.~_It(); + _M_index = -1; + [[fallthrough]]; + case 0b1001: + ::new((void*)std::__addressof(_M_sent)) _Sent(__x._M_sent); + _M_index = 1; + break; + case 0b0100: + _M_sent.~_Sent(); + _M_index = -1; + [[fallthrough]]; + case 0b1000: + ::new((void*)std::__addressof(_M_it)) _It(__x._M_it); + _M_index = 0; + break; + default: + __glibcxx_assert(__x._M_has_value()); + __builtin_unreachable(); + } + return *this; + } + + ~common_iterator() + { + switch (_M_index) + { + case 0: + _M_it.~_It(); + break; + case 1: + _M_sent.~_Sent(); + break; + } + } + + decltype(auto) + operator*() + { + __glibcxx_assert(_M_index == 0); + return *_M_it; + } + + decltype(auto) + operator*() const requires __detail::__dereferenceable + { + __glibcxx_assert(_M_index == 0); + return *_M_it; + } + + decltype(auto) + operator->() const requires __detail::__common_iter_has_arrow<_It> + { + __glibcxx_assert(_M_index == 0); + if constexpr (is_pointer_v<_It> || requires { _M_it.operator->(); }) + return _M_it; + else if constexpr (is_reference_v>) + { + auto&& __tmp = *_M_it; + return std::__addressof(__tmp); + } + else + return _Common_iter_proxy(*_M_it); + } + + common_iterator& + operator++() + { + __glibcxx_assert(_M_index == 0); + ++_M_it; + return *this; + } + + decltype(auto) + operator++(int) + { + __glibcxx_assert(_M_index == 0); + if constexpr (forward_iterator<_It>) + { + common_iterator __tmp = *this; + ++*this; + return __tmp; + } + else + return _M_it++; + } + + template _Sent2> + requires sentinel_for<_Sent, _It2> + friend bool + operator==(const common_iterator& __x, + const common_iterator<_It2, _Sent2>& __y) + { + switch(__x._M_index << 2 | __y._M_index) + { + case 0b0000: + case 0b0101: + return true; + case 0b0001: + return __x._M_it == __y._M_sent; + case 0b0100: + return __x._M_sent == __y._M_it; + default: + __glibcxx_assert(__x._M_has_value()); + __glibcxx_assert(__y._M_has_value()); + __builtin_unreachable(); + } + } + + template _Sent2> + requires sentinel_for<_Sent, _It2> && equality_comparable_with<_It, _It2> + friend bool + operator==(const common_iterator& __x, + const common_iterator<_It2, _Sent2>& __y) + { + switch(__x._M_index << 2 | __y._M_index) + { + case 0b0101: + return true; + case 0b0000: + return __x._M_it == __y._M_it; + case 0b0001: + return __x._M_it == __y._M_sent; + case 0b0100: + return __x._M_sent == __y._M_it; + default: + __glibcxx_assert(__x._M_has_value()); + __glibcxx_assert(__y._M_has_value()); + __builtin_unreachable(); + } + } + + template _It2, sized_sentinel_for<_It> _Sent2> + requires sized_sentinel_for<_Sent, _It2> + friend iter_difference_t<_It2> + operator-(const common_iterator& __x, + const common_iterator<_It2, _Sent2>& __y) + { + switch(__x._M_index << 2 | __y._M_index) + { + case 0b0101: + return 0; + case 0b0000: + return __x._M_it - __y._M_it; + case 0b0001: + return __x._M_it - __y._M_sent; + case 0b0100: + return __x._M_sent - __y._M_it; + default: + __glibcxx_assert(__x._M_has_value()); + __glibcxx_assert(__y._M_has_value()); + __builtin_unreachable(); + } + } + + friend iter_rvalue_reference_t<_It> + iter_move(const common_iterator& __i) + noexcept(noexcept(ranges::iter_move(std::declval()))) + requires input_iterator<_It> + { + __glibcxx_assert(__i._M_index == 0); + return ranges::iter_move(__i._M_it); + } + + template _It2, typename _Sent2> + friend void + iter_swap(const common_iterator& __x, + const common_iterator<_It2, _Sent2>& __y) + noexcept(noexcept(ranges::iter_swap(std::declval(), + std::declval()))) + { + __glibcxx_assert(__x._M_index == 0); + __glibcxx_assert(__y._M_index == 0); + return ranges::iter_swap(__x._M_it, __y._M_it); + } + + private: + template _Sent2> + friend class common_iterator; + + bool _M_has_value() const noexcept { return _M_index < 2; } + + union + { + _It _M_it; + _Sent _M_sent; + unsigned char _M_valueless; + }; + unsigned char _M_index; // 0==_M_it, 1==_M_sent, 2==valueless + }; + + template + struct incrementable_traits> + { + using difference_type = iter_difference_t<_It>; + }; + + namespace __detail + { + // FIXME: This has to be at namespace-scope because of PR 92078. + template + struct __common_iter_ptr + { + using type = void; + }; + + template + requires __detail::__common_iter_has_arrow<_Iter> + struct __common_iter_ptr<_Iter> + { + using type = decltype(std::declval().operator->()); + }; + } // namespace __detail + + template + struct iterator_traits> + { + using iterator_concept = conditional_t, + forward_iterator_tag, input_iterator_tag>; + using iterator_category = __detail::__clamp_iter_cat< + typename iterator_traits<_It>::iterator_category, + forward_iterator_tag, input_iterator_tag>; + using value_type = iter_value_t<_It>; + using difference_type = iter_difference_t<_It>; + using pointer = typename + __detail::__common_iter_ptr>::type; + using reference = iter_reference_t<_It>; + }; + + // [iterators.counted] Counted iterators + + /// An iterator adaptor that keeps track of the distance to the end. + template + class counted_iterator + { + public: + using iterator_type = _It; + + constexpr counted_iterator() = default; + + constexpr + counted_iterator(_It __i, iter_difference_t<_It> __n) + : _M_current(__i), _M_length(__n) + { __glibcxx_assert(__n >= 0); } + + template + requires convertible_to + constexpr + counted_iterator(const counted_iterator<_It2>& __x) + : _M_current(__x._M_current), _M_length(__x._M_length) + { } + + template + requires assignable_from<_It&, const _It2&> + constexpr counted_iterator& + operator=(const counted_iterator<_It2>& __x) + { + _M_current = __x._M_current; + _M_length = __x._M_length; + return *this; + } + + constexpr _It + base() const & + noexcept(is_nothrow_copy_constructible_v<_It>) + requires copy_constructible<_It> + { return _M_current; } + + constexpr _It + base() && + noexcept(is_nothrow_move_constructible_v<_It>) + { return std::move(_M_current); } + + constexpr iter_difference_t<_It> + count() const noexcept { return _M_length; } + + constexpr decltype(auto) + operator*() + noexcept(noexcept(*_M_current)) + { return *_M_current; } + + constexpr decltype(auto) + operator*() const + noexcept(noexcept(*_M_current)) + requires __detail::__dereferenceable + { return *_M_current; } + + constexpr counted_iterator& + operator++() + { + __glibcxx_assert(_M_length > 0); + ++_M_current; + --_M_length; + return *this; + } + + decltype(auto) + operator++(int) + { + __glibcxx_assert(_M_length > 0); + --_M_length; + __try + { + return _M_current++; + } __catch(...) { + ++_M_length; + throw; + } + + } + + constexpr counted_iterator + operator++(int) requires forward_iterator<_It> + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + constexpr counted_iterator& + operator--() requires bidirectional_iterator<_It> + { + --_M_current; + ++_M_length; + return *this; + } + + constexpr counted_iterator + operator--(int) requires bidirectional_iterator<_It> + { + auto __tmp = *this; + --*this; + return __tmp; + } + + constexpr counted_iterator + operator+(iter_difference_t<_It> __n) const + requires random_access_iterator<_It> + { return counted_iterator(_M_current + __n, _M_length - __n); } + + friend constexpr counted_iterator + operator+(iter_difference_t<_It> __n, const counted_iterator& __x) + requires random_access_iterator<_It> + { return __x + __n; } + + constexpr counted_iterator& + operator+=(iter_difference_t<_It> __n) + requires random_access_iterator<_It> + { + __glibcxx_assert(__n <= _M_length); + _M_current += __n; + _M_length -= __n; + return *this; + } + + constexpr counted_iterator + operator-(iter_difference_t<_It> __n) const + requires random_access_iterator<_It> + { return counted_iterator(_M_current - __n, _M_length + __n); } + + template _It2> + friend constexpr iter_difference_t<_It2> + operator-(const counted_iterator& __x, + const counted_iterator<_It2>& __y) + { return __y._M_length - __x._M_length; } + + friend constexpr iter_difference_t<_It> + operator-(const counted_iterator& __x, default_sentinel_t) + { return -__x._M_length; } + + friend constexpr iter_difference_t<_It> + operator-(default_sentinel_t, const counted_iterator& __y) + { return __y._M_length; } + + constexpr counted_iterator& + operator-=(iter_difference_t<_It> __n) + requires random_access_iterator<_It> + { + __glibcxx_assert(-__n <= _M_length); + _M_current -= __n; + _M_length += __n; + return *this; + } + + constexpr decltype(auto) + operator[](iter_difference_t<_It> __n) const + noexcept(noexcept(_M_current[__n])) + requires random_access_iterator<_It> + { + __glibcxx_assert(__n < _M_length); + return _M_current[__n]; + } + + template _It2> + friend constexpr bool + operator==(const counted_iterator& __x, + const counted_iterator<_It2>& __y) + { return __x._M_length == __y._M_length; } + + friend constexpr bool + operator==(const counted_iterator& __x, default_sentinel_t) + { return __x._M_length == 0; } + + template _It2> + friend constexpr strong_ordering + operator<=>(const counted_iterator& __x, + const counted_iterator<_It2>& __y) + { return __y._M_length <=> __x._M_length; } + + friend constexpr iter_rvalue_reference_t<_It> + iter_move(const counted_iterator& __i) + noexcept(noexcept(ranges::iter_move(__i._M_current))) + requires input_iterator<_It> + { return ranges::iter_move(__i._M_current); } + + template _It2> + friend constexpr void + iter_swap(const counted_iterator& __x, + const counted_iterator<_It2>& __y) + noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current))) + { ranges::iter_swap(__x._M_current, __y._M_current); } + + private: + template friend class counted_iterator; + + _It _M_current = _It(); + iter_difference_t<_It> _M_length = 0; + }; + + template + struct incrementable_traits> + { + using difference_type = iter_difference_t<_It>; + }; + + template + struct iterator_traits> : iterator_traits<_It> + { + using pointer = void; + }; +#endif // C++20 + // @} group iterators template @@ -1332,8 +2014,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __iter_to_alloc_t = pair>, __iter_val_t<_InputIterator>>; - -#endif +#endif // __cpp_deduction_guides _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc b/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc new file mode 100644 index 00000000000..275ef53fe6a --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc @@ -0,0 +1,160 @@ +// Copyright (C) 2019 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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + using I = std::common_iterator; + static_assert( std::is_default_constructible_v ); + static_assert( std::is_copy_constructible_v ); + static_assert( std::is_copy_assignable_v ); + static_assert( std::is_constructible_v ); + static_assert( std::is_constructible_v ); + + struct sentinel { operator int*() const { return nullptr; } }; + using K = std::common_iterator; + static_assert( std::is_constructible_v ); + static_assert( std::is_assignable_v ); + + struct sentinel2 + { + const int* p; + sentinel2(const int* p = 0) : p(p) { } + bool operator==(const int* p) const { return p == this->p; } + }; + + using J = std::common_iterator; + static_assert( std::is_constructible_v ); + static_assert( std::is_convertible_v ); +} + +void +test02() +{ + struct sentinel { int limit; }; + + struct iterator + { + using iterator_category = std::input_iterator_tag; + using value_type = int; + using difference_type = std::ptrdiff_t; + using reference = const int&; + + const int& operator*() const { return counter; } + + iterator& operator++() { ++counter; return *this; } + + iterator operator++(int) { auto i = *this; ++counter; return i; } + + bool operator==(sentinel s) const { return counter == s.limit; } + + int counter = 0; + }; + + static_assert( std::sentinel_for ); + + int out[5] = { }; + std::common_iterator obegin = std::begin(out); + std::common_iterator oend = std::cend(out); + + iterator i; + sentinel s{5}; + std::common_iterator begin = i, end = s; + while (begin != end) + *obegin++ = *begin++; + + VERIFY(obegin == oend); + for (int& i : out) + VERIFY( i == (&i - out) ); +} + +void +test03() +{ + int arr[2] = { 1, 2 }; + std::common_iterator i = std::ranges::begin(arr); + std::common_iterator end = std::ranges::cend(arr); + VERIFY( i != end ); + VERIFY( (end - i) == 2 ); + VERIFY( (i - end) == -2 ); + auto j = i; + VERIFY( j == i ); + VERIFY( (j - i) == 0 ); + j = end; + VERIFY( j != i ); + VERIFY( j == end ); + j = std::ranges::next(i); + VERIFY( j != i ); + VERIFY( j != end ); + VERIFY( (end - j) == 1 ); + VERIFY( (j - i) == 1 ); + VERIFY( (i - j) == -1 ); + ++j; + VERIFY( j == end ); + VERIFY( (end - j) == 0 ); + j = i; + VERIFY( j == i ); + VERIFY( (j - end) == -2 ); + VERIFY( (j - i) == 0 ); + + try + { + struct S { operator const int*() const { throw 1; } }; + i = std::common_iterator(S{}); + VERIFY( false ); + } + catch (int) + { + } +} + +void +test04() +{ + struct X + { + X(int i) : i(i) { } + X(X&& x) : i(x.i) { x.i = -1; } + X& operator=(X&& x) { i = x.i; x.i = 0; return *this; } + int i; + }; + + X arr[] = { 1, 2 }; + std::common_iterator i(arr), j(arr+1); + std::ranges::iter_swap(i, j); + VERIFY( arr[0].i == 2 ); + VERIFY( arr[1].i == 1 ); + + X x = std::ranges::iter_move(i); + VERIFY( arr[0].i == -1 ); + VERIFY( x.i == 2 ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/24_iterators/counted_iterator/1.cc b/libstdc++-v3/testsuite/24_iterators/counted_iterator/1.cc new file mode 100644 index 00000000000..b31469cdebf --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/counted_iterator/1.cc @@ -0,0 +1,101 @@ +// Copyright (C) 2019 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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + using I = std::counted_iterator; + static_assert( std::is_default_constructible_v ); + static_assert( std::is_copy_constructible_v ); + static_assert( std::is_copy_assignable_v ); + static_assert( ! std::is_constructible_v ); + static_assert( std::is_constructible_v ); + + using J = std::counted_iterator; + static_assert( std::is_constructible_v ); + static_assert( std::is_convertible_v ); +} + +void +test02() +{ + int in[3] = { 1, 2, 3 }; + std::counted_iterator in_iter(std::begin(in), std::ssize(in)); + VERIFY( in_iter.base() == in ); + VERIFY( (std::default_sentinel - in_iter) == 3 ); + VERIFY( (in_iter - std::default_sentinel) == -3 ); + + int out[4] = { }; + std::counted_iterator out_iter(std::begin(out), std::ssize(out)); + VERIFY( out_iter.base() == out ); + VERIFY( (std::default_sentinel - out_iter) == 4 ); + VERIFY( (out_iter - std::default_sentinel) == -4 ); + + while (in_iter != std::default_sentinel && out_iter != std::default_sentinel) + *out_iter++ = *in_iter++; + + VERIFY(in_iter == std::default_sentinel); + VERIFY(out_iter != std::default_sentinel); + VERIFY( out[0] == 1 ); + VERIFY( out[1] == 2 ); + VERIFY( out[2] == 3 ); + VERIFY( out[3] == 0 ); + + auto out2 = out_iter; + out2 += 1; + VERIFY( out2 == std::default_sentinel ); + VERIFY( (out2 <=> out_iter) == std::strong_ordering::greater ); + out2 -= 3; + VERIFY( (out_iter - out2) == 2 ); + VERIFY( (out2 <=> out_iter) == std::strong_ordering::less ); +} + +void +test03() +{ + struct X + { + X(int i) : i(i) { } + X(X&& x) : i(x.i) { x.i = -1; } + X& operator=(X&& x) { i = x.i; x.i = 0; return *this; } + int i; + }; + + X arr[] = { 1, 2 }; + std::counted_iterator i(arr, 2), j(arr + 1, 1); + std::ranges::iter_swap(i, j); + VERIFY( arr[0].i == 2 ); + VERIFY( arr[1].i == 1 ); + + X x = std::ranges::iter_move(i); + VERIFY( arr[0].i == -1 ); + VERIFY( x.i == 2 ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/cust.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/cust.cc new file mode 100644 index 00000000000..6d0817dc204 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/cust.cc @@ -0,0 +1,50 @@ +// Copyright (C) 2019 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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + struct X + { + X(int i) : i(i) { } + X(X&& x) : i(x.i) { x.i = -1; } + X& operator=(X&& x) { i = x.i; x.i = 0; return *this; } + int i; + }; + + X arr[] = { 1, 2 }; + std::move_iterator i(arr), j(arr + 1); + std::ranges::iter_swap(i, j); + VERIFY( arr[0].i == 2 ); + VERIFY( arr[1].i == 1 ); + + X x = std::ranges::iter_move(i); + VERIFY( arr[0].i == -1 ); + VERIFY( x.i == 2 ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/sentinel.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/sentinel.cc new file mode 100644 index 00000000000..875a8fc37c4 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/sentinel.cc @@ -0,0 +1,91 @@ +// Copyright (C) 2019 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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + using S = std::move_sentinel; + using M = std::move_iterator; + + static_assert( std::is_default_constructible_v ); + static_assert( std::is_copy_constructible_v ); + static_assert( std::is_copy_assignable_v ); + static_assert( std::is_constructible_v> ); + static_assert( std::is_assignable_v> ); + + constexpr S s; + static_assert( s.base() == nullptr ); + + constexpr M m; + static_assert( m == s ); + static_assert( s == m ); + static_assert( !(m != s) ); + static_assert( !(s != m) ); + + int i = 0; + M m2(&i); + VERIFY( m2 != s ); + VERIFY( s != m2 ); + VERIFY( !(m2 == s) ); + VERIFY( !(s == m2) ); +} + +void +test02() +{ + struct sentinel { int limit; }; + + struct iterator + { + using iterator_category = std::input_iterator_tag; + using value_type = int; + using difference_type = std::ptrdiff_t; + using reference = const int&; + + const int& operator*() const { return counter; } + + iterator& operator++() { ++counter; return *this; } + + iterator operator++(int) { auto i = *this; ++counter; return i; } + + bool operator==(sentinel s) const { return counter == s.limit; } + + int counter = 0; + }; + + static_assert( std::sentinel_for ); + + iterator i; + sentinel s{5}; + int count = 0; + for (auto m = std::make_move_iterator(i); m != std::move_sentinel{s}; ++m) + ++count; + VERIFY( count == 5 ); +} + +int +main() +{ + test01(); + test02(); +}