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 |
10 | |
11 | |
12 | // constexpr iterator_t<R> begin(); |
13 | // constexpr sentinel_t<R> end(); |
14 | // constexpr auto begin() const requires range<const R>; |
15 | // constexpr auto end() const requires range<const R>; |
16 | |
17 | #include <ranges> |
18 | |
19 | #include <array> |
20 | #include <cassert> |
21 | #include <concepts> |
22 | |
23 | #include "test_iterators.h" |
24 | #include "test_macros.h" |
25 | |
26 | struct Base { |
27 | constexpr int *begin() { return nullptr; } |
28 | constexpr auto end() { return sentinel_wrapper<int*>(nullptr); } |
29 | constexpr char *begin() const { return nullptr; } |
30 | constexpr auto end() const { return sentinel_wrapper<char*>(nullptr); } |
31 | }; |
32 | static_assert(std::same_as<std::ranges::iterator_t<Base>, int*>); |
33 | static_assert(std::same_as<std::ranges::sentinel_t<Base>, sentinel_wrapper<int*>>); |
34 | static_assert(std::same_as<std::ranges::iterator_t<const Base>, char*>); |
35 | static_assert(std::same_as<std::ranges::sentinel_t<const Base>, sentinel_wrapper<char*>>); |
36 | |
37 | struct NoConst { |
38 | int* begin(); |
39 | sentinel_wrapper<int*> end(); |
40 | }; |
41 | |
42 | struct DecayChecker { |
43 | int*& begin() const; |
44 | int*& end() const; |
45 | }; |
46 | |
47 | template <class T> |
48 | concept HasBegin = requires (T t) { |
49 | t.begin(); |
50 | }; |
51 | |
52 | template <class T> |
53 | concept HasEnd = requires (T t) { |
54 | t.end(); |
55 | }; |
56 | |
57 | constexpr bool test() |
58 | { |
59 | { |
60 | using OwningView = std::ranges::owning_view<Base>; |
61 | OwningView ov; |
62 | std::same_as<int*> decltype(auto) b1 = static_cast<OwningView&>(ov).begin(); |
63 | std::same_as<int*> decltype(auto) b2 = static_cast<OwningView&&>(ov).begin(); |
64 | std::same_as<char*> decltype(auto) b3 = static_cast<const OwningView&>(ov).begin(); |
65 | std::same_as<char*> decltype(auto) b4 = static_cast<const OwningView&&>(ov).begin(); |
66 | |
67 | std::same_as<sentinel_wrapper<int*>> decltype(auto) e1 = static_cast<OwningView&>(ov).end(); |
68 | std::same_as<sentinel_wrapper<int*>> decltype(auto) e2 = static_cast<OwningView&&>(ov).end(); |
69 | std::same_as<sentinel_wrapper<char*>> decltype(auto) e3 = static_cast<const OwningView&>(ov).end(); |
70 | std::same_as<sentinel_wrapper<char*>> decltype(auto) e4 = static_cast<const OwningView&&>(ov).end(); |
71 | |
72 | assert(b1 == e1); |
73 | assert(b2 == e2); |
74 | assert(b3 == e3); |
75 | assert(b4 == e4); |
76 | } |
77 | { |
78 | // NoConst has non-const begin() and end(); so does the owning_view. |
79 | using OwningView = std::ranges::owning_view<NoConst>; |
80 | static_assert(HasBegin<OwningView&>); |
81 | static_assert(HasBegin<OwningView&&>); |
82 | static_assert(!HasBegin<const OwningView&>); |
83 | static_assert(!HasBegin<const OwningView&&>); |
84 | static_assert(HasEnd<OwningView&>); |
85 | static_assert(HasEnd<OwningView&&>); |
86 | static_assert(!HasEnd<const OwningView&>); |
87 | static_assert(!HasEnd<const OwningView&&>); |
88 | } |
89 | { |
90 | // DecayChecker's begin() and end() return references; make sure the owning_view decays them. |
91 | using OwningView = std::ranges::owning_view<DecayChecker>; |
92 | OwningView ov; |
93 | ASSERT_SAME_TYPE(decltype(ov.begin()), int*); |
94 | ASSERT_SAME_TYPE(decltype(ov.end()), int*); |
95 | } |
96 | { |
97 | // Test an empty view. |
98 | int a[] = {1}; |
99 | auto ov = std::ranges::owning_view(std::ranges::subrange(a, a)); |
100 | assert(ov.begin() == a); |
101 | assert(std::as_const(ov).begin() == a); |
102 | assert(ov.end() == a); |
103 | assert(std::as_const(ov).end() == a); |
104 | } |
105 | { |
106 | // Test a non-empty view. |
107 | int a[] = {1}; |
108 | auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1)); |
109 | assert(ov.begin() == a); |
110 | assert(std::as_const(ov).begin() == a); |
111 | assert(ov.end() == a+1); |
112 | assert(std::as_const(ov).end() == a+1); |
113 | } |
114 | { |
115 | // Test a non-view. |
116 | std::array<int, 2> a = {1, 2}; |
117 | auto ov = std::ranges::owning_view(std::move(a)); |
118 | assert(std::to_address(ov.begin()) != std::to_address(a.begin())); // because it points into the copy |
119 | assert(std::to_address(std::as_const(ov).begin()) != std::to_address(a.begin())); |
120 | assert(std::to_address(ov.end()) != std::to_address(a.end())); |
121 | assert(std::to_address(std::as_const(ov).end()) != std::to_address(a.end())); |
122 | } |
123 | return true; |
124 | } |
125 | |
126 | int main(int, char**) { |
127 | test(); |
128 | static_assert(test()); |
129 | |
130 | return 0; |
131 | } |
132 | |