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 |
10 | // <optional> |
11 | |
12 | // template <class T> void swap(optional<T>& x, optional<T>& y) |
13 | // noexcept(noexcept(x.swap(y))); |
14 | |
15 | #include <optional> |
16 | #include <type_traits> |
17 | #include <cassert> |
18 | |
19 | #include "test_macros.h" |
20 | #include "archetypes.h" |
21 | |
22 | using std::optional; |
23 | |
24 | class X |
25 | { |
26 | int i_; |
27 | public: |
28 | static unsigned dtor_called; |
29 | X(int i) : i_(i) {} |
30 | X(X&& x) = default; |
31 | X& operator=(X&&) = default; |
32 | ~X() {++dtor_called;} |
33 | |
34 | friend bool operator==(const X& x, const X& y) {return x.i_ == y.i_;} |
35 | }; |
36 | |
37 | unsigned X::dtor_called = 0; |
38 | |
39 | class Y |
40 | { |
41 | int i_; |
42 | public: |
43 | static unsigned dtor_called; |
44 | Y(int i) : i_(i) {} |
45 | Y(Y&&) = default; |
46 | ~Y() {++dtor_called;} |
47 | |
48 | friend constexpr bool operator==(const Y& x, const Y& y) {return x.i_ == y.i_;} |
49 | friend void swap(Y& x, Y& y) {std::swap(x.i_, y.i_);} |
50 | }; |
51 | |
52 | unsigned Y::dtor_called = 0; |
53 | |
54 | class Z |
55 | { |
56 | int i_; |
57 | public: |
58 | Z(int i) : i_(i) {} |
59 | Z(Z&&) { TEST_THROW(7);} |
60 | |
61 | friend constexpr bool operator==(const Z& x, const Z& y) {return x.i_ == y.i_;} |
62 | friend void swap(Z&, Z&) { TEST_THROW(6);} |
63 | }; |
64 | |
65 | |
66 | struct NonSwappable { |
67 | NonSwappable(NonSwappable const&) = delete; |
68 | }; |
69 | void swap(NonSwappable&, NonSwappable&) = delete; |
70 | |
71 | void test_swap_sfinae() { |
72 | using std::optional; |
73 | { |
74 | using T = TestTypes::TestType; |
75 | static_assert(std::is_swappable_v<optional<T>>, "" ); |
76 | } |
77 | { |
78 | using T = TestTypes::MoveOnly; |
79 | static_assert(std::is_swappable_v<optional<T>>, "" ); |
80 | } |
81 | { |
82 | using T = TestTypes::Copyable; |
83 | static_assert(std::is_swappable_v<optional<T>>, "" ); |
84 | } |
85 | { |
86 | using T = TestTypes::NoCtors; |
87 | static_assert(!std::is_swappable_v<optional<T>>, "" ); |
88 | } |
89 | { |
90 | using T = NonSwappable; |
91 | static_assert(!std::is_swappable_v<optional<T>>, "" ); |
92 | } |
93 | { |
94 | // Even though CopyOnly has deleted move operations, those operations |
95 | // cause optional<CopyOnly> to have implicitly deleted move operations |
96 | // that decay into copies. |
97 | using T = TestTypes::CopyOnly; |
98 | using Opt = optional<T>; |
99 | T::reset(); |
100 | Opt L(101), R(42); |
101 | T::reset_constructors(); |
102 | std::swap(L, R); |
103 | assert(L->value == 42); |
104 | assert(R->value == 101); |
105 | assert(T::copy_constructed == 1); |
106 | assert(T::constructed == T::copy_constructed); |
107 | assert(T::assigned == 2); |
108 | assert(T::assigned == T::copy_assigned); |
109 | } |
110 | } |
111 | |
112 | int main(int, char**) |
113 | { |
114 | test_swap_sfinae(); |
115 | { |
116 | optional<int> opt1; |
117 | optional<int> opt2; |
118 | static_assert(noexcept(swap(opt1, opt2)) == true, "" ); |
119 | assert(static_cast<bool>(opt1) == false); |
120 | assert(static_cast<bool>(opt2) == false); |
121 | swap(opt1, opt2); |
122 | assert(static_cast<bool>(opt1) == false); |
123 | assert(static_cast<bool>(opt2) == false); |
124 | } |
125 | { |
126 | optional<int> opt1(1); |
127 | optional<int> opt2; |
128 | static_assert(noexcept(swap(opt1, opt2)) == true, "" ); |
129 | assert(static_cast<bool>(opt1) == true); |
130 | assert(*opt1 == 1); |
131 | assert(static_cast<bool>(opt2) == false); |
132 | swap(opt1, opt2); |
133 | assert(static_cast<bool>(opt1) == false); |
134 | assert(static_cast<bool>(opt2) == true); |
135 | assert(*opt2 == 1); |
136 | } |
137 | { |
138 | optional<int> opt1; |
139 | optional<int> opt2(2); |
140 | static_assert(noexcept(swap(opt1, opt2)) == true, "" ); |
141 | assert(static_cast<bool>(opt1) == false); |
142 | assert(static_cast<bool>(opt2) == true); |
143 | assert(*opt2 == 2); |
144 | swap(opt1, opt2); |
145 | assert(static_cast<bool>(opt1) == true); |
146 | assert(*opt1 == 2); |
147 | assert(static_cast<bool>(opt2) == false); |
148 | } |
149 | { |
150 | optional<int> opt1(1); |
151 | optional<int> opt2(2); |
152 | static_assert(noexcept(swap(opt1, opt2)) == true, "" ); |
153 | assert(static_cast<bool>(opt1) == true); |
154 | assert(*opt1 == 1); |
155 | assert(static_cast<bool>(opt2) == true); |
156 | assert(*opt2 == 2); |
157 | swap(opt1, opt2); |
158 | assert(static_cast<bool>(opt1) == true); |
159 | assert(*opt1 == 2); |
160 | assert(static_cast<bool>(opt2) == true); |
161 | assert(*opt2 == 1); |
162 | } |
163 | { |
164 | optional<X> opt1; |
165 | optional<X> opt2; |
166 | static_assert(noexcept(swap(opt1, opt2)) == true, "" ); |
167 | assert(static_cast<bool>(opt1) == false); |
168 | assert(static_cast<bool>(opt2) == false); |
169 | swap(opt1, opt2); |
170 | assert(static_cast<bool>(opt1) == false); |
171 | assert(static_cast<bool>(opt2) == false); |
172 | assert(X::dtor_called == 0); |
173 | } |
174 | { |
175 | optional<X> opt1(1); |
176 | optional<X> opt2; |
177 | static_assert(noexcept(swap(opt1, opt2)) == true, "" ); |
178 | assert(static_cast<bool>(opt1) == true); |
179 | assert(*opt1 == 1); |
180 | assert(static_cast<bool>(opt2) == false); |
181 | X::dtor_called = 0; |
182 | swap(opt1, opt2); |
183 | assert(X::dtor_called == 1); |
184 | assert(static_cast<bool>(opt1) == false); |
185 | assert(static_cast<bool>(opt2) == true); |
186 | assert(*opt2 == 1); |
187 | } |
188 | { |
189 | optional<X> opt1; |
190 | optional<X> opt2(2); |
191 | static_assert(noexcept(swap(opt1, opt2)) == true, "" ); |
192 | assert(static_cast<bool>(opt1) == false); |
193 | assert(static_cast<bool>(opt2) == true); |
194 | assert(*opt2 == 2); |
195 | X::dtor_called = 0; |
196 | swap(opt1, opt2); |
197 | assert(X::dtor_called == 1); |
198 | assert(static_cast<bool>(opt1) == true); |
199 | assert(*opt1 == 2); |
200 | assert(static_cast<bool>(opt2) == false); |
201 | } |
202 | { |
203 | optional<X> opt1(1); |
204 | optional<X> opt2(2); |
205 | static_assert(noexcept(swap(opt1, opt2)) == true, "" ); |
206 | assert(static_cast<bool>(opt1) == true); |
207 | assert(*opt1 == 1); |
208 | assert(static_cast<bool>(opt2) == true); |
209 | assert(*opt2 == 2); |
210 | X::dtor_called = 0; |
211 | swap(opt1, opt2); |
212 | assert(X::dtor_called == 1); // from inside std::swap |
213 | assert(static_cast<bool>(opt1) == true); |
214 | assert(*opt1 == 2); |
215 | assert(static_cast<bool>(opt2) == true); |
216 | assert(*opt2 == 1); |
217 | } |
218 | { |
219 | optional<Y> opt1; |
220 | optional<Y> opt2; |
221 | static_assert(noexcept(swap(opt1, opt2)) == false, "" ); |
222 | assert(static_cast<bool>(opt1) == false); |
223 | assert(static_cast<bool>(opt2) == false); |
224 | swap(opt1, opt2); |
225 | assert(static_cast<bool>(opt1) == false); |
226 | assert(static_cast<bool>(opt2) == false); |
227 | assert(Y::dtor_called == 0); |
228 | } |
229 | { |
230 | optional<Y> opt1(1); |
231 | optional<Y> opt2; |
232 | static_assert(noexcept(swap(opt1, opt2)) == false, "" ); |
233 | assert(static_cast<bool>(opt1) == true); |
234 | assert(*opt1 == 1); |
235 | assert(static_cast<bool>(opt2) == false); |
236 | Y::dtor_called = 0; |
237 | swap(opt1, opt2); |
238 | assert(Y::dtor_called == 1); |
239 | assert(static_cast<bool>(opt1) == false); |
240 | assert(static_cast<bool>(opt2) == true); |
241 | assert(*opt2 == 1); |
242 | } |
243 | { |
244 | optional<Y> opt1; |
245 | optional<Y> opt2(2); |
246 | static_assert(noexcept(swap(opt1, opt2)) == false, "" ); |
247 | assert(static_cast<bool>(opt1) == false); |
248 | assert(static_cast<bool>(opt2) == true); |
249 | assert(*opt2 == 2); |
250 | Y::dtor_called = 0; |
251 | swap(opt1, opt2); |
252 | assert(Y::dtor_called == 1); |
253 | assert(static_cast<bool>(opt1) == true); |
254 | assert(*opt1 == 2); |
255 | assert(static_cast<bool>(opt2) == false); |
256 | } |
257 | { |
258 | optional<Y> opt1(1); |
259 | optional<Y> opt2(2); |
260 | static_assert(noexcept(swap(opt1, opt2)) == false, "" ); |
261 | assert(static_cast<bool>(opt1) == true); |
262 | assert(*opt1 == 1); |
263 | assert(static_cast<bool>(opt2) == true); |
264 | assert(*opt2 == 2); |
265 | Y::dtor_called = 0; |
266 | swap(opt1, opt2); |
267 | assert(Y::dtor_called == 0); |
268 | assert(static_cast<bool>(opt1) == true); |
269 | assert(*opt1 == 2); |
270 | assert(static_cast<bool>(opt2) == true); |
271 | assert(*opt2 == 1); |
272 | } |
273 | { |
274 | optional<Z> opt1; |
275 | optional<Z> opt2; |
276 | static_assert(noexcept(swap(opt1, opt2)) == false, "" ); |
277 | assert(static_cast<bool>(opt1) == false); |
278 | assert(static_cast<bool>(opt2) == false); |
279 | swap(opt1, opt2); |
280 | assert(static_cast<bool>(opt1) == false); |
281 | assert(static_cast<bool>(opt2) == false); |
282 | } |
283 | #ifndef TEST_HAS_NO_EXCEPTIONS |
284 | { |
285 | optional<Z> opt1; |
286 | opt1.emplace(1); |
287 | optional<Z> opt2; |
288 | static_assert(noexcept(swap(opt1, opt2)) == false, "" ); |
289 | assert(static_cast<bool>(opt1) == true); |
290 | assert(*opt1 == 1); |
291 | assert(static_cast<bool>(opt2) == false); |
292 | try |
293 | { |
294 | swap(opt1, opt2); |
295 | assert(false); |
296 | } |
297 | catch (int i) |
298 | { |
299 | assert(i == 7); |
300 | } |
301 | assert(static_cast<bool>(opt1) == true); |
302 | assert(*opt1 == 1); |
303 | assert(static_cast<bool>(opt2) == false); |
304 | } |
305 | { |
306 | optional<Z> opt1; |
307 | optional<Z> opt2; |
308 | opt2.emplace(2); |
309 | static_assert(noexcept(swap(opt1, opt2)) == false, "" ); |
310 | assert(static_cast<bool>(opt1) == false); |
311 | assert(static_cast<bool>(opt2) == true); |
312 | assert(*opt2 == 2); |
313 | try |
314 | { |
315 | swap(opt1, opt2); |
316 | assert(false); |
317 | } |
318 | catch (int i) |
319 | { |
320 | assert(i == 7); |
321 | } |
322 | assert(static_cast<bool>(opt1) == false); |
323 | assert(static_cast<bool>(opt2) == true); |
324 | assert(*opt2 == 2); |
325 | } |
326 | { |
327 | optional<Z> opt1; |
328 | opt1.emplace(1); |
329 | optional<Z> opt2; |
330 | opt2.emplace(2); |
331 | static_assert(noexcept(swap(opt1, opt2)) == false, "" ); |
332 | assert(static_cast<bool>(opt1) == true); |
333 | assert(*opt1 == 1); |
334 | assert(static_cast<bool>(opt2) == true); |
335 | assert(*opt2 == 2); |
336 | try |
337 | { |
338 | swap(opt1, opt2); |
339 | assert(false); |
340 | } |
341 | catch (int i) |
342 | { |
343 | assert(i == 6); |
344 | } |
345 | assert(static_cast<bool>(opt1) == true); |
346 | assert(*opt1 == 1); |
347 | assert(static_cast<bool>(opt2) == true); |
348 | assert(*opt2 == 2); |
349 | } |
350 | #endif // TEST_HAS_NO_EXCEPTIONS |
351 | |
352 | return 0; |
353 | } |
354 | |