Message ID | 20241004020844.116894-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | libstdc++/ranges: Implement various small LWG issues | expand |
On Fri, 4 Oct 2024 at 03:09, Patrick Palka <ppalka@redhat.com> wrote: > > Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and perhaps > 13? OK for all, thanks. > > -- >8 -- > > This implements the following small LWG issues: > > 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor > 3851. chunk_view::inner-iterator missing custom iter_move and iter_swap > 3947. Unexpected constraints on adjacent_transform_view::base() > 4001. iota_view should provide empty > 4012. common_view::begin/end are missing the simple-view check > 4013. lazy_split_view::outer-iterator::value_type should not provide default constructor > 4035. single_view should provide empty > 4053. Unary call to std::views::repeat does not decay the argument > 4054. Repeating a repeat_view should repeat the view > > libstdc++-v3/ChangeLog: > > * include/std/ranges (single_view::empty): Define as per LWG 4035. > (iota_view::empty): Define as per LWG 4001. > (lazy_split_view::_OuterIter::value_type): Remove default > constructor and make other constructor private as per LWG 4013. > (common_view::begin): Disable non-const overload for simple > views as per LWG 4012. > (common_view::end): Likewise. > (adjacent_view::base): Define as per LWG 3848. > (adjacent_transform_view::base): Likewise. > (chunk_view::_InnerIter::iter_move): Define as per LWG 3851. > (chunk_view::_InnerIter::itep_swap): Likewise. > (slide_view::base): Define as per LWG 3848. > (repeat_view): Adjust deduction guide as per LWG 4053. > (_Repeat::operator()): Adjust single-parameter overload > as per LWG 4054. > * testsuite/std/ranges/adaptors/adjacent/1.cc: Verify existence > of base member function. > * testsuite/std/ranges/adaptors/adjacent_transform/1.cc: Likewise. > * testsuite/std/ranges/adaptors/chunk/1.cc: Test LWG 3851 example. > * testsuite/std/ranges/adaptors/slide/1.cc: Verify existence of > base member function. > * testsuite/std/ranges/iota/iota_view.cc: Test LWG 4001 example. > * testsuite/std/ranges/repeat/1.cc: Test LWG 4053/4054 examples. > --- > libstdc++-v3/include/std/ranges | 84 +++++++++++++++++-- > .../std/ranges/adaptors/adjacent/1.cc | 3 + > .../ranges/adaptors/adjacent_transform/1.cc | 3 + > .../testsuite/std/ranges/adaptors/chunk/1.cc | 15 ++++ > .../testsuite/std/ranges/adaptors/slide/1.cc | 3 + > .../testsuite/std/ranges/iota/iota_view.cc | 12 +++ > libstdc++-v3/testsuite/std/ranges/repeat/1.cc | 23 +++++ > 7 files changed, 135 insertions(+), 8 deletions(-) > > diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges > index 30f45e0a750..6e6e3b97d82 100644 > --- a/libstdc++-v3/include/std/ranges > +++ b/libstdc++-v3/include/std/ranges > @@ -335,6 +335,12 @@ namespace ranges > end() const noexcept > { return data() + 1; } > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 4035. single_view should provide empty > + static constexpr bool > + empty() noexcept > + { return false; } > + > static constexpr size_t > size() noexcept > { return 1; } > @@ -695,6 +701,12 @@ namespace ranges > end() const requires same_as<_Winc, _Bound> > { return _Iterator{_M_bound}; } > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 4001. iota_view should provide empty > + constexpr bool > + empty() const > + { return _M_value == _M_bound; } > + > constexpr auto > size() const > requires (same_as<_Winc, _Bound> && __detail::__advanceable<_Winc>) > @@ -3349,14 +3361,17 @@ namespace views::__adaptor > private: > _OuterIter _M_i = _OuterIter(); > > - public: > - value_type() = default; > - > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 4013. lazy_split_view::outer-iterator::value_type should not > + // provide default constructor > constexpr explicit > value_type(_OuterIter __i) > : _M_i(std::move(__i)) > { } > > + friend _OuterIter; > + > + public: > constexpr _InnerIter<_Const> > begin() const > { return _InnerIter<_Const>{_M_i}; } > @@ -3948,8 +3963,10 @@ namespace views::__adaptor > base() && > { return std::move(_M_base); } > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 4012. common_view::begin/end are missing the simple-view check > constexpr auto > - begin() > + begin() requires (!__detail::__simple_view<_Vp>) > { > if constexpr (random_access_range<_Vp> && sized_range<_Vp>) > return ranges::begin(_M_base); > @@ -3969,7 +3986,7 @@ namespace views::__adaptor > } > > constexpr auto > - end() > + end() requires (!__detail::__simple_view<_Vp>) > { > if constexpr (random_access_range<_Vp> && sized_range<_Vp>) > return ranges::begin(_M_base) + ranges::size(_M_base); > @@ -5316,6 +5333,16 @@ namespace views::__adaptor > : _M_base(std::move(__base)) > { } > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor > + constexpr _Vp > + base() const & requires copy_constructible<_Vp> > + { return _M_base; } > + > + constexpr _Vp > + base() && > + { return std::move(_M_base); } > + > constexpr auto > begin() requires (!__detail::__simple_view<_Vp>) > { return _Iterator<false>(ranges::begin(_M_base), ranges::end(_M_base)); } > @@ -5709,6 +5736,17 @@ namespace views::__adaptor > : _M_fun(std::move(__fun)), _M_inner(std::move(__base)) > { } > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor > + // 3947. Unexpected constraints on adjacent_transform_view::base() > + constexpr _Vp > + base() const & requires copy_constructible<_Vp> > + { return _M_inner.base(); } > + > + constexpr _Vp > + base() && > + { return std::move(_M_inner.base()); } > + > constexpr auto > begin() > { return _Iterator<false>(*this, _M_inner.begin()); } > @@ -6236,6 +6274,20 @@ namespace views::__adaptor > operator-(const _InnerIter& __x, default_sentinel_t __y) > requires sized_sentinel_for<sentinel_t<_Vp>, iterator_t<_Vp>> > { return -(__y - __x); } > + > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 3851. chunk_view::inner-iterator missing custom iter_move and iter_swap > + friend constexpr range_rvalue_reference_t<_Vp> > + iter_move(const _InnerIter& __i) > + noexcept(noexcept(ranges::iter_move(*__i._M_parent->_M_current))) > + { return ranges::iter_move(*__i._M_parent->_M_current); } > + > + friend constexpr void > + iter_swap(const _InnerIter& __x, const _InnerIter& __y) > + noexcept(noexcept(ranges::iter_swap(*__x._M_parent->_M_current, > + *__x._M_parent->_M_current))) > + requires indirectly_swappable<iterator_t<_Vp>> > + { return ranges::iter_swap(*__x._M_parent->_M_current, *__y._M_parent->_M_current); } > }; > > template<view _Vp> > @@ -6577,6 +6629,16 @@ namespace views::__adaptor > : _M_base(std::move(__base)), _M_n(__n) > { __glibcxx_assert(__n > 0); } > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor > + constexpr _Vp > + base() const & requires copy_constructible<_Vp> > + { return _M_base; } > + > + constexpr _Vp > + base() && > + { return std::move(_M_base); } > + > constexpr auto > begin() requires (!(__detail::__simple_view<_Vp> > && __detail::__slide_caches_nothing<const _Vp>)) > @@ -7692,8 +7754,10 @@ namespace views::__adaptor > { return __detail::__to_unsigned_like(_M_bound); } > }; > > - template<typename _Tp, typename _Bound> > - repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>; > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 4053. Unary call to std::views::repeat does not decay the argument > + 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>> > @@ -7840,7 +7904,11 @@ namespace views::__adaptor > requires __detail::__can_repeat_view<_Tp> > constexpr auto > operator() [[nodiscard]] (_Tp&& __value) const > - { return repeat_view(std::forward<_Tp>(__value)); } > + { > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 4054. Repeating a repeat_view should repeat the view > + return repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value)); > + } > > template<typename _Tp, typename _Bound> > requires __detail::__can_bounded_repeat_view<_Tp, _Bound> > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc > index b83743a745c..085cd4a8c54 100644 > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc > @@ -47,6 +47,9 @@ test01() > VERIFY( &std::get<2>(v3[i]) == &y[i] + 2 ); > } > > + // LWG 3848 - adjacent_view etc missing base accessor > + v3.base(); > + > const auto v5 = y | views::adjacent<5>; > VERIFY( ranges::equal(v5, views::single(std::make_tuple(1, 2, 3, 4, 5))) ); > > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc > index 6aeedbaa648..a5791b3da70 100644 > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc > @@ -39,6 +39,9 @@ test01() > VERIFY( ranges::size(v3) == 4 ); > VERIFY( ranges::equal(v3, (int[]){3, 4, 5, 6}) ); > > + // LWG 3848 - adjacent_transform_view etc missing base accessor > + v3.base(); > + > const auto v6 = y | views::adjacent_transform<6>([](auto...) { return 0; }); > VERIFY( ranges::equal(v6, (int[]){0}) ); > > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc > index 90eb608ca5e..82f9f1b674c 100644 > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc > @@ -8,6 +8,7 @@ > #endif > > #include <algorithm> > +#include <sstream> > #include <vector> > #include <testsuite_hooks.h> > #include <testsuite_iterators.h> > @@ -76,10 +77,24 @@ test02() > VERIFY( ranges::equal(wrapper(x) | views::chunk(i) | views::join, x) ); > } > > +void > +test03() > +{ > + // LWG 3851 - chunk_view::inner-iterator missing custom iter_move and iter_swap > + auto ints = std::istringstream{"0 1 2 3 4"}; > + std::vector<std::string> vs{"the", "quick", "brown", "fox"}; > + auto r = views::zip(vs, views::istream<int>(ints)) | views::chunk(2) | views::join; > + std::vector<std::tuple<std::string, int>> res; > + ranges::copy(std::move_iterator(r.begin()), std::move_sentinel(r.end()), > + std::back_inserter(res)); > + VERIFY( vs.front().empty() ); > +} > + > int > main() > { > static_assert(test01()); > test02<__gnu_test::test_input_range<int>>(); > test02<__gnu_test::test_forward_range<int>>(); > + test03(); > } > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc > index bafe9fbc4bf..a5d94ea6406 100644 > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc > @@ -50,6 +50,9 @@ test01() > VERIFY( &v3[i][2] == &y[i] + 2 ); > } > > + // LWG 3848 - slide_view etc missing base accessor > + v3.base(); > + > const auto v5 = y | views::slide(5); > VERIFY( ranges::size(v5) == 1 ); > VERIFY( ranges::equal(v5 | views::join, y) ); > diff --git a/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc b/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc > index bec4174a3da..9db61a76596 100644 > --- a/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc > +++ b/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc > @@ -19,6 +19,7 @@ > > #include <algorithm> > #include <ranges> > +#include <vector> > #include <testsuite_hooks.h> > > void > @@ -118,6 +119,16 @@ test07() > static_assert(!requires { iota(nullptr, nullptr); }); > } > > +void > +test08() > +{ > + // LWC 4001 - iota_view should provide empty > + std::vector<int> v; > + auto it = std::back_inserter(v); > + auto r = std::views::iota(it); > + VERIFY( !r.empty() ); > +} > + > int > main() > { > @@ -128,4 +139,5 @@ main() > test05(); > test06(); > test07(); > + test08(); > } > diff --git a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc > index cad8c8dcbe7..eb0c848e9ce 100644 > --- a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc > +++ b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc > @@ -151,6 +151,27 @@ test07() > auto d2 = std::views::repeat(std::make_unique<int>(5), 4) | std::views::drop(2); > } > > +void > +test08() > +{ > + // LWG 4053 - Unary call to std::views::repeat does not decay the argument > + using type = ranges::repeat_view<const char*>; > + using type = decltype(views::repeat("foo", std::unreachable_sentinel)); > + using type = decltype(views::repeat(+"foo", std::unreachable_sentinel)); > + using type = decltype(views::repeat("foo")); > + using type = decltype(views::repeat(+"foo")); > +} > + > +void > +test09() > +{ > + // LWG 4054 - Repeating a repeat_view should repeat the view > + auto v = views::repeat(views::repeat(5)); > + using type = decltype(v); > + using type = ranges::repeat_view<ranges::repeat_view<int>>; > + VERIFY( v[0][0] == 5 ); > +} > + > int > main() > { > @@ -161,4 +182,6 @@ main() > test05(); > test06(); > test07(); > + test08(); > + test09(); > } > -- > 2.47.0.rc1 >
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 30f45e0a750..6e6e3b97d82 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -335,6 +335,12 @@ namespace ranges end() const noexcept { return data() + 1; } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4035. single_view should provide empty + static constexpr bool + empty() noexcept + { return false; } + static constexpr size_t size() noexcept { return 1; } @@ -695,6 +701,12 @@ namespace ranges end() const requires same_as<_Winc, _Bound> { return _Iterator{_M_bound}; } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4001. iota_view should provide empty + constexpr bool + empty() const + { return _M_value == _M_bound; } + constexpr auto size() const requires (same_as<_Winc, _Bound> && __detail::__advanceable<_Winc>) @@ -3349,14 +3361,17 @@ namespace views::__adaptor private: _OuterIter _M_i = _OuterIter(); - public: - value_type() = default; - + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4013. lazy_split_view::outer-iterator::value_type should not + // provide default constructor constexpr explicit value_type(_OuterIter __i) : _M_i(std::move(__i)) { } + friend _OuterIter; + + public: constexpr _InnerIter<_Const> begin() const { return _InnerIter<_Const>{_M_i}; } @@ -3948,8 +3963,10 @@ namespace views::__adaptor base() && { return std::move(_M_base); } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4012. common_view::begin/end are missing the simple-view check constexpr auto - begin() + begin() requires (!__detail::__simple_view<_Vp>) { if constexpr (random_access_range<_Vp> && sized_range<_Vp>) return ranges::begin(_M_base); @@ -3969,7 +3986,7 @@ namespace views::__adaptor } constexpr auto - end() + end() requires (!__detail::__simple_view<_Vp>) { if constexpr (random_access_range<_Vp> && sized_range<_Vp>) return ranges::begin(_M_base) + ranges::size(_M_base); @@ -5316,6 +5333,16 @@ namespace views::__adaptor : _M_base(std::move(__base)) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor + constexpr _Vp + base() const & requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + constexpr auto begin() requires (!__detail::__simple_view<_Vp>) { return _Iterator<false>(ranges::begin(_M_base), ranges::end(_M_base)); } @@ -5709,6 +5736,17 @@ namespace views::__adaptor : _M_fun(std::move(__fun)), _M_inner(std::move(__base)) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor + // 3947. Unexpected constraints on adjacent_transform_view::base() + constexpr _Vp + base() const & requires copy_constructible<_Vp> + { return _M_inner.base(); } + + constexpr _Vp + base() && + { return std::move(_M_inner.base()); } + constexpr auto begin() { return _Iterator<false>(*this, _M_inner.begin()); } @@ -6236,6 +6274,20 @@ namespace views::__adaptor operator-(const _InnerIter& __x, default_sentinel_t __y) requires sized_sentinel_for<sentinel_t<_Vp>, iterator_t<_Vp>> { return -(__y - __x); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3851. chunk_view::inner-iterator missing custom iter_move and iter_swap + friend constexpr range_rvalue_reference_t<_Vp> + iter_move(const _InnerIter& __i) + noexcept(noexcept(ranges::iter_move(*__i._M_parent->_M_current))) + { return ranges::iter_move(*__i._M_parent->_M_current); } + + friend constexpr void + iter_swap(const _InnerIter& __x, const _InnerIter& __y) + noexcept(noexcept(ranges::iter_swap(*__x._M_parent->_M_current, + *__x._M_parent->_M_current))) + requires indirectly_swappable<iterator_t<_Vp>> + { return ranges::iter_swap(*__x._M_parent->_M_current, *__y._M_parent->_M_current); } }; template<view _Vp> @@ -6577,6 +6629,16 @@ namespace views::__adaptor : _M_base(std::move(__base)), _M_n(__n) { __glibcxx_assert(__n > 0); } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor + constexpr _Vp + base() const & requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + constexpr auto begin() requires (!(__detail::__simple_view<_Vp> && __detail::__slide_caches_nothing<const _Vp>)) @@ -7692,8 +7754,10 @@ namespace views::__adaptor { return __detail::__to_unsigned_like(_M_bound); } }; - template<typename _Tp, typename _Bound> - repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4053. Unary call to std::views::repeat does not decay the argument + 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>> @@ -7840,7 +7904,11 @@ namespace views::__adaptor requires __detail::__can_repeat_view<_Tp> constexpr auto operator() [[nodiscard]] (_Tp&& __value) const - { return repeat_view(std::forward<_Tp>(__value)); } + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4054. Repeating a repeat_view should repeat the view + return repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value)); + } template<typename _Tp, typename _Bound> requires __detail::__can_bounded_repeat_view<_Tp, _Bound> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc index b83743a745c..085cd4a8c54 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc @@ -47,6 +47,9 @@ test01() VERIFY( &std::get<2>(v3[i]) == &y[i] + 2 ); } + // LWG 3848 - adjacent_view etc missing base accessor + v3.base(); + const auto v5 = y | views::adjacent<5>; VERIFY( ranges::equal(v5, views::single(std::make_tuple(1, 2, 3, 4, 5))) ); diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc index 6aeedbaa648..a5791b3da70 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc @@ -39,6 +39,9 @@ test01() VERIFY( ranges::size(v3) == 4 ); VERIFY( ranges::equal(v3, (int[]){3, 4, 5, 6}) ); + // LWG 3848 - adjacent_transform_view etc missing base accessor + v3.base(); + const auto v6 = y | views::adjacent_transform<6>([](auto...) { return 0; }); VERIFY( ranges::equal(v6, (int[]){0}) ); diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc index 90eb608ca5e..82f9f1b674c 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc @@ -8,6 +8,7 @@ #endif #include <algorithm> +#include <sstream> #include <vector> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -76,10 +77,24 @@ test02() VERIFY( ranges::equal(wrapper(x) | views::chunk(i) | views::join, x) ); } +void +test03() +{ + // LWG 3851 - chunk_view::inner-iterator missing custom iter_move and iter_swap + auto ints = std::istringstream{"0 1 2 3 4"}; + std::vector<std::string> vs{"the", "quick", "brown", "fox"}; + auto r = views::zip(vs, views::istream<int>(ints)) | views::chunk(2) | views::join; + std::vector<std::tuple<std::string, int>> res; + ranges::copy(std::move_iterator(r.begin()), std::move_sentinel(r.end()), + std::back_inserter(res)); + VERIFY( vs.front().empty() ); +} + int main() { static_assert(test01()); test02<__gnu_test::test_input_range<int>>(); test02<__gnu_test::test_forward_range<int>>(); + test03(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc index bafe9fbc4bf..a5d94ea6406 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc @@ -50,6 +50,9 @@ test01() VERIFY( &v3[i][2] == &y[i] + 2 ); } + // LWG 3848 - slide_view etc missing base accessor + v3.base(); + const auto v5 = y | views::slide(5); VERIFY( ranges::size(v5) == 1 ); VERIFY( ranges::equal(v5 | views::join, y) ); diff --git a/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc b/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc index bec4174a3da..9db61a76596 100644 --- a/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc +++ b/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc @@ -19,6 +19,7 @@ #include <algorithm> #include <ranges> +#include <vector> #include <testsuite_hooks.h> void @@ -118,6 +119,16 @@ test07() static_assert(!requires { iota(nullptr, nullptr); }); } +void +test08() +{ + // LWC 4001 - iota_view should provide empty + std::vector<int> v; + auto it = std::back_inserter(v); + auto r = std::views::iota(it); + VERIFY( !r.empty() ); +} + int main() { @@ -128,4 +139,5 @@ main() test05(); test06(); test07(); + test08(); } diff --git a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc index cad8c8dcbe7..eb0c848e9ce 100644 --- a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc @@ -151,6 +151,27 @@ test07() auto d2 = std::views::repeat(std::make_unique<int>(5), 4) | std::views::drop(2); } +void +test08() +{ + // LWG 4053 - Unary call to std::views::repeat does not decay the argument + using type = ranges::repeat_view<const char*>; + using type = decltype(views::repeat("foo", std::unreachable_sentinel)); + using type = decltype(views::repeat(+"foo", std::unreachable_sentinel)); + using type = decltype(views::repeat("foo")); + using type = decltype(views::repeat(+"foo")); +} + +void +test09() +{ + // LWG 4054 - Repeating a repeat_view should repeat the view + auto v = views::repeat(views::repeat(5)); + using type = decltype(v); + using type = ranges::repeat_view<ranges::repeat_view<int>>; + VERIFY( v[0][0] == 5 ); +} + int main() { @@ -161,4 +182,6 @@ main() test05(); test06(); test07(); + test08(); + test09(); }