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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11 
12 // constexpr auto begin() requires (!(simple-view<Views> && ...));
13 // constexpr auto begin() const requires (range<const Views> && ...);
14 
15 #include <ranges>
16 
17 #include <cassert>
18 #include <concepts>
19 #include <tuple>
20 #include <utility>
21 
22 #include "types.h"
23 
24 template <class T>
25 concept HasConstBegin = requires(const T& ct) { ct.begin(); };
26 
27 template <class T>
28 concept HasBegin = requires(T& t) { t.begin(); };
29 
30 template <class T>
31 concept HasConstAndNonConstBegin =
32     HasConstBegin<T> &&
33     requires(T& t, const T& ct) { requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>; };
34 
35 template <class T>
36 concept HasOnlyNonConstBegin = HasBegin<T> && !
37 HasConstBegin<T>;
38 
39 template <class T>
40 concept HasOnlyConstBegin = HasConstBegin<T> && !
41 HasConstAndNonConstBegin<T>;
42 
43 struct NoConstBeginView : std::ranges::view_base {
44   int* begin();
45   int* end();
46 };
47 
test()48 constexpr bool test() {
49   int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
50   {
51     // all underlying iterators should be at the begin position
52     std::ranges::zip_view v(SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.));
53     std::same_as<std::tuple<int&, int, double&>> decltype(auto) val = *v.begin();
54     assert(val == std::make_tuple(1, 0, 2.0));
55     assert(&(std::get<0>(val)) == &buffer[0]);
56   }
57 
58   {
59     // with empty range
60     std::ranges::zip_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view<int>());
61     assert(v.begin() == v.end());
62   }
63 
64   {
65     // underlying ranges all model simple-view
66     std::ranges::zip_view v(SimpleCommon{buffer}, SimpleCommon{buffer});
67     static_assert(std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>);
68     assert(v.begin() == std::as_const(v).begin());
69     auto [x, y] = *std::as_const(v).begin();
70     assert(&x == &buffer[0]);
71     assert(&y == &buffer[0]);
72 
73     using View = decltype(v);
74     static_assert(HasOnlyConstBegin<View>);
75     static_assert(!HasOnlyNonConstBegin<View>);
76     static_assert(!HasConstAndNonConstBegin<View>);
77   }
78 
79   {
80     // not all underlying ranges model simple-view
81     std::ranges::zip_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer});
82     static_assert(!std::is_same_v<decltype(v.begin()), decltype(std::as_const(v).begin())>);
83     assert(v.begin() == std::as_const(v).begin());
84     auto [x, y] = *std::as_const(v).begin();
85     assert(&x == &buffer[0]);
86     assert(&y == &buffer[0]);
87 
88     using View = decltype(v);
89     static_assert(!HasOnlyConstBegin<View>);
90     static_assert(!HasOnlyNonConstBegin<View>);
91     static_assert(HasConstAndNonConstBegin<View>);
92   }
93 
94   {
95     // underlying const R is not a range
96     using View = std::ranges::zip_view<SimpleCommon, NoConstBeginView>;
97     static_assert(!HasOnlyConstBegin<View>);
98     static_assert(HasOnlyNonConstBegin<View>);
99     static_assert(!HasConstAndNonConstBegin<View>);
100   }
101   return true;
102 }
103 
main(int,char **)104 int main(int, char**) {
105   test();
106   static_assert(test());
107 
108   return 0;
109 }
110