Back to home page

EIC code displayed by LXR

 
 

    


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 // 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/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); // Possible ODR violation.
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); // Possible ODR violation.
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); // Possible ODR violation.
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); // Possible ODR violation.
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     // NOTE: Copy constructor implicitly deleted.
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     // This should be the default implementation, but std::is_convertible
0389     // breaks under COMPILER=/usr/bin/clang++ CXXSTD=11 clang 3.3.
0390     // On the other hand, the workaround exposes a rather severe bug in
0391     //__GNUC__ under 11: https://github.com/boostorg/leaf/issues/25.
0392 
0393     // SFINAE: T can be initialized with an A, e.g. result<std::string>("literal").
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     // SFINAE: T can be initialized with an A, e.g. result<std::string>("literal").
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     // NOTE: Assignment operator implicitly deleted.
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); // Possible ODR violation.
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     // NOTE: Copy constructor implicitly deleted.
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     // NOTE: Assignment operator implicitly deleted.
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