# define __cpp_lib_array_constexpr 201803
#endif
+#if __cplusplus > 201703L
+# include <compare>
+# include <new>
+#endif
+
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __it.base(); }
#if __cplusplus >= 201103L
-
/**
* @addtogroup iterators
* @{
*/
+#if __cplusplus > 201703L && __cpp_lib_concepts
+ template<semiregular _Sent>
+ 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<typename _S2> requires convertible_to<const _S2&, _Sent>
+ constexpr
+ move_sentinel(const move_sentinel<_S2>& __s)
+ noexcept(is_nothrow_constructible_v<_Sent, const _S2&>)
+ : _M_last(__s.base())
+ { }
+
+ template<typename _S2> 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<typename _Cat, typename _Limit, typename _Otherwise = _Cat>
+ using __clamp_iter_cat
+ = conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>;
+ }
+#endif // C++20
+
// 24.4.3 Move iterators
/**
* Class template move_iterator is an iterator adapter with the same
template<typename _Iterator>
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;
typedef typename conditional<is_reference<__base_ref>::value,
typename remove_reference<__base_ref>::type&&,
__base_ref>::type reference;
+#endif
_GLIBCXX17_CONSTEXPR
move_iterator()
_GLIBCXX17_CONSTEXPR reference
operator[](difference_type __n) const
{ return std::move(_M_current[__n]); }
+
+#if __cplusplus > 201703L && __cpp_lib_concepts
+ template<sentinel_for<_Iterator> _Sent>
+ friend constexpr bool
+ operator==(const move_iterator& __x, const move_sentinel<_Sent>& __y)
+ { return __x.base() == __y.base(); }
+
+ template<sized_sentinel_for<_Iterator> _Sent>
+ friend constexpr iter_difference_t<_Iterator>
+ operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y)
+ { return __x.base() - __y.base(); }
+
+ template<sized_sentinel_for<_Iterator> _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<indirectly_swappable<_Iterator> _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
__make_move_if_noexcept_iterator(_Tp* __i)
{ return _ReturnType(__i); }
+#if __cplusplus > 201703L && __cpp_lib_concepts
+ // [iterators.common] Common iterators
+
+ namespace __detail
+ {
+ template<input_or_output_iterator _It>
+ class _Common_iter_proxy
+ {
+ iter_value_t<_It> _M_keep;
+
+ _Common_iter_proxy(iter_reference_t<_It>&& __x)
+ : _M_keep(std::move(__x)) { }
+
+ template<typename _Iter, typename _Sent>
+ friend class common_iterator;
+
+ public:
+ const iter_value_t<_It>*
+ operator->() const
+ { return std::__addressof(_M_keep); }
+ };
+
+ template<typename _It>
+ concept __common_iter_has_arrow = readable<const _It>
+ && (requires(const _It& __it) { __it.operator->(); }
+ || is_reference_v<iter_reference_t<_It>>
+ || constructible_from<iter_value_t<_It>, iter_reference_t<_It>>);
+
+ } // namespace __detail
+
+ /// An iterator/sentinel adaptor for representing a non-common range.
+ template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
+ requires (!same_as<_It, _Sent>)
+ class common_iterator
+ {
+ template<typename _Tp, typename _Up>
+ 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<typename _It2, typename _Sent2>
+ 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<typename _It2, typename _Sent2>
+ requires convertible_to<const _It2&, _It>
+ && convertible_to<const _Sent2&, _Sent>
+ constexpr
+ common_iterator(const common_iterator<_It2, _Sent2>& __x)
+ noexcept(_S_noexcept<const _It2&, const _Sent2&>())
+ : _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<const _It&, const _Sent&>())
+ : _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<typename _It2, typename _Sent2>
+ requires convertible_to<const _It2&, _It>
+ && convertible_to<const _Sent2&, _Sent>
+ && 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<const _It>
+ {
+ __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<iter_reference_t<_It>>)
+ {
+ 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<typename _It2, sentinel_for<_It> _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<typename _It2, sentinel_for<_It> _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<sized_sentinel_for<_It> _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<const _It&>())))
+ requires input_iterator<_It>
+ {
+ __glibcxx_assert(__i._M_index == 0);
+ return ranges::iter_move(__i._M_it);
+ }
+
+ template<indirectly_swappable<_It> _It2, typename _Sent2>
+ friend void
+ iter_swap(const common_iterator& __x,
+ const common_iterator<_It2, _Sent2>& __y)
+ noexcept(noexcept(ranges::iter_swap(std::declval<const _It&>(),
+ std::declval<const _It2&>())))
+ {
+ __glibcxx_assert(__x._M_index == 0);
+ __glibcxx_assert(__y._M_index == 0);
+ return ranges::iter_swap(__x._M_it, __y._M_it);
+ }
+
+ private:
+ template<input_or_output_iterator _It2, sentinel_for<_It2> _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<typename _It, typename _Sent>
+ struct incrementable_traits<common_iterator<_It, _Sent>>
+ {
+ using difference_type = iter_difference_t<_It>;
+ };
+
+ namespace __detail
+ {
+ // FIXME: This has to be at namespace-scope because of PR 92078.
+ template<typename _Iter>
+ struct __common_iter_ptr
+ {
+ using type = void;
+ };
+
+ template<typename _Iter>
+ requires __detail::__common_iter_has_arrow<_Iter>
+ struct __common_iter_ptr<_Iter>
+ {
+ using type = decltype(std::declval<const _Iter&>().operator->());
+ };
+ } // namespace __detail
+
+ template<input_iterator _It, typename _Sent>
+ struct iterator_traits<common_iterator<_It, _Sent>>
+ {
+ using iterator_concept = conditional_t<forward_iterator<_It>,
+ 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<common_iterator<_It, _Sent>>::type;
+ using reference = iter_reference_t<_It>;
+ };
+
+ // [iterators.counted] Counted iterators
+
+ /// An iterator adaptor that keeps track of the distance to the end.
+ template<input_or_output_iterator _It>
+ 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<typename _It2>
+ requires convertible_to<const _It2&, _It>
+ constexpr
+ counted_iterator(const counted_iterator<_It2>& __x)
+ : _M_current(__x._M_current), _M_length(__x._M_length)
+ { }
+
+ template<typename _It2>
+ 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<const _It>
+ { 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<common_with<_It> _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<common_with<_It> _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<common_with<_It> _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<indirectly_swappable<_It> _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<input_or_output_iterator _It2> friend class counted_iterator;
+
+ _It _M_current = _It();
+ iter_difference_t<_It> _M_length = 0;
+ };
+
+ template<typename _It>
+ struct incrementable_traits<counted_iterator<_It>>
+ {
+ using difference_type = iter_difference_t<_It>;
+ };
+
+ template<input_iterator _It>
+ struct iterator_traits<counted_iterator<_It>> : iterator_traits<_It>
+ {
+ using pointer = void;
+ };
+#endif // C++20
+
// @} group iterators
template<typename _Iterator>
using __iter_to_alloc_t =
pair<add_const_t<__iter_key_t<_InputIterator>>,
__iter_val_t<_InputIterator>>;
-
-#endif
+#endif // __cpp_deduction_guides
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <iterator>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ using I = std::common_iterator<int*, const int*>;
+ static_assert( std::is_default_constructible_v<I> );
+ static_assert( std::is_copy_constructible_v<I> );
+ static_assert( std::is_copy_assignable_v<I> );
+ static_assert( std::is_constructible_v<I, int*> );
+ static_assert( std::is_constructible_v<I, const int*> );
+
+ struct sentinel { operator int*() const { return nullptr; } };
+ using K = std::common_iterator<int*, sentinel>;
+ static_assert( std::is_constructible_v<I, const K&> );
+ static_assert( std::is_assignable_v<I, const K&> );
+
+ 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<const int*, sentinel2>;
+ static_assert( std::is_constructible_v<J, const I&> );
+ static_assert( std::is_convertible_v<const I&, J> );
+}
+
+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<sentinel, iterator> );
+
+ int out[5] = { };
+ std::common_iterator<int*, const int*> obegin = std::begin(out);
+ std::common_iterator<int*, const int*> oend = std::cend(out);
+
+ iterator i;
+ sentinel s{5};
+ std::common_iterator<iterator, sentinel> 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<int*, const int*> i = std::ranges::begin(arr);
+ std::common_iterator<int*, const int*> 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<int*, S>(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<X*, const X*> 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();
+}