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-no-concepts
11 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
12 
13 // std::views::all;
14 
15 #include <ranges>
16 
17 #include <cassert>
18 #include <concepts>
19 #include <type_traits>
20 #include <utility>
21 
22 #include "test_macros.h"
23 #include "test_iterators.h"
24 
25 int globalBuff[8];
26 
27 template<bool IsNoexcept>
28 struct View : std::ranges::view_base {
29   int start_ = 0;
30   explicit View() noexcept(IsNoexcept) = default;
31   constexpr explicit View(int start) : start_(start) {}
32   View(View&&) noexcept(IsNoexcept) = default;
33   View& operator=(View&&) noexcept(IsNoexcept) = default;
34   friend constexpr int* begin(View& view) { return globalBuff + view.start_; }
35   friend constexpr int* begin(View const& view) { return globalBuff + view.start_; }
36   friend constexpr int* end(View&) { return globalBuff + 8; }
37   friend constexpr int* end(View const&) { return globalBuff + 8; }
38 };
39 static_assert(std::ranges::view<View<true>>);
40 static_assert(std::ranges::view<View<false>>);
41 
42 template<bool IsNoexcept>
43 struct CopyableView : std::ranges::view_base {
44   int start_ = 0;
45   explicit CopyableView() noexcept(IsNoexcept) = default;
46   CopyableView(CopyableView const&) noexcept(IsNoexcept) = default;
47   CopyableView& operator=(CopyableView const&) noexcept(IsNoexcept) = default;
48   constexpr explicit CopyableView(int start) noexcept : start_(start) {}
49   friend constexpr int* begin(CopyableView& view) { return globalBuff + view.start_; }
50   friend constexpr int* begin(CopyableView const& view) { return globalBuff + view.start_; }
51   friend constexpr int* end(CopyableView&) { return globalBuff + 8; }
52   friend constexpr int* end(CopyableView const&) { return globalBuff + 8; }
53 };
54 static_assert(std::ranges::view<CopyableView<true>>);
55 static_assert(std::ranges::view<CopyableView<false>>);
56 
57 struct Range {
58   int start_;
59   constexpr explicit Range(int start) noexcept : start_(start) {}
60   friend constexpr int* begin(Range const& range) { return globalBuff + range.start_; }
61   friend constexpr int* begin(Range& range) { return globalBuff + range.start_; }
62   friend constexpr int* end(Range const&) { return globalBuff + 8; }
63   friend constexpr int* end(Range&) { return globalBuff + 8; }
64 };
65 
66 struct BorrowableRange {
67   int start_;
68   constexpr explicit BorrowableRange(int start) noexcept : start_(start) {}
69   friend constexpr int* begin(BorrowableRange const& range) { return globalBuff + range.start_; }
70   friend constexpr int* begin(BorrowableRange& range) { return globalBuff + range.start_; }
71   friend constexpr int* end(BorrowableRange const&) { return globalBuff + 8; }
72   friend constexpr int* end(BorrowableRange&) { return globalBuff + 8; }
73 };
74 template<>
75 inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
76 
77 struct RandomAccessRange {
78   struct sentinel {
79     friend constexpr bool operator==(sentinel, const random_access_iterator<int*> rai) { return rai.base() == globalBuff + 8; }
80     friend constexpr std::ptrdiff_t operator-(sentinel, random_access_iterator<int*>) { return -8; }
81     friend constexpr std::ptrdiff_t operator-(random_access_iterator<int*>, sentinel) { return 8; }
82   };
83 
84   constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{globalBuff}; }
85   constexpr sentinel end() { return {}; }
86 };
87 template<>
88 inline constexpr bool std::ranges::enable_borrowed_range<RandomAccessRange> = true;
89 
90 template <class View, class T>
91 concept CanBePiped = requires (View&& view, T&& t) {
92   { std::forward<View>(view) | std::forward<T>(t) };
93 };
94 
95 constexpr bool test() {
96   {
97     ASSERT_SAME_TYPE(decltype(std::views::all(View<true>())), View<true>);
98     static_assert(noexcept(std::views::all(View<true>())));
99     static_assert(!noexcept(std::views::all(View<false>())));
100 
101     auto viewCopy = std::views::all(View<true>(2));
102     ASSERT_SAME_TYPE(decltype(viewCopy), View<true>);
103     assert(std::ranges::begin(viewCopy) == globalBuff + 2);
104     assert(std::ranges::end(viewCopy) == globalBuff + 8);
105   }
106 
107   {
108     ASSERT_SAME_TYPE(decltype(std::views::all(std::declval<const CopyableView<true>&>())), CopyableView<true>);
109     static_assert(noexcept(std::views::all(CopyableView<true>())));
110     static_assert(!noexcept(std::views::all(CopyableView<false>())));
111 
112     CopyableView<true> view(2);
113     auto viewCopy = std::views::all(view);
114     ASSERT_SAME_TYPE(decltype(viewCopy), CopyableView<true>);
115     assert(std::ranges::begin(viewCopy) == globalBuff + 2);
116     assert(std::ranges::end(viewCopy) == globalBuff + 8);
117   }
118 
119   {
120     Range range(2);
121     auto ref = std::views::all(range);
122     ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<Range>);
123     assert(std::ranges::begin(ref) == globalBuff + 2);
124     assert(std::ranges::end(ref) == globalBuff + 8);
125 
126     static_assert(!std::is_invocable_v<decltype(std::views::all), Range>);
127   }
128 
129   {
130     const Range range(2);
131     auto ref = std::views::all(range);
132     static_assert(!noexcept(std::views::all(range)));
133     ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<const Range>);
134     assert(std::ranges::begin(ref) == globalBuff + 2);
135     assert(std::ranges::end(ref) == globalBuff + 8);
136   }
137 
138   {
139     auto subrange = std::views::all(BorrowableRange(2));
140     static_assert(!noexcept(std::views::all(BorrowableRange(2))));
141     ASSERT_SAME_TYPE(decltype(subrange), std::ranges::subrange<int*>);
142     assert(std::ranges::begin(subrange) == globalBuff + 2);
143     assert(std::ranges::end(subrange) == globalBuff + 8);
144   }
145 
146   {
147     auto subrange = std::views::all(RandomAccessRange());
148     ASSERT_SAME_TYPE(decltype(subrange),
149                      std::ranges::subrange<random_access_iterator<int*>, RandomAccessRange::sentinel>);
150     assert(std::ranges::begin(subrange).base() == globalBuff);
151     assert(std::ranges::end(subrange) == std::ranges::begin(subrange) + 8);
152   }
153 
154   // Check SFINAE friendliness of the call operator
155   {
156     static_assert(!std::is_invocable_v<decltype(std::views::all)>);
157     static_assert(!std::is_invocable_v<decltype(std::views::all), RandomAccessRange, RandomAccessRange>);
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 
204 int main(int, char**) {
205   test();
206   static_assert(test());
207 
208   return 0;
209 }
210