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


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'


  /// @} 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