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