Back to home page

EIC code displayed by LXR

 
 

    


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 // Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
0005 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0006 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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); // Possible ODR violation.
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); // Possible ODR violation.
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); // Possible ODR violation.
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); // Possible ODR violation.
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); // Possible ODR violation.
0349 #endif
0350         }
0351     }
0352 
0353 public:
0354 
0355     using value_type = T;
0356 
0357     // NOTE: Copy constructor implicitly deleted.
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     // This should be the default implementation, but std::is_convertible
0403     // breaks under COMPILER=/usr/bin/clang++ CXXSTD=11 clang 3.3.
0404     // On the other hand, the workaround exposes a rather severe bug in
0405     //__GNUC__ under 11: https://github.com/boostorg/leaf/issues/25.
0406 
0407     // SFINAE: T can be initialized with an A, e.g. result<std::string>("literal").
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     // SFINAE: T can be initialized with an A, e.g. result<std::string>("literal").
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     // NOTE: Assignment operator implicitly deleted.
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     // NOTE: Copy constructor implicitly deleted.
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     // NOTE: Assignment operator implicitly deleted.
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 // BOOST_LEAF_RESULT_HPP_INCLUDED