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++98, 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;
X(int i)29     X(int i) : i_(i) {}
30     X(X&& x) = default;
31     X& operator=(X&&) = default;
~X()32     ~X() {++dtor_called;}
33 
operator ==(const X & x,const X & y)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;
Y(int i)44     Y(int i) : i_(i) {}
45     Y(Y&&) = default;
~Y()46     ~Y() {++dtor_called;}
47 
operator ==(const Y & x,const Y & y)48     friend constexpr bool operator==(const Y& x, const Y& y) {return x.i_ == y.i_;}
swap(Y & x,Y & y)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:
Z(int i)58     Z(int i) : i_(i) {}
Z(Z &&)59     Z(Z&&) { TEST_THROW(7);}
60 
operator ==(const Z & x,const Z & y)61     friend constexpr bool operator==(const Z& x, const Z& y) {return x.i_ == y.i_;}
swap(Z &,Z &)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 
test_swap_sfinae()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 
main(int,char **)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