libstdc++: Add move_sentinel, common_iterator and counted_iterator
authorJonathan Wakely <jwakely@redhat.com>
Mon, 25 Nov 2019 19:02:03 +0000 (19:02 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 25 Nov 2019 19:02:03 +0000 (19:02 +0000)
This implements most of the remaining C++20 additions to the <iterator>
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

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/iterator_concepts.h
libstdc++-v3/include/bits/stl_iterator.h
libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc [new file with mode: 0644]
libstdc++-v3/testsuite/24_iterators/counted_iterator/1.cc [new file with mode: 0644]
libstdc++-v3/testsuite/24_iterators/move_iterator/cust.cc [new file with mode: 0644]
libstdc++-v3/testsuite/24_iterators/move_iterator/sentinel.cc [new file with mode: 0644]

index 09202af787f2a58f4adb7ae15aa525505be01054..4ea06a37a1f9d18ec589eee4d908d3cb9383de08 100644 (file)
@@ -1,5 +1,17 @@
 2019-11-25  Jonathan Wakely  <jwakely@redhat.com>
 
+       * 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.
index 3843ba5d57fa9414941864f9f898680cf880a41a..97aed72e2554bcf33f9985dc72ca77e7d414685c 100644 (file)
@@ -700,7 +700,7 @@ namespace ranges
   namespace __cust_iswap
   {
     template<typename _It1, typename _It2>
-      void iter_swap(_It1&, _It2&) = delete;
+      void iter_swap(_It1, _It2) = delete;
 
     template<typename _Tp, typename _Up>
       concept __adl_iswap
@@ -744,7 +744,8 @@ namespace ranges
     public:
       template<typename _Tp, typename _Up>
        requires __adl_iswap<_Tp, _Up>
-       || (readable<_Tp> && readable<_Up>
+       || (readable<remove_reference_t<_Tp>>
+           && readable<remove_reference_t<_Up>>
            && swappable_with<iter_reference_t<_Tp>, iter_reference_t<_Up>>)
        || (indirectly_movable_storable<_Tp, _Up>
            && indirectly_movable_storable<_Up, _Tp>)
index a707621c9edb1dad90d47adcd1b52ba5390d7689..89cca64438ca92e291e7f83a3a8d343e39e90a1c 100644 (file)
 # define __cpp_lib_array_constexpr 201803
 #endif
 
+#if __cplusplus > 201703L
+# include <compare>
+# include <new>
+#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<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
@@ -1073,14 +1127,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   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;
@@ -1091,6 +1158,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef typename conditional<is_reference<__base_ref>::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<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
@@ -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<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>
@@ -1332,8 +2014,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     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
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 (file)
index 0000000..275ef53
--- /dev/null
@@ -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
+// <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();
+}
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 (file)
index 0000000..b31469c
--- /dev/null
@@ -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
+// <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::counted_iterator<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, int*, std::ptrdiff_t> );
+
+  using J = std::counted_iterator<const int*>;
+  static_assert( std::is_constructible_v<J, const I&> );
+  static_assert( std::is_convertible_v<const I&, J> );
+}
+
+void
+test02()
+{
+  int in[3] = { 1, 2, 3 };
+  std::counted_iterator<const int*> 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<int*> 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<X*> 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 (file)
index 0000000..6d0817d
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <iterator>
+#include <testsuite_hooks.h>
+
+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<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();
+}
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 (file)
index 0000000..875a8fc
--- /dev/null
@@ -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
+// <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 S = std::move_sentinel<const int*>;
+  using M = std::move_iterator<int*>;
+
+  static_assert( std::is_default_constructible_v<S> );
+  static_assert( std::is_copy_constructible_v<S> );
+  static_assert( std::is_copy_assignable_v<S> );
+  static_assert( std::is_constructible_v<S, std::move_sentinel<int*>> );
+  static_assert( std::is_assignable_v<S, std::move_sentinel<int*>> );
+
+  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<sentinel, iterator> );
+
+  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();
+}