On Tue, Sep 29, 2026 at 6:31 PM Jonathan Wakely <[email protected]> wrote:

> On Tue, 29 Sep 2026 at 08:56 +0200, Tomasz Kamiński wrote:
> >This patch extracts repeat_view::_Iterator to stand-alone _Repeat_iterator
> >declared in ranges_util.h. This allows it to be used to implement
> >(size_t, const T&) overloads of container function (using it in hive),
> >without including ranges header.
> >
> >As standard defines repeat_view::iterator(const T, index-type) as
> >private, the corresponding _Repeat_iterator constructor is kept private,
> >and std::__make_repeat_iterator is provided and used to construct it.
> >
> >Additionally, using _Repeat_iterator direclty, allows:
> >* referencing to existing elements (repeat_view stores copy)
> >* referencing to mutable elements (repeat_view yields const&)
> >* using same specialization for unreachable_sentinel and ptrdiff_t
> >  bound.
> >
> >The bits/ranges_util.h is used instead of bits/stl_iterator.h, to
> >avoid bringing dependency on __max_diff_type to that header.
> >
> >libstdc++-v3/ChangeLog:
> >
> >       * include/bits/ranges_base.h (ranges::__detail::__to_signed_like):
> >       Moved from std/ranges.
> >       * include/bits/ranges_util.h (std::_Repeat_iterator)
> >       [__glibcxx_ranges]: Extracted from repeat_view::_Iterator.
> >       Apply remove_cv_t on value_type (as it is now const). Updated
> >       _S_difference_type to use __to_signed_like direclty.
> >       (std::__make_repeat_iterator): Define.
> >       * include/std/ranges (ranges::__detail::__to_signed_like):
> >       Move to bits/ranges_base.h
> >       (repeat_view::__index_type): Define.
> >       (repeat_view::_Iterator): Extracted to standalone _Repeat_iterator,
> >       and replaced with alias to it.
> >       (repeat_view::begin, repeat_view::end): Implement using
> >       std::__make_repeat_iterator.
> >---
> >This also includes implementation of LWG4624, that I have posted
> separately
> >https://gcc.gnu.org/pipermail/libstdc++/2026-September/067846.html.
> >
> >Should I create an ranges_iterator.h file in this commit, or do it as
> >separate?
>
> That can be separate, just moving code around and not changing any
> types or functions.
>
> >Tested on powerpc64 anx 86_64 linux. OK for trunk?
>
> OK with one tweak (see below).

I would land this after following two are merged (waiting for approval),
as the _Repeat_iterator includes both fixes, and I do not want them
to be hidden in big move.
https://gcc.gnu.org/pipermail/libstdc++/2026-September/067816.html
https://gcc.gnu.org/pipermail/libstdc++/2026-September/067846.html

>


> >
> > libstdc++-v3/include/bits/ranges_base.h  |  19 +++
> > libstdc++-v3/include/bits/ranges_util.h  | 132 +++++++++++++++++++
> > libstdc++-v3/include/bits/stl_iterator.h |   2 +
> > libstdc++-v3/include/std/ranges          | 157 +----------------------
> > 4 files changed, 159 insertions(+), 151 deletions(-)
> >
> >diff --git a/libstdc++-v3/include/bits/ranges_base.h
> b/libstdc++-v3/include/bits/ranges_base.h
> >index 2c2b44c1ac6..7f4abbec341 100644
> >--- a/libstdc++-v3/include/bits/ranges_base.h
> >+++ b/libstdc++-v3/include/bits/ranges_base.h
> >@@ -88,6 +88,25 @@ namespace ranges
> >       using __make_unsigned_like_t
> >       = decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
> >
> >+    template<typename _Wp>
> >+      constexpr auto __to_signed_like(_Wp __w) noexcept
> >+      {
> >+      if constexpr (!integral<_Wp>)
> >+        return iter_difference_t<_Wp>();
> >+      else if constexpr (sizeof(iter_difference_t<_Wp>) > sizeof(_Wp))
> >+        return iter_difference_t<_Wp>(__w);
> >+      else if constexpr (sizeof(ptrdiff_t) > sizeof(_Wp))
> >+        return ptrdiff_t(__w);
> >+      else if constexpr (sizeof(long long) > sizeof(_Wp))
> >+        return (long long)(__w);
> >+#ifdef __SIZEOF_INT128__
> >+      else if constexpr (__SIZEOF_INT128__ > sizeof(_Wp))
> >+        return __int128(__w);
> >+#endif
> >+      else
> >+        return __max_diff_type(__w);
> >+      }
> >+
> >     // Part of the constraints of ranges::borrowed_range
> >     template<typename _Tp>
> >       concept __maybe_borrowed_range
> >diff --git a/libstdc++-v3/include/bits/ranges_util.h
> b/libstdc++-v3/include/bits/ranges_util.h
> >index 423767f00fc..e6c02aa1d92 100644
> >--- a/libstdc++-v3/include/bits/ranges_util.h
> >+++ b/libstdc++-v3/include/bits/ranges_util.h
> >@@ -850,6 +850,138 @@ namespace ranges
> >     struct tuple_element<1, const ranges::subrange<_Iter, _Sent, _Kind>>
> >     { using type = _Sent; };
> >
> >+template<typename _Tp, typename _IndexType>
> >+  class _Repeat_iterator;
> >+
> >+  template<typename _Tp, typename _IndexType>
> >+    constexpr _Repeat_iterator<_Tp, _IndexType>
> >+    __make_repeat_iterator(_Tp&, _IndexType);
> >+
> >+  template<typename _Tp, typename _IndexType>
> >+  class _Repeat_iterator
> >+  {
> >+    static auto
> >+    _S_difference_type()
> >+    {
> >+      if constexpr (__detail::__is_signed_integer_like<_IndexType>)
> >+      return _IndexType{};
> >+      else
> >+      return ranges::__detail::__to_signed_like(_IndexType{});
> >+    }
> >+
> >+    _Tp* _M_value = nullptr;
> >+    _IndexType _M_current = _IndexType();
> >+
> >+    constexpr explicit
> >+    _Repeat_iterator(const _Tp* __value, _IndexType __bound =
> _IndexType())
> >+    : _M_value(__value), _M_current(__bound)
> >+    { }
> >+
> >+  public:
> >+    using iterator_concept = random_access_iterator_tag;
> >+    using iterator_category = random_access_iterator_tag;
> >+    using value_type = remove_cv_t<_Tp>;
> >+    using difference_type = decltype(_S_difference_type());
> >+
> >+    _Repeat_iterator() = default;
> >+
> >+    constexpr _Tp&
> >+    operator*() const noexcept
> >+    { return *_M_value; }
> >+
> >+    constexpr _Repeat_iterator&
> >+    operator++()
> >+    {
> >+      ++_M_current;
> >+      return *this;
> >+    }
> >+
> >+    constexpr _Repeat_iterator
> >+    operator++(int)
> >+    {
> >+      auto __tmp = *this;
> >+      ++*this;
> >+      return __tmp;
> >+    }
> >+
> >+    constexpr _Repeat_iterator&
> >+    operator--()
> >+    {
> >+      __glibcxx_assert(_M_current > 0);
> >+      --_M_current;
> >+      return *this;
> >+    }
> >+
> >+    constexpr _Repeat_iterator
> >+    operator--(int)
> >+    {
> >+      auto __tmp = *this;
> >+      --*this;
> >+      return __tmp;
> >+    }
> >+
> >+    constexpr _Repeat_iterator&
> >+    operator+=(difference_type __n)
> >+    {
> >+      __glibcxx_assert(_M_current + __n >= 0);
> >+      _M_current += __n;
> >+      return *this;
> >+    }
> >+
> >+    constexpr _Repeat_iterator&
> >+    operator-=(difference_type __n)
> >+    {
> >+      __glibcxx_assert(_M_current - __n >= 0);
> >+      _M_current -= __n;
> >+      return *this;
> >+    }
> >+
> >+    constexpr _Tp&
> >+    operator[](difference_type __n) const noexcept
> >+    { return *(*this + __n); }
> >+
> >+    friend constexpr bool
> >+    operator==(const _Repeat_iterator& __x, const _Repeat_iterator& __y)
> >+    { return __x._M_current == __y._M_current; }
> >+
> >+    friend constexpr auto
> >+    operator<=>(const _Repeat_iterator& __x, const _Repeat_iterator& __y)
> >+    { return __x._M_current <=> __y._M_current; }
> >+
> >+    friend constexpr _Repeat_iterator
> >+    operator+(_Repeat_iterator __i, difference_type __n)
> >+    {
> >+      __i += __n;
> >+      return __i;
> >+    }
> >+
> >+    friend constexpr _Repeat_iterator
> >+    operator+(difference_type __n, _Repeat_iterator __i)
> >+    { return __i + __n; }
> >+
> >+    friend constexpr _Repeat_iterator
> >+    operator-(_Repeat_iterator __i, difference_type __n)
> >+    {
> >+      __i -= __n;
> >+      return __i;
> >+    }
> >+
> >+    friend constexpr difference_type
> >+    operator-(const _Repeat_iterator& __x, const _Repeat_iterator& __y)
> >+    {
> >+      return (static_cast<difference_type>(__x._M_current)
> >+            - static_cast<difference_type>(__y._M_current));
> >+    }
> >+
> >+    friend constexpr _Repeat_iterator<_Tp, _IndexType>
> >+    __make_repeat_iterator<_Tp, _IndexType>(_Tp&, _IndexType);
> >+  };
> >+
> >+  template<typename _Tp, typename _IndexType>
> >+    constexpr _Repeat_iterator<_Tp, _IndexType>
> >+    __make_repeat_iterator(_Tp& __tp, _IndexType __bound)
> >+    { return _Repeat_iterator<_Tp, _IndexType>(std::addressof(__tp),
> __bound); }
> >+
> > _GLIBCXX_END_NAMESPACE_VERSION
> > } // namespace std
> > #endif // library concepts
> >diff --git a/libstdc++-v3/include/bits/stl_iterator.h
> b/libstdc++-v3/include/bits/stl_iterator.h
> >index bcc22c50de5..ec008022b9b 100644
> >--- a/libstdc++-v3/include/bits/stl_iterator.h
> >+++ b/libstdc++-v3/include/bits/stl_iterator.h
> >@@ -3011,7 +3011,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >     make_const_sentinel(_Sent __s)
> >     noexcept(is_nothrow_convertible_v<_Sent, const_sentinel<_Sent>>)
> >     { return __s; }
> >+
> > #endif // C++23 ranges_as_const
> >+
> > #endif // C++20 ranges
>
> These whitespace-only changes to this file can be dropped from this
> commit, so that this commit doesn't appear to have been changed here
> when doing `git log include/bits/stl_iterator.h'
>
Ah, yes, these are leftover from defining _Repeat_iterator in stl_iterator,
that
I forgot to remove.

>
> >
> >   /// @} group iterators
> >diff --git a/libstdc++-v3/include/std/ranges
> b/libstdc++-v3/include/std/ranges
> >index fe7c87b8f6e..dde4ed90080 100644
> >--- a/libstdc++-v3/include/std/ranges
> >+++ b/libstdc++-v3/include/std/ranges
> >@@ -502,25 +502,6 @@ namespace ranges
> >
> >   namespace __detail
> >   {
> >-    template<typename _Wp>
> >-      constexpr auto __to_signed_like(_Wp __w) noexcept
> >-      {
> >-      if constexpr (!integral<_Wp>)
> >-        return iter_difference_t<_Wp>();
> >-      else if constexpr (sizeof(iter_difference_t<_Wp>) > sizeof(_Wp))
> >-        return iter_difference_t<_Wp>(__w);
> >-      else if constexpr (sizeof(ptrdiff_t) > sizeof(_Wp))
> >-        return ptrdiff_t(__w);
> >-      else if constexpr (sizeof(long long) > sizeof(_Wp))
> >-        return (long long)(__w);
> >-#ifdef __SIZEOF_INT128__
> >-      else if constexpr (__SIZEOF_INT128__ > sizeof(_Wp))
> >-        return __int128(__w);
> >-#endif
> >-      else
> >-        return __max_diff_type(__w);
> >-      }
> >-
> >     template<typename _Wp>
> >       using __iota_diff_t =
> decltype(__to_signed_like(std::declval<_Wp>()));
> >
> >@@ -7981,11 +7962,13 @@ namespace views::__adaptor
> >         || same_as<_Bound, unreachable_sentinel_t>)
> >   class repeat_view : public view_interface<repeat_view<_Tp, _Bound>>
> >   {
> >+    using __index_type
> >+      = __conditional_t<same_as<_Bound, unreachable_sentinel_t>,
> ptrdiff_t, _Bound>;
> >+    using _Iterator = _Repeat_iterator<const _Tp, __index_type>;
> >+
> >     [[no_unique_address]] __detail::__box<_Tp> _M_value;
> >     [[no_unique_address]] _Bound _M_bound = _Bound();
> >
> >-    class _Iterator;
> >-
> >     template<typename _Range>
> >     friend constexpr auto
> >     views::__detail::__take_of_repeat_view(_Range&&,
> range_difference_t<_Range>);
> >@@ -8030,11 +8013,11 @@ namespace views::__adaptor
> >
> >     constexpr _Iterator
> >     begin() const
> >-    { return _Iterator(std::__addressof(*_M_value)); }
> >+    { return std::__make_repeat_iterator(*_M_value, __index_type(0)); }
> >
> >     constexpr _Iterator
> >     end() const requires (!same_as<_Bound, unreachable_sentinel_t>)
> >-    { return _Iterator(std::__addressof(*_M_value), _M_bound); }
> >+    { return std::__make_repeat_iterator(*_M_value, _M_bound); }
> >
> >     constexpr unreachable_sentinel_t
> >     end() const noexcept
> >@@ -8050,134 +8033,6 @@ namespace views::__adaptor
> >   template<typename _Tp, typename _Bound = unreachable_sentinel_t>
> >     repeat_view(_Tp, _Bound = _Bound()) -> repeat_view<_Tp, _Bound>;
> >
> >-  template<move_constructible _Tp, semiregular _Bound>
> >-    requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
> >-      && (__detail::__is_signed_integer_like<_Bound>
> >-        || (__detail::__is_integer_like<_Bound> &&
> weakly_incrementable<_Bound>)
> >-        || same_as<_Bound, unreachable_sentinel_t>)
> >-  class repeat_view<_Tp, _Bound>::_Iterator
> >-  {
> >-    using __index_type
> >-      = __conditional_t<same_as<_Bound, unreachable_sentinel_t>,
> ptrdiff_t, _Bound>;
> >-
> >-    static auto
> >-    _S_difference_type()
> >-    {
> >-      if constexpr (__detail::__is_signed_integer_like<__index_type>)
> >-      return __index_type{};
> >-      else
> >-      return __detail::__iota_diff_t<__index_type>{};
> >-    }
> >-
> >-    const _Tp* _M_value = nullptr;
> >-    __index_type _M_current = __index_type();
> >-
> >-    constexpr explicit
> >-    _Iterator(const _Tp* __value, __index_type __bound = __index_type())
> >-    : _M_value(__value), _M_current(__bound)
> >-    { }
> >-
> >-    friend repeat_view;
> >-
> >-  public:
> >-    using iterator_concept = random_access_iterator_tag;
> >-    using iterator_category = random_access_iterator_tag;
> >-    using value_type = _Tp;
> >-    using difference_type = decltype(_S_difference_type());
> >-
> >-    _Iterator() = default;
> >-
> >-    constexpr const _Tp&
> >-    operator*() const noexcept
> >-    { return *_M_value; }
> >-
> >-    constexpr _Iterator&
> >-    operator++()
> >-    {
> >-      ++_M_current;
> >-      return *this;
> >-    }
> >-
> >-    constexpr _Iterator
> >-    operator++(int)
> >-    {
> >-      auto __tmp = *this;
> >-      ++*this;
> >-      return __tmp;
> >-    }
> >-
> >-    constexpr _Iterator&
> >-    operator--()
> >-    {
> >-      // _GLIBCXX_RESOLVE_LIB_DEFECTS
> >-      // 4624. Inconsistent preconditions in repeat_view::iterator
> >-      __glibcxx_assert(_M_current > 0);
> >-      --_M_current;
> >-      return *this;
> >-    }
> >-
> >-    constexpr _Iterator
> >-    operator--(int)
> >-    {
> >-      auto __tmp = *this;
> >-      --*this;
> >-      return __tmp;
> >-    }
> >-
> >-    constexpr _Iterator&
> >-    operator+=(difference_type __n)
> >-    {
> >-      __glibcxx_assert(_M_current + __n >= 0);
> >-      _M_current += __n;
> >-      return *this;
> >-    }
> >-
> >-    constexpr _Iterator&
> >-    operator-=(difference_type __n)
> >-    {
> >-      __glibcxx_assert(_M_current - __n >= 0);
> >-      _M_current -= __n;
> >-      return *this;
> >-    }
> >-
> >-    constexpr const _Tp&
> >-    operator[](difference_type __n) const noexcept
> >-    { return *(*this + __n); }
> >-
> >-    friend constexpr bool
> >-    operator==(const _Iterator& __x, const _Iterator& __y)
> >-    { return __x._M_current == __y._M_current; }
> >-
> >-    friend constexpr auto
> >-    operator<=>(const _Iterator& __x, const _Iterator& __y)
> >-    { return __x._M_current <=> __y._M_current; }
> >-
> >-    friend constexpr _Iterator
> >-    operator+(_Iterator __i, difference_type __n)
> >-    {
> >-      __i += __n;
> >-      return __i;
> >-    }
> >-
> >-    friend constexpr _Iterator
> >-    operator+(difference_type __n, _Iterator __i)
> >-    { return __i + __n; }
> >-
> >-    friend constexpr _Iterator
> >-    operator-(_Iterator __i, difference_type __n)
> >-    {
> >-      __i -= __n;
> >-      return __i;
> >-    }
> >-
> >-    friend constexpr difference_type
> >-    operator-(const _Iterator& __x, const _Iterator& __y)
> >-    {
> >-      return (static_cast<difference_type>(__x._M_current)
> >-            - static_cast<difference_type>(__y._M_current));
> >-    }
> >-  };
> >-
> >   namespace views
> >   {
> >     namespace __detail
> >--
> >2.55.0
> >
> >
>
>

Reply via email to