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   constexpr int* begin() const { return globalBuff + start_; }
35   constexpr int* end() const { return globalBuff + 8; }
36 };
37 static_assert(std::ranges::view<View<true>>);
38 static_assert(std::ranges::view<View<false>>);
39 
40 template<bool IsNoexcept>
41 struct CopyableView : std::ranges::view_base {
42   int start_ = 0;
43   explicit CopyableView() noexcept(IsNoexcept) = default;
44   CopyableView(CopyableView const&) noexcept(IsNoexcept) = default;
45   CopyableView& operator=(CopyableView const&) noexcept(IsNoexcept) = default;
46   constexpr explicit CopyableView(int start) noexcept : start_(start) {}
47   constexpr int* begin() const { return globalBuff + start_; }
48   constexpr int* end() const { return globalBuff + 8; }
49 };
50 static_assert(std::ranges::view<CopyableView<true>>);
51 static_assert(std::ranges::view<CopyableView<false>>);
52 
53 struct Range {
54   int start_;
55   constexpr explicit Range(int start) noexcept : start_(start) {}
56   constexpr int* begin() const { return globalBuff + start_; }
57   constexpr int* end() const { return globalBuff + 8; }
58 };
59 
60 struct BorrowableRange {
61   int start_;
62   constexpr explicit BorrowableRange(int start) noexcept : start_(start) {}
63   constexpr int* begin() const { return globalBuff + start_; }
64   constexpr int* end() const { return globalBuff + 8; }
65 };
66 template<>
67 inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
68 
69 struct RandomAccessRange {
70   constexpr auto begin() { return random_access_iterator<int*>(globalBuff); }
71   constexpr auto end() { return sized_sentinel(random_access_iterator<int*>(globalBuff + 8)); }
72 };
73 template<>
74 inline constexpr bool std::ranges::enable_borrowed_range<RandomAccessRange> = true;
75 
76 template <class View, class T>
77 concept CanBePiped = requires (View&& view, T&& t) {
78   { std::forward<View>(view) | std::forward<T>(t) };
79 };
80 
81 constexpr bool test() {
82   {
83     ASSERT_SAME_TYPE(decltype(std::views::all(View<true>())), View<true>);
84     static_assert(noexcept(std::views::all(View<true>())));
85     static_assert(!noexcept(std::views::all(View<false>())));
86 
87     auto viewCopy = std::views::all(View<true>(2));
88     ASSERT_SAME_TYPE(decltype(viewCopy), View<true>);
89     assert(std::ranges::begin(viewCopy) == globalBuff + 2);
90     assert(std::ranges::end(viewCopy) == globalBuff + 8);
91   }
92 
93   {
94     ASSERT_SAME_TYPE(decltype(std::views::all(std::declval<const CopyableView<true>&>())), CopyableView<true>);
95     static_assert(noexcept(std::views::all(CopyableView<true>())));
96     static_assert(!noexcept(std::views::all(CopyableView<false>())));
97 
98     CopyableView<true> view(2);
99     auto viewCopy = std::views::all(view);
100     ASSERT_SAME_TYPE(decltype(viewCopy), CopyableView<true>);
101     assert(std::ranges::begin(viewCopy) == globalBuff + 2);
102     assert(std::ranges::end(viewCopy) == globalBuff + 8);
103   }
104 
105   {
106     Range range(2);
107     auto ref = std::views::all(range);
108     ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<Range>);
109     assert(std::ranges::begin(ref) == globalBuff + 2);
110     assert(std::ranges::end(ref) == globalBuff + 8);
111 
112     auto own = std::views::all(std::move(range));
113     ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<Range>);
114     assert(std::ranges::begin(own) == globalBuff + 2);
115     assert(std::ranges::end(own) == globalBuff + 8);
116 
117     auto cref = std::views::all(std::as_const(range));
118     ASSERT_SAME_TYPE(decltype(cref), std::ranges::ref_view<const Range>);
119     assert(std::ranges::begin(cref) == globalBuff + 2);
120     assert(std::ranges::end(cref) == globalBuff + 8);
121 
122     static_assert(!std::is_invocable_v<decltype(std::views::all), const Range&&>);
123   }
124 
125   {
126     auto own = std::views::all(BorrowableRange(2));
127     ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<BorrowableRange>);
128     assert(std::ranges::begin(own) == globalBuff + 2);
129     assert(std::ranges::end(own) == globalBuff + 8);
130   }
131 
132   {
133     auto own = std::views::all(RandomAccessRange());
134     ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<RandomAccessRange>);
135     assert(base(std::ranges::begin(own)) == globalBuff);
136     assert(base(base(std::ranges::end(own))) == globalBuff + 8);
137   }
138 
139   // Check SFINAE friendliness of the call operator
140   {
141     static_assert(!std::is_invocable_v<decltype(std::views::all)>);
142     static_assert(!std::is_invocable_v<decltype(std::views::all), RandomAccessRange, RandomAccessRange>);
143   }
144 
145   // Test that std::views::all is a range adaptor
146   {
147     // Test `v | views::all`
148     {
149       Range range(0);
150       auto result = range | std::views::all;
151       ASSERT_SAME_TYPE(decltype(result), std::ranges::ref_view<Range>);
152       assert(&result.base() == &range);
153     }
154 
155     // Test `adaptor | views::all`
156     {
157       Range range(0);
158       auto f = [](int i) { return i; };
159       auto const partial = std::views::transform(f) | std::views::all;
160       using Result = std::ranges::transform_view<std::ranges::ref_view<Range>, decltype(f)>;
161       std::same_as<Result> auto result = partial(range);
162       assert(&result.base().base() == &range);
163     }
164 
165     // Test `views::all | adaptor`
166     {
167       Range range(0);
168       auto f = [](int i) { return i; };
169       auto const partial = std::views::all | std::views::transform(f);
170       using Result = std::ranges::transform_view<std::ranges::ref_view<Range>, decltype(f)>;
171       std::same_as<Result> auto result = partial(range);
172       assert(&result.base().base() == &range);
173     }
174 
175     {
176       struct NotAView { };
177       static_assert( CanBePiped<Range&,    decltype(std::views::all)>);
178       static_assert(!CanBePiped<NotAView,  decltype(std::views::all)>);
179     }
180   }
181 
182   {
183     static_assert(std::same_as<decltype(std::views::all), decltype(std::ranges::views::all)>);
184   }
185 
186   return true;
187 }
188 
189 int main(int, char**) {
190   test();
191   static_assert(test());
192 
193   return 0;
194 }
195