Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement P2770R0 "Stashing stashing iterators for proper flattening" #3466

Merged
merged 25 commits into from
Mar 3, 2023

Conversation

cpplearner
Copy link
Contributor

Fixes #3450

@cpplearner cpplearner requested a review from a team as a code owner February 14, 2023 11:55
@StephanTLavavej StephanTLavavej added the cxx23 C++23 feature label Feb 14, 2023
stl/inc/regex Outdated Show resolved Hide resolved
stl/inc/ranges Outdated Show resolved Hide resolved
stl/inc/ranges Show resolved Hide resolved
stl/inc/ranges Outdated Show resolved Hide resolved
stl/inc/ranges Outdated Show resolved Hide resolved
stl/inc/ranges Outdated Show resolved Hide resolved
@StephanTLavavej

This comment was marked as resolved.

@cpplearner
Copy link
Contributor Author

It seems that P2770 breaks iterator(iterator<!Const> i) when forward_range<V> is false and forward_range<const V> is true: said constructor initializes outer_ with std::move(i.outer_), but i.outer_ is not present in this case.

(P2770R0 correctly points out that Const can only be true when forward_range<const V> is true, so outer_ is always present.)

cc @timsong-cpp

@timsong-cpp
Copy link
Contributor

when forward_range<V> is false and forward_range<const V> is true

That is not a scenario I care about (where's @CaseyCarter's promised paper when you need it?) - I know of no realistic range where adding const strengthens the iterator concept (it can make it not-a-range, of course, and there was some musings at one point about weakening to input for views that would otherwise need to cache).

That said, lazy_split_view does additionally constrain its const begin/end with forward_range<V>, so I'm not opposed to an LWG issue that adds that for consistency.

@hewillk
Copy link
Contributor

hewillk commented Feb 22, 2023

I think you should define an alias to replace _InnerRng<_Const>, for example:

using _InnerBase = _InnerRng<_Const>;

since _InnerRng<_Const> is repeated too many times, it is a bit dazzling.

I believe this increases readability:

        constexpr decltype(auto) operator++(int) {
            if constexpr (_Deref_is_glvalue && forward_range<_Base> && forward_range<_InnerBase>) {
                auto _Tmp = *this;
                ++*this;
                return _Tmp;
            } else {
                ++*this;
            }
        }

@StephanTLavavej
Copy link
Member

@hewillk That's pre-existing (24 occurrences) - I would have no objection to introducing such an alias, but I think it should be done in a followup PR because so much code is affected.

@StephanTLavavej StephanTLavavej self-assigned this Feb 24, 2023
@StephanTLavavej

This comment was marked as resolved.

@StephanTLavavej StephanTLavavej removed their assignment Feb 24, 2023
GH 3493 "<ranges>: Fix misused list-initializations" added test coverage
for GH 3014 "<ranges>: list-initialization is misused". This defined an
input_iterator named init_list_not_constructible_iterator. Now, P2770R0
"Stashing Stashing Iterators For Proper Flattening" is upgrading
join_view and join_with_view's const overload of begin() to require
forward_range<const V>. Therefore, we need to upgrade
init_list_not_constructible_iterator to be a forward_iterator:

* Mark its iterator_category as forward_iterator_tag.
* Make it equality comparable, required for forward iterators.
* Verify that it is now a forward_iterator.
* Rename usage from InRange to FwdRange.

Finally, this found two more improper uses of braces in <ranges>,
within join_view::_Iterator_base and join_with_view::_Iterator_base.
@StephanTLavavej
Copy link
Member

StephanTLavavej commented Feb 26, 2023

  • I've pushed a merge with main, mechanically resolving merge conflicts:
    • In <ranges>, kept this PR's changes, but converted braces to parentheses in mem-initializer-lists.
    • In P0896R4_views_join/test.cpp and P2441R2_views_join_with/test.cpp, resolved trivial adjacent-add conflicts.
  • Then, I added a commit for non-trivial semantic merge conflict resolutions. <ranges>: Fix misused list-initializations #3493 added test coverage for <ranges>: list-initialization is misused #3014. This defined an input_iterator named init_list_not_constructible_iterator. Now, this PR is upgrading join_view and join_with_view's const overload of begin() to require forward_range<const V>. Therefore, we need to upgrade init_list_not_constructible_iterator to be a forward_iterator:
    • Mark its iterator_category as forward_iterator_tag.
    • Make it equality comparable, required for forward iterators.
    • Verify that it is now a forward_iterator.
    • Rename usage from InRange to FwdRange.
  • Finally, this found two more improper uses of braces in <ranges> (in code added by this PR), within join_view::_Iterator_base and join_with_view::_Iterator_base.

@StephanTLavavej
Copy link
Member

I'm a greedy kitty who wants treats 😼 and is speculatively mirroring this to the MSVC-internal repo - please notify me if any further changes are pushed.

Copy link
Contributor

@strega-nil-ms strega-nil-ms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Minor change, but it's pre-existing so no need to reset testing.

#endif // ^^^ workaround ^^^

template <class _Ty>
_NODISCARD constexpr _Ty& _As_lvalue(_Ty&& _Val) noexcept {
return static_cast<_Ty&>(_Val);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change requested since it's in the standard like this, but this static_cast is unnecessary I believe.

Copy link
Contributor Author

@cpplearner cpplearner Mar 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, this static_cast was unnecessary before WG21-P2266, but WG21-P2266 makes _Val an xvalue in return _Val;, and thus an explicit cast is now needed to make it not move-eligible.

@@ -3567,37 +3567,36 @@ namespace ranges {

#ifdef __clang__
template <class _Rng> // TRANSITION, LLVM-47414
concept _Can_const_join = input_range<const _Rng> && is_reference_v<range_reference_t<const _Rng>>;
concept _Can_const_join = forward_range<const _Rng> && is_reference_v<range_reference_t<const _Rng>>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pre-existing, but I really don't like how _Can_const_join splits the primary template definition of _Join_view_base from the specialization; adding _As_lvalue makes this even worse. Can you move _As_lvalue and _Can_const_join above the primary template definition?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know a guy who just created a dozen cleanup PRs - I'll tell him to add this change to one of them. 😹

@StephanTLavavej StephanTLavavej merged commit 9f751b1 into microsoft:main Mar 3, 2023
@StephanTLavavej
Copy link
Member

Thanks for implementing this feature, incrementing the repo towards C++23 conformance! 📈 🎉 😻

@StephanTLavavej StephanTLavavej mentioned this pull request Mar 4, 2023
@cpplearner cpplearner deleted the P2770R0 branch March 4, 2023 04:03
@frederick-vs-ja
Copy link
Contributor

Will this be backported to a future version of VS2019?

It seems that #2727 hasn't been backported to VS2019 16.11.25 yet, so I'm afraid that there's already some ABI-incompatible uses of join_view between VS2019 and VS2022.

@StephanTLavavej
Copy link
Member

At this time, we aren't planning to service VS 2019 for anything that isn't a security bug or a massively impactful bug. It's unfortunate that #2727 was merged days after we announced the backport (2022-05-23 vs. 2022-05-10), and while this means that ABI-incompatible uses aren't blocked, I believe that the affected code will be minimal. We completed C++20 and its DRs in VS 2019 but we can't keep changing it forever, and this change just missed the train. Users who are interested in using the most advanced features should really upgrade to VS 2022.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cxx23 C++23 feature ranges C++20/23 ranges
Projects
None yet
Development

Successfully merging this pull request may close these issues.

P2770R0 Stashing Stashing Iterators For Proper Flattening
7 participants