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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4ccfc5e
Revert "`<ranges>`: Temporarily disable `join_view` for non-`forward_…
cpplearner Feb 13, 2023
259eba9
LWG-3698 (join_view part)
cpplearner Feb 13, 2023
42046d3
LWG-3698 (join_with_view part)
cpplearner Feb 13, 2023
e173647
LWG-3698 (regex_iterator & regex_token_iterator part)
cpplearner Feb 13, 2023
d3431f9
Add tests for LWG-3698
cpplearner Feb 14, 2023
02e58e5
LWG-3700 The const begin of the join_view family does not require Inn…
cpplearner Feb 13, 2023
a701dd1
Add tests for LWG-3700
cpplearner Feb 14, 2023
3414a57
LWG-3791 join_view::iterator::operator-- may be ill-formed
cpplearner Feb 13, 2023
fae90be
Add ProxyRef::xvalue in range_algorithm_support.hpp
cpplearner Feb 14, 2023
aae58b7
Add test for LWG-3791
cpplearner Feb 14, 2023
0553cc4
Make join_view::iterator's constructors private
cpplearner Feb 14, 2023
e93956e
Simplify join_with_view::iterator::operator--
cpplearner Feb 14, 2023
ae4236e
Update libc++ skips
cpplearner Feb 14, 2023
57cfc02
Add iterator_concept only if _HAS_CXX20
cpplearner Feb 15, 2023
9343d0c
Fix LWG-3791 test
cpplearner Feb 16, 2023
0681646
Address review comments from StephanTLavavej
cpplearner Feb 17, 2023
ba47b18
Add tests for ranges that do not model simple-view
cpplearner Feb 17, 2023
f402d29
Remove redundant forward declarations of _Sentinel
cpplearner Feb 17, 2023
1f68bba
Fix test
cpplearner Feb 17, 2023
acf3592
Fix test
cpplearner Feb 18, 2023
8171166
Merge branch 'main' into P2770R0
CaseyCarter Feb 21, 2023
63a7ffb
Code review feedback.
StephanTLavavej Feb 22, 2023
b10ab4c
Merge branch 'main' into P2770R0
StephanTLavavej Feb 24, 2023
e8682cf
Merge branch 'main' into P2770R0
StephanTLavavej Feb 26, 2023
6ba7036
NON-TRIVIAL merge conflict resolutions!
StephanTLavavej Feb 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
277 changes: 182 additions & 95 deletions stl/inc/ranges

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions stl/inc/regex
Original file line number Diff line number Diff line change
Expand Up @@ -2387,6 +2387,9 @@ public:
using pointer = const value_type*;
using reference = const value_type&;
using iterator_category = forward_iterator_tag;
#if _HAS_CXX20
using iterator_concept = input_iterator_tag;
#endif // _HAS_CXX20

regex_iterator() : _MyRe(nullptr) {} // construct end of sequence iterator

Expand Down Expand Up @@ -2523,6 +2526,9 @@ public:
using pointer = const value_type*;
using reference = const value_type&;
using iterator_category = forward_iterator_tag;
#if _HAS_CXX20
using iterator_concept = input_iterator_tag;
#endif // _HAS_CXX20

regex_token_iterator() : _Res(nullptr) {} // construct end of sequence iterator

Expand Down
1 change: 1 addition & 0 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@
// P2602R2 Poison Pills Are Too Toxic
// P2609R3 Relaxing Ranges Just A Smidge
// P2711R1 Making Multi-Param Constructors Of Views explicit
// P2770R0 Stashing Stashing Iterators For Proper Flattening

// _HAS_CXX20 indirectly controls:
// P0619R4 Removing C++17-Deprecated Features
Expand Down
9 changes: 9 additions & 0 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ std/ranges/range.access/rbegin.pass.cpp FAIL
std/ranges/range.access/rend.pass.cpp FAIL
std/ranges/range.access/size.pass.cpp FAIL

# libc++ doesn't implement P2770R0 "Stashing stashing iterators for proper flattening"
std/ranges/range.adaptors/range.join.view/end.pass.cpp FAIL
std/ranges/range.adaptors/range.join.view/iterator/ctor.other.pass.cpp FAIL
std/ranges/range.adaptors/range.join.view/iterator/ctor.parent.outer.pass.cpp FAIL
std/ranges/range.adaptors/range.join.view/iterator/eq.pass.cpp FAIL
std/ranges/range.adaptors/range.join.view/sentinel/eq.pass.cpp FAIL
std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp FAIL
std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp FAIL

# libc++ doesn't implement LWG-3865 Sorting a range of pairs
std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp FAIL

Expand Down
2 changes: 1 addition & 1 deletion tests/libcxx/usual_matrix.lst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

RUNALL_INCLUDE ..\universal_prefix.lst
RUNALL_CROSSLIST
PM_CL="/EHsc /MTd /std:c++latest /permissive- /utf-8 /FImsvc_stdlib_force_include.h /wd4643 /D_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER /D_USE_JOIN_VIEW_INPUT_RANGE"
PM_CL="/EHsc /MTd /std:c++latest /permissive- /utf-8 /FImsvc_stdlib_force_include.h /wd4643 /D_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER"
RUNALL_CROSSLIST
PM_CL="/analyze:autolog- /Zc:preprocessor /wd6262"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call"
15 changes: 9 additions & 6 deletions tests/std/include/range_algorithm_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ namespace test {

enum class CanDifference : bool { no, yes };
enum class CanCompare : bool { no, yes };
enum class ProxyRef { no, yes, prvalue };
enum class ProxyRef { no, yes, prvalue, xvalue };
enum class WrappedState {
wrapped,
unwrapped,
Expand Down Expand Up @@ -394,8 +394,9 @@ namespace test {

template <class T>
struct init_list_not_constructible_iterator {
using difference_type = int;
using value_type = T;
using iterator_category = std::forward_iterator_tag;
using difference_type = int;
using value_type = T;

init_list_not_constructible_iterator() = default;
init_list_not_constructible_iterator(T*) {}
Expand All @@ -407,10 +408,11 @@ namespace test {
init_list_not_constructible_iterator& operator++(); // not defined
init_list_not_constructible_iterator operator++(int); // not defined

bool operator==(init_list_not_constructible_iterator) const; // not defined
bool operator==(init_list_not_constructible_sentinel<T>) const; // not defined
};

static_assert(std::input_iterator<init_list_not_constructible_iterator<int>>);
static_assert(std::forward_iterator<init_list_not_constructible_iterator<int>>);
static_assert(
std::sentinel_for<init_list_not_constructible_sentinel<int>, init_list_not_constructible_iterator<int>>);

Expand All @@ -433,7 +435,8 @@ namespace test {
static constexpr bool at_least = derived_from<Category, T>;

using ReferenceType = conditional_t<Proxy == ProxyRef::yes, proxy_reference<Category, Element>,
conditional_t<Proxy == ProxyRef::prvalue, std::remove_cv_t<Element>, Element&>>;
conditional_t<Proxy == ProxyRef::prvalue, std::remove_cv_t<Element>,
conditional_t<Proxy == ProxyRef::xvalue, Element&&, Element&>>>;

struct post_increment_proxy {
Element* ptr_;
Expand Down Expand Up @@ -475,7 +478,7 @@ namespace test {
}

[[nodiscard]] constexpr ReferenceType operator*() const noexcept {
return ReferenceType{*ptr_};
return static_cast<ReferenceType>(*ptr_);
}

template <WrappedState OtherWrapped>
Expand Down
4 changes: 2 additions & 2 deletions tests/std/tests/P0896R4_views_elements/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ constexpr void instantiation_test() {

// GH-3014 "<ranges>: list-initialization is misused"
void test_gh_3014() { // COMPILE-ONLY
struct InRange {
struct FwdRange {
P* begin() {
return nullptr;
}
Expand All @@ -410,7 +410,7 @@ void test_gh_3014() { // COMPILE-ONLY
}
};

auto r = InRange{} | views::elements<0>;
auto r = FwdRange{} | views::elements<0>;
[[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator<!Const> i)'
}

Expand Down
97 changes: 91 additions & 6 deletions tests/std/tests/P0896R4_views_join/test.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#define _USE_JOIN_VIEW_INPUT_RANGE

#include <algorithm>
#include <array>
#include <cassert>
Expand Down Expand Up @@ -145,7 +143,10 @@ constexpr bool test_one(Outer&& rng, Expected&& expected) {

// Validate join_view::begin
static_assert(CanMemberBegin<R>);
static_assert(CanMemberBegin<const R> == (input_range<const V> && is_reference_v<range_reference_t<const V>>) );
// clang-format off
static_assert(CanMemberBegin<const R> == (forward_range<const V> && is_reference_v<range_reference_t<const V>>
&& input_range<range_reference_t<const V>>) );
// clang-format on
if (forward_range<R>) {
const iterator_t<R> i = r.begin();
if (!is_empty) {
Expand Down Expand Up @@ -179,8 +180,9 @@ constexpr bool test_one(Outer&& rng, Expected&& expected) {

// Validate join_view::end
static_assert(CanMemberEnd<R>);
static_assert(CanMemberEnd<const R> == (input_range<const V> && is_reference_v<range_reference_t<const V>>) );
// clang-format off
static_assert(CanMemberEnd<const R> == (forward_range<const V> && is_reference_v<range_reference_t<const V>>
&& input_range<range_reference_t<const V>>) );
static_assert(common_range<R> == (forward_range<V> && is_reference_v<range_reference_t<V>> && common_range<V>
&& forward_range<Inner> && common_range<Inner>) );
static_assert(common_range<const R> == (forward_range<const V> && is_reference_v<range_reference_t<const V>>
Expand Down Expand Up @@ -512,7 +514,7 @@ void test_non_trivially_destructible_type() { // COMPILE-ONLY

// GH-3014 "<ranges>: list-initialization is misused"
void test_gh_3014() { // COMPILE-ONLY
struct InRange {
struct FwdRange {
string* begin() {
return nullptr;
}
Expand All @@ -526,10 +528,87 @@ void test_gh_3014() { // COMPILE-ONLY
}
};

auto r = InRange{} | views::join;
auto r = FwdRange{} | views::join;
[[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator<!Const> i)'
}

constexpr bool test_lwg3698() {
// LWG-3698 "regex_iterator and join_view don't work together very well"
struct stashing_iterator {
using difference_type = int;
using value_type = span<const int>;

int x = 1;

constexpr stashing_iterator& operator++() {
++x;
return *this;
}
constexpr void operator++(int) {
++x;
}
constexpr value_type operator*() const {
return {&x, &x + 1};
}
constexpr bool operator==(default_sentinel_t) const {
return x > 3;
}
};

auto r = ranges::subrange{stashing_iterator{}, default_sentinel} | views::join;
auto r2 = r;
auto it = r.begin();
auto it2 = r2.begin();

auto itcopy = it;
it = ++it2;
assert(*itcopy == 1);

struct intricate_range {
constexpr stashing_iterator begin() {
return {};
}
constexpr default_sentinel_t end() {
return {};
}
constexpr const span<const int>* begin() const {
return ranges::begin(intervals);
}
constexpr const span<const int>* end() const {
return ranges::end(intervals);
}
};

auto jv = intricate_range{} | views::join;
auto cit = as_const(jv).begin();
assert(*++cit == 1);
assert(*--cit == 0);
assert(ranges::equal(as_const(jv), expected_ints));

return true;
}

void test_lwg3700() { // COMPILE-ONLY
// LWG-3700 "The const begin of the join_view family does not require InnerRng to be a range"
auto r = views::iota(0, 5) | views::filter([](auto) { return true; });
auto j = views::single(r) | views::join;
using J = decltype(j);
STATIC_ASSERT(!CanMemberBegin<const J>);
STATIC_ASSERT(!CanMemberEnd<const J>);
}

constexpr bool test_lwg3791() {
// LWG-3791 "join_view::iterator::operator-- may be ill-formed"
// Validate that join_view<V> works when range_reference_t<V> is an rvalue reference
using inner = test::range<bidirectional_iterator_tag, const int>;
using outer = test::range<bidirectional_iterator_tag, inner, test::Sized::no, test::CanDifference::no,
test::Common::yes, test::CanCompare::yes, test::ProxyRef::xvalue, test::CanView::yes>;

instantiator::call<inner, outer>();

return true;
}

int main() {
// Validate views
constexpr string_view expected = "Hello World!"sv;
Expand Down Expand Up @@ -622,4 +701,10 @@ int main() {

STATIC_ASSERT(instantiation_test());
instantiation_test();

STATIC_ASSERT(test_lwg3698());
assert(test_lwg3698());

STATIC_ASSERT(test_lwg3791());
assert(test_lwg3791());
}
4 changes: 2 additions & 2 deletions tests/std/tests/P0896R4_views_transform/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@ void test_gh_1709() {

// GH-3014 "<ranges>: list-initialization is misused"
void test_gh_3014() { // COMPILE-ONLY
struct InRange {
struct FwdRange {
int* begin() {
return nullptr;
}
Expand All @@ -827,7 +827,7 @@ void test_gh_3014() { // COMPILE-ONLY
}
};

auto r = InRange{} | views::transform(identity{});
auto r = FwdRange{} | views::transform(identity{});
[[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator<!Const> i)'
}

Expand Down
Loading