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