Back to home page

EIC code displayed by LXR

 
 

    


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 // Copyright 2018-2023 Emil Dotchevski and Reverge Studios, Inc.
0005 
0006 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0007 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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); // Possible ODR violation.
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); // Possible ODR violation.
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); // Possible ODR violation.
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); // Possible ODR violation.
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); // Possible ODR violation.
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     // This should be the default implementation, but std::is_convertible
0372     // breaks under COMPILER=/usr/bin/clang++ CXXSTD=11 clang 3.3.
0373     // On the other hand, the workaround exposes a rather severe bug in
0374     //__GNUC__ under 11: https://github.com/boostorg/leaf/issues/25.
0375 
0376     // SFINAE: T can be initialized with a U, e.g. result<std::string>("literal").
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     // SFINAE: T can be initialized with a U, e.g. result<std::string>("literal").
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); // Possible ODR violation.
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