]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/outcome/detail/value_storage.hpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / boost / outcome / detail / value_storage.hpp
CommitLineData
92f5a8d4 1/* Essentially an internal optional implementation :)
f67539c2 2(C) 2017-2020 Niall Douglas <http://www.nedproductions.biz/> (24 commits)
92f5a8d4
TL
3File Created: June 2017
4
5
6Boost Software License - Version 1.0 - August 17th, 2003
7
8Permission is hereby granted, free of charge, to any person or organization
9obtaining a copy of the software and accompanying documentation covered by
10this license (the "Software") to use, reproduce, display, distribute,
11execute, and transmit the Software, and to prepare derivative works of the
12Software, and to permit third-parties to whom the Software is furnished to
13do so, all subject to the following:
14
15The copyright notices in the Software and this entire statement, including
16the above license grant, this restriction and the following disclaimer,
17must be included in all copies of the Software, in whole or in part, and
18all derivative works of the Software, unless such copies or derivative
19works are solely in the form of machine-executable object code generated by
20a source language processor.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
25SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
26FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
27ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28DEALINGS IN THE SOFTWARE.
29*/
30
31#ifndef BOOST_OUTCOME_VALUE_STORAGE_HPP
32#define BOOST_OUTCOME_VALUE_STORAGE_HPP
33
34#include "../config.hpp"
35
f67539c2
TL
36#include <cassert>
37
92f5a8d4
TL
38BOOST_OUTCOME_V2_NAMESPACE_BEGIN
39
40namespace detail
41{
42 template <class T, bool nothrow> struct strong_swap_impl
43 {
44 constexpr strong_swap_impl(bool &allgood, T &a, T &b)
45 {
46 allgood = true;
47 using std::swap;
48 swap(a, b);
49 }
50 };
51#ifndef BOOST_NO_EXCEPTIONS
52 template <class T> struct strong_swap_impl<T, false>
53 {
54 strong_swap_impl(bool &allgood, T &a, T &b)
55 {
56 allgood = true;
57 T v(static_cast<T &&>(a));
58 try
59 {
60 a = static_cast<T &&>(b);
61 }
62 catch(...)
63 {
64 // Try to put back a
65 try
66 {
67 a = static_cast<T &&>(v);
68 // fall through as all good
69 }
70 catch(...)
71 {
72 // failed to completely restore
73 allgood = false;
74 // throw away second exception
75 }
76 throw; // rethrow original exception
77 }
78 // b has been moved to a, try to move v to b
79 try
80 {
81 b = static_cast<T &&>(v);
82 }
83 catch(...)
84 {
85 // Try to restore a to b, and v to a
86 try
87 {
88 b = static_cast<T &&>(a);
89 a = static_cast<T &&>(v);
90 // fall through as all good
91 }
92 catch(...)
93 {
94 // failed to completely restore
95 allgood = false;
96 // throw away second exception
97 }
98 throw; // rethrow original exception
99 }
100 }
101 };
102#endif
103} // namespace detail
104
105/*!
106 */
107BOOST_OUTCOME_TEMPLATE(class T)
108BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
109constexpr inline void strong_swap(bool &allgood, T &a, T &b) noexcept(detail::is_nothrow_swappable<T>::value)
110{
111 detail::strong_swap_impl<T, detail::is_nothrow_swappable<T>::value>(allgood, a, b);
112}
113
114namespace detail
115{
f67539c2
TL
116 template <class T>
117 constexpr
118#ifdef _MSC_VER
119 __declspec(noreturn)
120#elif defined(__GNUC__) || defined(__clang__)
121 __attribute__((noreturn))
122#endif
123 void make_ub(T && /*unused*/)
124 {
125 assert(false); // NOLINT
126#if defined(__GNUC__) || defined(__clang__)
127 __builtin_unreachable();
128#elif defined(_MSC_VER)
129 __assume(0);
130#endif
131 }
132
133 /* Outcome v1 used a C bitfield whose values were tracked by compiler optimisers nicely,
134 but that produces ICEs when used in constexpr.
135
136 Outcome v2.0-v2.1 used a 32 bit integer and manually set and cleared bits. Unfortunately
137 only GCC's optimiser tracks bit values during constant folding, and only per byte, and
138 even then unreliably. https://wg21.link/P1886 "Error speed benchmarking" showed just how
139 poorly clang and MSVC fails to optimise outcome-using code, if you manually set bits.
140
141 Outcome v2.2 therefore uses an enum with fixed values, and constexpr manipulation functions
142 to change the value to one of the enum's values. This is stupid to look at in source code,
143 but it make clang's optimiser do the right thing, so it's worth it.
144 */
145#define BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS 0
146 enum class status : uint16_t
147 {
148 // WARNING: These bits are not tracked by abi-dumper, but changing them will break ABI!
149 none = 0,
150
151 have_value = (1U << 0U),
152 have_error = (1U << 1U),
153 have_exception = (2U << 1U),
154 have_error_exception = (3U << 1U),
155
156 // failed to complete a strong swap
157 have_lost_consistency = (1U << 3U),
158 have_value_lost_consistency = (1U << 0U) | (1U << 3U),
159 have_error_lost_consistency = (1U << 1U) | (1U << 3U),
160 have_exception_lost_consistency = (2U << 1U) | (1U << 3U),
161 have_error_exception_lost_consistency = (3U << 1U) | (1U << 3U),
162
163 // can errno be set from this error?
164 have_error_is_errno = (1U << 4U),
165 have_error_error_is_errno = (1U << 1U) | (1U << 4U),
166 have_error_exception_error_is_errno = (3U << 1U) | (1U << 4U),
167
168 have_error_lost_consistency_error_is_errno = (1U << 1U) | (1U << 3U) | (1U << 4U),
169 have_error_exception_lost_consistency_error_is_errno = (3U << 1U) | (1U << 3U) | (1U << 4U),
170
171 // value has been moved from
172 have_moved_from = (1U << 5U)
173 };
174 struct status_bitfield_type
175 {
176 status status_value{status::none};
177 uint16_t spare_storage_value{0}; // hooks::spare_storage()
178
179 constexpr status_bitfield_type() = default;
180 constexpr status_bitfield_type(status v) noexcept
181 : status_value(v)
182 {
183 } // NOLINT
184 constexpr status_bitfield_type(status v, uint16_t s) noexcept
185 : status_value(v)
186 , spare_storage_value(s)
187 {
188 }
189 constexpr status_bitfield_type(const status_bitfield_type &) = default;
190 constexpr status_bitfield_type(status_bitfield_type &&) = default;
191 constexpr status_bitfield_type &operator=(const status_bitfield_type &) = default;
192 constexpr status_bitfield_type &operator=(status_bitfield_type &&) = default;
193 //~status_bitfield_type() = default; // Do NOT uncomment this, it breaks older clangs!
194
195 constexpr bool have_value() const noexcept
196 {
197#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
198 return (status_value == status::have_value) //
199 || (status_value == status::have_value_lost_consistency) //
200 ;
201#else
202 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_value)) != 0;
203#endif
204 }
205 constexpr bool have_error() const noexcept
206 {
207#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
208 return (status_value == status::have_error) //
209 || (status_value == status::have_error_exception) //
210 || (status_value == status::have_error_lost_consistency) //
211 || (status_value == status::have_error_exception_lost_consistency) //
212 || (status_value == status::have_error_error_is_errno) //
213 || (status_value == status::have_error_exception_error_is_errno) //
214 || (status_value == status::have_error_lost_consistency_error_is_errno) //
215 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
216 ;
217#else
218 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error)) != 0;
219#endif
220 }
221 constexpr bool have_exception() const noexcept
222 {
223#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
224 return (status_value == status::have_exception) //
225 || (status_value == status::have_error_exception) //
226 || (status_value == status::have_exception_lost_consistency) //
227 || (status_value == status::have_error_exception_lost_consistency) //
228 || (status_value == status::have_error_exception_error_is_errno) //
229 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
230 ;
231#else
232 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_exception)) != 0;
233#endif
234 }
235 constexpr bool have_lost_consistency() const noexcept
236 {
237#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
238 return (status_value == status::have_value_lost_consistency) //
239 || (status_value == status::have_error_lost_consistency) //
240 || (status_value == status::have_exception_lost_consistency) //
241 || (status_value == status::have_error_lost_consistency_error_is_errno) //
242 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
243 ;
244#else
245 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_lost_consistency)) != 0;
246#endif
247 }
248 constexpr bool have_error_is_errno() const noexcept
249 {
250#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
251 return (status_value == status::have_error_error_is_errno) //
252 || (status_value == status::have_error_exception_error_is_errno) //
253 || (status_value == status::have_error_lost_consistency_error_is_errno) //
254 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
255 ;
256#else
257 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error_is_errno)) != 0;
258#endif
259 }
260 constexpr bool have_moved_from() const noexcept
261 {
262#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
263#error Fixme
264#else
265 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_moved_from)) != 0;
266#endif
267 }
92f5a8d4 268
f67539c2
TL
269 constexpr status_bitfield_type &set_have_value(bool v) noexcept
270 {
271#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
272 switch(status_value)
273 {
274 case status::none:
275 if(v)
276 {
277 status_value = status::have_value;
278 }
279 break;
280 case status::have_value:
281 if(!v)
282 {
283 status_value = status::none;
284 }
285 break;
286 case status::have_error:
287 if(v)
288 {
289 make_ub(*this);
290 }
291 break;
292 case status::have_exception:
293 if(v)
294 {
295 make_ub(*this);
296 }
297 break;
298 case status::have_error_exception:
299 if(v)
300 {
301 make_ub(*this);
302 }
303 break;
304 case status::have_value_lost_consistency:
305 if(!v)
306 {
307 status_value = status::none;
308 }
309 break;
310 case status::have_error_lost_consistency:
311 if(v)
312 {
313 make_ub(*this);
314 }
315 break;
316 case status::have_exception_lost_consistency:
317 if(v)
318 {
319 make_ub(*this);
320 }
321 break;
322 case status::have_error_exception_lost_consistency:
323 if(v)
324 {
325 make_ub(*this);
326 }
327 break;
328 case status::have_error_error_is_errno:
329 if(v)
330 {
331 make_ub(*this);
332 }
333 break;
334 case status::have_error_exception_error_is_errno:
335 if(v)
336 {
337 make_ub(*this);
338 }
339 break;
340 case status::have_error_lost_consistency_error_is_errno:
341 if(v)
342 {
343 make_ub(*this);
344 }
345 break;
346 case status::have_error_exception_lost_consistency_error_is_errno:
347 if(v)
348 {
349 make_ub(*this);
350 }
351 break;
352 }
353#else
354 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_value)) :
355 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_value)));
356#endif
357 return *this;
358 }
359 constexpr status_bitfield_type &set_have_error(bool v) noexcept
360 {
361#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
362 switch(status_value)
363 {
364 case status::none:
365 if(v)
366 {
367 status_value = status::have_error;
368 }
369 break;
370 case status::have_value:
371 if(v)
372 {
373 make_ub(*this);
374 }
375 break;
376 case status::have_error:
377 if(!v)
378 {
379 status_value = status::none;
380 }
381 break;
382 case status::have_exception:
383 if(v)
384 {
385 status_value = status::have_error_exception;
386 }
387 break;
388 case status::have_error_exception:
389 if(!v)
390 {
391 status_value = status::have_exception;
392 }
393 break;
394 case status::have_value_lost_consistency:
395 if(v)
396 {
397 make_ub(*this);
398 }
399 break;
400 case status::have_error_lost_consistency:
401 if(!v)
402 {
403 status_value = status::none;
404 }
405 break;
406 case status::have_exception_lost_consistency:
407 if(v)
408 {
409 status_value = status::have_error_exception_lost_consistency;
410 }
411 break;
412 case status::have_error_exception_lost_consistency:
413 if(!v)
414 {
415 status_value = status::have_exception_lost_consistency;
416 }
417 break;
418 case status::have_error_error_is_errno:
419 if(!v)
420 {
421 status_value = status::none;
422 }
423 break;
424 case status::have_error_exception_error_is_errno:
425 if(!v)
426 {
427 status_value = status::have_exception;
428 }
429 break;
430 case status::have_error_lost_consistency_error_is_errno:
431 if(!v)
432 {
433 status_value = status::none;
434 }
435 break;
436 case status::have_error_exception_lost_consistency_error_is_errno:
437 if(!v)
438 {
439 status_value = status::have_exception_lost_consistency;
440 }
441 break;
442 }
443#else
444 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error)) :
445 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error)));
446#endif
447 return *this;
448 }
449 constexpr status_bitfield_type &set_have_exception(bool v) noexcept
450 {
451#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
452 switch(status_value)
453 {
454 case status::none:
455 if(v)
456 {
457 status_value = status::have_exception;
458 }
459 break;
460 case status::have_value:
461 if(v)
462 {
463 make_ub(*this);
464 }
465 break;
466 case status::have_error:
467 if(v)
468 {
469 status_value = status::have_error_exception;
470 }
471 break;
472 case status::have_exception:
473 if(!v)
474 {
475 status_value = status::none;
476 }
477 break;
478 case status::have_error_exception:
479 if(!v)
480 {
481 status_value = status::have_error;
482 }
483 break;
484 case status::have_value_lost_consistency:
485 if(v)
486 {
487 make_ub(*this);
488 }
489 break;
490 case status::have_error_lost_consistency:
491 if(v)
492 {
493 status_value = status::have_error_exception_lost_consistency;
494 }
495 break;
496 case status::have_exception_lost_consistency:
497 if(!v)
498 {
499 status_value = status::none;
500 }
501 break;
502 case status::have_error_exception_lost_consistency:
503 if(!v)
504 {
505 status_value = status::have_error_lost_consistency;
506 }
507 break;
508 case status::have_error_error_is_errno:
509 if(v)
510 {
511 status_value = status::have_error_exception_error_is_errno;
512 }
513 break;
514 case status::have_error_exception_error_is_errno:
515 if(!v)
516 {
517 status_value = status::have_error_error_is_errno;
518 }
519 break;
520 case status::have_error_lost_consistency_error_is_errno:
521 if(v)
522 {
523 status_value = status::have_error_exception_lost_consistency_error_is_errno;
524 }
525 break;
526 case status::have_error_exception_lost_consistency_error_is_errno:
527 if(!v)
528 {
529 status_value = status::have_error_lost_consistency_error_is_errno;
530 }
531 break;
532 }
533#else
534 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_exception)) :
535 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_exception)));
536#endif
537 return *this;
538 }
539 constexpr status_bitfield_type &set_have_error_is_errno(bool v) noexcept
540 {
541#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
542 switch(status_value)
543 {
544 case status::none:
545 make_ub(*this);
546 break;
547 case status::have_value:
548 make_ub(*this);
549 break;
550 case status::have_error:
551 if(v)
552 {
553 status_value = status::have_error_error_is_errno;
554 }
555 break;
556 case status::have_exception:
557 make_ub(*this);
558 break;
559 case status::have_error_exception:
560 if(v)
561 {
562 status_value = status::have_error_exception_error_is_errno;
563 }
564 break;
565 case status::have_value_lost_consistency:
566 make_ub(*this);
567 break;
568 case status::have_error_lost_consistency:
569 if(v)
570 {
571 status_value = status::have_error_lost_consistency_error_is_errno;
572 }
573 break;
574 case status::have_exception_lost_consistency:
575 make_ub(*this);
576 break;
577 case status::have_error_exception_lost_consistency:
578 if(v)
579 {
580 status_value = status::have_error_exception_lost_consistency_error_is_errno;
581 }
582 break;
583 case status::have_error_error_is_errno:
584 if(!v)
585 {
586 status_value = status::have_error;
587 }
588 break;
589 case status::have_error_exception_error_is_errno:
590 if(!v)
591 {
592 status_value = status::have_error_exception;
593 }
594 break;
595 case status::have_error_lost_consistency_error_is_errno:
596 if(!v)
597 {
598 status_value = status::have_error_lost_consistency;
599 }
600 break;
601 case status::have_error_exception_lost_consistency_error_is_errno:
602 if(!v)
603 {
604 status_value = status::have_error_exception_lost_consistency;
605 }
606 break;
607 }
608#else
609 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error_is_errno)) :
610 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error_is_errno)));
611#endif
612 return *this;
613 }
614 constexpr status_bitfield_type &set_have_lost_consistency(bool v) noexcept
615 {
616#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
617 switch(status_value)
618 {
619 case status::none:
620 if(v)
621 {
622 make_ub(*this);
623 }
624 break;
625 case status::have_value:
626 if(v)
627 {
628 status_value = status::have_value_lost_consistency;
629 }
630 break;
631 case status::have_error:
632 if(v)
633 {
634 status_value = status::have_error_lost_consistency;
635 }
636 break;
637 case status::have_exception:
638 if(v)
639 {
640 status_value = status::have_exception_lost_consistency;
641 }
642 break;
643 case status::have_error_exception:
644 if(v)
645 {
646 status_value = status::have_error_exception_lost_consistency;
647 }
648 break;
649 case status::have_value_lost_consistency:
650 if(!v)
651 {
652 status_value = status::have_value;
653 }
654 break;
655 case status::have_error_lost_consistency:
656 if(!v)
657 {
658 status_value = status::have_error;
659 }
660 break;
661 case status::have_exception_lost_consistency:
662 if(!v)
663 {
664 status_value = status::have_exception;
665 }
666 break;
667 case status::have_error_exception_lost_consistency:
668 if(!v)
669 {
670 status_value = status::have_error_exception;
671 }
672 break;
673 case status::have_error_error_is_errno:
674 if(v)
675 {
676 status_value = status::have_error_lost_consistency_error_is_errno;
677 }
678 break;
679 case status::have_error_exception_error_is_errno:
680 if(v)
681 {
682 status_value = status::have_error_exception_lost_consistency_error_is_errno;
683 }
684 break;
685 case status::have_error_lost_consistency_error_is_errno:
686 if(!v)
687 {
688 status_value = status::have_error_exception_error_is_errno;
689 }
690 break;
691 case status::have_error_exception_lost_consistency_error_is_errno:
692 if(!v)
693 {
694 status_value = status::have_error_exception_error_is_errno;
695 }
696 break;
697 }
698#else
699 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_lost_consistency)) :
700 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_lost_consistency)));
701#endif
702 return *this;
703 }
704 constexpr status_bitfield_type &set_have_moved_from(bool v) noexcept
705 {
706#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
707#error Fixme
708#else
709 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_moved_from)) :
710 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_moved_from)));
711#endif
712 return *this;
713 }
714 };
715#if !defined(NDEBUG)
716 // Check is trivial in all ways except default constructibility
717 static_assert(sizeof(status_bitfield_type) == 4, "status_bitfield_type is not sized 4 bytes!");
718 static_assert(std::is_trivially_copyable<status_bitfield_type>::value, "status_bitfield_type is not trivially copyable!");
719 static_assert(std::is_trivially_assignable<status_bitfield_type, status_bitfield_type>::value, "status_bitfield_type is not trivially assignable!");
720 static_assert(std::is_trivially_destructible<status_bitfield_type>::value, "status_bitfield_type is not trivially destructible!");
721 static_assert(std::is_trivially_copy_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially copy constructible!");
722 static_assert(std::is_trivially_move_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially move constructible!");
723 static_assert(std::is_trivially_copy_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially copy assignable!");
724 static_assert(std::is_trivially_move_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially move assignable!");
725 // Also check is standard layout
726 static_assert(std::is_standard_layout<status_bitfield_type>::value, "status_bitfield_type is not a standard layout type!");
727#endif
92f5a8d4
TL
728
729 // Used if T is trivial
730 template <class T> struct value_storage_trivial
731 {
732 using value_type = T;
733 union {
734 empty_type _empty;
735 devoid<T> _value;
736 };
f67539c2 737 status_bitfield_type _status;
92f5a8d4
TL
738 constexpr value_storage_trivial() noexcept
739 : _empty{}
740 {
741 }
f67539c2
TL
742 // Special from-void catchall constructor, always constructs default T irrespective of whether void is valued or not (can do no better if T cannot be
743 // copied)
92f5a8d4
TL
744 struct disable_void_catchall
745 {
746 };
747 using void_value_storage_trivial = std::conditional_t<std::is_void<T>::value, disable_void_catchall, value_storage_trivial<void>>;
748 explicit constexpr value_storage_trivial(const void_value_storage_trivial &o) noexcept(std::is_nothrow_default_constructible<value_type>::value)
749 : _value()
750 , _status(o._status)
751 {
752 }
753 value_storage_trivial(const value_storage_trivial &) = default; // NOLINT
754 value_storage_trivial(value_storage_trivial &&) = default; // NOLINT
755 value_storage_trivial &operator=(const value_storage_trivial &) = default; // NOLINT
756 value_storage_trivial &operator=(value_storage_trivial &&) = default; // NOLINT
757 ~value_storage_trivial() = default;
758 constexpr explicit value_storage_trivial(status_bitfield_type status)
759 : _empty()
760 , _status(status)
761 {
762 }
763 template <class... Args>
f67539c2
TL
764 constexpr explicit value_storage_trivial(in_place_type_t<value_type> /*unused*/,
765 Args &&... args) noexcept(std::is_nothrow_constructible<value_type, Args...>::value)
92f5a8d4 766 : _value(static_cast<Args &&>(args)...)
f67539c2 767 , _status(status::have_value)
92f5a8d4
TL
768 {
769 }
770 template <class U, class... Args>
f67539c2
TL
771 constexpr value_storage_trivial(in_place_type_t<value_type> /*unused*/, std::initializer_list<U> il,
772 Args &&... args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<U>, Args...>::value)
92f5a8d4 773 : _value(il, static_cast<Args &&>(args)...)
f67539c2 774 , _status(status::have_value)
92f5a8d4
TL
775 {
776 }
f67539c2
TL
777 template <class U>
778 static constexpr bool enable_converting_constructor = !std::is_same<std::decay_t<U>, value_type>::value && std::is_constructible<value_type, U>::value;
92f5a8d4
TL
779 BOOST_OUTCOME_TEMPLATE(class U)
780 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
781 constexpr explicit value_storage_trivial(const value_storage_trivial<U> &o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
f67539c2 782 : value_storage_trivial(o._status.have_value() ? value_storage_trivial(in_place_type<value_type>, o._value) : value_storage_trivial()) // NOLINT
92f5a8d4
TL
783 {
784 _status = o._status;
785 }
786 BOOST_OUTCOME_TEMPLATE(class U)
787 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
788 constexpr explicit value_storage_trivial(value_storage_trivial<U> &&o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
f67539c2
TL
789 : value_storage_trivial(o._status.have_value() ? value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
790 value_storage_trivial()) // NOLINT
92f5a8d4
TL
791 {
792 _status = o._status;
793 }
794 constexpr void swap(value_storage_trivial &o) noexcept
795 {
796 // storage is trivial, so just use assignment
797 auto temp = static_cast<value_storage_trivial &&>(*this);
798 *this = static_cast<value_storage_trivial &&>(o);
799 o = static_cast<value_storage_trivial &&>(temp);
800 }
801 };
802 // Used if T is non-trivial
803 template <class T> struct value_storage_nontrivial
804 {
805 using value_type = T;
806 union {
807 empty_type _empty;
808 value_type _value;
809 };
f67539c2 810 status_bitfield_type _status;
92f5a8d4
TL
811 value_storage_nontrivial() noexcept
812 : _empty{}
813 {
814 }
f67539c2
TL
815 value_storage_nontrivial &operator=(const value_storage_nontrivial &) = default; // if reaches here, copy assignment is trivial
816 value_storage_nontrivial &operator=(value_storage_nontrivial &&) = default; // NOLINT if reaches here, move assignment is trivial
92f5a8d4
TL
817 value_storage_nontrivial(value_storage_nontrivial &&o) noexcept(std::is_nothrow_move_constructible<value_type>::value) // NOLINT
818 : _status(o._status)
819 {
f67539c2 820 if(this->_status.have_value())
92f5a8d4 821 {
f67539c2 822 this->_status.set_have_value(false);
92f5a8d4
TL
823 new(&_value) value_type(static_cast<value_type &&>(o._value)); // NOLINT
824 _status = o._status;
825 }
826 }
827 value_storage_nontrivial(const value_storage_nontrivial &o) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
828 : _status(o._status)
829 {
f67539c2 830 if(this->_status.have_value())
92f5a8d4 831 {
f67539c2 832 this->_status.set_have_value(false);
92f5a8d4
TL
833 new(&_value) value_type(o._value); // NOLINT
834 _status = o._status;
835 }
836 }
837 // Special from-void constructor, constructs default T if void valued
838 explicit value_storage_nontrivial(const value_storage_trivial<void> &o) noexcept(std::is_nothrow_default_constructible<value_type>::value)
839 : _status(o._status)
840 {
f67539c2 841 if(this->_status.have_value())
92f5a8d4 842 {
f67539c2 843 this->_status.set_have_value(false);
92f5a8d4
TL
844 new(&_value) value_type; // NOLINT
845 _status = o._status;
846 }
847 }
848 explicit value_storage_nontrivial(status_bitfield_type status)
849 : _empty()
850 , _status(status)
851 {
852 }
853 template <class... Args>
f67539c2
TL
854 explicit value_storage_nontrivial(in_place_type_t<value_type> /*unused*/,
855 Args &&... args) noexcept(std::is_nothrow_constructible<value_type, Args...>::value)
92f5a8d4 856 : _value(static_cast<Args &&>(args)...) // NOLINT
f67539c2 857 , _status(status::have_value)
92f5a8d4
TL
858 {
859 }
860 template <class U, class... Args>
f67539c2
TL
861 value_storage_nontrivial(in_place_type_t<value_type> /*unused*/, std::initializer_list<U> il,
862 Args &&... args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<U>, Args...>::value)
92f5a8d4 863 : _value(il, static_cast<Args &&>(args)...)
f67539c2 864 , _status(status::have_value)
92f5a8d4
TL
865 {
866 }
f67539c2
TL
867 template <class U>
868 static constexpr bool enable_converting_constructor = !std::is_same<std::decay_t<U>, value_type>::value && std::is_constructible<value_type, U>::value;
92f5a8d4
TL
869 BOOST_OUTCOME_TEMPLATE(class U)
870 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
871 constexpr explicit value_storage_nontrivial(const value_storage_nontrivial<U> &o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
f67539c2 872 : value_storage_nontrivial(o._status.have_value() ? value_storage_nontrivial(in_place_type<value_type>, o._value) : value_storage_nontrivial())
92f5a8d4
TL
873 {
874 _status = o._status;
875 }
876 BOOST_OUTCOME_TEMPLATE(class U)
877 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
878 constexpr explicit value_storage_nontrivial(const value_storage_trivial<U> &o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
f67539c2 879 : value_storage_nontrivial(o._status.have_value() ? value_storage_nontrivial(in_place_type<value_type>, o._value) : value_storage_nontrivial())
92f5a8d4
TL
880 {
881 _status = o._status;
882 }
883 BOOST_OUTCOME_TEMPLATE(class U)
884 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
885 constexpr explicit value_storage_nontrivial(value_storage_nontrivial<U> &&o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
f67539c2
TL
886 : value_storage_nontrivial(o._status.have_value() ? value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
887 value_storage_nontrivial())
92f5a8d4
TL
888 {
889 _status = o._status;
890 }
891 BOOST_OUTCOME_TEMPLATE(class U)
892 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
893 constexpr explicit value_storage_nontrivial(value_storage_trivial<U> &&o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
f67539c2
TL
894 : value_storage_nontrivial(o._status.have_value() ? value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
895 value_storage_nontrivial())
92f5a8d4
TL
896 {
897 _status = o._status;
898 }
899 ~value_storage_nontrivial() noexcept(std::is_nothrow_destructible<T>::value)
900 {
f67539c2 901 if(this->_status.have_value())
92f5a8d4
TL
902 {
903 this->_value.~value_type(); // NOLINT
f67539c2 904 this->_status.set_have_value(false);
92f5a8d4
TL
905 }
906 }
907 constexpr void swap(value_storage_nontrivial &o) noexcept(detail::is_nothrow_swappable<value_type>::value)
908 {
909 using std::swap;
f67539c2 910 if(!_status.have_value() && !o._status.have_value())
92f5a8d4
TL
911 {
912 swap(_status, o._status);
913 return;
914 }
f67539c2 915 if(_status.have_value() && o._status.have_value())
92f5a8d4
TL
916 {
917 struct _
918 {
f67539c2 919 status_bitfield_type &a, &b;
92f5a8d4
TL
920 bool all_good{false};
921 ~_()
922 {
923 if(!all_good)
924 {
925 // We lost one of the values
f67539c2
TL
926 a.set_have_lost_consistency(true);
927 b.set_have_lost_consistency(true);
92f5a8d4
TL
928 }
929 }
930 } _{_status, o._status};
931 strong_swap(_.all_good, _value, o._value);
932 swap(_status, o._status);
933 return;
934 }
935 // One must be empty and the other non-empty, so use move construction
f67539c2 936 if(_status.have_value())
92f5a8d4
TL
937 {
938 // Move construct me into other
939 new(&o._value) value_type(static_cast<value_type &&>(_value)); // NOLINT
940 this->_value.~value_type(); // NOLINT
941 swap(_status, o._status);
942 }
943 else
944 {
945 // Move construct other into me
946 new(&_value) value_type(static_cast<value_type &&>(o._value)); // NOLINT
947 o._value.~value_type(); // NOLINT
948 swap(_status, o._status);
949 }
950 }
951 };
952 template <class Base> struct value_storage_delete_copy_constructor : Base // NOLINT
953 {
954 using Base::Base;
955 using value_type = typename Base::value_type;
956 value_storage_delete_copy_constructor() = default;
957 value_storage_delete_copy_constructor(const value_storage_delete_copy_constructor &) = delete;
958 value_storage_delete_copy_constructor(value_storage_delete_copy_constructor &&) = default; // NOLINT
959 };
960 template <class Base> struct value_storage_delete_copy_assignment : Base // NOLINT
961 {
962 using Base::Base;
963 using value_type = typename Base::value_type;
964 value_storage_delete_copy_assignment() = default;
965 value_storage_delete_copy_assignment(const value_storage_delete_copy_assignment &) = default;
966 value_storage_delete_copy_assignment(value_storage_delete_copy_assignment &&) = default; // NOLINT
967 value_storage_delete_copy_assignment &operator=(const value_storage_delete_copy_assignment &o) = delete;
968 value_storage_delete_copy_assignment &operator=(value_storage_delete_copy_assignment &&o) = default; // NOLINT
969 };
970 template <class Base> struct value_storage_delete_move_assignment : Base // NOLINT
971 {
972 using Base::Base;
973 using value_type = typename Base::value_type;
974 value_storage_delete_move_assignment() = default;
975 value_storage_delete_move_assignment(const value_storage_delete_move_assignment &) = default;
976 value_storage_delete_move_assignment(value_storage_delete_move_assignment &&) = default; // NOLINT
977 value_storage_delete_move_assignment &operator=(const value_storage_delete_move_assignment &o) = default;
978 value_storage_delete_move_assignment &operator=(value_storage_delete_move_assignment &&o) = delete;
979 };
980 template <class Base> struct value_storage_delete_move_constructor : Base // NOLINT
981 {
982 using Base::Base;
983 using value_type = typename Base::value_type;
984 value_storage_delete_move_constructor() = default;
985 value_storage_delete_move_constructor(const value_storage_delete_move_constructor &) = default;
986 value_storage_delete_move_constructor(value_storage_delete_move_constructor &&) = delete;
987 };
988 template <class Base> struct value_storage_nontrivial_move_assignment : Base // NOLINT
989 {
990 using Base::Base;
991 using value_type = typename Base::value_type;
992 value_storage_nontrivial_move_assignment() = default;
993 value_storage_nontrivial_move_assignment(const value_storage_nontrivial_move_assignment &) = default;
994 value_storage_nontrivial_move_assignment(value_storage_nontrivial_move_assignment &&) = default; // NOLINT
995 value_storage_nontrivial_move_assignment &operator=(const value_storage_nontrivial_move_assignment &o) = default;
f67539c2
TL
996 value_storage_nontrivial_move_assignment &
997 operator=(value_storage_nontrivial_move_assignment &&o) noexcept(std::is_nothrow_move_assignable<value_type>::value) // NOLINT
92f5a8d4 998 {
f67539c2 999 if(this->_status.have_value() && o._status.have_value())
92f5a8d4
TL
1000 {
1001 this->_value = static_cast<value_type &&>(o._value); // NOLINT
1002 }
f67539c2 1003 else if(this->_status.have_value() && !o._status.have_value())
92f5a8d4
TL
1004 {
1005 this->_value.~value_type(); // NOLINT
1006 }
f67539c2 1007 else if(!this->_status.have_value() && o._status.have_value())
92f5a8d4
TL
1008 {
1009 new(&this->_value) value_type(static_cast<value_type &&>(o._value)); // NOLINT
1010 }
1011 this->_status = o._status;
1012 return *this;
1013 }
1014 };
1015 template <class Base> struct value_storage_nontrivial_copy_assignment : Base // NOLINT
1016 {
1017 using Base::Base;
1018 using value_type = typename Base::value_type;
1019 value_storage_nontrivial_copy_assignment() = default;
1020 value_storage_nontrivial_copy_assignment(const value_storage_nontrivial_copy_assignment &) = default;
1021 value_storage_nontrivial_copy_assignment(value_storage_nontrivial_copy_assignment &&) = default; // NOLINT
1022 value_storage_nontrivial_copy_assignment &operator=(value_storage_nontrivial_copy_assignment &&o) = default; // NOLINT
f67539c2
TL
1023 value_storage_nontrivial_copy_assignment &
1024 operator=(const value_storage_nontrivial_copy_assignment &o) noexcept(std::is_nothrow_copy_assignable<value_type>::value)
92f5a8d4 1025 {
f67539c2 1026 if(this->_status.have_value() && o._status.have_value())
92f5a8d4
TL
1027 {
1028 this->_value = o._value; // NOLINT
1029 }
f67539c2 1030 else if(this->_status.have_value() && !o._status.have_value())
92f5a8d4
TL
1031 {
1032 this->_value.~value_type(); // NOLINT
1033 }
f67539c2 1034 else if(!this->_status.have_value() && o._status.have_value())
92f5a8d4
TL
1035 {
1036 new(&this->_value) value_type(o._value); // NOLINT
1037 }
1038 this->_status = o._status;
1039 return *this;
1040 }
1041 };
1042
1043 // We don't actually need all of std::is_trivial<>, std::is_trivially_copyable<> is sufficient
92f5a8d4 1044 template <class T>
f67539c2
TL
1045 using value_storage_select_trivality =
1046 std::conditional_t<std::is_trivially_copyable<devoid<T>>::value, value_storage_trivial<T>, value_storage_nontrivial<T>>;
1047 template <class T>
1048 using value_storage_select_move_constructor = std::conditional_t<std::is_move_constructible<devoid<T>>::value, value_storage_select_trivality<T>,
1049 value_storage_delete_move_constructor<value_storage_select_trivality<T>>>;
1050 template <class T>
1051 using value_storage_select_copy_constructor = std::conditional_t<std::is_copy_constructible<devoid<T>>::value, value_storage_select_move_constructor<T>,
1052 value_storage_delete_copy_constructor<value_storage_select_move_constructor<T>>>;
1053 template <class T>
1054 using value_storage_select_move_assignment = std::conditional_t<
1055 std::is_trivially_move_assignable<devoid<T>>::value, value_storage_select_copy_constructor<T>,
1056 std::conditional_t<std::is_move_assignable<devoid<T>>::value, value_storage_nontrivial_move_assignment<value_storage_select_copy_constructor<T>>,
1057 value_storage_delete_copy_assignment<value_storage_select_copy_constructor<T>>>>;
92f5a8d4 1058 template <class T>
f67539c2
TL
1059 using value_storage_select_copy_assignment = std::conditional_t<
1060 std::is_trivially_copy_assignable<devoid<T>>::value, value_storage_select_move_assignment<T>,
1061 std::conditional_t<std::is_copy_assignable<devoid<T>>::value, value_storage_nontrivial_copy_assignment<value_storage_select_move_assignment<T>>,
1062 value_storage_delete_copy_assignment<value_storage_select_move_assignment<T>>>>;
92f5a8d4
TL
1063 template <class T> using value_storage_select_impl = value_storage_select_copy_assignment<T>;
1064#ifndef NDEBUG
1065 // Check is trivial in all ways except default constructibility
1066 // static_assert(std::is_trivial<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivial!");
f67539c2
TL
1067 // static_assert(std::is_trivially_default_constructible<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially default
1068 // constructible!");
92f5a8d4 1069 static_assert(std::is_trivially_copyable<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially copyable!");
f67539c2
TL
1070 static_assert(std::is_trivially_assignable<value_storage_select_impl<int>, value_storage_select_impl<int>>::value,
1071 "value_storage_select_impl<int> is not trivially assignable!");
92f5a8d4 1072 static_assert(std::is_trivially_destructible<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially destructible!");
f67539c2
TL
1073 static_assert(std::is_trivially_copy_constructible<value_storage_select_impl<int>>::value,
1074 "value_storage_select_impl<int> is not trivially copy constructible!");
1075 static_assert(std::is_trivially_move_constructible<value_storage_select_impl<int>>::value,
1076 "value_storage_select_impl<int> is not trivially move constructible!");
92f5a8d4
TL
1077 static_assert(std::is_trivially_copy_assignable<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially copy assignable!");
1078 static_assert(std::is_trivially_move_assignable<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially move assignable!");
1079 // Also check is standard layout
1080 static_assert(std::is_standard_layout<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not a standard layout type!");
1081#endif
1082} // namespace detail
1083
1084BOOST_OUTCOME_V2_NAMESPACE_END
1085
1086#endif