[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