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
24struct SizedView : std::ranges::view_base {
25 int* begin_ = nullptr;
26 int* end_ = nullptr;
27 constexpr SizedView(int* begin, int* end) : begin_(begin), end_(end) {}
28
29 constexpr auto begin() const { return forward_iterator<int*>(begin_); }
30 constexpr auto end() const { return sized_sentinel<forward_iterator<int*>>(forward_iterator<int*>(end_)); }
31};
32static_assert(std::ranges::forward_range<SizedView>);
33static_assert(std::ranges::sized_range<SizedView>);
34static_assert(std::ranges::view<SizedView>);
35
36template <class T>
37constexpr 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
46constexpr 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(input: 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
230int main(int, char**) {
231 test();
232 static_assert(test());
233
234 return 0;
235}
236

source code of libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp