[libc] Build with -Wdeprecated, fix some warnings (#125373)
[llvm-project.git] / libcxx / test / std / ranges / range.utility / range.utility.conv / to.pass.cpp
bloba983745fd636e8771ce33220173e649220960333
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 //===----------------------------------------------------------------------===//
9 // MSVC warning C4244: 'argument': conversion from '_Ty' to 'int', possible loss of data
10 // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4244
12 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
14 // template<class C, input_range R, class... Args> requires (!view<C>)
15 // constexpr C to(R&& r, Args&&... args); // Since C++23
17 #include <ranges>
19 #include <algorithm>
20 #include <array>
21 #include <cassert>
22 #include <vector>
23 #include "container.h"
24 #include "test_iterators.h"
25 #include "test_macros.h"
26 #include "test_range.h"
28 template <class Container, class Range, class... Args>
29 concept HasTo = requires (Range&& range, Args ...args) {
30 std::ranges::to<Container>(std::forward<Range>(range), std::forward<Args>(args)...);
33 struct InputRange {
34 int x = 0;
35 constexpr cpp20_input_iterator<int*> begin() {
36 return cpp20_input_iterator<int*>(&x);
38 constexpr sentinel_wrapper<cpp20_input_iterator<int*>> end() {
39 return sentinel_wrapper<cpp20_input_iterator<int*>>(begin());
42 static_assert(std::ranges::input_range<InputRange>);
44 struct common_cpp20_input_iterator {
45 using value_type = int;
46 using difference_type = long long;
47 using iterator_concept = std::input_iterator_tag;
48 // Deliberately not defining `iterator_category` to make sure this class satisfies the `input_iterator` concept but
49 // would fail `derived_from<iterator_category, input_iterator_tag>`.
51 int x = 0;
53 // Copyable so that it can be used as a sentinel against itself.
54 constexpr decltype(auto) operator*() const { return x; }
55 constexpr common_cpp20_input_iterator& operator++() { return *this; }
56 constexpr void operator++(int) {}
57 constexpr friend bool operator==(common_cpp20_input_iterator, common_cpp20_input_iterator) { return true; }
59 static_assert(std::input_iterator<common_cpp20_input_iterator>);
60 static_assert(std::sentinel_for<common_cpp20_input_iterator, common_cpp20_input_iterator>);
61 template <class T>
62 concept HasIteratorCategory = requires {
63 typename std::iterator_traits<T>::iterator_category;
65 static_assert(!HasIteratorCategory<common_cpp20_input_iterator>);
67 struct CommonInputRange {
68 int x = 0;
69 constexpr common_cpp20_input_iterator begin() { return {}; }
70 constexpr common_cpp20_input_iterator end() { return begin(); }
72 static_assert(std::ranges::input_range<CommonInputRange>);
73 static_assert(std::ranges::common_range<CommonInputRange>);
75 struct CommonRange {
76 int x = 0;
77 constexpr forward_iterator<int*> begin() {
78 return forward_iterator<int*>(&x);
80 constexpr forward_iterator<int*> end() {
81 return begin();
84 static_assert(std::ranges::input_range<CommonRange>);
85 static_assert(std::ranges::common_range<CommonRange>);
87 struct NonCommonRange {
88 int x = 0;
89 constexpr forward_iterator<int*> begin() {
90 return forward_iterator<int*>(&x);
92 constexpr sentinel_wrapper<forward_iterator<int*>> end() {
93 return sentinel_wrapper<forward_iterator<int*>>(begin());
96 static_assert(std::ranges::input_range<NonCommonRange>);
97 static_assert(!std::ranges::common_range<NonCommonRange>);
98 static_assert(std::derived_from<
99 typename std::iterator_traits<std::ranges::iterator_t<NonCommonRange>>::iterator_category,
100 std::input_iterator_tag>);
102 using ContainerT = int;
103 static_assert(!std::ranges::view<ContainerT>);
104 static_assert(HasTo<ContainerT, InputRange>);
105 static_assert(!HasTo<test_view<forward_iterator>, InputRange>);
107 // Note: it's not possible to check the `input_range` constraint because if it's not satisfied, the pipe adaptor
108 // overload hijacks the call (it takes unconstrained variadic arguments).
110 // Check the exact constraints for each one of the cases inside `ranges::to`.
112 struct Empty {};
114 struct Fallback {
115 using value_type = int;
117 CtrChoice ctr_choice = CtrChoice::Invalid;
118 int x = 0;
120 constexpr Fallback() : ctr_choice(CtrChoice::DefaultCtrAndInsert) {}
121 constexpr Fallback(Empty) : ctr_choice(CtrChoice::DefaultCtrAndInsert) {}
123 constexpr void push_back(value_type) {}
124 constexpr value_type* begin() { return &x; }
125 constexpr value_type* end() { return &x; }
126 std::size_t size() const { return 0; }
129 struct CtrDirectOrFallback : Fallback {
130 using Fallback::Fallback;
131 constexpr CtrDirectOrFallback(InputRange&&, int = 0) { ctr_choice = CtrChoice::DirectCtr; }
134 struct CtrFromRangeTOrFallback : Fallback {
135 using Fallback::Fallback;
136 constexpr CtrFromRangeTOrFallback(std::from_range_t, InputRange&&, int = 0) { ctr_choice = CtrChoice::FromRangeT; }
139 struct CtrBeginEndPairOrFallback : Fallback {
140 using Fallback::Fallback;
141 template <class Iter>
142 constexpr CtrBeginEndPairOrFallback(Iter, Iter, int = 0) { ctr_choice = CtrChoice::BeginEndPair; }
145 template <bool HasSize>
146 struct MaybeSizedRange {
147 int x = 0;
148 constexpr forward_iterator<int*> begin() { return forward_iterator<int*>(&x); }
149 constexpr forward_iterator<int*> end() { return begin(); }
151 constexpr std::size_t size() const
152 requires HasSize {
153 return 0;
156 static_assert(std::ranges::sized_range<MaybeSizedRange<true>>);
157 static_assert(!std::ranges::sized_range<MaybeSizedRange<false>>);
159 template <bool HasCapacity = true, bool CapacityReturnsSizeT = true,
160 bool HasMaxSize = true, bool MaxSizeReturnsSizeT = true>
161 struct Reservable : Fallback {
162 bool reserve_called = false;
164 using Fallback::Fallback;
166 constexpr std::size_t capacity() const
167 requires (HasCapacity && CapacityReturnsSizeT) {
168 return 0;
170 constexpr int capacity() const
171 requires (HasCapacity && !CapacityReturnsSizeT) {
172 return 0;
175 constexpr std::size_t max_size() const
176 requires (HasMaxSize && MaxSizeReturnsSizeT) {
177 return 0;
179 constexpr int max_size() const
180 requires (HasMaxSize && !MaxSizeReturnsSizeT) {
181 return 0;
184 constexpr void reserve(std::size_t) {
185 reserve_called = true;
188 LIBCPP_STATIC_ASSERT(std::ranges::__reservable_container<Reservable<>>);
190 constexpr void test_constraints() {
191 { // Case 1 -- construct directly from the range.
192 { // (range)
193 auto result = std::ranges::to<CtrDirectOrFallback>(InputRange());
194 assert(result.ctr_choice == CtrChoice::DirectCtr);
197 { // (range, arg)
198 auto result = std::ranges::to<CtrDirectOrFallback>(InputRange(), 1);
199 assert(result.ctr_choice == CtrChoice::DirectCtr);
202 { // (range, convertible-to-arg)
203 auto result = std::ranges::to<CtrDirectOrFallback>(InputRange(), 1.0);
204 assert(result.ctr_choice == CtrChoice::DirectCtr);
207 { // (range, BAD_arg)
208 auto result = std::ranges::to<CtrDirectOrFallback>(InputRange(), Empty());
209 assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
213 { // Case 2 -- construct using the `from_range_t` tagged constructor.
214 { // (range)
215 auto result = std::ranges::to<CtrFromRangeTOrFallback>(InputRange());
216 assert(result.ctr_choice == CtrChoice::FromRangeT);
219 { // (range, arg)
220 auto result = std::ranges::to<CtrFromRangeTOrFallback>(InputRange(), 1);
221 assert(result.ctr_choice == CtrChoice::FromRangeT);
224 { // (range, convertible-to-arg)
225 auto result = std::ranges::to<CtrFromRangeTOrFallback>(InputRange(), 1.0);
226 assert(result.ctr_choice == CtrChoice::FromRangeT);
229 { // (range, BAD_arg)
230 auto result = std::ranges::to<CtrFromRangeTOrFallback>(InputRange(), Empty());
231 assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
235 { // Case 3 -- construct from a begin-end iterator pair.
236 { // (range)
237 auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonRange());
238 assert(result.ctr_choice == CtrChoice::BeginEndPair);
241 { // (range, arg)
242 auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonRange(), 1);
243 assert(result.ctr_choice == CtrChoice::BeginEndPair);
246 { // (range, convertible-to-arg)
247 auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonRange(), 1.0);
248 assert(result.ctr_choice == CtrChoice::BeginEndPair);
251 { // (BAD_range) -- not a common range.
252 auto result = std::ranges::to<CtrBeginEndPairOrFallback>(NonCommonRange());
253 assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
256 { // (BAD_range) -- iterator type not derived from `input_iterator_tag`.
257 auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonInputRange());
258 assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
261 { // (range, BAD_arg)
262 auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonRange(), Empty());
263 assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
267 { // Case 4 -- default-construct (or construct from the extra arguments) and insert, reserving the size if possible.
268 // Note: it's not possible to check the constraints on the default constructor using this approach because there is
269 // nothing to fall back to -- the call will result in a hard error.
270 // However, it's possible to check the constraints on reserving the capacity.
272 { // All constraints satisfied.
273 using C = Reservable<>;
274 auto result = std::ranges::to<C>(MaybeSizedRange<true>());
275 assert(result.reserve_called);
278 { // !sized_range
279 using C = Reservable<>;
280 auto result = std::ranges::to<C>(MaybeSizedRange<false>());
281 assert(!result.reserve_called);
284 { // Missing `capacity`.
285 using C = Reservable</*HasCapacity=*/false>;
286 auto result = std::ranges::to<C>(MaybeSizedRange<true>());
287 assert(!result.reserve_called);
290 { // `capacity` doesn't return `size_type`.
291 using C = Reservable</*HasCapacity=*/true, /*CapacityReturnsSizeT=*/false>;
292 auto result = std::ranges::to<C>(MaybeSizedRange<true>());
293 assert(!result.reserve_called);
296 { // Missing `max_size`.
297 using C = Reservable</*HasCapacity=*/true, /*CapacityReturnsSizeT=*/true, /*HasMaxSize=*/false>;
298 auto result = std::ranges::to<C>(MaybeSizedRange<true>());
299 assert(!result.reserve_called);
302 { // `max_size` doesn't return `size_type`.
303 using C = Reservable<
304 /*HasCapacity=*/true, /*CapacityReturnsSizeT=*/true, /*HasMaxSize=*/true, /*MaxSizeReturnsSizeT=*/false>;
305 auto result = std::ranges::to<C>(MaybeSizedRange<true>());
306 assert(!result.reserve_called);
311 constexpr void test_ctr_choice_order() {
312 std::array in = {1, 2, 3, 4, 5};
313 int arg1 = 42;
314 char arg2 = 'a';
316 { // Case 1 -- construct directly from the given range.
318 using C = Container<int, CtrChoice::DirectCtr>;
319 std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
321 assert(result.ctr_choice == CtrChoice::DirectCtr);
322 assert(std::ranges::equal(result, in));
323 assert((in | std::ranges::to<C>()) == result);
324 auto closure = std::ranges::to<C>();
325 assert((in | closure) == result);
328 { // Extra arguments.
329 using C = Container<int, CtrChoice::DirectCtr>;
330 std::same_as<C> decltype(auto) result = std::ranges::to<C>(in, arg1, arg2);
332 assert(result.ctr_choice == CtrChoice::DirectCtr);
333 assert(std::ranges::equal(result, in));
334 assert(result.extra_arg1 == arg1);
335 assert(result.extra_arg2 == arg2);
336 assert((in | std::ranges::to<C>(arg1, arg2)) == result);
337 auto closure = std::ranges::to<C>(arg1, arg2);
338 assert((in | closure) == result);
342 { // Case 2 -- construct using the `from_range_t` tag.
344 using C = Container<int, CtrChoice::FromRangeT>;
345 std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
347 assert(result.ctr_choice == CtrChoice::FromRangeT);
348 assert(std::ranges::equal(result, in));
349 assert((in | std::ranges::to<C>()) == result);
350 auto closure = std::ranges::to<C>();
351 assert((in | closure) == result);
354 { // Extra arguments.
355 using C = Container<int, CtrChoice::FromRangeT>;
356 std::same_as<C> decltype(auto) result = std::ranges::to<C>(in, arg1, arg2);
358 assert(result.ctr_choice == CtrChoice::FromRangeT);
359 assert(std::ranges::equal(result, in));
360 assert(result.extra_arg1 == arg1);
361 assert(result.extra_arg2 == arg2);
362 assert((in | std::ranges::to<C>(arg1, arg2)) == result);
363 auto closure = std::ranges::to<C>(arg1, arg2);
364 assert((in | closure) == result);
368 { // Case 3 -- construct from a begin-end pair.
370 using C = Container<int, CtrChoice::BeginEndPair>;
371 std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
373 assert(result.ctr_choice == CtrChoice::BeginEndPair);
374 assert(std::ranges::equal(result, in));
375 assert((in | std::ranges::to<C>()) == result);
376 auto closure = std::ranges::to<C>();
377 assert((in | closure) == result);
380 { // Extra arguments.
381 using C = Container<int, CtrChoice::BeginEndPair>;
382 std::same_as<C> decltype(auto) result = std::ranges::to<C>(in, arg1, arg2);
384 assert(result.ctr_choice == CtrChoice::BeginEndPair);
385 assert(std::ranges::equal(result, in));
386 assert(result.extra_arg1 == arg1);
387 assert(result.extra_arg2 == arg2);
388 assert((in | std::ranges::to<C>(arg1, arg2)) == result);
389 auto closure = std::ranges::to<C>(arg1, arg2);
390 assert((in | closure) == result);
394 { // Case 4 -- default-construct then insert elements.
395 auto case_4 = [in, arg1, arg2]<auto InserterChoice, bool CanReserve>() {
396 using C = Container<int, CtrChoice::DefaultCtrAndInsert, InserterChoice, CanReserve>;
398 [[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
400 assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
401 assert(result.inserter_choice == InserterChoice);
402 assert(std::ranges::equal(result, in));
404 if constexpr (CanReserve) {
405 assert(result.called_reserve);
406 } else {
407 assert(!result.called_reserve);
410 assert((in | std::ranges::to<C>()) == result);
411 [[maybe_unused]] auto closure = std::ranges::to<C>();
412 assert((in | closure) == result);
415 { // Extra arguments
416 [[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in, arg1, arg2);
418 assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
419 assert(result.inserter_choice == InserterChoice);
420 assert(std::ranges::equal(result, in));
421 assert(result.extra_arg1 == arg1);
422 assert(result.extra_arg2 == arg2);
424 if constexpr (CanReserve) {
425 assert(result.called_reserve);
426 } else {
427 assert(!result.called_reserve);
430 assert((in | std::ranges::to<C>(arg1, arg2)) == result);
431 [[maybe_unused]] auto closure = std::ranges::to<C>(arg1, arg2);
432 assert((in | closure) == result);
436 case_4.operator()<InserterChoice::Insert, false>();
437 case_4.operator()<InserterChoice::Insert, true>();
438 case_4.operator()<InserterChoice::Emplace, false>();
439 case_4.operator()<InserterChoice::Emplace, true>();
440 case_4.operator()<InserterChoice::PushBack, false>();
441 case_4.operator()<InserterChoice::PushBack, true>();
442 case_4.operator()<InserterChoice::EmplaceBack, false>();
443 case_4.operator()<InserterChoice::EmplaceBack, true>();
447 template <CtrChoice Rank>
448 struct NotARange {
449 using value_type = int;
451 constexpr NotARange(std::ranges::input_range auto&&)
452 requires (Rank >= CtrChoice::DirectCtr)
455 constexpr NotARange(std::from_range_t, std::ranges::input_range auto&&)
456 requires (Rank >= CtrChoice::FromRangeT)
459 template <class Iter>
460 constexpr NotARange(Iter, Iter)
461 requires (Rank >= CtrChoice::BeginEndPair)
464 constexpr NotARange()
465 requires (Rank >= CtrChoice::DefaultCtrAndInsert)
466 = default;
468 constexpr void push_back(int) {}
471 static_assert(!std::ranges::range<NotARange<CtrChoice::DirectCtr>>);
473 constexpr void test_lwg_3785() {
474 // Test LWG 3785 ("`ranges::to` is over-constrained on the destination type being a range") -- make sure it's possible
475 // to convert the given input range to a non-range type.
476 std::array in = {1, 2, 3, 4, 5};
479 using C = NotARange<CtrChoice::DirectCtr>;
480 [[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
484 using C = NotARange<CtrChoice::FromRangeT>;
485 [[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
489 using C = NotARange<CtrChoice::BeginEndPair>;
490 [[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
494 using C = NotARange<CtrChoice::DefaultCtrAndInsert>;
495 [[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
499 constexpr void test_recursive() {
500 using C1 = Container<int, CtrChoice::DirectCtr>;
501 using C2 = Container<C1, CtrChoice::FromRangeT>;
502 using C3 = Container<C2, CtrChoice::BeginEndPair>;
503 using C4 = Container<C3, CtrChoice::DefaultCtrAndInsert, InserterChoice::PushBack>;
504 using A1 = std::array<int, 4>;
505 using A2 = std::array<A1, 3>;
506 using A3 = std::array<A2, 2>;
507 using A4 = std::array<A3, 2>;
509 A4 in = {};
510 { // Fill the nested array with incremental values.
511 int x = 0;
512 for (auto& a3 : in) {
513 for (auto& a2 : a3) {
514 for (auto& a1 : a2) {
515 for (int& el : a1) {
516 el = x++;
523 std::same_as<C4> decltype(auto) result = std::ranges::to<C4>(in);
525 assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
527 int expected_value = 0;
528 for (auto& c3 : result) {
529 assert(c3.ctr_choice == CtrChoice::BeginEndPair);
531 for (auto& c2 : c3) {
532 assert(c2.ctr_choice == CtrChoice::FromRangeT);
534 for (auto& c1 : c2) {
535 assert(c1.ctr_choice == CtrChoice::DirectCtr);
537 for (int el : c1) {
538 assert(el == expected_value);
539 ++expected_value;
545 assert((in | std::ranges::to<C4>()) == result);
547 // LWG3984: ranges::to's recursion branch may be ill-formed
548 auto in_owning_view = std::views::all(std::move(in));
549 static_assert(!std::ranges::viewable_range<decltype((in_owning_view))>);
550 assert(std::ranges::to<C4>(in_owning_view) == result);
553 constexpr bool test() {
554 test_constraints();
555 test_ctr_choice_order();
556 test_lwg_3785();
557 test_recursive();
559 return true;
562 int main(int, char**) {
563 test();
564 static_assert(test());
566 return 0;