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