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 auto begin() requires (!(simple-view<Views> && ...)); |
12 | // constexpr auto begin() const requires (range<const Views> && ...); |
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 HasBegin = requires(T& t) { t.begin(); }; |
28 | |
29 | template <class T> |
30 | concept HasConstAndNonConstBegin = |
31 | HasConstBegin<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 = HasBegin<T> && ! |
36 | HasConstBegin<T>; |
37 | |
38 | template <class T> |
39 | concept HasOnlyConstBegin = HasConstBegin<T> && ! |
40 | HasConstAndNonConstBegin<T>; |
41 | |
42 | struct NoConstBeginView : std::ranges::view_base { |
43 | int* begin(); |
44 | int* end(); |
45 | }; |
46 | |
47 | constexpr bool test() { |
48 | int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; |
49 | { |
50 | // all underlying iterators should be at the begin position |
51 | std::ranges::zip_view v(SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.)); |
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 | |
57 | { |
58 | // with empty range |
59 | std::ranges::zip_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view<int>()); |
60 | assert(v.begin() == v.end()); |
61 | } |
62 | |
63 | { |
64 | // underlying ranges all model simple-view |
65 | std::ranges::zip_view v(SimpleCommon{buffer}, SimpleCommon{buffer}); |
66 | static_assert(std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>); |
67 | assert(v.begin() == std::as_const(v).begin()); |
68 | auto [x, y] = *std::as_const(v).begin(); |
69 | assert(&x == &buffer[0]); |
70 | assert(&y == &buffer[0]); |
71 | |
72 | using View = decltype(v); |
73 | static_assert(HasOnlyConstBegin<View>); |
74 | static_assert(!HasOnlyNonConstBegin<View>); |
75 | static_assert(!HasConstAndNonConstBegin<View>); |
76 | } |
77 | |
78 | { |
79 | // not all underlying ranges model simple-view |
80 | std::ranges::zip_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer}); |
81 | static_assert(!std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>); |
82 | assert(v.begin() == std::as_const(v).begin()); |
83 | auto [x, y] = *std::as_const(v).begin(); |
84 | assert(&x == &buffer[0]); |
85 | assert(&y == &buffer[0]); |
86 | |
87 | using View = decltype(v); |
88 | static_assert(!HasOnlyConstBegin<View>); |
89 | static_assert(!HasOnlyNonConstBegin<View>); |
90 | static_assert(HasConstAndNonConstBegin<View>); |
91 | } |
92 | |
93 | { |
94 | // underlying const R is not a range |
95 | using View = std::ranges::zip_view<SimpleCommon, NoConstBeginView>; |
96 | static_assert(!HasOnlyConstBegin<View>); |
97 | static_assert(HasOnlyNonConstBegin<View>); |
98 | static_assert(!HasConstAndNonConstBegin<View>); |
99 | } |
100 | return true; |
101 | } |
102 | |
103 | int main(int, char**) { |
104 | test(); |
105 | static_assert(test()); |
106 | |
107 | return 0; |
108 | } |
109 | |