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// template<class I>
12// unspecified iter_swap;
13
14#include <iterator>
15
16#include <array>
17#include <cassert>
18
19#include "../unqualified_lookup_wrapper.h"
20#include "test_iterators.h"
21
22using IterSwapT = decltype(std::ranges::iter_swap);
23
24struct HasIterSwap {
25 int &value_;
26 constexpr explicit HasIterSwap(int &value) : value_(value) { assert(value == 0); }
27
28 friend constexpr void iter_swap(HasIterSwap& a, HasIterSwap& b) {
29 a.value_ = 1;
30 b.value_ = 1;
31 }
32 friend constexpr void iter_swap(HasIterSwap& a, int& b) {
33 a.value_ = 2;
34 b = 2;
35 }
36};
37
38static_assert( std::is_invocable_v<IterSwapT, HasIterSwap&, HasIterSwap&>);
39static_assert( std::is_invocable_v<IterSwapT, HasIterSwap&, int&>);
40static_assert(!std::is_invocable_v<IterSwapT, int&, HasIterSwap&>);
41
42static_assert( std::is_invocable_v<IterSwapT&, HasIterSwap&, HasIterSwap&>);
43static_assert( std::is_invocable_v<IterSwapT&, HasIterSwap&, int&>);
44static_assert(!std::is_invocable_v<IterSwapT&, int&, HasIterSwap&>);
45
46static_assert( std::is_invocable_v<IterSwapT&&, HasIterSwap&, HasIterSwap&>);
47static_assert( std::is_invocable_v<IterSwapT&&, HasIterSwap&, int&>);
48static_assert(!std::is_invocable_v<IterSwapT&&, int&, HasIterSwap&>);
49
50struct StructWithNotMoreSpecializedIterSwap {
51 friend void iter_swap(auto&, auto&);
52};
53
54static_assert(
55 !std::is_invocable_v<IterSwapT, StructWithNotMoreSpecializedIterSwap&, StructWithNotMoreSpecializedIterSwap&>);
56
57struct NodiscardIterSwap {
58 [[nodiscard]] friend int iter_swap(NodiscardIterSwap&, NodiscardIterSwap&) { return 0; }
59};
60
61void ensureVoidCast(NodiscardIterSwap& a, NodiscardIterSwap& b) { std::ranges::iter_swap(a, b); }
62
63struct HasRangesSwap {
64 int &value_;
65 constexpr explicit HasRangesSwap(int &value) : value_(value) { assert(value == 0); }
66
67 friend constexpr void swap(HasRangesSwap& a, HasRangesSwap& b) {
68 a.value_ = 1;
69 b.value_ = 1;
70 }
71 friend constexpr void swap(HasRangesSwap& a, int& b) {
72 a.value_ = 2;
73 b = 2;
74 }
75};
76
77struct HasRangesSwapWrapper {
78 using value_type = HasRangesSwap;
79
80 HasRangesSwap &value_;
81 constexpr explicit HasRangesSwapWrapper(HasRangesSwap &value) : value_(value) {}
82
83 constexpr HasRangesSwap& operator*() const { return value_; }
84};
85
86static_assert( std::is_invocable_v<IterSwapT, HasRangesSwapWrapper&, HasRangesSwapWrapper&>);
87// Does not satisfy swappable_with, even though swap(X, Y) is valid.
88static_assert(!std::is_invocable_v<IterSwapT, HasRangesSwapWrapper&, int&>);
89static_assert(!std::is_invocable_v<IterSwapT, int&, HasRangesSwapWrapper&>);
90
91struct B;
92
93struct A {
94 bool value = false;
95 constexpr A& operator=(const B&) {
96 value = true;
97 return *this;
98 };
99};
100
101struct B {
102 bool value = false;
103 constexpr B& operator=(const A&) {
104 value = true;
105 return *this;
106 };
107};
108
109struct MoveOnly2;
110
111struct MoveOnly1 {
112 bool value = false;
113
114 MoveOnly1() = default;
115 MoveOnly1(MoveOnly1&&) = default;
116 MoveOnly1& operator=(MoveOnly1&&) = default;
117 MoveOnly1(const MoveOnly1&) = delete;
118 MoveOnly1& operator=(const MoveOnly1&) = delete;
119
120 constexpr MoveOnly1& operator=(MoveOnly2 &&) {
121 value = true;
122 return *this;
123 };
124};
125
126struct MoveOnly2 {
127 bool value = false;
128
129 MoveOnly2() = default;
130 MoveOnly2(MoveOnly2&&) = default;
131 MoveOnly2& operator=(MoveOnly2&&) = default;
132 MoveOnly2(const MoveOnly2&) = delete;
133 MoveOnly2& operator=(const MoveOnly2&) = delete;
134
135 constexpr MoveOnly2& operator=(MoveOnly1 &&) {
136 value = true;
137 return *this;
138 };
139};
140
141constexpr bool test()
142{
143 {
144 int value1 = 0;
145 int value2 = 0;
146 HasIterSwap a(value1), b(value2);
147 std::ranges::iter_swap(a, b);
148 assert(value1 == 1 && value2 == 1);
149 }
150 {
151 int value1 = 0;
152 int value2 = 0;
153 HasRangesSwap c(value1), d(value2);
154 HasRangesSwapWrapper cWrapper(c), dWrapper(d);
155 std::ranges::iter_swap(cWrapper, dWrapper);
156 assert(value1 == 1 && value2 == 1);
157 }
158 {
159 int value1 = 0;
160 int value2 = 0;
161 HasRangesSwap c(value1), d(value2);
162 std::ranges::iter_swap(HasRangesSwapWrapper(c), HasRangesSwapWrapper(d));
163 assert(value1 == 1 && value2 == 1);
164 }
165 {
166 A e; B f;
167 A *ePtr = &e;
168 B *fPtr = &f;
169 std::ranges::iter_swap(ePtr, fPtr);
170 assert(e.value && f.value);
171 }
172 {
173 MoveOnly1 g; MoveOnly2 h;
174 std::ranges::iter_swap(&g, &h);
175 assert(g.value && h.value);
176 }
177 {
178 auto arr = std::array<move_tracker, 2>();
179 std::ranges::iter_swap(arr.begin(), arr.begin() + 1);
180 if (std::is_constant_evaluated()) {
181 assert(arr[0].moves() == 1 && arr[1].moves() == 3);
182 } else {
183 assert(arr[0].moves() == 1 && arr[1].moves() == 2);
184 }
185 }
186 {
187 int buff[2] = {1, 2};
188 std::ranges::iter_swap(buff + 0, buff + 1);
189 assert(buff[0] == 2 && buff[1] == 1);
190
191 std::ranges::iter_swap(cpp20_input_iterator(buff), cpp20_input_iterator(buff + 1));
192 assert(buff[0] == 1 && buff[1] == 2);
193
194 std::ranges::iter_swap(cpp17_input_iterator(buff), cpp17_input_iterator(buff + 1));
195 assert(buff[0] == 2 && buff[1] == 1);
196
197 std::ranges::iter_swap(forward_iterator(buff), forward_iterator(buff + 1));
198 assert(buff[0] == 1 && buff[1] == 2);
199
200 std::ranges::iter_swap(bidirectional_iterator(buff), bidirectional_iterator(buff + 1));
201 assert(buff[0] == 2 && buff[1] == 1);
202
203 std::ranges::iter_swap(random_access_iterator(buff), random_access_iterator(buff + 1));
204 assert(buff[0] == 1 && buff[1] == 2);
205
206 std::ranges::iter_swap(contiguous_iterator(buff), contiguous_iterator(buff + 1));
207 assert(buff[0] == 2 && buff[1] == 1);
208 }
209 return true;
210}
211
212static_assert(!std::is_invocable_v<IterSwapT, int*>); // too few arguments
213static_assert(!std::is_invocable_v<IterSwapT, int*, int*, int*>); // too many arguments
214static_assert(!std::is_invocable_v<IterSwapT, int, int*>);
215static_assert(!std::is_invocable_v<IterSwapT, int*, int>);
216static_assert(!std::is_invocable_v<IterSwapT, void*, void*>);
217
218// Test ADL-proofing.
219struct Incomplete;
220template<class T> struct Holder { T t; };
221static_assert(std::is_invocable_v<IterSwapT, Holder<Incomplete>**, Holder<Incomplete>**>);
222static_assert(std::is_invocable_v<IterSwapT, Holder<Incomplete>**, Holder<Incomplete>**&>);
223static_assert(std::is_invocable_v<IterSwapT, Holder<Incomplete>**&, Holder<Incomplete>**>);
224static_assert(std::is_invocable_v<IterSwapT, Holder<Incomplete>**&, Holder<Incomplete>**&>);
225
226int main(int, char**)
227{
228 test();
229 static_assert(test());
230
231 return 0;
232}
233

source code of libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp