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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11
12 // std::views::all;
13
14 #include <ranges>
15
16 #include <cassert>
17 #include <concepts>
18 #include <type_traits>
19 #include <utility>
20
21 #include "test_macros.h"
22 #include "test_iterators.h"
23
24 int globalBuff[8];
25
26 template<bool IsNoexcept>
27 struct View : std::ranges::view_base {
28 int start_ = 0;
29 explicit View() noexcept(IsNoexcept) = default;
ViewView30 constexpr explicit View(int start) : start_(start) {}
31 View(View&&) noexcept(IsNoexcept) = default;
32 View& operator=(View&&) noexcept(IsNoexcept) = default;
beginView33 constexpr int* begin() const { return globalBuff + start_; }
endView34 constexpr int* end() const { return globalBuff + 8; }
35 };
36 static_assert(std::ranges::view<View<true>>);
37 static_assert(std::ranges::view<View<false>>);
38
39 template<bool IsNoexcept>
40 struct CopyableView : std::ranges::view_base {
41 int start_ = 0;
42 explicit CopyableView() noexcept(IsNoexcept) = default;
43 CopyableView(CopyableView const&) noexcept(IsNoexcept) = default;
44 CopyableView& operator=(CopyableView const&) noexcept(IsNoexcept) = default;
CopyableViewCopyableView45 constexpr explicit CopyableView(int start) noexcept : start_(start) {}
beginCopyableView46 constexpr int* begin() const { return globalBuff + start_; }
endCopyableView47 constexpr int* end() const { return globalBuff + 8; }
48 };
49 static_assert(std::ranges::view<CopyableView<true>>);
50 static_assert(std::ranges::view<CopyableView<false>>);
51
52 struct MoveOnlyView : std::ranges::view_base{
53 MoveOnlyView() = default;
54 MoveOnlyView(const MoveOnlyView&) = delete;
55 MoveOnlyView& operator=(const MoveOnlyView&) = delete;
56 MoveOnlyView(MoveOnlyView&&) = default;
57 MoveOnlyView& operator=(MoveOnlyView&&) = default;
58
59 int* begin() const;
60 int* end() const;
61 };
62
63 struct Range {
64 int start_;
RangeRange65 constexpr explicit Range(int start) noexcept : start_(start) {}
beginRange66 constexpr int* begin() const { return globalBuff + start_; }
endRange67 constexpr int* end() const { return globalBuff + 8; }
68 };
69
70 struct BorrowableRange {
71 int start_;
BorrowableRangeBorrowableRange72 constexpr explicit BorrowableRange(int start) noexcept : start_(start) {}
beginBorrowableRange73 constexpr int* begin() const { return globalBuff + start_; }
endBorrowableRange74 constexpr int* end() const { return globalBuff + 8; }
75 };
76 template<>
77 inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
78
79 struct RandomAccessRange {
beginRandomAccessRange80 constexpr auto begin() { return random_access_iterator<int*>(globalBuff); }
endRandomAccessRange81 constexpr auto end() { return sized_sentinel(random_access_iterator<int*>(globalBuff + 8)); }
82 };
83 template<>
84 inline constexpr bool std::ranges::enable_borrowed_range<RandomAccessRange> = true;
85
86 template <class View, class T>
87 concept CanBePiped = requires (View&& view, T&& t) {
88 { std::forward<View>(view) | std::forward<T>(t) };
89 };
90
test()91 constexpr bool test() {
92 {
93 ASSERT_SAME_TYPE(decltype(std::views::all(View<true>())), View<true>);
94 static_assert(noexcept(std::views::all(View<true>())));
95 static_assert(!noexcept(std::views::all(View<false>())));
96
97 auto viewCopy = std::views::all(View<true>(2));
98 ASSERT_SAME_TYPE(decltype(viewCopy), View<true>);
99 assert(std::ranges::begin(viewCopy) == globalBuff + 2);
100 assert(std::ranges::end(viewCopy) == globalBuff + 8);
101 }
102
103 {
104 ASSERT_SAME_TYPE(decltype(std::views::all(std::declval<const CopyableView<true>&>())), CopyableView<true>);
105 static_assert(noexcept(std::views::all(CopyableView<true>())));
106 static_assert(!noexcept(std::views::all(CopyableView<false>())));
107
108 CopyableView<true> view(2);
109 auto viewCopy = std::views::all(view);
110 ASSERT_SAME_TYPE(decltype(viewCopy), CopyableView<true>);
111 assert(std::ranges::begin(viewCopy) == globalBuff + 2);
112 assert(std::ranges::end(viewCopy) == globalBuff + 8);
113 }
114
115 {
116 Range range(2);
117 auto ref = std::views::all(range);
118 ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<Range>);
119 assert(std::ranges::begin(ref) == globalBuff + 2);
120 assert(std::ranges::end(ref) == globalBuff + 8);
121
122 auto own = std::views::all(std::move(range));
123 ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<Range>);
124 assert(std::ranges::begin(own) == globalBuff + 2);
125 assert(std::ranges::end(own) == globalBuff + 8);
126
127 auto cref = std::views::all(std::as_const(range));
128 ASSERT_SAME_TYPE(decltype(cref), std::ranges::ref_view<const Range>);
129 assert(std::ranges::begin(cref) == globalBuff + 2);
130 assert(std::ranges::end(cref) == globalBuff + 8);
131
132 static_assert(!std::is_invocable_v<decltype(std::views::all), const Range&&>);
133 }
134
135 {
136 auto own = std::views::all(BorrowableRange(2));
137 ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<BorrowableRange>);
138 assert(std::ranges::begin(own) == globalBuff + 2);
139 assert(std::ranges::end(own) == globalBuff + 8);
140 }
141
142 {
143 auto own = std::views::all(RandomAccessRange());
144 ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<RandomAccessRange>);
145 assert(base(std::ranges::begin(own)) == globalBuff);
146 assert(base(base(std::ranges::end(own))) == globalBuff + 8);
147 }
148
149 // Check SFINAE friendliness of the call operator
150 {
151 static_assert(!std::is_invocable_v<decltype(std::views::all)>);
152 static_assert(!std::is_invocable_v<decltype(std::views::all), RandomAccessRange, RandomAccessRange>);
153
154 // `views::all(v)` is expression equivalent to `decay-copy(v)` if the decayed type
155 // of `v` models `view`. If `v` is an lvalue-reference to a move-only view, the
156 // expression should be ill-formed because `v` is not copyable
157 static_assert(!std::is_invocable_v<decltype(std::views::all), MoveOnlyView&>);
158 }
159
160 // Test that std::views::all is a range adaptor
161 {
162 // Test `v | views::all`
163 {
164 Range range(0);
165 auto result = range | std::views::all;
166 ASSERT_SAME_TYPE(decltype(result), std::ranges::ref_view<Range>);
167 assert(&result.base() == &range);
168 }
169
170 // Test `adaptor | views::all`
171 {
172 Range range(0);
173 auto f = [](int i) { return i; };
174 auto const partial = std::views::transform(f) | std::views::all;
175 using Result = std::ranges::transform_view<std::ranges::ref_view<Range>, decltype(f)>;
176 std::same_as<Result> auto result = partial(range);
177 assert(&result.base().base() == &range);
178 }
179
180 // Test `views::all | adaptor`
181 {
182 Range range(0);
183 auto f = [](int i) { return i; };
184 auto const partial = std::views::all | std::views::transform(f);
185 using Result = std::ranges::transform_view<std::ranges::ref_view<Range>, decltype(f)>;
186 std::same_as<Result> auto result = partial(range);
187 assert(&result.base().base() == &range);
188 }
189
190 {
191 struct NotAView { };
192 static_assert( CanBePiped<Range&, decltype(std::views::all)>);
193 static_assert(!CanBePiped<NotAView, decltype(std::views::all)>);
194 }
195 }
196
197 {
198 static_assert(std::same_as<decltype(std::views::all), decltype(std::ranges::views::all)>);
199 }
200
201 return true;
202 }
203
main(int,char **)204 int main(int, char**) {
205 test();
206 static_assert(test());
207
208 return 0;
209 }
210