1#ifndef BOOST_SYSTEM_RESULT_HPP_INCLUDED
2#define BOOST_SYSTEM_RESULT_HPP_INCLUDED
3
4// Copyright 2017, 2021, 2022 Peter Dimov.
5// Distributed under the Boost Software License, Version 1.0.
6// https://www.boost.org/LICENSE_1_0.txt
7
8#include <boost/system/errc.hpp>
9#include <boost/system/system_error.hpp>
10#include <boost/system/detail/error_code.hpp>
11#include <boost/system/detail/error_category_impl.hpp>
12#include <boost/variant2/variant.hpp>
13#include <boost/throw_exception.hpp>
14#include <boost/assert/source_location.hpp>
15#include <boost/assert.hpp>
16#include <boost/config.hpp>
17#include <type_traits>
18#include <utility>
19#include <iosfwd>
20#include <system_error>
21#include <exception>
22
23//
24
25namespace boost
26{
27namespace system
28{
29
30// throw_exception_from_error
31
32#if defined(__GNUC__) && __GNUC__ >= 7 && __GNUC__ <= 8
33# pragma GCC diagnostic push
34# pragma GCC diagnostic ignored "-Wattributes"
35#endif
36
37BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( error_code const & e, boost::source_location const& loc )
38{
39 boost::throw_with_location( e: system_error( e ), loc );
40}
41
42BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( errc::errc_t const & e, boost::source_location const& loc )
43{
44 boost::throw_with_location( e: system_error( make_error_code( e ) ), loc );
45}
46
47BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( std::error_code const & e, boost::source_location const& loc )
48{
49 boost::throw_with_location( e: std::system_error( e ), loc );
50}
51
52BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( std::errc const & e, boost::source_location const& loc )
53{
54 boost::throw_with_location( e: std::system_error( make_error_code( e: e ) ), loc );
55}
56
57BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( std::exception_ptr const & p, boost::source_location const& loc )
58{
59 if( p )
60 {
61 std::rethrow_exception( p );
62 }
63 else
64 {
65 boost::throw_with_location( e: std::bad_exception(), loc );
66 }
67}
68
69#if defined(__GNUC__) && __GNUC__ >= 7 && __GNUC__ <= 8
70# pragma GCC diagnostic pop
71#endif
72
73// in_place_*
74
75using in_place_value_t = variant2::in_place_index_t<0>;
76constexpr in_place_value_t in_place_value{};
77
78using in_place_error_t = variant2::in_place_index_t<1>;
79constexpr in_place_error_t in_place_error{};
80
81namespace detail
82{
83
84template<class T> using remove_cvref = typename std::remove_cv< typename std::remove_reference<T>::type >::type;
85
86template<class... T> using is_errc_t = std::is_same<mp11::mp_list<remove_cvref<T>...>, mp11::mp_list<errc::errc_t>>;
87
88template<class T, class... A> struct is_constructible: std::is_constructible<T, A...> {};
89template<class A> struct is_constructible<bool, A>: std::is_convertible<A, bool> {};
90template<class A> struct is_constructible<bool const, A>: std::is_convertible<A, bool> {};
91
92} // namespace detail
93
94// result
95
96template<class T, class E = error_code> class result
97{
98private:
99
100 variant2::variant<T, E> v_;
101
102public:
103
104 using value_type = T;
105 using error_type = E;
106
107 static constexpr in_place_value_t in_place_value{};
108 static constexpr in_place_error_t in_place_error{};
109
110public:
111
112 // constructors
113
114 // default
115 template<class En2 = void, class En = typename std::enable_if<
116 std::is_void<En2>::value &&
117 std::is_default_constructible<T>::value
118 >::type>
119 constexpr result()
120 noexcept( std::is_nothrow_default_constructible<T>::value )
121 : v_( in_place_value )
122 {
123 }
124
125 // implicit, value
126 template<class A = T, typename std::enable_if<
127 std::is_convertible<A, T>::value &&
128 !(detail::is_errc_t<A>::value && std::is_arithmetic<T>::value) &&
129 !std::is_convertible<A, E>::value, int>::type = 0>
130 constexpr result( A&& a )
131 noexcept( std::is_nothrow_constructible<T, A>::value )
132 : v_( in_place_value, std::forward<A>(a) )
133 {
134 }
135
136 // implicit, error
137 template<class A = E, class = void, typename std::enable_if<
138 std::is_convertible<A, E>::value &&
139 !std::is_convertible<A, T>::value, int>::type = 0>
140 constexpr result( A&& a )
141 noexcept( std::is_nothrow_constructible<E, A>::value )
142 : v_( in_place_error, std::forward<A>(a) )
143 {
144 }
145
146 // explicit, value
147 template<class... A, class En = typename std::enable_if<
148 detail::is_constructible<T, A...>::value &&
149 !(detail::is_errc_t<A...>::value && std::is_arithmetic<T>::value) &&
150 !detail::is_constructible<E, A...>::value &&
151 sizeof...(A) >= 1
152 >::type>
153 explicit constexpr result( A&&... a )
154 noexcept( std::is_nothrow_constructible<T, A...>::value )
155 : v_( in_place_value, std::forward<A>(a)... )
156 {
157 }
158
159 // explicit, error
160 template<class... A, class En2 = void, class En = typename std::enable_if<
161 !detail::is_constructible<T, A...>::value &&
162 detail::is_constructible<E, A...>::value &&
163 sizeof...(A) >= 1
164 >::type>
165 explicit constexpr result( A&&... a )
166 noexcept( std::is_nothrow_constructible<E, A...>::value )
167 : v_( in_place_error, std::forward<A>(a)... )
168 {
169 }
170
171 // tagged, value
172 template<class... A, class En = typename std::enable_if<
173 std::is_constructible<T, A...>::value
174 >::type>
175 constexpr result( in_place_value_t, A&&... a )
176 noexcept( std::is_nothrow_constructible<T, A...>::value )
177 : v_( in_place_value, std::forward<A>(a)... )
178 {
179 }
180
181 // tagged, error
182 template<class... A, class En = typename std::enable_if<
183 std::is_constructible<E, A...>::value
184 >::type>
185 constexpr result( in_place_error_t, A&&... a )
186 noexcept( std::is_nothrow_constructible<E, A...>::value )
187 : v_( in_place_error, std::forward<A>(a)... )
188 {
189 }
190
191 // converting
192 template<class T2, class E2, class En = typename std::enable_if<
193 std::is_convertible<T2, T>::value &&
194 std::is_convertible<E2, E>::value &&
195 !std::is_convertible<result<T2, E2> const&, T>::value
196 >::type>
197 BOOST_CXX14_CONSTEXPR result( result<T2, E2> const& r2 )
198 noexcept(
199 std::is_nothrow_constructible<T, T2 const&>::value &&
200 std::is_nothrow_constructible<E, E2>::value &&
201 std::is_nothrow_default_constructible<E2>::value &&
202 std::is_nothrow_copy_constructible<E2>::value )
203 : v_( in_place_error, r2.error() )
204 {
205 if( r2 )
206 {
207 v_.template emplace<0>( *r2 );
208 }
209 }
210
211 template<class T2, class E2, class En = typename std::enable_if<
212 std::is_convertible<T2, T>::value &&
213 std::is_convertible<E2, E>::value &&
214 !std::is_convertible<result<T2, E2>&&, T>::value
215 >::type>
216 BOOST_CXX14_CONSTEXPR result( result<T2, E2>&& r2 )
217 noexcept(
218 std::is_nothrow_constructible<T, T2&&>::value &&
219 std::is_nothrow_constructible<E, E2>::value &&
220 std::is_nothrow_default_constructible<E2>::value &&
221 std::is_nothrow_copy_constructible<E2>::value )
222 : v_( in_place_error, r2.error() )
223 {
224 if( r2 )
225 {
226 v_.template emplace<0>( std::move( *r2 ) );
227 }
228 }
229
230 // queries
231
232 constexpr bool has_value() const noexcept
233 {
234 return v_.index() == 0;
235 }
236
237 constexpr bool has_error() const noexcept
238 {
239 return v_.index() == 1;
240 }
241
242 constexpr explicit operator bool() const noexcept
243 {
244 return v_.index() == 0;
245 }
246
247 // checked value access
248#if defined( BOOST_NO_CXX11_REF_QUALIFIERS )
249
250 BOOST_CXX14_CONSTEXPR T value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const
251 {
252 if( has_value() )
253 {
254 return variant2::unsafe_get<0>( v_ );
255 }
256 else
257 {
258 throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
259 }
260 }
261
262#else
263
264 BOOST_CXX14_CONSTEXPR T& value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) &
265 {
266 if( has_value() )
267 {
268 return variant2::unsafe_get<0>( v_ );
269 }
270 else
271 {
272 throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
273 }
274 }
275
276 BOOST_CXX14_CONSTEXPR T const& value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const&
277 {
278 if( has_value() )
279 {
280 return variant2::unsafe_get<0>( v_ );
281 }
282 else
283 {
284 throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
285 }
286 }
287
288 template<class U = T>
289 BOOST_CXX14_CONSTEXPR
290 typename std::enable_if<std::is_move_constructible<U>::value, T>::type
291 value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) &&
292 {
293 return std::move( value( loc ) );
294 }
295
296 template<class U = T>
297 BOOST_CXX14_CONSTEXPR
298 typename std::enable_if<!std::is_move_constructible<U>::value, T&&>::type
299 value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) &&
300 {
301 return std::move( value( loc ) );
302 }
303
304 template<class U = T>
305 BOOST_CXX14_CONSTEXPR
306 typename std::enable_if<std::is_move_constructible<U>::value, T>::type
307 value() const && = delete;
308
309 template<class U = T>
310 BOOST_CXX14_CONSTEXPR
311 typename std::enable_if<!std::is_move_constructible<U>::value, T const&&>::type
312 value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const &&
313 {
314 return std::move( value( loc ) );
315 }
316
317#endif
318
319 // unchecked value access
320
321 BOOST_CXX14_CONSTEXPR T* operator->() noexcept
322 {
323 return variant2::get_if<0>( &v_ );
324 }
325
326 BOOST_CXX14_CONSTEXPR T const* operator->() const noexcept
327 {
328 return variant2::get_if<0>( &v_ );
329 }
330
331#if defined( BOOST_NO_CXX11_REF_QUALIFIERS )
332
333 BOOST_CXX14_CONSTEXPR T& operator*() noexcept
334 {
335 T* p = operator->();
336
337 BOOST_ASSERT( p != 0 );
338
339 return *p;
340 }
341
342 BOOST_CXX14_CONSTEXPR T const& operator*() const noexcept
343 {
344 T const* p = operator->();
345
346 BOOST_ASSERT( p != 0 );
347
348 return *p;
349 }
350
351#else
352
353 BOOST_CXX14_CONSTEXPR T& operator*() & noexcept
354 {
355 T* p = operator->();
356
357 BOOST_ASSERT( p != 0 );
358
359 return *p;
360 }
361
362 BOOST_CXX14_CONSTEXPR T const& operator*() const & noexcept
363 {
364 T const* p = operator->();
365
366 BOOST_ASSERT( p != 0 );
367
368 return *p;
369 }
370
371 template<class U = T>
372 BOOST_CXX14_CONSTEXPR
373 typename std::enable_if<std::is_move_constructible<U>::value, T>::type
374 operator*() && noexcept(std::is_nothrow_move_constructible<T>::value)
375 {
376 return std::move(**this);
377 }
378
379 template<class U = T>
380 BOOST_CXX14_CONSTEXPR
381 typename std::enable_if<!std::is_move_constructible<U>::value, T&&>::type
382 operator*() && noexcept
383 {
384 return std::move(**this);
385 }
386
387 template<class U = T>
388 BOOST_CXX14_CONSTEXPR
389 typename std::enable_if<std::is_move_constructible<U>::value, T>::type
390 operator*() const && noexcept = delete;
391
392 template<class U = T>
393 BOOST_CXX14_CONSTEXPR
394 typename std::enable_if<!std::is_move_constructible<U>::value, T const&&>::type
395 operator*() const && noexcept
396 {
397 return std::move(**this);
398 }
399
400#endif
401
402 // error access
403
404 constexpr E error() const &
405 noexcept( std::is_nothrow_default_constructible<E>::value && std::is_nothrow_copy_constructible<E>::value )
406 {
407 return has_error()? variant2::unsafe_get<1>( v_ ): E();
408 }
409
410 BOOST_CXX14_CONSTEXPR E error() &&
411 noexcept( std::is_nothrow_default_constructible<E>::value && std::is_nothrow_move_constructible<E>::value )
412 {
413 return has_error()? std::move( variant2::unsafe_get<1>( v_ ) ): E();
414 }
415
416 // emplace
417
418 template<class... A>
419 BOOST_CXX14_CONSTEXPR T& emplace( A&&... a )
420 {
421 return v_.template emplace<0>( std::forward<A>(a)... );
422 }
423
424 // swap
425
426 BOOST_CXX14_CONSTEXPR void swap( result& r )
427 noexcept( noexcept( v_.swap( r.v_ ) ) )
428 {
429 v_.swap( r.v_ );
430 }
431
432 friend BOOST_CXX14_CONSTEXPR void swap( result & r1, result & r2 )
433 noexcept( noexcept( r1.swap( r&: r2 ) ) )
434 {
435 r1.swap( r&: r2 );
436 }
437
438 // equality
439
440 friend constexpr bool operator==( result const & r1, result const & r2 )
441 noexcept( noexcept( r1.v_ == r2.v_ ) )
442 {
443 return r1.v_ == r2.v_;
444 }
445
446 friend constexpr bool operator!=( result const & r1, result const & r2 )
447 noexcept( noexcept( !( r1 == r2 ) ) )
448 {
449 return !( r1 == r2 );
450 }
451};
452
453#if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
454
455template<class T, class E> constexpr in_place_value_t result<T, E>::in_place_value;
456template<class T, class E> constexpr in_place_error_t result<T, E>::in_place_error;
457
458#endif
459
460template<class Ch, class Tr, class T, class E> std::basic_ostream<Ch, Tr>& operator<<( std::basic_ostream<Ch, Tr>& os, result<T, E> const & r )
461{
462 if( r.has_value() )
463 {
464 os << "value:" << *r;
465 }
466 else
467 {
468 os << "error:" << r.error();
469 }
470
471 return os;
472}
473
474// result<void>
475
476template<class E> class result<void, E>
477{
478private:
479
480 variant2::variant<variant2::monostate, E> v_;
481
482public:
483
484 using value_type = void;
485 using error_type = E;
486
487 static constexpr in_place_value_t in_place_value{};
488 static constexpr in_place_error_t in_place_error{};
489
490public:
491
492 // constructors
493
494 // default
495 constexpr result() noexcept
496 : v_( in_place_value )
497 {
498 }
499
500 // explicit, error
501 template<class A, class En = typename std::enable_if<
502 std::is_constructible<E, A>::value &&
503 !std::is_convertible<A, E>::value
504 >::type>
505 explicit constexpr result( A&& a )
506 noexcept( std::is_nothrow_constructible<E, A>::value )
507 : v_( in_place_error, std::forward<A>(a) )
508 {
509 }
510
511 // implicit, error
512 template<class A, class En2 = void, class En = typename std::enable_if<
513 std::is_convertible<A, E>::value
514 >::type>
515 constexpr result( A&& a )
516 noexcept( std::is_nothrow_constructible<E, A>::value )
517 : v_( in_place_error, std::forward<A>(a) )
518 {
519 }
520
521 // more than one arg, error
522 template<class... A, class En2 = void, class En3 = void, class En = typename std::enable_if<
523 std::is_constructible<E, A...>::value &&
524 sizeof...(A) >= 2
525 >::type>
526 constexpr result( A&&... a )
527 noexcept( std::is_nothrow_constructible<E, A...>::value )
528 : v_( in_place_error, std::forward<A>(a)... )
529 {
530 }
531
532 // tagged, value
533 constexpr result( in_place_value_t ) noexcept
534 : v_( in_place_value )
535 {
536 }
537
538 // tagged, error
539 template<class... A, class En = typename std::enable_if<
540 std::is_constructible<E, A...>::value
541 >::type>
542 constexpr result( in_place_error_t, A&&... a )
543 noexcept( std::is_nothrow_constructible<E, A...>::value )
544 : v_( in_place_error, std::forward<A>(a)... )
545 {
546 }
547
548 // converting
549 template<class E2, class En = typename std::enable_if<
550 std::is_convertible<E2, E>::value
551 >::type>
552 BOOST_CXX14_CONSTEXPR result( result<void, E2> const& r2 )
553 noexcept(
554 std::is_nothrow_constructible<E, E2>::value &&
555 std::is_nothrow_default_constructible<E2>::value &&
556 std::is_nothrow_copy_constructible<E2>::value )
557 : v_( in_place_error, r2.error() )
558 {
559 if( r2 )
560 {
561 this->emplace();
562 }
563 }
564
565 // queries
566
567 constexpr bool has_value() const noexcept
568 {
569 return v_.index() == 0;
570 }
571
572 constexpr bool has_error() const noexcept
573 {
574 return v_.index() == 1;
575 }
576
577 constexpr explicit operator bool() const noexcept
578 {
579 return v_.index() == 0;
580 }
581
582 // checked value access
583
584 BOOST_CXX14_CONSTEXPR void value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const
585 {
586 if( has_value() )
587 {
588 }
589 else
590 {
591 throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
592 }
593 }
594
595 // unchecked value access
596
597 BOOST_CXX14_CONSTEXPR void* operator->() noexcept
598 {
599 return variant2::get_if<0>( &v_ );
600 }
601
602 BOOST_CXX14_CONSTEXPR void const* operator->() const noexcept
603 {
604 return variant2::get_if<0>( &v_ );
605 }
606
607 BOOST_CXX14_CONSTEXPR void operator*() const noexcept
608 {
609 BOOST_ASSERT( has_value() );
610 }
611
612 // error access
613
614 constexpr E error() const &
615 noexcept( std::is_nothrow_default_constructible<E>::value && std::is_nothrow_copy_constructible<E>::value )
616 {
617 return has_error()? variant2::unsafe_get<1>( v_ ): E();
618 }
619
620 BOOST_CXX14_CONSTEXPR E error() &&
621 noexcept( std::is_nothrow_default_constructible<E>::value && std::is_nothrow_move_constructible<E>::value )
622 {
623 return has_error()? std::move( variant2::unsafe_get<1>( v_ ) ): E();
624 }
625
626 // emplace
627
628 BOOST_CXX14_CONSTEXPR void emplace()
629 {
630 v_.template emplace<0>();
631 }
632
633 // swap
634
635 BOOST_CXX14_CONSTEXPR void swap( result& r )
636 noexcept( noexcept( v_.swap( r.v_ ) ) )
637 {
638 v_.swap( r.v_ );
639 }
640
641 friend BOOST_CXX14_CONSTEXPR void swap( result & r1, result & r2 )
642 noexcept( noexcept( r1.swap( r&: r2 ) ) )
643 {
644 r1.swap( r&: r2 );
645 }
646
647 // equality
648
649 friend constexpr bool operator==( result const & r1, result const & r2 )
650 noexcept( noexcept( r1.v_ == r2.v_ ) )
651 {
652 return r1.v_ == r2.v_;
653 }
654
655 friend constexpr bool operator!=( result const & r1, result const & r2 )
656 noexcept( noexcept( !( r1 == r2 ) ) )
657 {
658 return !( r1 == r2 );
659 }
660};
661
662#if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
663
664template<class E> constexpr in_place_value_t result<void, E>::in_place_value;
665template<class E> constexpr in_place_error_t result<void, E>::in_place_error;
666
667#endif
668
669template<class Ch, class Tr, class E> std::basic_ostream<Ch, Tr>& operator<<( std::basic_ostream<Ch, Tr>& os, result<void, E> const & r )
670{
671 if( r.has_value() )
672 {
673 os << "value:void";
674 }
675 else
676 {
677 os << "error:" << r.error();
678 }
679
680 return os;
681}
682
683// result<T&, E>
684
685namespace detail
686{
687
688template<class U, class A> struct reference_to_temporary: std::integral_constant<bool,
689 !std::is_reference<A>::value ||
690 !std::is_convertible<typename std::remove_reference<A>::type*, U*>::value
691> {};
692
693} // namespace detail
694
695template<class U, class E> class result<U&, E>
696{
697private:
698
699 variant2::variant<U*, E> v_;
700
701public:
702
703 using value_type = U&;
704 using error_type = E;
705
706 static constexpr in_place_value_t in_place_value{};
707 static constexpr in_place_error_t in_place_error{};
708
709public:
710
711 // constructors
712
713 // implicit, value
714 template<class A, typename std::enable_if<
715 std::is_convertible<A, U&>::value &&
716 !detail::reference_to_temporary<U, A>::value &&
717 !std::is_convertible<A, E>::value, int>::type = 0>
718 constexpr result( A&& a )
719 noexcept( std::is_nothrow_constructible<U&, A>::value )
720 : v_( in_place_value, &static_cast<U&>( std::forward<A>(a) ) )
721 {
722 }
723
724 // implicit, error
725 template<class A = E, class = void, typename std::enable_if<
726 std::is_convertible<A, E>::value &&
727 !std::is_convertible<A, U&>::value, int>::type = 0>
728 constexpr result( A&& a )
729 noexcept( std::is_nothrow_constructible<E, A>::value )
730 : v_( in_place_error, std::forward<A>(a) )
731 {
732 }
733
734 // explicit, value
735 template<class A, class En = typename std::enable_if<
736 detail::is_constructible<U&, A>::value &&
737 !std::is_convertible<A, U&>::value &&
738 !detail::reference_to_temporary<U, A>::value &&
739 !detail::is_constructible<E, A>::value
740 >::type>
741 explicit constexpr result( A&& a )
742 noexcept( std::is_nothrow_constructible<U&, A>::value )
743 : v_( in_place_value, &static_cast<U&>( std::forward<A>(a) ) )
744 {
745 }
746
747 // explicit, error
748 template<class... A, class En2 = void, class En = typename std::enable_if<
749 !detail::is_constructible<U&, A...>::value &&
750 detail::is_constructible<E, A...>::value &&
751 sizeof...(A) >= 1
752 >::type>
753 explicit constexpr result( A&&... a )
754 noexcept( std::is_nothrow_constructible<E, A...>::value )
755 : v_( in_place_error, std::forward<A>(a)... )
756 {
757 }
758
759 // tagged, value
760 template<class A, class En = typename std::enable_if<
761 std::is_constructible<U&, A>::value &&
762 !detail::reference_to_temporary<U, A>::value
763 >::type>
764 constexpr result( in_place_value_t, A&& a )
765 noexcept( std::is_nothrow_constructible<U&, A>::value )
766 : v_( in_place_value, &static_cast<U&>( std::forward<A>(a) ) )
767 {
768 }
769
770 // tagged, error
771 template<class... A, class En = typename std::enable_if<
772 std::is_constructible<E, A...>::value
773 >::type>
774 constexpr result( in_place_error_t, A&&... a )
775 noexcept( std::is_nothrow_constructible<E, A...>::value )
776 : v_( in_place_error, std::forward<A>(a)... )
777 {
778 }
779
780 // converting
781 template<class U2, class E2, class En = typename std::enable_if<
782 std::is_convertible<U2&, U&>::value &&
783 !detail::reference_to_temporary<U, U2&>::value &&
784 std::is_convertible<E2, E>::value &&
785 !std::is_convertible<result<U2&, E2> const&, U&>::value
786 >::type>
787 BOOST_CXX14_CONSTEXPR result( result<U2&, E2> const& r2 )
788 noexcept(
789 std::is_nothrow_constructible<U&, U2&>::value &&
790 std::is_nothrow_constructible<E, E2>::value &&
791 std::is_nothrow_default_constructible<E2>::value &&
792 std::is_nothrow_copy_constructible<E2>::value )
793 : v_( in_place_error, r2.error() )
794 {
795 if( r2 )
796 {
797 this->emplace( *r2 );
798 }
799 }
800
801 // queries
802
803 constexpr bool has_value() const noexcept
804 {
805 return v_.index() == 0;
806 }
807
808 constexpr bool has_error() const noexcept
809 {
810 return v_.index() == 1;
811 }
812
813 constexpr explicit operator bool() const noexcept
814 {
815 return v_.index() == 0;
816 }
817
818 // checked value access
819
820 BOOST_CXX14_CONSTEXPR U& value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const
821 {
822 if( has_value() )
823 {
824 return *variant2::unsafe_get<0>( v_ );
825 }
826 else
827 {
828 throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc );
829 }
830 }
831
832 // unchecked value access
833
834 BOOST_CXX14_CONSTEXPR U* operator->() const noexcept
835 {
836 return has_value()? variant2::unsafe_get<0>( v_ ): 0;
837 }
838
839 BOOST_CXX14_CONSTEXPR U& operator*() const noexcept
840 {
841 U* p = operator->();
842
843 BOOST_ASSERT( p != 0 );
844
845 return *p;
846 }
847
848 // error access
849
850 constexpr E error() const &
851 noexcept( std::is_nothrow_default_constructible<E>::value && std::is_nothrow_copy_constructible<E>::value )
852 {
853 return has_error()? variant2::unsafe_get<1>( v_ ): E();
854 }
855
856 BOOST_CXX14_CONSTEXPR E error() &&
857 noexcept( std::is_nothrow_default_constructible<E>::value && std::is_nothrow_move_constructible<E>::value )
858 {
859 return has_error()? std::move( variant2::unsafe_get<1>( v_ ) ): E();
860 }
861
862 // emplace
863
864 template<class A, class En = typename std::enable_if<
865 detail::is_constructible<U&, A>::value &&
866 !detail::reference_to_temporary<U, A>::value
867 >::type>
868 BOOST_CXX14_CONSTEXPR U& emplace( A&& a )
869 {
870 return *v_.template emplace<0>( &static_cast<U&>( a ) );
871 }
872
873 // swap
874
875 BOOST_CXX14_CONSTEXPR void swap( result& r )
876 noexcept( noexcept( v_.swap( r.v_ ) ) )
877 {
878 v_.swap( r.v_ );
879 }
880
881 friend BOOST_CXX14_CONSTEXPR void swap( result & r1, result & r2 )
882 noexcept( noexcept( r1.swap( r&: r2 ) ) )
883 {
884 r1.swap( r&: r2 );
885 }
886
887 // equality
888
889 friend constexpr bool operator==( result const & r1, result const & r2 )
890 noexcept( noexcept( r1 && r2? *r1 == *r2: r1.v_ == r2.v_ ) )
891 {
892 return r1 && r2? *r1 == *r2: r1.v_ == r2.v_;
893 }
894
895 friend constexpr bool operator!=( result const & r1, result const & r2 )
896 noexcept( noexcept( !( r1 == r2 ) ) )
897 {
898 return !( r1 == r2 );
899 }
900};
901
902#if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
903
904template<class U, class E> constexpr in_place_value_t result<U&, E>::in_place_value;
905template<class U, class E> constexpr in_place_error_t result<U&, E>::in_place_error;
906
907#endif
908
909// operator|
910
911namespace detail
912{
913
914// is_value_convertible_to
915
916template<class T, class U> struct is_value_convertible_to: std::is_convertible<T, U>
917{
918};
919
920template<class T, class U> struct is_value_convertible_to<T, U&>:
921 std::integral_constant<bool,
922 std::is_lvalue_reference<T>::value &&
923 std::is_convertible<typename std::remove_reference<T>::type*, U*>::value>
924{
925};
926
927// is_result
928
929template<class T> struct is_result: std::false_type {};
930template<class T, class E> struct is_result< result<T, E> >: std::true_type {};
931
932} // namespace detail
933
934// result | value
935
936template<class T, class E, class U,
937 class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
938>
939T operator|( result<T, E> const& r, U&& u )
940{
941 if( r )
942 {
943 return *r;
944 }
945 else
946 {
947 return std::forward<U>( u );
948 }
949}
950
951template<class T, class E, class U,
952 class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
953>
954T operator|( result<T, E>&& r, U&& u )
955{
956 if( r )
957 {
958 return *std::move( r );
959 }
960 else
961 {
962 return std::forward<U>( u );
963 }
964}
965
966// result | nullary-returning-value
967
968template<class T, class E, class F,
969 class U = decltype( std::declval<F>()() ),
970 class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
971>
972T operator|( result<T, E> const& r, F&& f )
973{
974 if( r )
975 {
976 return *r;
977 }
978 else
979 {
980 return std::forward<F>( f )();
981 }
982}
983
984template<class T, class E, class F,
985 class U = decltype( std::declval<F>()() ),
986 class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
987>
988T operator|( result<T, E>&& r, F&& f )
989{
990 if( r )
991 {
992 return *std::move( r );
993 }
994 else
995 {
996 return std::forward<F>( f )();
997 }
998}
999
1000// result | nullary-returning-result
1001
1002template<class T, class E, class F,
1003 class U = decltype( std::declval<F>()() ),
1004 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1005 class En2 = typename std::enable_if<detail::is_value_convertible_to<T, typename U::value_type>::value>::type
1006>
1007U operator|( result<T, E> const& r, F&& f )
1008{
1009 if( r )
1010 {
1011 return *r;
1012 }
1013 else
1014 {
1015 return std::forward<F>( f )();
1016 }
1017}
1018
1019template<class T, class E, class F,
1020 class U = decltype( std::declval<F>()() ),
1021 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1022 class En2 = typename std::enable_if<detail::is_value_convertible_to<T, typename U::value_type>::value>::type
1023>
1024U operator|( result<T, E>&& r, F&& f )
1025{
1026 if( r )
1027 {
1028 return *std::move( r );
1029 }
1030 else
1031 {
1032 return std::forward<F>( f )();
1033 }
1034}
1035
1036template<class E, class F,
1037 class U = decltype( std::declval<F>()() ),
1038 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1039 class En2 = typename std::enable_if<std::is_void<typename U::value_type>::value>::type
1040>
1041U operator|( result<void, E> const& r, F&& f )
1042{
1043 if( r )
1044 {
1045 return {};
1046 }
1047 else
1048 {
1049 return std::forward<F>( f )();
1050 }
1051}
1052
1053template<class E, class F,
1054 class U = decltype( std::declval<F>()() ),
1055 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1056 class En2 = typename std::enable_if<std::is_void<typename U::value_type>::value>::type
1057>
1058U operator|( result<void, E>&& r, F&& f )
1059{
1060 if( r )
1061 {
1062 return {};
1063 }
1064 else
1065 {
1066 return std::forward<F>( f )();
1067 }
1068}
1069
1070// operator|=
1071
1072// result |= value
1073
1074template<class T, class E, class U,
1075 class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
1076>
1077result<T, E>& operator|=( result<T, E>& r, U&& u )
1078{
1079 if( !r )
1080 {
1081 r = std::forward<U>( u );
1082 }
1083
1084 return r;
1085}
1086
1087// result |= nullary-returning-value
1088
1089template<class T, class E, class F,
1090 class U = decltype( std::declval<F>()() ),
1091 class En = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
1092>
1093result<T, E>& operator|=( result<T, E>& r, F&& f )
1094{
1095 if( !r )
1096 {
1097 r = std::forward<F>( f )();
1098 }
1099
1100 return r;
1101}
1102
1103// result |= nullary-returning-result
1104
1105template<class T, class E, class F,
1106 class U = decltype( std::declval<F>()() ),
1107 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1108 class En2 = typename std::enable_if<detail::is_value_convertible_to<typename U::value_type, T>::value>::type,
1109 class En3 = typename std::enable_if<std::is_convertible<typename U::error_type, E>::value>::type
1110>
1111result<T, E>& operator|=( result<T, E>& r, F&& f )
1112{
1113 if( !r )
1114 {
1115 r = std::forward<F>( f )();
1116 }
1117
1118 return r;
1119}
1120
1121// operator&
1122
1123// result & unary-returning-value
1124
1125template<class T, class E, class F,
1126 class U = decltype( std::declval<F>()( std::declval<T const&>() ) ),
1127 class En = typename std::enable_if<!detail::is_result<U>::value>::type
1128>
1129result<U, E> operator&( result<T, E> const& r, F&& f )
1130{
1131 if( r.has_error() )
1132 {
1133 return r.error();
1134 }
1135 else
1136 {
1137 return std::forward<F>( f )( *r );
1138 }
1139}
1140
1141template<class T, class E, class F,
1142 class U = decltype( std::declval<F>()( std::declval<T>() ) ),
1143 class En = typename std::enable_if<!detail::is_result<U>::value>::type
1144>
1145result<U, E> operator&( result<T, E>&& r, F&& f )
1146{
1147 if( r.has_error() )
1148 {
1149 return r.error();
1150 }
1151 else
1152 {
1153 return std::forward<F>( f )( *std::move( r ) );
1154 }
1155}
1156
1157template<class E, class F,
1158 class U = decltype( std::declval<F>()() ),
1159 class En = typename std::enable_if<!detail::is_result<U>::value>::type
1160>
1161result<U, E> operator&( result<void, E> const& r, F&& f )
1162{
1163 if( r.has_error() )
1164 {
1165 return r.error();
1166 }
1167 else
1168 {
1169 return std::forward<F>( f )();
1170 }
1171}
1172
1173// result & unary-returning-result
1174
1175template<class T, class E, class F,
1176 class U = decltype( std::declval<F>()( std::declval<T const&>() ) ),
1177 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1178 class En2 = typename std::enable_if<std::is_convertible<E, typename U::error_type>::value>::type
1179>
1180U operator&( result<T, E> const& r, F&& f )
1181{
1182 if( r.has_error() )
1183 {
1184 return r.error();
1185 }
1186 else
1187 {
1188 return std::forward<F>( f )( *r );
1189 }
1190}
1191
1192template<class T, class E, class F,
1193 class U = decltype( std::declval<F>()( std::declval<T>() ) ),
1194 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1195 class En2 = typename std::enable_if<std::is_convertible<E, typename U::error_type>::value>::type
1196>
1197U operator&( result<T, E>&& r, F&& f )
1198{
1199 if( r.has_error() )
1200 {
1201 return r.error();
1202 }
1203 else
1204 {
1205 return std::forward<F>( f )( *std::move( r ) );
1206 }
1207}
1208
1209template<class E, class F,
1210 class U = decltype( std::declval<F>()() ),
1211 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1212 class En2 = typename std::enable_if<std::is_convertible<E, typename U::error_type>::value>::type
1213>
1214U operator&( result<void, E> const& r, F&& f )
1215{
1216 if( r.has_error() )
1217 {
1218 return r.error();
1219 }
1220 else
1221 {
1222 return std::forward<F>( f )();
1223 }
1224}
1225
1226// operator&=
1227
1228// result &= unary-returning-value
1229
1230template<class T, class E, class F,
1231 class U = decltype( std::declval<F>()( std::declval<T>() ) ),
1232 class En1 = typename std::enable_if<!detail::is_result<U>::value>::type,
1233 class En2 = typename std::enable_if<detail::is_value_convertible_to<U, T>::value>::type
1234>
1235result<T, E>& operator&=( result<T, E>& r, F&& f )
1236{
1237 if( r )
1238 {
1239 r = std::forward<F>( f )( *std::move( r ) );
1240 }
1241
1242 return r;
1243}
1244
1245// result &= unary-returning-result
1246
1247template<class T, class E, class F,
1248 class U = decltype( std::declval<F>()( std::declval<T>() ) ),
1249 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1250 class En2 = typename std::enable_if<detail::is_value_convertible_to<typename U::value_type, T>::value>::type,
1251 class En3 = typename std::enable_if<std::is_convertible<typename U::error_type, E>::value>::type
1252>
1253result<T, E>& operator&=( result<T, E>& r, F&& f )
1254{
1255 if( r )
1256 {
1257 r = std::forward<F>( f )( *std::move( r ) );
1258 }
1259
1260 return r;
1261}
1262
1263template<class E, class F,
1264 class U = decltype( std::declval<F>()() ),
1265 class En1 = typename std::enable_if<detail::is_result<U>::value>::type,
1266 class En2 = typename std::enable_if<std::is_void<typename U::value_type>::value>::type,
1267 class En3 = typename std::enable_if<std::is_convertible<typename U::error_type, E>::value>::type
1268>
1269result<void, E>& operator&=( result<void, E>& r, F&& f )
1270{
1271 if( r )
1272 {
1273 r = std::forward<F>( f )();
1274 }
1275
1276 return r;
1277}
1278
1279} // namespace system
1280} // namespace boost
1281
1282#endif // #ifndef BOOST_SYSTEM_RESULT_HPP_INCLUDED
1283

source code of boost/libs/system/include/boost/system/result.hpp