On Tue, 29 Sept 2026 at 17:36, Tomasz Kaminski <[email protected]> wrote:
>
>
>
>
> 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

That one has been approved.

> https://gcc.gnu.org/pipermail/libstdc++/2026-September/067846.html

Ah I thought you mean that one was subsumed by the patch below. But it
builds on top of it.

>>
>>
>>
>>
>> >
>> > 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