[PATCH] libstdc++: Extract repeat_view::_Iterator to bits/ranges_util.h.
Jonathan Wakely
jwakely@redhat.com
Tue Sep 29 19:25:39 GMT 2026
On Tue, 29 Sept 2026 at 17:36, Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>
>
>
>
> On Tue, Sep 29, 2026 at 6:31 PM Jonathan Wakely <jwakely@redhat.com> 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
>> >
>> >
>>
More information about the Libstdc++
mailing list