Skip to content

Commit ea66101

Browse files
committed
test view::begin() WIP
1 parent e07cd58 commit ea66101

File tree

4 files changed

+571
-8
lines changed

4 files changed

+571
-8
lines changed

libcxx/include/__ranges/cartesian_product_view.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,24 +132,27 @@ class cartesian_product_view : public view_interface<cartesian_product_view<Firs
132132
constexpr iterator<is_const> end_impl() const {
133133
bool is_empty = end_is_empty();
134134
const auto ranges_to_iterators = [is_empty, &b = bases_]<std::size_t... I>(std::index_sequence<I...>) {
135-
const auto begin_or_first_end = [is_empty]<bool is_first>(const auto& rng) {
136-
if constexpr (is_first)
135+
const auto begin_or_first_end = [is_empty]<class is_first>(is_first, const auto& rng) {
136+
if constexpr (is_first::value)
137137
return is_empty ? ranges::begin(rng) : cartesian_common_arg_end(rng);
138138
return ranges::begin(rng);
139139
};
140-
return std::make_tuple(begin_or_first_end<I == 0>(std::get<I>(b))...);
140+
141+
return std::make_tuple(begin_or_first_end(std::bool_constant<I == 0>{}, std::get<I>(b))...);
141142
};
142143
iterator<is_const> it(*this, ranges_to_iterators(std::make_index_sequence<1 + sizeof...(Vs)>{}));
143144
return it;
144145
}
145146

146-
template <auto N = 1>
147+
template <std::size_t N = 1>
147148
constexpr bool end_is_empty() const {
148149
if constexpr (N == 1 + sizeof...(Vs))
149150
return false;
150-
if (const auto& v = std::get<N>(bases_); ranges::empty(v))
151-
return true;
152-
return end_is_empty<N + 1>();
151+
else {
152+
if (const auto& v = std::get<N>(bases_); ranges::empty(v))
153+
return true;
154+
return end_is_empty<N + 1>();
155+
}
153156
}
154157

155158
constexpr auto size_impl() const {
@@ -180,6 +183,8 @@ class cartesian_product_view<First, Vs...>::iterator {
180183
return input_iterator_tag{};
181184
}
182185

186+
friend cartesian_product_view;
187+
183188
public:
184189
using iterator_category = input_iterator_tag;
185190
using iterator_concept = decltype(get_iterator_tag());
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10+
11+
// constexpr iterator<false> begin() requires (!simple-view<First> || ... || !simple-view <Vs>);
12+
// constexpr iterator<true > begin() const requires (range<const First> && ... && range<const Vs>);
13+
14+
#include <ranges>
15+
16+
// #include <cassert>
17+
// #include <concepts>
18+
// #include <tuple>
19+
// #include <utility>
20+
21+
#include "types.h"
22+
23+
template <class T>
24+
concept HasConstBegin = requires(const T& ct) { ct.begin(); };
25+
26+
template <class T>
27+
concept HasNonConstBegin = requires(T& t) { t.begin(); };
28+
29+
template <class T>
30+
concept HasConstAndNonConstBegin =
31+
HasConstBegin<T> && HasNonConstBegin<T> &&
32+
requires(T& t, const T& ct) { requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>; };
33+
34+
template <class T>
35+
concept HasOnlyNonConstBegin = HasNonConstBegin<T> && !HasConstBegin<T>;
36+
37+
template <class T>
38+
concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
39+
40+
struct OnlyNonConstBeginView : std::ranges::view_base {
41+
int* begin();
42+
int* end();
43+
};
44+
45+
constexpr bool test() {
46+
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
47+
48+
{ // all underlying iterators should be at the begin position
49+
{ // non-const
50+
std::ranges::cartesian_product_view v(
51+
SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.0));
52+
std::same_as<std::tuple<int&, int, double&>> decltype(auto) val = *v.begin();
53+
assert(val == std::make_tuple(1, 0, 2.0));
54+
assert(&(std::get<0>(val)) == &buffer[0]);
55+
}
56+
{ // const
57+
const std::ranges::cartesian_product_view v(
58+
SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.0));
59+
std::same_as<std::tuple<int&, int, const double&>> decltype(auto) val = *v.begin();
60+
assert(val == std::make_tuple(1, 0, 2.0));
61+
assert(&(std::get<0>(val)) == &buffer[0]);
62+
}
63+
}
64+
65+
{ // with empty range
66+
{ // non-const
67+
std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view<int>());
68+
assert(v.begin() == v.end());
69+
}
70+
{ // const
71+
const std::ranges::cartesian_product_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view<int>());
72+
assert(v.begin() == v.end());
73+
}
74+
}
75+
76+
{
77+
// underlying ranges all model simple-view
78+
std::ranges::cartesian_product_view v(SimpleCommon{buffer}, SimpleCommon{buffer});
79+
static_assert(std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>);
80+
assert(v.begin() == std::as_const(v).begin());
81+
auto [x, y] = *std::as_const(v).begin();
82+
assert(&x == &buffer[0]);
83+
assert(&y == &buffer[0]);
84+
85+
using View = decltype(v);
86+
static_assert(std::ranges::__simple_view<SimpleCommon>);
87+
static_assert(HasOnlyConstBegin<View>);
88+
static_assert(!HasOnlyNonConstBegin<View>);
89+
static_assert(!HasConstAndNonConstBegin<View>);
90+
}
91+
92+
// {
93+
// // not all underlying ranges model simple-view
94+
// std::ranges::zip_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer});
95+
// static_assert(!std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>);
96+
// assert(v.begin() == std::as_const(v).begin());
97+
// auto [x, y] = *std::as_const(v).begin();
98+
// assert(&x == &buffer[0]);
99+
// assert(&y == &buffer[0]);
100+
101+
// using View = decltype(v);
102+
// static_assert(!HasOnlyConstBegin<View>);
103+
// static_assert(!HasOnlyNonConstBegin<View>);
104+
// static_assert(HasConstAndNonConstBegin<View>);
105+
// }
106+
107+
// {
108+
// // underlying const R is not a range
109+
// using View = std::ranges::zip_view<SimpleCommon, NoConstBeginView>;
110+
// static_assert(!HasOnlyConstBegin<View>);
111+
// static_assert(HasOnlyNonConstBegin<View>);
112+
// static_assert(!HasConstAndNonConstBegin<View>);
113+
// }
114+
return true;
115+
}
116+
117+
int main() {
118+
test();
119+
static_assert(test());
120+
}

0 commit comments

Comments
 (0)