]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/variant/test/variant_nonempty_check.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / variant / test / variant_nonempty_check.cpp
1 //-----------------------------------------------------------------------------
2 // boost-libs variant/test/variant_nonempty_check.cpp source file
3 // See http://www.boost.org for updates, documentation, and revision history.
4 //-----------------------------------------------------------------------------
5 //
6 // Copyright (c) 2014 Antony Polukhin
7 //
8 // Distributed under the Boost Software License, Version 1.0. (See
9 // accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
11
12
13 // In this file we are making tests to ensure that variant guarantees nonemptiness.
14 //
15 // For that purpose we create a `throwing_class`, that throws exception at a specified
16 // assignment attempt. If exception was thrown during move/assignemnt operation we make sure
17 // that data in variant is same as before move/assignemnt operation or that a fallback type is
18 // stored in variant.
19 //
20 // Different nonthrowing_class'es are used to tests different variant internal policies:
21 // with/without fallback type + throw/nothrow copyable + throw/nothrow movable
22
23
24 #include "boost/variant/variant.hpp"
25 #include "boost/variant/get.hpp"
26 #include "boost/test/minimal.hpp"
27 #include <stdexcept>
28
29 struct exception_on_assignment : std::exception {};
30 struct exception_on_move_assignment : exception_on_assignment {};
31
32 void prevent_compiler_noexcept_detection() {
33 char* p = new char;
34 *p = '\0';
35 delete p;
36 }
37
38
39 struct throwing_class {
40 int trash;
41 enum helper_enum {
42 do_not_throw = 780,
43 throw_after_5,
44 throw_after_4,
45 throw_after_3,
46 throw_after_2,
47 throw_after_1
48 };
49
50 bool is_throw() {
51 if (trash < do_not_throw) {
52 return true;
53 }
54
55 if (trash > do_not_throw && trash <= throw_after_1) {
56 ++ trash;
57 return false;
58 }
59
60 return trash != do_not_throw;
61 }
62
63 throwing_class(int value = 123) BOOST_NOEXCEPT_IF(false) : trash(value) {
64 prevent_compiler_noexcept_detection();
65 }
66
67 throwing_class(const throwing_class& b) BOOST_NOEXCEPT_IF(false) : trash(b.trash) {
68 if (is_throw()) {
69 throw exception_on_assignment();
70 }
71 }
72
73 const throwing_class& operator=(const throwing_class& b) BOOST_NOEXCEPT_IF(false) {
74 trash = b.trash;
75 if (is_throw()) {
76 throw exception_on_assignment();
77 }
78
79 return *this;
80 }
81
82 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
83 throwing_class(throwing_class&& b) BOOST_NOEXCEPT_IF(false) : trash(b.trash) {
84 if (is_throw()) {
85 throw exception_on_move_assignment();
86 }
87 }
88
89 const throwing_class& operator=(throwing_class&& b) BOOST_NOEXCEPT_IF(false) {
90 trash = b.trash;
91 if (is_throw()) {
92 throw exception_on_move_assignment();
93 }
94
95 return *this;
96 }
97 #endif
98
99 virtual ~throwing_class() {}
100 };
101
102 struct nonthrowing_class {
103 int trash;
104
105 nonthrowing_class() BOOST_NOEXCEPT_IF(false) : trash(123) {
106 prevent_compiler_noexcept_detection();
107 }
108
109 nonthrowing_class(const nonthrowing_class&) BOOST_NOEXCEPT_IF(false) {
110 prevent_compiler_noexcept_detection();
111 }
112
113 const nonthrowing_class& operator=(const nonthrowing_class&) BOOST_NOEXCEPT_IF(false) {
114 prevent_compiler_noexcept_detection();
115 return *this;
116 }
117
118 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
119 nonthrowing_class(nonthrowing_class&&) BOOST_NOEXCEPT_IF(false) {
120 prevent_compiler_noexcept_detection();
121 }
122
123 const nonthrowing_class& operator=(nonthrowing_class&&) BOOST_NOEXCEPT_IF(false) {
124 prevent_compiler_noexcept_detection();
125 return *this;
126 }
127 #endif
128 };
129
130 struct nonthrowing_class2 {
131 int trash;
132
133 nonthrowing_class2() BOOST_NOEXCEPT_IF(false) : trash(123) {
134 prevent_compiler_noexcept_detection();
135 }
136 };
137
138 struct nonthrowing_class3 {
139 int trash;
140
141 nonthrowing_class3() BOOST_NOEXCEPT_IF(true) : trash(123) {}
142
143 nonthrowing_class3(const nonthrowing_class3&) BOOST_NOEXCEPT_IF(false) {
144 prevent_compiler_noexcept_detection();
145 }
146
147 const nonthrowing_class3& operator=(const nonthrowing_class3&) BOOST_NOEXCEPT_IF(false) {
148 prevent_compiler_noexcept_detection();
149 return *this;
150 }
151
152 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
153 nonthrowing_class3(nonthrowing_class3&&) BOOST_NOEXCEPT_IF(false) {
154 prevent_compiler_noexcept_detection();
155 }
156
157 const nonthrowing_class3& operator=(nonthrowing_class3&&) BOOST_NOEXCEPT_IF(false) {
158 prevent_compiler_noexcept_detection();
159 return *this;
160 }
161 #endif
162 };
163
164 struct nonthrowing_class4 {
165 int trash;
166
167 nonthrowing_class4() BOOST_NOEXCEPT_IF(false) : trash(123) {
168 prevent_compiler_noexcept_detection();
169 }
170
171 nonthrowing_class4(const nonthrowing_class4&) BOOST_NOEXCEPT_IF(false) {
172 prevent_compiler_noexcept_detection();
173 }
174
175 const nonthrowing_class4& operator=(const nonthrowing_class4&) BOOST_NOEXCEPT_IF(false) {
176 prevent_compiler_noexcept_detection();
177 return *this;
178 }
179
180 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
181 nonthrowing_class4(nonthrowing_class4&&) BOOST_NOEXCEPT_IF(true) {
182 }
183
184 const nonthrowing_class4& operator=(nonthrowing_class4&&) BOOST_NOEXCEPT_IF(true) {
185 return *this;
186 }
187 #endif
188 };
189
190
191 // Tests /////////////////////////////////////////////////////////////////////////////////////
192
193
194 template <class Nonthrowing>
195 inline void check_1_impl(int helper)
196 {
197 boost::variant<throwing_class, Nonthrowing> v;
198 try {
199 v = throwing_class(helper);
200 BOOST_CHECK(!v.which());
201 BOOST_CHECK(boost::get<throwing_class>(&v));
202 } catch (const exception_on_assignment& /*e*/) {
203 BOOST_CHECK(!v.which());
204 BOOST_CHECK(boost::get<throwing_class>(&v));
205 }
206
207 try {
208 throwing_class tc(helper);
209 v = tc;
210 BOOST_CHECK(!v.which());
211 BOOST_CHECK(boost::get<throwing_class>(&v));
212 } catch (const exception_on_assignment& /*e*/) {
213 BOOST_CHECK(!v.which());
214 BOOST_CHECK(boost::get<throwing_class>(&v));
215 }
216 }
217
218 inline void check_1(int helper = 1)
219 {
220 check_1_impl<nonthrowing_class>(helper);
221 check_1_impl<nonthrowing_class2>(helper);
222 check_1_impl<nonthrowing_class3>(helper);
223 check_1_impl<nonthrowing_class4>(helper);
224 check_1_impl<boost::blank>(helper);
225 }
226
227 template <class Nonthrowing>
228 inline void check_2_impl(int helper)
229 {
230 boost::variant<Nonthrowing, throwing_class> v;
231 try {
232 v = throwing_class(helper);
233 BOOST_CHECK(v.which() == 1);
234 BOOST_CHECK(boost::get<throwing_class>(&v));
235 } catch (const exception_on_assignment& /*e*/) {
236 BOOST_CHECK(!v.which());
237 BOOST_CHECK(boost::get<Nonthrowing>(&v));
238 }
239
240 try {
241 throwing_class cl(helper);
242 v = cl;
243 BOOST_CHECK(v.which() == 1);
244 BOOST_CHECK(boost::get<throwing_class>(&v));
245 } catch (const exception_on_assignment& /*e*/) {
246 BOOST_CHECK(!v.which());
247 BOOST_CHECK(boost::get<Nonthrowing>(&v));
248 }
249 }
250
251 inline void check_2(int helper = 1)
252 {
253 check_2_impl<nonthrowing_class>(helper);
254 check_2_impl<nonthrowing_class2>(helper);
255 check_2_impl<nonthrowing_class3>(helper);
256 check_2_impl<nonthrowing_class4>(helper);
257 check_2_impl<boost::blank>(helper);
258 }
259
260 template <class Nonthrowing>
261 inline void check_3_impl(int helper)
262 {
263 boost::variant<Nonthrowing, throwing_class> v1, v2;
264
265 swap(v1, v2);
266 try {
267 v1 = throwing_class(helper);
268 BOOST_CHECK(v1.which() == 1);
269 BOOST_CHECK(boost::get<throwing_class>(&v1));
270 } catch (const exception_on_assignment& /*e*/) {
271 BOOST_CHECK(!v1.which());
272 BOOST_CHECK(boost::get<Nonthrowing>(&v1));
273 }
274
275
276 try {
277 v2 = throwing_class(helper);
278 BOOST_CHECK(v2.which() == 1);
279 BOOST_CHECK(boost::get<throwing_class>(&v2));
280 } catch (const exception_on_assignment& /*e*/) {
281 BOOST_CHECK(!v2.which());
282 BOOST_CHECK(boost::get<Nonthrowing>(&v2));
283 }
284
285
286 if (!v1.which() && !v2.which()) {
287 swap(v1, v2); // Make sure that two backup holders swap well
288 BOOST_CHECK(!v1.which());
289 BOOST_CHECK(boost::get<Nonthrowing>(&v1));
290 BOOST_CHECK(!v2.which());
291 BOOST_CHECK(boost::get<Nonthrowing>(&v2));
292
293 v1 = v2;
294 }
295 }
296
297 inline void check_3(int helper = 1)
298 {
299 check_3_impl<nonthrowing_class>(helper);
300 check_3_impl<nonthrowing_class2>(helper);
301 check_3_impl<nonthrowing_class3>(helper);
302 check_3_impl<nonthrowing_class4>(helper);
303 check_3_impl<boost::blank>(helper);
304 }
305
306 inline void check_4(int helper = 1)
307 {
308 // This one has a fallback
309 boost::variant<int, throwing_class> v1, v2;
310
311 swap(v1, v2);
312 try {
313 v1 = throwing_class(helper);
314 BOOST_CHECK(v1.which() == 1);
315 BOOST_CHECK(boost::get<throwing_class>(&v1));
316 } catch (const exception_on_assignment& /*e*/) {
317 BOOST_CHECK(!v1.which());
318 BOOST_CHECK(boost::get<int>(&v1));
319 }
320
321
322 try {
323 v2 = throwing_class(helper);
324 BOOST_CHECK(v2.which() == 1);
325 BOOST_CHECK(boost::get<throwing_class>(&v2));
326 } catch (const exception_on_assignment& /*e*/) {
327 BOOST_CHECK(!v2.which());
328 BOOST_CHECK(boost::get<int>(&v2));
329 }
330
331 if (!v1.which() && !v2.which()) {
332 swap(v1, v2);
333 BOOST_CHECK(!v1.which());
334 BOOST_CHECK(boost::get<int>(&v1));
335 BOOST_CHECK(!v2.which());
336 BOOST_CHECK(boost::get<int>(&v2));
337
338 v1 = v2;
339 }
340 }
341
342 template <class Nonthrowing>
343 inline void check_5_impl(int helper)
344 {
345 boost::variant<Nonthrowing, throwing_class> v1, v2;
346 throwing_class throw_not_now;
347 throw_not_now.trash = throwing_class::do_not_throw;
348 v1 = throw_not_now;
349 v2 = throw_not_now;
350
351 boost::get<throwing_class>(v1).trash = 1;
352 boost::get<throwing_class>(v2).trash = 1;
353
354 try {
355 v1 = throwing_class(helper);
356 BOOST_CHECK(v1.which() == 1);
357 BOOST_CHECK(boost::get<throwing_class>(&v1));
358 } catch (const exception_on_assignment& /*e*/) {
359 BOOST_CHECK(v1.which() == 1);
360 BOOST_CHECK(boost::get<throwing_class>(&v1));
361 }
362
363 boost::get<throwing_class>(v1).trash = throwing_class::do_not_throw;
364 boost::get<throwing_class>(v2).trash = throwing_class::do_not_throw;
365 v1 = Nonthrowing();
366 v2 = Nonthrowing();
367 try {
368 v1 = throwing_class(helper);
369 BOOST_CHECK(v1.which() == 1);
370 BOOST_CHECK(boost::get<throwing_class>(&v1));
371 } catch (const exception_on_assignment& /*e*/) {
372 BOOST_CHECK(v1.which() == 0);
373 BOOST_CHECK(boost::get<Nonthrowing>(&v1));
374 }
375
376 int v1_type = v1.which();
377 int v2_type = v2.which();
378 try {
379 swap(v1, v2); // Make sure that backup holders swap well
380 BOOST_CHECK(v1.which() == v2_type);
381 BOOST_CHECK(v2.which() == v1_type);
382 } catch (const exception_on_assignment& /*e*/) {
383 BOOST_CHECK(v1.which() == v1_type);
384 BOOST_CHECK(v2.which() == v2_type);
385 }
386 }
387
388
389 inline void check_5(int helper = 1)
390 {
391 check_5_impl<nonthrowing_class>(helper);
392 check_5_impl<nonthrowing_class2>(helper);
393 check_5_impl<nonthrowing_class3>(helper);
394 check_5_impl<nonthrowing_class4>(helper);
395 check_5_impl<boost::blank>(helper);
396 }
397
398 template <class Nonthrowing>
399 inline void check_6_impl(int helper)
400 {
401 boost::variant<Nonthrowing, throwing_class> v1, v2;
402 throwing_class throw_not_now;
403 throw_not_now.trash = throwing_class::do_not_throw;
404 v1 = throw_not_now;
405 v2 = throw_not_now;
406
407 v1 = throw_not_now;
408 v2 = throw_not_now;
409 swap(v1, v2);
410 boost::get<throwing_class>(v1).trash = 1;
411 boost::get<throwing_class>(v2).trash = 1;
412
413 v1 = throwing_class(throw_not_now);
414 v2 = v1;
415
416 v1 = Nonthrowing();
417 try {
418 throwing_class tc;
419 tc.trash = helper;
420 v1 = tc;
421 BOOST_CHECK(v1.which() == 1);
422 BOOST_CHECK(boost::get<throwing_class>(&v1));
423 } catch (const exception_on_assignment& /*e*/) {
424 BOOST_CHECK(v1.which() == 0);
425 }
426
427 v2 = Nonthrowing();
428 try {
429 v2 = 2;
430 BOOST_CHECK(false);
431 } catch (const exception_on_assignment& /*e*/) {
432 BOOST_CHECK(v2.which() == 0);
433 }
434
435 // Probably the most significant test:
436 // unsuccessful swap must preserve old values of variant
437 v1 = throw_not_now;
438 boost::get<throwing_class>(v1).trash = helper;
439 try {
440 swap(v1, v2);
441 } catch (const exception_on_assignment& /*e*/) {
442 BOOST_CHECK(v1.which() == 1);
443 BOOST_CHECK(v2.which() == 0);
444 BOOST_CHECK(boost::get<throwing_class>(v1).trash == helper);
445 }
446 }
447
448
449 inline void check_6(int helper = 1)
450 {
451 check_6_impl<nonthrowing_class>(helper);
452 check_6_impl<nonthrowing_class2>(helper);
453 check_6_impl<nonthrowing_class3>(helper);
454 check_6_impl<nonthrowing_class4>(helper);
455 check_6_impl<boost::blank>(helper);
456 }
457
458 int test_main(int , char* [])
459 {
460 // throwing_class::throw_after_1 + 1 => throw on first assignment/construction
461 // throwing_class::throw_after_1 => throw on second assignment/construction
462 // throwing_class::throw_after_2 => throw on third assignment/construction
463 // ...
464 for (int i = throwing_class::throw_after_1 + 1; i != throwing_class::do_not_throw; --i) {
465 check_1(i);
466 check_2(i);
467 check_3(i);
468 check_4(i);
469 check_5(i);
470 check_6(i);
471 }
472
473 return boost::exit_success;
474 }