From 2fc08026800bd67c37887a0c1c5f6a44a1126fa6 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 1 Mar 2023 22:12:01 +0100 Subject: [PATCH 1/4] Implement LWG-3851 --- stl/inc/ranges | 16 ++++++ tests/std/tests/P2442R1_views_chunk/env.lst | 2 +- tests/std/tests/P2442R1_views_chunk/test.cpp | 54 +++++++++++++++++++- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index f99d906a71f..fb1bce9c06b 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -6286,6 +6286,10 @@ namespace ranges { return (_STD min)(_Parent->_Remainder, _RANGES end(_Parent->_Range) - *_Parent->_Current); } + _NODISCARD constexpr const iterator_t<_Vw>& _Get_current() const noexcept { + return *_Parent->_Current; + } + public: using iterator_concept = input_iterator_tag; using difference_type = range_difference_t<_Vw>; @@ -6352,6 +6356,18 @@ namespace ranges { { return -_Left._Get_size(); } + + _NODISCARD_FRIEND constexpr range_rvalue_reference_t<_Vw> iter_move(const _Inner_iterator& _It) noexcept( + noexcept(_RANGES iter_move(_It._Get_current()))) { + return _RANGES iter_move(_It._Get_current()); + } + + friend constexpr void iter_swap(const _Inner_iterator& _Left, const _Inner_iterator& _Right) noexcept( + noexcept(_RANGES iter_swap(_Left._Get_current(), _Right._Get_current()))) + requires indirectly_swappable> + { + _RANGES iter_swap(_Left._Get_current(), _Right._Get_current()); + } }; class _Outer_iterator { diff --git a/tests/std/tests/P2442R1_views_chunk/env.lst b/tests/std/tests/P2442R1_views_chunk/env.lst index 18e2d7c71ec..8ac7033b206 100644 --- a/tests/std/tests/P2442R1_views_chunk/env.lst +++ b/tests/std/tests/P2442R1_views_chunk/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst diff --git a/tests/std/tests/P2442R1_views_chunk/test.cpp b/tests/std/tests/P2442R1_views_chunk/test.cpp index 685ac77ac66..892c6b124f0 100644 --- a/tests/std/tests/P2442R1_views_chunk/test.cpp +++ b/tests/std/tests/P2442R1_views_chunk/test.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include #include @@ -464,8 +466,9 @@ template constexpr bool test_input(Rng&& rng, Expected&& expected) { using ranges::chunk_view, ranges::equal, ranges::iterator_t, ranges::sentinel_t; - using V = views::all_t; - using R = chunk_view; + using V = views::all_t; + using BI = ranges::iterator_t; + using R = chunk_view; same_as auto r = chunk_view{forward(rng), 2}; auto outer_iter = r.begin(); @@ -478,6 +481,19 @@ constexpr bool test_input(Rng&& rng, Expected&& expected) { auto inner_iter = val_ty.begin(); same_as auto inner_sen = val_ty.end(); + + { // Check iter_move (other tests are defined in 'test_lwg3851' function) + same_as> decltype(auto) rval = iter_move(as_const(inner_iter)); + assert(rval == expected[0][0]); + STATIC_ASSERT(noexcept(iter_move(inner_iter)) == noexcept(ranges::iter_move(declval()))); + } + + if constexpr (indirectly_swappable) { // Check iter_swap (other tests are defined in 'test_lwg3851' function) + STATIC_ASSERT(is_void_v); + STATIC_ASSERT(noexcept(iter_swap(inner_iter, inner_iter)) + == noexcept(ranges::iter_swap(declval(), declval()))); + } + assert(inner_iter != inner_sen); if constexpr (sized_sentinel_for, iterator_t>) { assert(inner_sen - inner_iter == 2); @@ -579,6 +595,38 @@ using move_only_view = test::range}, test::ProxyRef{!derived_from}, test::CanView::yes, test::Copyability::move_only>; +// Check LWG-3851: 'chunk_view::inner-iterator missing custom iter_move and iter_swap' +void test_lwg3851() { +#if 0 // FIXME Requires #3466 (Implement P2770R0 "Stashing stashing iterators for proper flattening") + { // Check 'iter_move' (example from LWG-3851) + istringstream ints{"0 1 2 3 4"}; + vector vs{"the", "quick", "brown", "fox"}; + auto r = views::zip(vs, views::istream(ints)) | views::chunk(2) | views::join; + vector> res; + ranges::copy(move_iterator(r.begin()), move_sentinel(r.end()), back_inserter(res)); + assert(vs.front().empty()); // Implementation defined: moved out string shall be empty + } +#endif + + { // Check 'iter_swap' + istringstream s1{"0 1 2 3 4"}; + auto v1 = views::istream(s1) | views::chunk(2); + auto o1 = v1.begin(); + auto c1 = *o1; + auto i1 = c1.begin(); + + istringstream s2{"5 6 7 8 9"}; + auto v2 = views::istream(s2) | views::chunk(2); + auto o2 = v2.begin(); + auto c2 = *o2; + auto i2 = c2.begin(); + + iter_swap(as_const(i1), as_const(i2)); + assert(*i1 == 5); + assert(*i2 == 0); + } +} + int main() { { // Validate views // ... copyable @@ -617,4 +665,6 @@ int main() { STATIC_ASSERT((instantiation_test(), true)); instantiation_test(); + + test_lwg3851(); } From 4d3beb55439b50f6c7f03d3f65a3bb07d1d85435 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 1 Mar 2023 22:25:37 +0100 Subject: [PATCH 2/4] Quick decision: let's not use example from LWG-3851 and add custom test --- tests/std/tests/P2442R1_views_chunk/test.cpp | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/std/tests/P2442R1_views_chunk/test.cpp b/tests/std/tests/P2442R1_views_chunk/test.cpp index 892c6b124f0..8d427d37ae7 100644 --- a/tests/std/tests/P2442R1_views_chunk/test.cpp +++ b/tests/std/tests/P2442R1_views_chunk/test.cpp @@ -597,26 +597,26 @@ using move_only_view = test::range vs{"the", "quick", "brown", "fox"}; - auto r = views::zip(vs, views::istream(ints)) | views::chunk(2) | views::join; - vector> res; - ranges::copy(move_iterator(r.begin()), move_sentinel(r.end()), back_inserter(res)); - assert(vs.front().empty()); // Implementation defined: moved out string shall be empty + auto v = views::istream(ints) | views::chunk(2); + auto o = v.begin(); + auto c = *o; + auto i = c.begin(); + + same_as decltype(auto) rval = iter_move(i); + assert(rval == 0); } -#endif { // Check 'iter_swap' - istringstream s1{"0 1 2 3 4"}; - auto v1 = views::istream(s1) | views::chunk(2); + istringstream ints1{"0 1 2 3 4"}; + auto v1 = views::istream(ints1) | views::chunk(2); auto o1 = v1.begin(); auto c1 = *o1; auto i1 = c1.begin(); - istringstream s2{"5 6 7 8 9"}; - auto v2 = views::istream(s2) | views::chunk(2); + istringstream ints2{"5 6 7 8 9"}; + auto v2 = views::istream(ints2) | views::chunk(2); auto o2 = v2.begin(); auto c2 = *o2; auto i2 = c2.begin(); From 619dbbdb3be3114511946cdf0376aa111662eb0b Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 1 Mar 2023 22:52:00 +0100 Subject: [PATCH 3/4] Looks like death test must be `strict` too --- tests/std/tests/P2442R1_views_chunk_death/env.lst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P2442R1_views_chunk_death/env.lst b/tests/std/tests/P2442R1_views_chunk_death/env.lst index 18e2d7c71ec..8ac7033b206 100644 --- a/tests/std/tests/P2442R1_views_chunk_death/env.lst +++ b/tests/std/tests/P2442R1_views_chunk_death/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst From e2403733ec75a2ef25649a2679873aa7a17419db Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Mar 2023 05:10:16 -0800 Subject: [PATCH 4/4] We have a using-declaration above. --- tests/std/tests/P2442R1_views_chunk/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P2442R1_views_chunk/test.cpp b/tests/std/tests/P2442R1_views_chunk/test.cpp index 8d427d37ae7..be07d71a871 100644 --- a/tests/std/tests/P2442R1_views_chunk/test.cpp +++ b/tests/std/tests/P2442R1_views_chunk/test.cpp @@ -467,7 +467,7 @@ constexpr bool test_input(Rng&& rng, Expected&& expected) { using ranges::chunk_view, ranges::equal, ranges::iterator_t, ranges::sentinel_t; using V = views::all_t; - using BI = ranges::iterator_t; + using BI = iterator_t; using R = chunk_view; same_as auto r = chunk_view{forward(rng), 2};