File indexing completed on 2025-06-30 08:17:56
0001 #ifndef BOOST_LEAF_RESULT_HPP_INCLUDED
0002 #define BOOST_LEAF_RESULT_HPP_INCLUDED
0003
0004
0005
0006
0007
0008
0009 #include <boost/leaf/config.hpp>
0010 #include <boost/leaf/detail/print.hpp>
0011 #include <boost/leaf/detail/capture_list.hpp>
0012 #include <boost/leaf/exception.hpp>
0013
0014 #include <climits>
0015 #include <functional>
0016
0017 namespace boost { namespace leaf {
0018
0019 namespace leaf_detail { class dynamic_allocator; }
0020
0021
0022
0023 class bad_result:
0024 public std::exception,
0025 public error_id
0026 {
0027 char const * what() const noexcept final override
0028 {
0029 return "boost::leaf::bad_result";
0030 }
0031
0032 public:
0033
0034 explicit bad_result( error_id id ) noexcept:
0035 error_id(id)
0036 {
0037 BOOST_LEAF_ASSERT(value());
0038 }
0039 };
0040
0041
0042
0043 namespace leaf_detail
0044 {
0045 template <class T, bool Printable = is_printable<T>::value>
0046 struct result_value_printer;
0047
0048 template <class T>
0049 struct result_value_printer<T, true>
0050 {
0051 template <class CharT, class Traits>
0052 static void print( std::basic_ostream<CharT, Traits> & s, T const & x )
0053 {
0054 (void) (s << x);
0055 }
0056 };
0057
0058 template <class T>
0059 struct result_value_printer<T, false>
0060 {
0061 template <class CharT, class Traits>
0062 static void print( std::basic_ostream<CharT, Traits> & s, T const & )
0063 {
0064 (void) (s << "{not printable}");
0065 }
0066 };
0067
0068 template <class CharT, class Traits, class T>
0069 void print_result_value( std::basic_ostream<CharT, Traits> & s, T const & x )
0070 {
0071 result_value_printer<T>::print(s, x);
0072 }
0073 }
0074
0075
0076
0077 namespace leaf_detail
0078 {
0079 template <class T>
0080 struct stored
0081 {
0082 using type = T;
0083 using value_no_ref = T;
0084 using value_no_ref_const = T const;
0085 using value_cref = T const &;
0086 using value_ref = T &;
0087 using value_rv_cref = T const &&;
0088 using value_rv_ref = T &&;
0089
0090 static value_no_ref_const * cptr( type const & v ) noexcept
0091 {
0092 return &v;
0093 }
0094
0095 static value_no_ref * ptr( type & v ) noexcept
0096 {
0097 return &v;
0098 }
0099 };
0100
0101 template <class T>
0102 struct stored<T &>
0103 {
0104 using type = std::reference_wrapper<T>;
0105 using value_no_ref = T;
0106 using value_no_ref_const = T;
0107 using value_ref = T &;
0108 using value_cref = T &;
0109 using value_rv_ref = T &;
0110 using value_rv_cref = T &;
0111
0112 static value_no_ref_const * cptr( type const & v ) noexcept
0113 {
0114 return &v.get();
0115 }
0116
0117 static value_no_ref * ptr( type const & v ) noexcept
0118 {
0119 return &v.get();
0120 }
0121 };
0122
0123 class result_discriminant
0124 {
0125 int state_;
0126
0127 public:
0128
0129 enum kind_t
0130 {
0131 err_id_zero = 0,
0132 err_id = 1,
0133 err_id_capture_list = 2,
0134 val = 3
0135 };
0136
0137 explicit result_discriminant( error_id id ) noexcept:
0138 state_(id.value())
0139 {
0140 BOOST_LEAF_ASSERT(state_ == 0 || (state_&3) == 1);
0141 BOOST_LEAF_ASSERT(kind()==err_id_zero || kind()==err_id);
0142 }
0143
0144 #if BOOST_LEAF_CFG_CAPTURE
0145 explicit result_discriminant( int err_id, leaf_detail::capture_list const & ) noexcept:
0146 state_((err_id&~3) | 2)
0147 {
0148 BOOST_LEAF_ASSERT((err_id&3) == 1);
0149 BOOST_LEAF_ASSERT(kind() == err_id_capture_list);
0150 }
0151 #endif
0152
0153 struct kind_val { };
0154 explicit result_discriminant( kind_val ) noexcept:
0155 state_(val)
0156 {
0157 BOOST_LEAF_ASSERT((state_&3) == 3);
0158 BOOST_LEAF_ASSERT(kind()==val);
0159 }
0160
0161 kind_t kind() const noexcept
0162 {
0163 return kind_t(state_&3);
0164 }
0165
0166 error_id get_error_id() const noexcept
0167 {
0168 BOOST_LEAF_ASSERT(kind()==err_id_zero || kind()==err_id || kind()==err_id_capture_list);
0169 return make_error_id(int((state_&~3)|1));
0170 }
0171 };
0172 }
0173
0174
0175
0176 template <class T>
0177 class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
0178 {
0179 template <class U>
0180 friend class result;
0181
0182 friend class leaf_detail::dynamic_allocator;
0183
0184 #if BOOST_LEAF_CFG_CAPTURE
0185 using capture_list = leaf_detail::capture_list;
0186 #endif
0187
0188 using result_discriminant = leaf_detail::result_discriminant;
0189 using stored_type = typename leaf_detail::stored<T>::type;
0190 using value_no_ref = typename leaf_detail::stored<T>::value_no_ref;
0191 using value_no_ref_const = typename leaf_detail::stored<T>::value_no_ref_const;
0192 using value_ref = typename leaf_detail::stored<T>::value_ref;
0193 using value_cref = typename leaf_detail::stored<T>::value_cref;
0194 using value_rv_ref = typename leaf_detail::stored<T>::value_rv_ref;
0195 using value_rv_cref = typename leaf_detail::stored<T>::value_rv_cref;
0196
0197 union
0198 {
0199 stored_type stored_;
0200 #if BOOST_LEAF_CFG_CAPTURE
0201 mutable capture_list cap_;
0202 #endif
0203 };
0204
0205 result_discriminant what_;
0206
0207 struct error_result
0208 {
0209 error_result( error_result && ) = default;
0210 error_result( error_result const & ) = delete;
0211 error_result & operator=( error_result const & ) = delete;
0212
0213 result & r_;
0214
0215 error_result( result & r ) noexcept:
0216 r_(r)
0217 {
0218 }
0219
0220 template <class U>
0221 operator result<U>() noexcept
0222 {
0223 result_discriminant const what = r_.what_;
0224 switch( what.kind() )
0225 {
0226 case result_discriminant::val:
0227 return result<U>(error_id());
0228 case result_discriminant::err_id_capture_list:
0229 #if BOOST_LEAF_CFG_CAPTURE
0230 return result<U>(what.get_error_id().value(), std::move(r_.cap_));
0231 #else
0232 BOOST_LEAF_ASSERT(0);
0233 #endif
0234 case result_discriminant::err_id_zero:
0235 case result_discriminant::err_id:
0236 return result<U>(what.get_error_id());
0237 }
0238 }
0239
0240 operator error_id() noexcept
0241 {
0242 result_discriminant const what = r_.what_;
0243 return what.kind() == result_discriminant::val? error_id() : what.get_error_id();
0244 }
0245 };
0246
0247 void destroy() const noexcept
0248 {
0249 switch(this->what_.kind())
0250 {
0251 case result_discriminant::err_id_zero:
0252 case result_discriminant::err_id:
0253 break;
0254 case result_discriminant::err_id_capture_list:
0255 #if BOOST_LEAF_CFG_CAPTURE
0256 cap_.~capture_list();
0257 #else
0258 BOOST_LEAF_ASSERT(0);
0259 #endif
0260 break;
0261 case result_discriminant::val:
0262 stored_.~stored_type();
0263 }
0264 }
0265
0266 template <class U>
0267 result_discriminant move_from( result<U> && x ) noexcept
0268 {
0269 auto x_what = x.what_;
0270 switch(x_what.kind())
0271 {
0272 case result_discriminant::err_id_zero:
0273 case result_discriminant::err_id:
0274 break;
0275 case result_discriminant::err_id_capture_list:
0276 #if BOOST_LEAF_CFG_CAPTURE
0277 (void) new(&cap_) capture_list(std::move(x.cap_));
0278 #else
0279 BOOST_LEAF_ASSERT(0);
0280 #endif
0281 break;
0282 case result_discriminant::val:
0283 (void) new(&stored_) stored_type(std::move(x.stored_));
0284 }
0285 return x_what;
0286 }
0287
0288 error_id get_error_id() const noexcept
0289 {
0290 BOOST_LEAF_ASSERT(what_.kind() != result_discriminant::val);
0291 return what_.get_error_id();
0292 }
0293
0294 stored_type const * get() const noexcept
0295 {
0296 return has_value() ? &stored_ : nullptr;
0297 }
0298
0299 stored_type * get() noexcept
0300 {
0301 return has_value() ? &stored_ : nullptr;
0302 }
0303
0304 protected:
0305
0306 #if BOOST_LEAF_CFG_CAPTURE
0307 result( int err_id, leaf_detail::capture_list && cap ) noexcept:
0308 cap_(std::move(cap)),
0309 what_(err_id, cap)
0310 {
0311 }
0312 #endif
0313
0314 void enforce_value_state() const
0315 {
0316 switch( what_.kind() )
0317 {
0318 case result_discriminant::err_id_capture_list:
0319 #if BOOST_LEAF_CFG_CAPTURE
0320 cap_.unload(what_.get_error_id().value());
0321 #else
0322 BOOST_LEAF_ASSERT(0);
0323 #endif
0324 case result_discriminant::err_id_zero:
0325 case result_discriminant::err_id:
0326 ::boost::leaf::leaf_detail::throw_exception_impl(bad_result(get_error_id()));
0327 case result_discriminant::val:
0328 break;
0329 }
0330 }
0331
0332 template <class U>
0333 void move_assign( result<U> && x ) noexcept
0334 {
0335 destroy();
0336 what_ = move_from(std::move(x));
0337 }
0338
0339 public:
0340
0341 using value_type = T;
0342
0343
0344
0345 result( result && x ) noexcept:
0346 what_(move_from(std::move(x)))
0347 {
0348 }
0349
0350 template <class U, class = typename std::enable_if<std::is_convertible<U, T>::value>::type>
0351 result( result<U> && x ) noexcept:
0352 what_(move_from(std::move(x)))
0353 {
0354 }
0355
0356 result():
0357 stored_(stored_type()),
0358 what_(result_discriminant::kind_val{})
0359 {
0360 }
0361
0362 result( value_no_ref && v ) noexcept:
0363 stored_(std::forward<value_no_ref>(v)),
0364 what_(result_discriminant::kind_val{})
0365 {
0366 }
0367
0368 result( value_no_ref const & v ):
0369 stored_(v),
0370 what_(result_discriminant::kind_val{})
0371 {
0372 }
0373
0374 template<class... A, class = typename std::enable_if<std::is_constructible<T, A...>::value && sizeof...(A) >= 2>::type>
0375 result( A && ... a ) noexcept:
0376 stored_(std::forward<A>(a)...),
0377 what_(result_discriminant::kind_val{})
0378 {
0379 }
0380
0381 result( error_id err ) noexcept:
0382 what_(err)
0383 {
0384 }
0385
0386 #if defined(BOOST_STRICT_CONFIG) || !defined(__clang__)
0387
0388
0389
0390
0391
0392
0393
0394 template<class A, class = typename std::enable_if<std::is_constructible<T, A>::value && std::is_convertible<A, T>::value>::type>
0395 result( A && a ) noexcept:
0396 stored_(std::forward<A>(a)),
0397 what_(result_discriminant::kind_val{})
0398 {
0399 }
0400
0401 #else
0402
0403 private:
0404 static int init_T_with_A( T && );
0405 public:
0406
0407
0408 template <class A>
0409 result( A && a, decltype(init_T_with_A(std::forward<A>(a))) * = nullptr ):
0410 stored_(std::forward<A>(a)),
0411 what_(result_discriminant::kind_val{})
0412 {
0413 }
0414
0415 #endif
0416
0417 #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
0418 result( std::error_code const & ec ) noexcept:
0419 what_(error_id(ec))
0420 {
0421 }
0422
0423 template <class Enum, class = typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type>
0424 result( Enum e ) noexcept:
0425 what_(error_id(e))
0426 {
0427 }
0428 #endif
0429
0430 ~result() noexcept
0431 {
0432 destroy();
0433 }
0434
0435
0436
0437 result & operator=( result && x ) noexcept
0438 {
0439 move_assign(std::move(x));
0440 return *this;
0441 }
0442
0443 template <class U, class = typename std::enable_if<std::is_convertible<U, T>::value>::type>
0444 result & operator=( result<U> && x ) noexcept
0445 {
0446 move_assign(std::move(x));
0447 return *this;
0448 }
0449
0450 bool has_value() const noexcept
0451 {
0452 return what_.kind() == result_discriminant::val;
0453 }
0454
0455 bool has_error() const noexcept
0456 {
0457 return !has_value();
0458 }
0459
0460 explicit operator bool() const noexcept
0461 {
0462 return has_value();
0463 }
0464
0465 #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
0466
0467 value_cref value() const
0468 {
0469 enforce_value_state();
0470 return stored_;
0471 }
0472
0473 value_ref value()
0474 {
0475 enforce_value_state();
0476 return stored_;
0477 }
0478
0479 #else
0480
0481 value_cref value() const &
0482 {
0483 enforce_value_state();
0484 return stored_;
0485 }
0486
0487 value_ref value() &
0488 {
0489 enforce_value_state();
0490 return stored_;
0491 }
0492
0493 value_rv_cref value() const &&
0494 {
0495 enforce_value_state();
0496 return std::move(stored_);
0497 }
0498
0499 value_rv_ref value() &&
0500 {
0501 enforce_value_state();
0502 return std::move(stored_);
0503 }
0504
0505 #endif
0506
0507 value_no_ref_const * operator->() const noexcept
0508 {
0509 return has_value() ? leaf_detail::stored<T>::cptr(stored_) : nullptr;
0510 }
0511
0512 value_no_ref * operator->() noexcept
0513 {
0514 return has_value() ? leaf_detail::stored<T>::ptr(stored_) : nullptr;
0515 }
0516
0517 #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
0518
0519 value_cref operator*() const noexcept
0520 {
0521 auto p = get();
0522 BOOST_LEAF_ASSERT(p != nullptr);
0523 return *p;
0524 }
0525
0526 value_ref operator*() noexcept
0527 {
0528 auto p = get();
0529 BOOST_LEAF_ASSERT(p != nullptr);
0530 return *p;
0531 }
0532
0533 #else
0534
0535 value_cref operator*() const & noexcept
0536 {
0537 auto p = get();
0538 BOOST_LEAF_ASSERT(p != nullptr);
0539 return *p;
0540 }
0541
0542 value_ref operator*() & noexcept
0543 {
0544 auto p = get();
0545 BOOST_LEAF_ASSERT(p != nullptr);
0546 return *p;
0547 }
0548
0549 value_rv_cref operator*() const && noexcept
0550 {
0551 auto p = get();
0552 BOOST_LEAF_ASSERT(p != nullptr);
0553 return std::move(*p);
0554 }
0555
0556 value_rv_ref operator*() && noexcept
0557 {
0558 auto p = get();
0559 BOOST_LEAF_ASSERT(p != nullptr);
0560 return std::move(*p);
0561 }
0562
0563 #endif
0564
0565 error_result error() noexcept
0566 {
0567 return error_result{*this};
0568 }
0569
0570 template <class... Item>
0571 error_id load( Item && ... item ) noexcept
0572 {
0573 return error_id(error()).load(std::forward<Item>(item)...);
0574 }
0575
0576 void unload()
0577 {
0578 #if BOOST_LEAF_CFG_CAPTURE
0579 if( what_.kind() == result_discriminant::err_id_capture_list )
0580 cap_.unload(what_.get_error_id().value());
0581 #endif
0582 }
0583
0584 template <class CharT, class Traits>
0585 void print( std::basic_ostream<CharT, Traits> & os ) const
0586 {
0587 result_discriminant const what = what_;
0588 if( what.kind() == result_discriminant::val )
0589 leaf_detail::print_result_value(os, value());
0590 else
0591 {
0592 error_id const err_id = what.get_error_id();
0593 os << "Error ID " << err_id;
0594 if( what.kind() == result_discriminant::err_id_capture_list )
0595 {
0596 #if BOOST_LEAF_CFG_CAPTURE
0597 # if BOOST_LEAF_CFG_DIAGNOSTICS
0598 cap_.print(os, ". Captured error objects:\n", err_id.value());
0599 # endif
0600 #else
0601 BOOST_LEAF_ASSERT(0);
0602 #endif
0603 }
0604 }
0605 }
0606
0607 template <class CharT, class Traits>
0608 friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, result const & r )
0609 {
0610 r.print(os);
0611 return os;
0612 }
0613 };
0614
0615
0616
0617 namespace leaf_detail
0618 {
0619 struct void_ { };
0620 }
0621
0622 template <>
0623 class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result<void>:
0624 result<leaf_detail::void_>
0625 {
0626 template <class U>
0627 friend class result;
0628
0629 friend class leaf_detail::dynamic_allocator;
0630
0631 using result_discriminant = leaf_detail::result_discriminant;
0632 using void_ = leaf_detail::void_;
0633 using base = result<void_>;
0634
0635 #if BOOST_LEAF_CFG_CAPTURE
0636 result( int err_id, leaf_detail::capture_list && cap ) noexcept:
0637 base(err_id, std::move(cap))
0638 {
0639 }
0640 #endif
0641
0642 public:
0643
0644 using value_type = void;
0645
0646
0647 result( result && x ) noexcept:
0648 base(std::move(x))
0649 {
0650 }
0651
0652 result() noexcept
0653 {
0654 }
0655
0656 result( error_id err ) noexcept:
0657 base(err)
0658 {
0659 }
0660
0661 #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
0662 result( std::error_code const & ec ) noexcept:
0663 base(ec)
0664 {
0665 }
0666
0667 template <class Enum, class = typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type>
0668 result( Enum e ) noexcept:
0669 base(e)
0670 {
0671 }
0672 #endif
0673
0674 ~result() noexcept
0675 {
0676 }
0677
0678
0679 result & operator=( result && x ) noexcept
0680 {
0681 base::move_assign(std::move(x));
0682 return *this;
0683 }
0684
0685 void value() const
0686 {
0687 base::enforce_value_state();
0688 }
0689
0690 void const * operator->() const noexcept
0691 {
0692 return base::operator->();
0693 }
0694
0695 void * operator->() noexcept
0696 {
0697 return base::operator->();
0698 }
0699
0700 void operator*() const noexcept
0701 {
0702 BOOST_LEAF_ASSERT(has_value());
0703 }
0704
0705 template <class CharT, class Traits>
0706 void print( std::basic_ostream<CharT, Traits> & os ) const
0707 {
0708 if( what_.kind() == result_discriminant::val )
0709 os << "No error";
0710 else
0711 os << *static_cast<base const *>(this);
0712 }
0713
0714 template <class CharT, class Traits>
0715 friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, result const & r )
0716 {
0717 r.print(os);
0718 return os;
0719 }
0720
0721 using base::operator=;
0722 using base::operator bool;
0723 using base::get_error_id;
0724 using base::error;
0725 using base::load;
0726 using base::unload;
0727 };
0728
0729
0730
0731 template <class R>
0732 struct is_result_type;
0733
0734 template <class T>
0735 struct is_result_type<result<T>>: std::true_type
0736 {
0737 };
0738
0739 } }
0740
0741 #endif