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 https://gcc.gnu.org/pipermail/libstdc++/2026-September/067846.html > > > > > 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 > > > > > >
