xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp (revision ba2236d3000645d3127f972aa7ac1844c47e299c)
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 // std::views::take
12 
13 #include <ranges>
14 
15 #include <cassert>
16 #include <concepts>
17 #include <span>
18 #include <string_view>
19 #include <utility>
20 
21 #include "test_iterators.h"
22 #include "test_range.h"
23 
24 struct SizedView : std::ranges::view_base {
25   int* begin_ = nullptr;
26   int* end_ = nullptr;
SizedViewSizedView27   constexpr SizedView(int* begin, int* end) : begin_(begin), end_(end) {}
28 
beginSizedView29   constexpr auto begin() const { return forward_iterator<int*>(begin_); }
endSizedView30   constexpr auto end() const { return sized_sentinel<forward_iterator<int*>>(forward_iterator<int*>(end_)); }
31 };
32 static_assert(std::ranges::forward_range<SizedView>);
33 static_assert(std::ranges::sized_range<SizedView>);
34 static_assert(std::ranges::view<SizedView>);
35 
36 template <class T>
test_small_range(const T & input)37 constexpr void test_small_range(const T& input) {
38   constexpr int N = 100;
39   auto size = std::ranges::size(input);
40 
41   auto result = input | std::views::take(N);
42   assert(size < N);
43   assert(result.size() == size);
44 }
45 
test()46 constexpr bool test() {
47   constexpr int N = 8;
48   int buf[N] = {1, 2, 3, 4, 5, 6, 7, 8};
49 
50   // Test that `std::views::take` is a range adaptor.
51   {
52     using SomeView = SizedView;
53 
54     // Test `view | views::take`
55     {
56       SomeView view(buf, buf + N);
57       std::same_as<std::ranges::take_view<SomeView>> decltype(auto) result = view | std::views::take(3);
58       assert(result.base().begin_ == buf);
59       assert(result.base().end_ == buf + N);
60       assert(result.size() == 3);
61     }
62 
63     // Test `adaptor | views::take`
64     {
65       SomeView view(buf, buf + N);
66       auto f = [](int i) { return i; };
67       auto const partial = std::views::transform(f) | std::views::take(3);
68 
69       using Result = std::ranges::take_view<std::ranges::transform_view<SomeView, decltype(f)>>;
70       std::same_as<Result> decltype(auto) result = partial(view);
71       assert(result.base().base().begin_ == buf);
72       assert(result.base().base().end_ == buf + N);
73       assert(result.size() == 3);
74     }
75 
76     // Test `views::take | adaptor`
77     {
78       SomeView view(buf, buf + N);
79       auto f = [](int i) { return i; };
80       auto const partial = std::views::take(3) | std::views::transform(f);
81 
82       using Result = std::ranges::transform_view<std::ranges::take_view<SomeView>, decltype(f)>;
83       std::same_as<Result> decltype(auto) result = partial(view);
84       assert(result.base().base().begin_ == buf);
85       assert(result.base().base().end_ == buf + N);
86       assert(result.size() == 3);
87     }
88 
89     // Check SFINAE friendliness
90     {
91       struct NotAView { };
92       static_assert(!std::is_invocable_v<decltype(std::views::take)>);
93       static_assert(!std::is_invocable_v<decltype(std::views::take), NotAView, int>);
94       static_assert( CanBePiped<SomeView&,   decltype(std::views::take(3))>);
95       static_assert( CanBePiped<int(&)[10],  decltype(std::views::take(3))>);
96       static_assert(!CanBePiped<int(&&)[10], decltype(std::views::take(3))>);
97       static_assert(!CanBePiped<NotAView,    decltype(std::views::take(3))>);
98 
99       static_assert(!CanBePiped<SomeView&,   decltype(std::views::take(/*n=*/NotAView{}))>);
100     }
101   }
102 
103   {
104     static_assert(std::same_as<decltype(std::views::take), decltype(std::ranges::views::take)>);
105   }
106 
107   // `views::take(empty_view, n)` returns an `empty_view`.
108   {
109     using Result = std::ranges::empty_view<int>;
110     [[maybe_unused]] std::same_as<Result> decltype(auto) result = std::views::empty<int> | std::views::take(3);
111   }
112 
113   // `views::take(span, n)` returns a `span`.
114   {
115     std::span<int> s(buf);
116     std::same_as<decltype(s)> decltype(auto) result = s | std::views::take(3);
117     assert(result.size() == 3);
118   }
119 
120   // `views::take(span, n)` returns a `span` with a dynamic extent, regardless of the input `span`.
121   {
122     std::span<int, 8> s(buf);
123     std::same_as<std::span<int, std::dynamic_extent>> decltype(auto) result = s | std::views::take(3);
124     assert(result.size() == 3);
125   }
126 
127   // `views::take(string_view, n)` returns a `string_view`.
128   {
129     {
130       std::string_view sv = "abcdef";
131       std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::take(3);
132       assert(result.size() == 3);
133     }
134 
135     {
136       std::u32string_view sv = U"abcdef";
137       std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::take(3);
138       assert(result.size() == 3);
139     }
140   }
141 
142   // `views::take(subrange, n)` returns a `subrange`.
143   {
144     auto subrange = std::ranges::subrange(buf, buf + N);
145     using Result = std::ranges::subrange<int*>;
146     std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);
147     assert(result.size() == 3);
148   }
149 
150   // `views::take(subrange, n)` doesn't return a `subrange` if it's not a random access range.
151   {
152     SizedView v(buf, buf + N);
153     auto subrange = std::ranges::subrange(v.begin(), v.end());
154 
155     using Result = std::ranges::take_view<std::ranges::subrange<forward_iterator<int*>,
156         sized_sentinel<forward_iterator<int*>>>>;
157     std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);
158     assert(result.size() == 3);
159   }
160 
161   // `views::take(subrange, n)` returns a `subrange` with all default template arguments.
162   {
163     std::ranges::subrange<int*, sized_sentinel<int*>, std::ranges::subrange_kind::sized> subrange;
164 
165     using Result = std::ranges::subrange<int*, int*, std::ranges::subrange_kind::sized>;
166     [[maybe_unused]] std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);
167   }
168 
169   // `views::take(iota_view, n)` returns an `iota_view`.
170   {
171     auto iota = std::views::iota(1, 8);
172     // The second template argument of the resulting `iota_view` is same as the first.
173     using Result                               = std::ranges::iota_view<int, int>;
174     std::same_as<Result> decltype(auto) result = iota | std::views::take(3);
175     assert(result.size() == 3);
176   }
177 
178 #if TEST_STD_VER >= 23
179   // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` models `sized_range`.
180   {
181     auto repeat                                = std::ranges::repeat_view<int, int>(1, 8);
182     using Result                               = std::ranges::repeat_view<int, int>;
183     std::same_as<Result> decltype(auto) result = repeat | std::views::take(3);
184     static_assert(std::ranges::sized_range<Result>);
185     assert(result.size() == 3);
186     assert(*result.begin() == 1);
187   }
188 
189   // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` doesn't model `sized_range`.
190   {
191     auto repeat  = std::ranges::repeat_view<int>(1);
192     using Result = std::ranges::repeat_view<int, std::ranges::range_difference_t<decltype(repeat)>>;
193     std::same_as<Result> decltype(auto) result = repeat | std::views::take(3);
194     assert(result.size() == 3);
195     assert(*result.begin() == 1);
196   }
197 #endif
198 
199   // When the size of the input range `s` is shorter than `n`, only `s` elements are taken.
200   {
201     test_small_range(std::span(buf));
202     test_small_range(std::string_view("abcdef"));
203     test_small_range(std::ranges::subrange(buf, buf + N));
204     test_small_range(std::views::iota(1, 8));
205   }
206 
207   // Test that it's possible to call `std::views::take` with any single argument as long as the resulting closure is
208   // never invoked. There is no good use case for it, but it's valid.
209   {
210     struct X { };
211     [[maybe_unused]] auto partial = std::views::take(X{});
212   }
213 
214   // Test when `subrange<Iter>` is not well formed
215   {
216     int input[] = {1, 2, 3};
217     using Iter  = cpp20_input_iterator<int*>;
218     using Sent  = sentinel_wrapper<Iter>;
219     std::ranges::subrange r{Iter{input}, Sent{Iter{input + 3}}};
220     auto tv = std::views::take(std::move(r), 1);
221     auto it                  = tv.begin();
222     assert(*it == 1);
223     ++it;
224     assert(it == tv.end());
225   }
226 
227   return true;
228 }
229 
main(int,char **)230 int main(int, char**) {
231   test();
232   static_assert(test());
233 
234   return 0;
235 }
236