1/* Essentially an internal optional implementation :)
2(C) 2017-2024 Niall Douglas <http://www.nedproductions.biz/> (24 commits)
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
36BOOST_OUTCOME_V2_NAMESPACE_EXPORT_BEGIN
37
38namespace detail
39{
40 // Helpers for move assigning to empty storage
41 template <class T, bool isCopyOrMoveConstructible = std::is_copy_constructible<T>::value || std::is_move_constructible<T>::value,
42 bool isDefaultConstructibleAndCopyOrMoveAssignable =
43 std::is_default_constructible<T>::value && (std::is_copy_assignable<T>::value || std::is_move_assignable<T>::value)>
44 struct move_assign_to_empty;
45 // Prefer to use move or copy construction
46 template <class T> struct move_assign_to_empty<T, true, false>
47 {
48 move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible<T>::value) { new(dest) T(static_cast<T &&>(*o)); }
49 };
50 template <class T> struct move_assign_to_empty<T, true, true>
51 {
52 move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible<T>::value) { new(dest) T(static_cast<T &&>(*o)); }
53 };
54 // But fall back on default construction and move assign if necessary
55 template <class T> struct move_assign_to_empty<T, false, true>
56 {
57 move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_default_constructible<T>::value && std::is_nothrow_move_assignable<T>::value)
58 {
59 new(dest) T;
60 *dest = static_cast<T &&>(*o);
61 }
62 };
63 // Void does nothing
64 template <> struct move_assign_to_empty<void, false, false>
65 {
66 move_assign_to_empty(void *, void *) noexcept
67 { /* nothing to assign */
68 }
69 };
70 template <> struct move_assign_to_empty<const void, false, false>
71 {
72 move_assign_to_empty(const void *, const void *) noexcept
73 { /* nothing to assign */
74 }
75 };
76 // Helpers for copy assigning to empty storage
77 template <class T, bool isCopyConstructible = std::is_copy_constructible<T>::value,
78 bool isDefaultConstructibleAndCopyAssignable = std::is_default_constructible<T>::value && std::is_copy_assignable<T>::value>
79 struct copy_assign_to_empty;
80 // Prefer to use copy construction
81 template <class T> struct copy_assign_to_empty<T, true, false>
82 {
83 copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible<T>::value) { new(dest) T(*o); }
84 };
85 template <class T> struct copy_assign_to_empty<T, true, true>
86 {
87 copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible<T>::value) { new(dest) T(*o); }
88 };
89 // But fall back on default construction and copy assign if necessary
90 template <class T> struct copy_assign_to_empty<T, false, true>
91 {
92 copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_default_constructible<T>::value && std::is_nothrow_copy_assignable<T>::value)
93 {
94 new(dest) T;
95 *dest = *o;
96 }
97 };
98 // Void does nothing
99 template <> struct copy_assign_to_empty<void, false, false>
100 {
101 copy_assign_to_empty(void *, void *) noexcept
102 { /* nothing to assign */
103 }
104 };
105 template <> struct copy_assign_to_empty<const void, false, false>
106 {
107 copy_assign_to_empty(const void *, const void *) noexcept
108 { /* nothing to assign */
109 }
110 };
111
112 template <class T, bool nothrow> struct strong_swap_impl
113 {
114 constexpr strong_swap_impl(bool &allgood, T &a, T &b)
115 {
116 allgood = true;
117 using std::swap;
118 swap(a, b);
119 }
120 };
121 template <class T, bool nothrow> struct strong_placement_impl
122 {
123 template <class F> constexpr strong_placement_impl(bool &allgood, T *a, T *b, F &&f)
124 {
125 allgood = true;
126 new(a) T(static_cast<T &&>(*b));
127 b->~T();
128 f();
129 }
130 };
131#ifndef BOOST_NO_EXCEPTIONS
132 template <class T> struct strong_swap_impl<T, false>
133 {
134 strong_swap_impl(bool &allgood, T &a, T &b)
135 {
136 allgood = true;
137 T v(static_cast<T &&>(a));
138 try
139 {
140 a = static_cast<T &&>(b);
141 }
142 catch(...)
143 {
144 // Try to put back a
145 try
146 {
147 a = static_cast<T &&>(v);
148 // fall through as all good
149 }
150 catch(...)
151 {
152 // failed to completely restore
153 allgood = false;
154 // throw away second exception
155 }
156 throw; // rethrow original exception
157 }
158 // b has been moved to a, try to move v to b
159 try
160 {
161 b = static_cast<T &&>(v);
162 }
163 catch(...)
164 {
165 // Try to restore a to b, and v to a
166 try
167 {
168 b = static_cast<T &&>(a);
169 a = static_cast<T &&>(v);
170 // fall through as all good
171 }
172 catch(...)
173 {
174 // failed to completely restore
175 allgood = false;
176 // throw away second exception
177 }
178 throw; // rethrow original exception
179 }
180 }
181 };
182 template <class T> struct strong_placement_impl<T, false>
183 {
184 template <class F> strong_placement_impl(bool &allgood, T *a, T *b, F &&f)
185 {
186 new(a) T(static_cast<T &&>(*b));
187 try
188 {
189 b->~T();
190 f();
191 }
192 catch(...)
193 {
194 // Try to put back a, but only if we are still good
195 if(allgood)
196 {
197 try
198 {
199 new(b) T(static_cast<T &&>(*a));
200 // fall through as all good
201 }
202 catch(...)
203 {
204 // failed to completely restore
205 allgood = false;
206 // throw away second exception
207 }
208 throw; // rethrow original exception
209 }
210 }
211 }
212 };
213#endif
214} // namespace detail
215
216/*!
217 */
218BOOST_OUTCOME_TEMPLATE(class T)
219BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
220constexpr inline void strong_swap(bool &allgood, T &a, T &b) noexcept(detail::is_nothrow_swappable<T>::value)
221{
222 detail::strong_swap_impl<T, detail::is_nothrow_swappable<T>::value>(allgood, a, b);
223}
224/*!
225 */
226BOOST_OUTCOME_TEMPLATE(class T, class F)
227BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
228constexpr inline void strong_placement(bool &allgood, T *a, T *b, F &&f) noexcept(std::is_nothrow_move_constructible<T>::value)
229{
230 detail::strong_placement_impl<T, std::is_nothrow_move_constructible<T>::value>(allgood, a, b, static_cast<F &&>(f));
231}
232
233namespace detail
234{
235 template <class T>
236 constexpr
237#ifdef _MSC_VER
238 __declspec(noreturn)
239#elif defined(__GNUC__) || defined(__clang__)
240 __attribute__((noreturn))
241#endif
242 void make_ub(T && /*unused*/)
243 {
244 BOOST_OUTCOME_ASSERT(false); // NOLINT
245#if defined(__GNUC__) || defined(__clang__)
246 __builtin_unreachable();
247#elif defined(_MSC_VER)
248 __assume(0);
249#endif
250 }
251
252 /* Outcome v1 used a C bitfield whose values were tracked by compiler optimisers nicely,
253 but that produces ICEs when used in constexpr.
254
255 Outcome v2.0-v2.1 used a 32 bit integer and manually set and cleared bits. Unfortunately
256 only GCC's optimiser tracks bit values during constant folding, and only per byte, and
257 even then unreliably. https://wg21.link/P1886 "Error speed benchmarking" showed just how
258 poorly clang and MSVC fails to optimise outcome-using code, if you manually set bits.
259
260 Outcome v2.2 therefore uses an enum with fixed values, and constexpr manipulation functions
261 to change the value to one of the enum's values. This is stupid to look at in source code,
262 but it make clang's optimiser do the right thing, so it's worth it.
263 */
264#define BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS 0
265 enum class status : uint16_t
266 {
267 // WARNING: These bits are not tracked by abi-dumper, but changing them will break ABI!
268 none = 0,
269
270 have_value = (1U << 0U),
271 have_error = (1U << 1U),
272 have_exception = (2U << 1U),
273 have_error_exception = (3U << 1U),
274
275 // failed to complete a strong swap
276 have_lost_consistency = (1U << 3U),
277 have_value_lost_consistency = (1U << 0U) | (1U << 3U),
278 have_error_lost_consistency = (1U << 1U) | (1U << 3U),
279 have_exception_lost_consistency = (2U << 1U) | (1U << 3U),
280 have_error_exception_lost_consistency = (3U << 1U) | (1U << 3U),
281
282 // can errno be set from this error?
283 have_error_is_errno = (1U << 4U),
284 have_error_error_is_errno = (1U << 1U) | (1U << 4U),
285 have_error_exception_error_is_errno = (3U << 1U) | (1U << 4U),
286
287 have_error_lost_consistency_error_is_errno = (1U << 1U) | (1U << 3U) | (1U << 4U),
288 have_error_exception_lost_consistency_error_is_errno = (3U << 1U) | (1U << 3U) | (1U << 4U),
289
290 // value has been moved from
291 have_moved_from = (1U << 5U)
292 };
293 struct status_bitfield_type
294 {
295 status status_value{status::none};
296 uint16_t spare_storage_value{0}; // hooks::spare_storage()
297
298 constexpr status_bitfield_type() = default;
299 constexpr status_bitfield_type(status v) noexcept
300 : status_value(v)
301 {
302 } // NOLINT
303 constexpr status_bitfield_type(status v, uint16_t s) noexcept
304 : status_value(v)
305 , spare_storage_value(s)
306 {
307 }
308 constexpr status_bitfield_type(const status_bitfield_type &) = default;
309 constexpr status_bitfield_type(status_bitfield_type &&) = default;
310 constexpr status_bitfield_type &operator=(const status_bitfield_type &) = default;
311 constexpr status_bitfield_type &operator=(status_bitfield_type &&) = default;
312 //~status_bitfield_type() = default; // Do NOT uncomment this, it breaks older clangs!
313
314 constexpr bool have_value() const noexcept
315 {
316#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
317 return (status_value == status::have_value) //
318 || (status_value == status::have_value_lost_consistency) //
319 ;
320#else
321 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_value)) != 0;
322#endif
323 }
324 constexpr bool have_error() const noexcept
325 {
326#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
327 return (status_value == status::have_error) //
328 || (status_value == status::have_error_exception) //
329 || (status_value == status::have_error_lost_consistency) //
330 || (status_value == status::have_error_exception_lost_consistency) //
331 || (status_value == status::have_error_error_is_errno) //
332 || (status_value == status::have_error_exception_error_is_errno) //
333 || (status_value == status::have_error_lost_consistency_error_is_errno) //
334 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
335 ;
336#else
337 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error)) != 0;
338#endif
339 }
340 constexpr bool have_exception() const noexcept
341 {
342#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
343 return (status_value == status::have_exception) //
344 || (status_value == status::have_error_exception) //
345 || (status_value == status::have_exception_lost_consistency) //
346 || (status_value == status::have_error_exception_lost_consistency) //
347 || (status_value == status::have_error_exception_error_is_errno) //
348 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
349 ;
350#else
351 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_exception)) != 0;
352#endif
353 }
354 constexpr bool have_lost_consistency() const noexcept
355 {
356#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
357 return (status_value == status::have_value_lost_consistency) //
358 || (status_value == status::have_error_lost_consistency) //
359 || (status_value == status::have_exception_lost_consistency) //
360 || (status_value == status::have_error_lost_consistency_error_is_errno) //
361 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
362 ;
363#else
364 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_lost_consistency)) != 0;
365#endif
366 }
367 constexpr bool have_error_is_errno() const noexcept
368 {
369#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
370 return (status_value == status::have_error_error_is_errno) //
371 || (status_value == status::have_error_exception_error_is_errno) //
372 || (status_value == status::have_error_lost_consistency_error_is_errno) //
373 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
374 ;
375#else
376 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error_is_errno)) != 0;
377#endif
378 }
379 constexpr bool have_moved_from() const noexcept
380 {
381#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
382#error Fixme
383#else
384 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_moved_from)) != 0;
385#endif
386 }
387
388 constexpr status_bitfield_type &set_have_value(bool v) noexcept
389 {
390#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
391 switch(status_value)
392 {
393 case status::none:
394 if(v)
395 {
396 status_value = status::have_value;
397 }
398 break;
399 case status::have_value:
400 if(!v)
401 {
402 status_value = status::none;
403 }
404 break;
405 case status::have_error:
406 if(v)
407 {
408 make_ub(*this);
409 }
410 break;
411 case status::have_exception:
412 if(v)
413 {
414 make_ub(*this);
415 }
416 break;
417 case status::have_error_exception:
418 if(v)
419 {
420 make_ub(*this);
421 }
422 break;
423 case status::have_value_lost_consistency:
424 if(!v)
425 {
426 status_value = status::none;
427 }
428 break;
429 case status::have_error_lost_consistency:
430 if(v)
431 {
432 make_ub(*this);
433 }
434 break;
435 case status::have_exception_lost_consistency:
436 if(v)
437 {
438 make_ub(*this);
439 }
440 break;
441 case status::have_error_exception_lost_consistency:
442 if(v)
443 {
444 make_ub(*this);
445 }
446 break;
447 case status::have_error_error_is_errno:
448 if(v)
449 {
450 make_ub(*this);
451 }
452 break;
453 case status::have_error_exception_error_is_errno:
454 if(v)
455 {
456 make_ub(*this);
457 }
458 break;
459 case status::have_error_lost_consistency_error_is_errno:
460 if(v)
461 {
462 make_ub(*this);
463 }
464 break;
465 case status::have_error_exception_lost_consistency_error_is_errno:
466 if(v)
467 {
468 make_ub(*this);
469 }
470 break;
471 }
472#else
473 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_value)) :
474 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_value)));
475#endif
476 return *this;
477 }
478 constexpr status_bitfield_type &set_have_error(bool v) noexcept
479 {
480#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
481 switch(status_value)
482 {
483 case status::none:
484 if(v)
485 {
486 status_value = status::have_error;
487 }
488 break;
489 case status::have_value:
490 if(v)
491 {
492 make_ub(*this);
493 }
494 break;
495 case status::have_error:
496 if(!v)
497 {
498 status_value = status::none;
499 }
500 break;
501 case status::have_exception:
502 if(v)
503 {
504 status_value = status::have_error_exception;
505 }
506 break;
507 case status::have_error_exception:
508 if(!v)
509 {
510 status_value = status::have_exception;
511 }
512 break;
513 case status::have_value_lost_consistency:
514 if(v)
515 {
516 make_ub(*this);
517 }
518 break;
519 case status::have_error_lost_consistency:
520 if(!v)
521 {
522 status_value = status::none;
523 }
524 break;
525 case status::have_exception_lost_consistency:
526 if(v)
527 {
528 status_value = status::have_error_exception_lost_consistency;
529 }
530 break;
531 case status::have_error_exception_lost_consistency:
532 if(!v)
533 {
534 status_value = status::have_exception_lost_consistency;
535 }
536 break;
537 case status::have_error_error_is_errno:
538 if(!v)
539 {
540 status_value = status::none;
541 }
542 break;
543 case status::have_error_exception_error_is_errno:
544 if(!v)
545 {
546 status_value = status::have_exception;
547 }
548 break;
549 case status::have_error_lost_consistency_error_is_errno:
550 if(!v)
551 {
552 status_value = status::none;
553 }
554 break;
555 case status::have_error_exception_lost_consistency_error_is_errno:
556 if(!v)
557 {
558 status_value = status::have_exception_lost_consistency;
559 }
560 break;
561 }
562#else
563 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error)) :
564 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error)));
565#endif
566 return *this;
567 }
568 constexpr status_bitfield_type &set_have_exception(bool v) noexcept
569 {
570#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
571 switch(status_value)
572 {
573 case status::none:
574 if(v)
575 {
576 status_value = status::have_exception;
577 }
578 break;
579 case status::have_value:
580 if(v)
581 {
582 make_ub(*this);
583 }
584 break;
585 case status::have_error:
586 if(v)
587 {
588 status_value = status::have_error_exception;
589 }
590 break;
591 case status::have_exception:
592 if(!v)
593 {
594 status_value = status::none;
595 }
596 break;
597 case status::have_error_exception:
598 if(!v)
599 {
600 status_value = status::have_error;
601 }
602 break;
603 case status::have_value_lost_consistency:
604 if(v)
605 {
606 make_ub(*this);
607 }
608 break;
609 case status::have_error_lost_consistency:
610 if(v)
611 {
612 status_value = status::have_error_exception_lost_consistency;
613 }
614 break;
615 case status::have_exception_lost_consistency:
616 if(!v)
617 {
618 status_value = status::none;
619 }
620 break;
621 case status::have_error_exception_lost_consistency:
622 if(!v)
623 {
624 status_value = status::have_error_lost_consistency;
625 }
626 break;
627 case status::have_error_error_is_errno:
628 if(v)
629 {
630 status_value = status::have_error_exception_error_is_errno;
631 }
632 break;
633 case status::have_error_exception_error_is_errno:
634 if(!v)
635 {
636 status_value = status::have_error_error_is_errno;
637 }
638 break;
639 case status::have_error_lost_consistency_error_is_errno:
640 if(v)
641 {
642 status_value = status::have_error_exception_lost_consistency_error_is_errno;
643 }
644 break;
645 case status::have_error_exception_lost_consistency_error_is_errno:
646 if(!v)
647 {
648 status_value = status::have_error_lost_consistency_error_is_errno;
649 }
650 break;
651 }
652#else
653 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_exception)) :
654 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_exception)));
655#endif
656 return *this;
657 }
658 constexpr status_bitfield_type &set_have_error_is_errno(bool v) noexcept
659 {
660#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
661 switch(status_value)
662 {
663 case status::none:
664 make_ub(*this);
665 break;
666 case status::have_value:
667 make_ub(*this);
668 break;
669 case status::have_error:
670 if(v)
671 {
672 status_value = status::have_error_error_is_errno;
673 }
674 break;
675 case status::have_exception:
676 make_ub(*this);
677 break;
678 case status::have_error_exception:
679 if(v)
680 {
681 status_value = status::have_error_exception_error_is_errno;
682 }
683 break;
684 case status::have_value_lost_consistency:
685 make_ub(*this);
686 break;
687 case status::have_error_lost_consistency:
688 if(v)
689 {
690 status_value = status::have_error_lost_consistency_error_is_errno;
691 }
692 break;
693 case status::have_exception_lost_consistency:
694 make_ub(*this);
695 break;
696 case status::have_error_exception_lost_consistency:
697 if(v)
698 {
699 status_value = status::have_error_exception_lost_consistency_error_is_errno;
700 }
701 break;
702 case status::have_error_error_is_errno:
703 if(!v)
704 {
705 status_value = status::have_error;
706 }
707 break;
708 case status::have_error_exception_error_is_errno:
709 if(!v)
710 {
711 status_value = status::have_error_exception;
712 }
713 break;
714 case status::have_error_lost_consistency_error_is_errno:
715 if(!v)
716 {
717 status_value = status::have_error_lost_consistency;
718 }
719 break;
720 case status::have_error_exception_lost_consistency_error_is_errno:
721 if(!v)
722 {
723 status_value = status::have_error_exception_lost_consistency;
724 }
725 break;
726 }
727#else
728 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error_is_errno)) :
729 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error_is_errno)));
730#endif
731 return *this;
732 }
733 constexpr status_bitfield_type &set_have_lost_consistency(bool v) noexcept
734 {
735#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
736 switch(status_value)
737 {
738 case status::none:
739 if(v)
740 {
741 make_ub(*this);
742 }
743 break;
744 case status::have_value:
745 if(v)
746 {
747 status_value = status::have_value_lost_consistency;
748 }
749 break;
750 case status::have_error:
751 if(v)
752 {
753 status_value = status::have_error_lost_consistency;
754 }
755 break;
756 case status::have_exception:
757 if(v)
758 {
759 status_value = status::have_exception_lost_consistency;
760 }
761 break;
762 case status::have_error_exception:
763 if(v)
764 {
765 status_value = status::have_error_exception_lost_consistency;
766 }
767 break;
768 case status::have_value_lost_consistency:
769 if(!v)
770 {
771 status_value = status::have_value;
772 }
773 break;
774 case status::have_error_lost_consistency:
775 if(!v)
776 {
777 status_value = status::have_error;
778 }
779 break;
780 case status::have_exception_lost_consistency:
781 if(!v)
782 {
783 status_value = status::have_exception;
784 }
785 break;
786 case status::have_error_exception_lost_consistency:
787 if(!v)
788 {
789 status_value = status::have_error_exception;
790 }
791 break;
792 case status::have_error_error_is_errno:
793 if(v)
794 {
795 status_value = status::have_error_lost_consistency_error_is_errno;
796 }
797 break;
798 case status::have_error_exception_error_is_errno:
799 if(v)
800 {
801 status_value = status::have_error_exception_lost_consistency_error_is_errno;
802 }
803 break;
804 case status::have_error_lost_consistency_error_is_errno:
805 if(!v)
806 {
807 status_value = status::have_error_exception_error_is_errno;
808 }
809 break;
810 case status::have_error_exception_lost_consistency_error_is_errno:
811 if(!v)
812 {
813 status_value = status::have_error_exception_error_is_errno;
814 }
815 break;
816 }
817#else
818 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_lost_consistency)) :
819 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_lost_consistency)));
820#endif
821 return *this;
822 }
823 constexpr status_bitfield_type &set_have_moved_from(bool v) noexcept
824 {
825#if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
826#error Fixme
827#else
828 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_moved_from)) :
829 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_moved_from)));
830#endif
831 return *this;
832 }
833 };
834#if !defined(NDEBUG)
835 // Check is trivial in all ways except default constructibility
836 static_assert(sizeof(status_bitfield_type) == 4, "status_bitfield_type is not sized 4 bytes!");
837 static_assert(std::is_trivially_copyable<status_bitfield_type>::value, "status_bitfield_type is not trivially copyable!");
838 static_assert(std::is_trivially_assignable<status_bitfield_type, status_bitfield_type>::value, "status_bitfield_type is not trivially assignable!");
839 static_assert(std::is_trivially_destructible<status_bitfield_type>::value, "status_bitfield_type is not trivially destructible!");
840 static_assert(std::is_trivially_copy_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially copy constructible!");
841 static_assert(std::is_trivially_move_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially move constructible!");
842 static_assert(std::is_trivially_copy_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially copy assignable!");
843 static_assert(std::is_trivially_move_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially move assignable!");
844 // Also check is standard layout
845 static_assert(std::is_standard_layout<status_bitfield_type>::value, "status_bitfield_type is not a standard layout type!");
846#endif
847
848 template <class State> constexpr inline void _set_error_is_errno(State & /*unused*/) {}
849
850#ifdef _MSC_VER
851#pragma warning(push)
852#pragma warning(disable : 4127) // conditional expression is constant
853#pragma warning(disable : 4624) // destructor was implicitly defined as deleted
854#endif
855 // Used if both T and E are trivial
856 template <class T, class E> struct value_storage_trivial
857 {
858 using value_type = T;
859 using error_type = E;
860
861 // Disable in place construction if they are the same type
862 struct disable_in_place_value_type
863 {
864 };
865 struct disable_in_place_error_type
866 {
867 };
868 using _value_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_value_type, value_type>;
869 using _error_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_error_type, error_type>;
870 using _value_type_ = devoid<value_type>;
871 using _error_type_ = devoid<error_type>;
872
873 union
874 {
875 empty_type _empty;
876 _value_type_ _value;
877 _error_type_ _error;
878 };
879 status_bitfield_type _status;
880 constexpr value_storage_trivial() noexcept
881 : _empty{}
882 {
883 }
884 value_storage_trivial(const value_storage_trivial &) = default; // NOLINT
885 value_storage_trivial(value_storage_trivial &&) = default; // NOLINT
886 value_storage_trivial &operator=(const value_storage_trivial &) = default; // NOLINT
887 value_storage_trivial &operator=(value_storage_trivial &&) = default; // NOLINT
888 ~value_storage_trivial() = default;
889 constexpr explicit value_storage_trivial(status_bitfield_type status)
890 : _empty()
891 , _status(status)
892 {
893 }
894 template <class... Args>
895 constexpr explicit value_storage_trivial(in_place_type_t<_value_type> /*unused*/,
896 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, Args...>)
897 : _value(static_cast<Args &&>(args)...)
898 , _status(status::have_value)
899 {
900 }
901 template <class U, class... Args>
902 constexpr value_storage_trivial(in_place_type_t<_value_type> /*unused*/, std::initializer_list<U> il,
903 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, std::initializer_list<U>, Args...>)
904 : _value(il, static_cast<Args &&>(args)...)
905 , _status(status::have_value)
906 {
907 }
908 template <class... Args>
909 constexpr explicit value_storage_trivial(in_place_type_t<_error_type> /*unused*/,
910 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, Args...>)
911 : _error(static_cast<Args &&>(args)...)
912 , _status(status::have_error)
913 {
914 _set_error_is_errno(*this);
915 }
916 template <class U, class... Args>
917 constexpr value_storage_trivial(in_place_type_t<_error_type> /*unused*/, std::initializer_list<U> il,
918 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, std::initializer_list<U>, Args...>)
919 : _error(il, static_cast<Args &&>(args)...)
920 , _status(status::have_error)
921 {
922 _set_error_is_errno(*this);
923 }
924
925 struct nonvoid_converting_constructor_tag
926 {
927 };
928 template <class U, class V>
929 static constexpr bool enable_nonvoid_converting_constructor =
930 !(std::is_same<std::decay_t<U>, value_type>::value && std::is_same<std::decay_t<V>, error_type>::value) //
931 && detail::is_constructible<value_type, U> && detail::is_constructible<error_type, V>;
932 BOOST_OUTCOME_TEMPLATE(class U, class V)
933 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
934 constexpr explicit value_storage_trivial(const value_storage_trivial<U, V> &o,
935 nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(detail::is_nothrow_constructible<_value_type_, U> &&
936 detail::is_nothrow_constructible<_error_type_, V>)
937 : value_storage_trivial(o._status.have_value() ?
938 value_storage_trivial(in_place_type<value_type>, o._value) :
939 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, o._error) : value_storage_trivial())) // NOLINT
940 {
941 _status = o._status;
942 }
943 BOOST_OUTCOME_TEMPLATE(class U, class V)
944 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
945 constexpr explicit value_storage_trivial(value_storage_trivial<U, V> &&o,
946 nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(detail::is_nothrow_constructible<_value_type_, U> &&
947 detail::is_nothrow_constructible<_error_type_, V>)
948 : value_storage_trivial(
949 o._status.have_value() ?
950 value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
951 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_trivial())) // NOLINT
952 {
953 _status = o._status;
954 }
955
956 struct void_value_converting_constructor_tag
957 {
958 };
959 template <class V>
960 static constexpr bool enable_void_value_converting_constructor =
961 std::is_default_constructible<value_type>::value && detail::is_constructible<error_type, V>;
962 BOOST_OUTCOME_TEMPLATE(class V)
963 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
964 constexpr explicit value_storage_trivial(const value_storage_trivial<void, V> &o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
965 std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
966 : value_storage_trivial(o._status.have_value() ?
967 value_storage_trivial(in_place_type<value_type>) :
968 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, o._error) : value_storage_trivial())) // NOLINT
969 {
970 _status = o._status;
971 }
972 BOOST_OUTCOME_TEMPLATE(class V)
973 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
974 constexpr explicit value_storage_trivial(value_storage_trivial<void, V> &&o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
975 std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
976 : value_storage_trivial(
977 o._status.have_value() ?
978 value_storage_trivial(in_place_type<value_type>) :
979 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_trivial())) // NOLINT
980 {
981 _status = o._status;
982 }
983
984 struct void_error_converting_constructor_tag
985 {
986 };
987 template <class U>
988 static constexpr bool enable_void_error_converting_constructor =
989 std::is_default_constructible<error_type>::value && detail::is_constructible<value_type, U>;
990 BOOST_OUTCOME_TEMPLATE(class U)
991 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
992 constexpr explicit value_storage_trivial(const value_storage_trivial<U, void> &o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
993 detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
994 : value_storage_trivial(o._status.have_value() ?
995 value_storage_trivial(in_place_type<value_type>, o._value) :
996 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>) : value_storage_trivial())) // NOLINT
997 {
998 _status = o._status;
999 }
1000 BOOST_OUTCOME_TEMPLATE(class U)
1001 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
1002 constexpr explicit value_storage_trivial(value_storage_trivial<U, void> &&o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
1003 detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
1004 : value_storage_trivial(o._status.have_value() ?
1005 value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
1006 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>) : value_storage_trivial())) // NOLINT
1007 {
1008 _status = o._status;
1009 }
1010 constexpr void swap(value_storage_trivial &o) noexcept
1011 {
1012 // storage is trivial, so just use assignment
1013 auto temp = static_cast<value_storage_trivial &&>(*this);
1014 *this = static_cast<value_storage_trivial &&>(o);
1015 o = static_cast<value_storage_trivial &&>(temp);
1016 }
1017 };
1018
1019 /* Used if T or E is non-trivial. The additional constexpr is injected in C++ 20 to enable Outcome to
1020 work in constexpr evaluation contexts in C++ 20 where non-trivial constexpr destructors are now allowed.
1021 */
1022 template <class T, class E> struct value_storage_nontrivial
1023 {
1024 using value_type = T;
1025 using error_type = E;
1026 struct disable_in_place_value_type
1027 {
1028 };
1029 struct disable_in_place_error_type
1030 {
1031 };
1032 using _value_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_value_type, value_type>;
1033 using _error_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_error_type, error_type>;
1034 using _value_type_ = devoid<value_type>;
1035 using _error_type_ = devoid<error_type>;
1036
1037 union
1038 {
1039 empty_type _empty1;
1040 _value_type_ _value;
1041 };
1042 status_bitfield_type _status;
1043 union
1044 {
1045 empty_type _empty2;
1046 _error_type_ _error;
1047 };
1048#if __cplusplus >= 202000L || _HAS_CXX20
1049 constexpr
1050#endif
1051 value_storage_nontrivial() noexcept
1052 : _empty1{}
1053 , _empty2{}
1054 {
1055 }
1056 value_storage_nontrivial &operator=(const value_storage_nontrivial &) = default; // if reaches here, copy assignment is trivial
1057 value_storage_nontrivial &operator=(value_storage_nontrivial &&) = default; // NOLINT if reaches here, move assignment is trivial
1058#if __cplusplus >= 202000L || _HAS_CXX20
1059 constexpr
1060#endif
1061 value_storage_nontrivial(value_storage_nontrivial &&o) noexcept(std::is_nothrow_move_constructible<_value_type_>::value &&
1062 std::is_nothrow_move_constructible<_error_type_>::value) // NOLINT
1063 {
1064 if(o._status.have_value())
1065 {
1066 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value)); // NOLINT
1067 }
1068 else if(o._status.have_error())
1069 {
1070 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error)); // NOLINT
1071 }
1072 _status = o._status;
1073 o._status.set_have_moved_from(true);
1074 }
1075#if __cplusplus >= 202000L || _HAS_CXX20
1076 constexpr
1077#endif
1078 value_storage_nontrivial(const value_storage_nontrivial &o) noexcept(std::is_nothrow_copy_constructible<_value_type_>::value &&
1079 std::is_nothrow_copy_constructible<_error_type_>::value)
1080 {
1081 if(o._status.have_value())
1082 {
1083 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(o._value); // NOLINT
1084 }
1085 else if(o._status.have_error())
1086 {
1087 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error); // NOLINT
1088 }
1089 _status = o._status;
1090 }
1091#if __cplusplus >= 202000L || _HAS_CXX20
1092 constexpr
1093#endif
1094 explicit value_storage_nontrivial(status_bitfield_type status)
1095 : _empty1()
1096 , _status(status)
1097 , _empty2()
1098 {
1099 }
1100 template <class... Args>
1101 constexpr explicit value_storage_nontrivial(in_place_type_t<_value_type> /*unused*/,
1102 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, Args...>)
1103 : _value(static_cast<Args &&>(args)...) // NOLINT
1104 , _status(status::have_value)
1105 {
1106 }
1107 template <class U, class... Args>
1108 constexpr value_storage_nontrivial(in_place_type_t<_value_type> /*unused*/, std::initializer_list<U> il,
1109 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, std::initializer_list<U>, Args...>)
1110 : _value(il, static_cast<Args &&>(args)...)
1111 , _status(status::have_value)
1112 {
1113 }
1114 template <class... Args>
1115 constexpr explicit value_storage_nontrivial(in_place_type_t<_error_type> /*unused*/,
1116 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, Args...>)
1117 : _status(status::have_error)
1118 , _error(static_cast<Args &&>(args)...) // NOLINT
1119 {
1120 _set_error_is_errno(*this);
1121 }
1122 template <class U, class... Args>
1123 constexpr value_storage_nontrivial(in_place_type_t<_error_type> /*unused*/, std::initializer_list<U> il,
1124 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, std::initializer_list<U>, Args...>)
1125 : _status(status::have_error)
1126 , _error(il, static_cast<Args &&>(args)...)
1127 {
1128 _set_error_is_errno(*this);
1129 }
1130
1131 struct nonvoid_converting_constructor_tag
1132 {
1133 };
1134 template <class U, class V>
1135 static constexpr bool enable_nonvoid_converting_constructor =
1136 !(std::is_same<std::decay_t<U>, value_type>::value && std::is_same<std::decay_t<V>, error_type>::value) //
1137 && detail::is_constructible<value_type, U> && detail::is_constructible<error_type, V>;
1138 BOOST_OUTCOME_TEMPLATE(class U, class V)
1139 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
1140 constexpr explicit value_storage_nontrivial(const value_storage_trivial<U, V> &o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
1141 detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
1142 : value_storage_nontrivial(o._status.have_value() ?
1143 value_storage_nontrivial(in_place_type<value_type>, o._value) :
1144 (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, o._error) : value_storage_nontrivial()))
1145 {
1146 _status = o._status;
1147 }
1148 BOOST_OUTCOME_TEMPLATE(class U, class V)
1149 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
1150 constexpr explicit value_storage_nontrivial(value_storage_trivial<U, V> &&o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
1151 detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
1152 : value_storage_nontrivial(
1153 o._status.have_value() ?
1154 value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
1155 (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_nontrivial()))
1156 {
1157 _status = o._status;
1158 }
1159 BOOST_OUTCOME_TEMPLATE(class U, class V)
1160 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
1161 constexpr explicit value_storage_nontrivial(const value_storage_nontrivial<U, V> &o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
1162 detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
1163 : value_storage_nontrivial(o._status.have_value() ?
1164 value_storage_nontrivial(in_place_type<value_type>, o._value) :
1165 (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, o._error) : value_storage_nontrivial()))
1166 {
1167 _status = o._status;
1168 }
1169 BOOST_OUTCOME_TEMPLATE(class U, class V)
1170 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
1171 constexpr explicit value_storage_nontrivial(value_storage_nontrivial<U, V> &&o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
1172 detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
1173 : value_storage_nontrivial(
1174 o._status.have_value() ?
1175 value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
1176 (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_nontrivial()))
1177 {
1178 _status = o._status;
1179 }
1180
1181 struct void_value_converting_constructor_tag
1182 {
1183 };
1184 template <class V>
1185 static constexpr bool enable_void_value_converting_constructor =
1186 std::is_default_constructible<value_type>::value && detail::is_constructible<error_type, V>;
1187 BOOST_OUTCOME_TEMPLATE(class V)
1188 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
1189 constexpr explicit value_storage_nontrivial(const value_storage_trivial<void, V> &o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
1190 std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
1191 {
1192 if(o._status.have_value())
1193 {
1194 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(); // NOLINT
1195 }
1196 else if(o._status.have_error())
1197 {
1198 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error); // NOLINT
1199 }
1200 _status = o._status;
1201 }
1202 BOOST_OUTCOME_TEMPLATE(class V)
1203 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
1204 constexpr explicit value_storage_nontrivial(value_storage_trivial<void, V> &&o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
1205 std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
1206 {
1207 if(o._status.have_value())
1208 {
1209 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(); // NOLINT
1210 }
1211 else if(o._status.have_error())
1212 {
1213 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error)); // NOLINT
1214 }
1215 _status = o._status;
1216 o._status.set_have_moved_from(true);
1217 }
1218
1219 struct void_error_converting_constructor_tag
1220 {
1221 };
1222 template <class U>
1223 static constexpr bool enable_void_error_converting_constructor =
1224 std::is_default_constructible<error_type>::value && detail::is_constructible<value_type, U>;
1225 BOOST_OUTCOME_TEMPLATE(class U)
1226 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
1227 constexpr explicit value_storage_nontrivial(const value_storage_trivial<U, void> &o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
1228 detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
1229 {
1230 if(o._status.have_value())
1231 {
1232 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(o._value); // NOLINT
1233 }
1234 else if(o._status.have_error())
1235 {
1236 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(); // NOLINT
1237 }
1238 _status = o._status;
1239 }
1240 BOOST_OUTCOME_TEMPLATE(class U)
1241 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
1242 constexpr explicit value_storage_nontrivial(value_storage_trivial<U, void> &&o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
1243 detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
1244 {
1245 if(o._status.have_value())
1246 {
1247 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value)); // NOLINT
1248 }
1249 else if(o._status.have_error())
1250 {
1251 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(); // NOLINT
1252 }
1253 _status = o._status;
1254 o._status.set_have_moved_from(true);
1255 }
1256
1257#if __cplusplus >= 202000L || _HAS_CXX20
1258 constexpr
1259#endif
1260 ~value_storage_nontrivial() noexcept(std::is_nothrow_destructible<_value_type_>::value && std::is_nothrow_destructible<_error_type_>::value)
1261 {
1262 if(this->_status.have_value())
1263 {
1264 if(!trait::is_move_bitcopying<value_type>::value || !this->_status.have_moved_from())
1265 {
1266 this->_value.~_value_type_(); // NOLINT
1267 }
1268 this->_status.set_have_value(false);
1269 }
1270 else if(this->_status.have_error())
1271 {
1272 if(!trait::is_move_bitcopying<error_type>::value || !this->_status.have_moved_from())
1273 {
1274 this->_error.~_error_type_(); // NOLINT
1275 }
1276 this->_status.set_have_error(false);
1277 }
1278 }
1279#if __cplusplus >= 202000L || _HAS_CXX20
1280 constexpr
1281#endif
1282 void
1283 swap(value_storage_nontrivial &o) noexcept(detail::is_nothrow_swappable<_value_type_>::value && detail::is_nothrow_swappable<_error_type_>::value)
1284 {
1285 using std::swap;
1286 // empty/empty
1287 if(!_status.have_value() && !o._status.have_value() && !_status.have_error() && !o._status.have_error())
1288 {
1289 swap(_status, o._status);
1290 return;
1291 }
1292 // value/value
1293 if(_status.have_value() && o._status.have_value())
1294 {
1295 struct _
1296 {
1297 status_bitfield_type &a, &b;
1298 bool all_good{false};
1299 ~_()
1300 {
1301 if(!this->all_good)
1302 {
1303 // We lost one of the values
1304 this->a.set_have_lost_consistency(true);
1305 this->b.set_have_lost_consistency(true);
1306 }
1307 }
1308 } _{_status, o._status};
1309 strong_swap(_.all_good, _value, o._value);
1310 swap(_status, o._status);
1311 return;
1312 }
1313 // error/error
1314 if(_status.have_error() && o._status.have_error())
1315 {
1316 struct _
1317 {
1318 status_bitfield_type &a, &b;
1319 bool all_good{false};
1320 ~_()
1321 {
1322 if(!this->all_good)
1323 {
1324 // We lost one of the values
1325 this->a.set_have_lost_consistency(true);
1326 this->b.set_have_lost_consistency(true);
1327 }
1328 }
1329 } _{_status, o._status};
1330 strong_swap(_.all_good, _error, o._error);
1331 swap(_status, o._status);
1332 return;
1333 }
1334 // Could be value/empty, error/empty, etc
1335 if(_status.have_value() && !o._status.have_error())
1336 {
1337 // Move construct me into other
1338 new(BOOST_OUTCOME_ADDRESS_OF(o._value)) _value_type_(static_cast<_value_type_ &&>(_value)); // NOLINT
1339 if(!trait::is_move_bitcopying<value_type>::value)
1340 {
1341 this->_value.~value_type(); // NOLINT
1342 }
1343 swap(_status, o._status);
1344 return;
1345 }
1346 if(o._status.have_value() && !_status.have_error())
1347 {
1348 // Move construct other into me
1349 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value)); // NOLINT
1350 if(!trait::is_move_bitcopying<value_type>::value)
1351 {
1352 o._value.~value_type(); // NOLINT
1353 }
1354 swap(_status, o._status);
1355 return;
1356 }
1357 if(_status.have_error() && !o._status.have_value())
1358 {
1359 // Move construct me into other
1360 new(BOOST_OUTCOME_ADDRESS_OF(o._error)) _error_type_(static_cast<_error_type_ &&>(_error)); // NOLINT
1361 if(!trait::is_move_bitcopying<error_type>::value)
1362 {
1363 this->_error.~error_type(); // NOLINT
1364 }
1365 swap(_status, o._status);
1366 return;
1367 }
1368 if(o._status.have_error() && !_status.have_value())
1369 {
1370 // Move construct other into me
1371 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error)); // NOLINT
1372 if(!trait::is_move_bitcopying<error_type>::value)
1373 {
1374 o._error.~error_type(); // NOLINT
1375 }
1376 swap(_status, o._status);
1377 return;
1378 }
1379 // It can now only be value/error, or error/value
1380 struct _
1381 {
1382 status_bitfield_type &a, &b;
1383 _value_type_ *value, *o_value;
1384 _error_type_ *error, *o_error;
1385 bool all_good{true};
1386 ~_()
1387 {
1388 if(!this->all_good)
1389 {
1390 // We lost one of the values
1391 this->a.set_have_lost_consistency(true);
1392 this->b.set_have_lost_consistency(true);
1393 }
1394 }
1395 } _{_status, o._status, BOOST_OUTCOME_ADDRESS_OF(_value), BOOST_OUTCOME_ADDRESS_OF(o._value), BOOST_OUTCOME_ADDRESS_OF(_error), BOOST_OUTCOME_ADDRESS_OF(o._error)};
1396 if(_status.have_value() && o._status.have_error())
1397 {
1398 strong_placement(_.all_good, _.o_value, _.value, [&_] { //
1399 strong_placement(_.all_good, _.error, _.o_error, [&_] { //
1400 swap(_.a, _.b); //
1401 });
1402 });
1403 return;
1404 }
1405 if(_status.have_error() && o._status.have_value())
1406 {
1407 strong_placement(_.all_good, _.o_error, _.error, [&_] { //
1408 strong_placement(_.all_good, _.value, _.o_value, [&_] { //
1409 swap(_.a, _.b); //
1410 });
1411 });
1412 return;
1413 }
1414 // Should never reach here
1415 make_ub(_value);
1416 }
1417 };
1418 template <class Base> struct value_storage_delete_copy_constructor : Base // NOLINT
1419 {
1420 using Base::Base;
1421 using value_type = typename Base::value_type;
1422 using error_type = typename Base::error_type;
1423 value_storage_delete_copy_constructor() = default;
1424 value_storage_delete_copy_constructor(const value_storage_delete_copy_constructor &) = delete;
1425 value_storage_delete_copy_constructor(value_storage_delete_copy_constructor &&) = default; // NOLINT
1426 value_storage_delete_copy_constructor &operator=(const value_storage_delete_copy_constructor &o) = default;
1427 value_storage_delete_copy_constructor &operator=(value_storage_delete_copy_constructor &&o) = default; // NOLINT
1428 ~value_storage_delete_copy_constructor() = default;
1429 };
1430 template <class Base> struct value_storage_delete_copy_assignment : Base // NOLINT
1431 {
1432 using Base::Base;
1433 using value_type = typename Base::value_type;
1434 using error_type = typename Base::error_type;
1435 value_storage_delete_copy_assignment() = default;
1436 value_storage_delete_copy_assignment(const value_storage_delete_copy_assignment &) = default;
1437 value_storage_delete_copy_assignment(value_storage_delete_copy_assignment &&) = default; // NOLINT
1438 value_storage_delete_copy_assignment &operator=(const value_storage_delete_copy_assignment &o) = delete;
1439 value_storage_delete_copy_assignment &operator=(value_storage_delete_copy_assignment &&o) = default; // NOLINT
1440 ~value_storage_delete_copy_assignment() = default;
1441 };
1442 template <class Base> struct value_storage_delete_move_assignment : Base // NOLINT
1443 {
1444 using Base::Base;
1445 using value_type = typename Base::value_type;
1446 using error_type = typename Base::error_type;
1447 value_storage_delete_move_assignment() = default;
1448 value_storage_delete_move_assignment(const value_storage_delete_move_assignment &) = default;
1449 value_storage_delete_move_assignment(value_storage_delete_move_assignment &&) = default; // NOLINT
1450 value_storage_delete_move_assignment &operator=(const value_storage_delete_move_assignment &o) = default;
1451 value_storage_delete_move_assignment &operator=(value_storage_delete_move_assignment &&o) = delete;
1452 ~value_storage_delete_move_assignment() = default;
1453 };
1454 template <class Base> struct value_storage_delete_move_constructor : Base // NOLINT
1455 {
1456 using Base::Base;
1457 using value_type = typename Base::value_type;
1458 using error_type = typename Base::error_type;
1459 value_storage_delete_move_constructor() = default;
1460 value_storage_delete_move_constructor(const value_storage_delete_move_constructor &) = default;
1461 value_storage_delete_move_constructor(value_storage_delete_move_constructor &&) = delete;
1462 value_storage_delete_move_constructor &operator=(const value_storage_delete_move_constructor &o) = default;
1463 value_storage_delete_move_constructor &operator=(value_storage_delete_move_constructor &&o) = default;
1464 ~value_storage_delete_move_constructor() = default;
1465 };
1466 template <class Base> struct value_storage_nontrivial_move_assignment : Base // NOLINT
1467 {
1468 using Base::Base;
1469 using value_type = typename Base::value_type;
1470 using error_type = typename Base::error_type;
1471 value_storage_nontrivial_move_assignment() = default;
1472 value_storage_nontrivial_move_assignment(const value_storage_nontrivial_move_assignment &) = default;
1473 value_storage_nontrivial_move_assignment(value_storage_nontrivial_move_assignment &&) = default; // NOLINT
1474 value_storage_nontrivial_move_assignment &operator=(const value_storage_nontrivial_move_assignment &o) = default;
1475 ~value_storage_nontrivial_move_assignment() = default;
1476#if __cplusplus >= 202000L || _HAS_CXX20
1477 constexpr
1478#endif
1479 value_storage_nontrivial_move_assignment &
1480 operator=(value_storage_nontrivial_move_assignment &&o) noexcept(
1481 std::is_nothrow_move_assignable<value_type>::value &&
1482 std::is_nothrow_move_assignable<error_type>::value && noexcept(move_assign_to_empty<value_type>(
1483 static_cast<value_type *>(nullptr),
1484 static_cast<value_type *>(nullptr))) && noexcept(move_assign_to_empty<error_type>(static_cast<error_type *>(nullptr),
1485 static_cast<error_type *>(nullptr)))) // NOLINT
1486 {
1487 using _value_type_ = typename Base::_value_type_;
1488 using _error_type_ = typename Base::_error_type_;
1489 if(!this->_status.have_value() && !this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1490 {
1491 this->_status = o._status;
1492 o._status.set_have_moved_from(true);
1493 return *this;
1494 }
1495 if(this->_status.have_value() && o._status.have_value())
1496 {
1497 this->_value = static_cast<_value_type_ &&>(o._value); // NOLINT
1498 this->_status = o._status;
1499 o._status.set_have_moved_from(true);
1500 return *this;
1501 }
1502 if(this->_status.have_error() && o._status.have_error())
1503 {
1504 this->_error = static_cast<_error_type_ &&>(o._error); // NOLINT
1505 this->_status = o._status;
1506 o._status.set_have_moved_from(true);
1507 return *this;
1508 }
1509 if(this->_status.have_value() && !o._status.have_value() && !o._status.have_error())
1510 {
1511 if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1512 {
1513 this->_value.~_value_type_(); // NOLINT
1514 }
1515 this->_status = o._status;
1516 o._status.set_have_moved_from(true);
1517 return *this;
1518 }
1519 if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value())
1520 {
1521 move_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1522 this->_status = o._status;
1523 o._status.set_have_moved_from(true);
1524 return *this;
1525 }
1526 if(this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1527 {
1528 if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1529 {
1530 this->_error.~_error_type_(); // NOLINT
1531 }
1532 this->_status = o._status;
1533 o._status.set_have_moved_from(true);
1534 return *this;
1535 }
1536 if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error())
1537 {
1538 move_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1539 this->_status = o._status;
1540 o._status.set_have_moved_from(true);
1541 return *this;
1542 }
1543 if(this->_status.have_value() && o._status.have_error())
1544 {
1545 if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1546 {
1547 this->_value.~_value_type_(); // NOLINT
1548 }
1549 move_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1550 this->_status = o._status;
1551 o._status.set_have_moved_from(true);
1552 return *this;
1553 }
1554 if(this->_status.have_error() && o._status.have_value())
1555 {
1556 if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1557 {
1558 this->_error.~_error_type_(); // NOLINT
1559 }
1560 move_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1561 this->_status = o._status;
1562 o._status.set_have_moved_from(true);
1563 return *this;
1564 }
1565 // Should never reach here
1566 make_ub(this->_value);
1567 }
1568 };
1569 template <class Base> struct value_storage_nontrivial_copy_assignment : Base // NOLINT
1570 {
1571 using Base::Base;
1572 using value_type = typename Base::value_type;
1573 using error_type = typename Base::error_type;
1574 value_storage_nontrivial_copy_assignment() = default;
1575 value_storage_nontrivial_copy_assignment(const value_storage_nontrivial_copy_assignment &) = default;
1576 value_storage_nontrivial_copy_assignment(value_storage_nontrivial_copy_assignment &&) = default; // NOLINT
1577 value_storage_nontrivial_copy_assignment &operator=(value_storage_nontrivial_copy_assignment &&o) = default; // NOLINT
1578 ~value_storage_nontrivial_copy_assignment() = default;
1579#if __cplusplus >= 202000L || _HAS_CXX20
1580 constexpr
1581#endif
1582 value_storage_nontrivial_copy_assignment &
1583 operator=(const value_storage_nontrivial_copy_assignment &o) noexcept(
1584 std::is_nothrow_copy_assignable<value_type>::value &&
1585 std::is_nothrow_copy_assignable<error_type>::value && noexcept(copy_assign_to_empty<value_type>(
1586 static_cast<value_type *>(nullptr), static_cast<value_type *>(nullptr))) && noexcept(copy_assign_to_empty<error_type>(static_cast<error_type *>(nullptr),
1587 static_cast<error_type *>(nullptr))))
1588 {
1589 using _value_type_ = typename Base::_value_type_;
1590 using _error_type_ = typename Base::_error_type_;
1591 if(!this->_status.have_value() && !this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1592 {
1593 this->_status = o._status;
1594 return *this;
1595 }
1596 if(this->_status.have_value() && o._status.have_value())
1597 {
1598 this->_value = o._value; // NOLINT
1599 this->_status = o._status;
1600 return *this;
1601 }
1602 if(this->_status.have_error() && o._status.have_error())
1603 {
1604 this->_error = o._error; // NOLINT
1605 this->_status = o._status;
1606 return *this;
1607 }
1608 if(this->_status.have_value() && !o._status.have_value() && !o._status.have_error())
1609 {
1610 if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1611 {
1612 this->_value.~_value_type_(); // NOLINT
1613 }
1614 this->_status = o._status;
1615 return *this;
1616 }
1617 if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value())
1618 {
1619 copy_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1620 this->_status = o._status;
1621 return *this;
1622 }
1623 if(this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1624 {
1625 if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1626 {
1627 this->_error.~_error_type_(); // NOLINT
1628 }
1629 this->_status = o._status;
1630 return *this;
1631 }
1632 if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error())
1633 {
1634 copy_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1635 this->_status = o._status;
1636 return *this;
1637 }
1638 if(this->_status.have_value() && o._status.have_error())
1639 {
1640 if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1641 {
1642 this->_value.~_value_type_(); // NOLINT
1643 }
1644 copy_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1645 this->_status = o._status;
1646 return *this;
1647 }
1648 if(this->_status.have_error() && o._status.have_value())
1649 {
1650 if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1651 {
1652 this->_error.~_error_type_(); // NOLINT
1653 }
1654 copy_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1655 this->_status = o._status;
1656 return *this;
1657 }
1658 // Should never reach here
1659 make_ub(this->_value);
1660 }
1661 };
1662#ifdef _MSC_VER
1663#pragma warning(pop)
1664#endif
1665
1666 // is_trivially_copyable is true even if type is not copyable, so handle that here
1667 template <class T> struct is_storage_trivial
1668 {
1669 static constexpr bool value = std::is_void<T>::value || (std::is_trivially_copy_constructible<T>::value && std::is_trivially_copyable<T>::value);
1670 };
1671 // work around libstdc++ 7 bug
1672 template <> struct is_storage_trivial<void>
1673 {
1674 static constexpr bool value = true;
1675 };
1676 template <> struct is_storage_trivial<const void>
1677 {
1678 static constexpr bool value = true;
1679 };
1680 // Ability to do copy assigns needs more than just copy assignment
1681 template <class T> struct is_copy_assignable
1682 {
1683 static constexpr bool value = std::is_copy_assignable<T>::value && (std::is_copy_constructible<T>::value || std::is_default_constructible<T>::value);
1684 };
1685 // Ability to do move assigns needs more than just move assignment
1686 template <class T> struct is_move_assignable
1687 {
1688 static constexpr bool value = std::is_move_assignable<T>::value && (std::is_move_constructible<T>::value || std::is_default_constructible<T>::value);
1689 };
1690
1691 template <class T, class E>
1692 using value_storage_select_trivality =
1693 std::conditional_t<is_storage_trivial<T>::value && is_storage_trivial<E>::value, value_storage_trivial<T, E>, value_storage_nontrivial<T, E>>;
1694 template <class T, class E>
1695 using value_storage_select_move_constructor =
1696 std::conditional_t<std::is_move_constructible<devoid<T>>::value && std::is_move_constructible<devoid<E>>::value, value_storage_select_trivality<T, E>,
1697 value_storage_delete_move_constructor<value_storage_select_trivality<T, E>>>;
1698 template <class T, class E>
1699 using value_storage_select_copy_constructor =
1700 std::conditional_t<std::is_copy_constructible<devoid<T>>::value && std::is_copy_constructible<devoid<E>>::value, value_storage_select_move_constructor<T, E>,
1701 value_storage_delete_copy_constructor<value_storage_select_move_constructor<T, E>>>;
1702 template <class T, class E>
1703 using value_storage_select_move_assignment =
1704 std::conditional_t<std::is_trivially_move_assignable<devoid<T>>::value && std::is_trivially_move_assignable<devoid<E>>::value,
1705 value_storage_select_copy_constructor<T, E>,
1706 std::conditional_t<is_move_assignable<devoid<T>>::value && is_move_assignable<devoid<E>>::value,
1707 value_storage_nontrivial_move_assignment<value_storage_select_copy_constructor<T, E>>,
1708 value_storage_delete_move_assignment<value_storage_select_copy_constructor<T, E>>>>;
1709 template <class T, class E>
1710 using value_storage_select_copy_assignment =
1711 std::conditional_t<std::is_trivially_copy_assignable<devoid<T>>::value && std::is_trivially_copy_assignable<devoid<E>>::value,
1712 value_storage_select_move_assignment<T, E>,
1713 std::conditional_t<is_copy_assignable<devoid<T>>::value && is_copy_assignable<devoid<E>>::value,
1714 value_storage_nontrivial_copy_assignment<value_storage_select_move_assignment<T, E>>,
1715 value_storage_delete_copy_assignment<value_storage_select_move_assignment<T, E>>>>;
1716 template <class T, class E> using value_storage_select_impl = value_storage_select_copy_assignment<T, E>;
1717#ifndef NDEBUG
1718 // Check is trivial in all ways except default constructibility
1719 // static_assert(std::is_trivial<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not trivial!");
1720 // static_assert(std::is_trivially_default_constructible<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not
1721 // trivially default constructible!");
1722 static_assert(std::is_trivially_copyable<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not trivially copyable!");
1723 static_assert(std::is_trivially_assignable<value_storage_select_impl<int, long>, value_storage_select_impl<int, long>>::value,
1724 "value_storage_select_impl<int, long> is not trivially assignable!");
1725 static_assert(std::is_trivially_destructible<value_storage_select_impl<int, long>>::value,
1726 "value_storage_select_impl<int, long> is not trivially destructible!");
1727 static_assert(std::is_trivially_copy_constructible<value_storage_select_impl<int, long>>::value,
1728 "value_storage_select_impl<int, long> is not trivially copy constructible!");
1729 static_assert(std::is_trivially_move_constructible<value_storage_select_impl<int, long>>::value,
1730 "value_storage_select_impl<int, long> is not trivially move constructible!");
1731 static_assert(std::is_trivially_copy_assignable<value_storage_select_impl<int, long>>::value,
1732 "value_storage_select_impl<int, long> is not trivially copy assignable!");
1733 static_assert(std::is_trivially_move_assignable<value_storage_select_impl<int, long>>::value,
1734 "value_storage_select_impl<int, long> is not trivially move assignable!");
1735 // Also check is standard layout
1736 static_assert(std::is_standard_layout<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not a standard layout type!");
1737#endif
1738} // namespace detail
1739
1740BOOST_OUTCOME_V2_NAMESPACE_END
1741
1742#endif
1743

source code of boost/libs/outcome/include/boost/outcome/detail/value_storage.hpp