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