[PATCH] libstdc++: Extract repeat_view::_Iterator to bits/ranges_util.h.

Jonathan Wakely jwakely@redhat.com
Tue Sep 29 16:30:57 GMT 2026


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



More information about the Libstdc++ mailing list