xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/iter_swap.pass.cpp (revision f5832bab6f5024cabe32a9f668b7f44e6b7cfef5)
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, c++20
10 
11 // friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below)
12 //   requires (indirectly_swappable<iterator_t<maybe-const<Const, Views>>> && ...);
13 
14 #include <array>
15 #include <cassert>
16 #include <ranges>
17 
18 #include "../types.h"
19 
20 struct ThrowingMove {
21   ThrowingMove() = default;
ThrowingMoveThrowingMove22   ThrowingMove(ThrowingMove&&) {}
operator =ThrowingMove23   ThrowingMove& operator=(ThrowingMove&&){return *this;}
24 };
25 
test()26 constexpr bool test() {
27   {
28     std::array a1{1, 2, 3, 4};
29     std::array a2{0.1, 0.2, 0.3};
30     std::ranges::zip_view v(a1, a2);
31     auto iter1 = v.begin();
32     auto iter2 = ++v.begin();
33 
34     std::ranges::iter_swap(iter1, iter2);
35 
36     assert(a1[0] == 2);
37     assert(a1[1] == 1);
38     assert(a2[0] == 0.2);
39     assert(a2[1] == 0.1);
40 
41     auto [x1, y1] = *iter1;
42     assert(&x1 == &a1[0]);
43     assert(&y1 == &a2[0]);
44 
45     auto [x2, y2] = *iter2;
46     assert(&x2 == &a1[1]);
47     assert(&y2 == &a2[1]);
48 
49     static_assert(noexcept(std::ranges::iter_swap(iter1, iter2)));
50   }
51 
52   {
53     // underlying iter_swap may throw
54     std::array<ThrowingMove, 2> iterSwapMayThrow{};
55     std::ranges::zip_view v(iterSwapMayThrow);
56     auto iter1 = v.begin();
57     auto iter2 = ++v.begin();
58     static_assert(!noexcept(std::ranges::iter_swap(iter1, iter2)));
59   }
60 
61   {
62     // underlying iterators' iter_move are called through ranges::iter_swap
63     adltest::IterMoveSwapRange r1, r2;
64     assert(r1.iter_swap_called_times == 0);
65     assert(r2.iter_swap_called_times == 0);
66 
67     std::ranges::zip_view v{r1, r2};
68     auto it1 = v.begin();
69     auto it2 = std::ranges::next(it1, 3);
70 
71     std::ranges::iter_swap(it1, it2);
72     assert(r1.iter_swap_called_times == 2);
73     assert(r2.iter_swap_called_times == 2);
74 
75     std::ranges::iter_swap(it1, it2);
76     assert(r1.iter_swap_called_times == 4);
77     assert(r2.iter_swap_called_times == 4);
78   }
79   return true;
80 }
81 
main(int,char **)82 int main(int, char**) {
83   test();
84   static_assert(test());
85 
86   return 0;
87 }
88