Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:26

0001 
0002 #ifndef BOOST_CONTRACT_DETAIL_COND_SUBCONTRACTING_HPP_
0003 #define BOOST_CONTRACT_DETAIL_COND_SUBCONTRACTING_HPP_
0004 
0005 // Copyright (C) 2008-2018 Lorenzo Caminiti
0006 // Distributed under the Boost Software License, Version 1.0 (see accompanying
0007 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
0008 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
0009 
0010 #include <boost/contract/core/config.hpp>
0011 #if     !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \
0012         !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
0013         !defined(BOOST_CONTRACT_NO_EXCEPTS)
0014     #include <boost/contract/core/exception.hpp>
0015 #endif
0016 #include <boost/contract/detail/condition/cond_inv.hpp>
0017 #include <boost/contract/detail/decl.hpp>
0018 #include <boost/contract/detail/tvariadic.hpp>
0019 #ifndef BOOST_CONTRACT_NO_CONDITIONS
0020     #include <boost/contract/core/virtual.hpp>
0021     #include <boost/contract/core/access.hpp>
0022     #include <boost/contract/detail/type_traits/optional.hpp>
0023     #include <boost/contract/detail/type_traits/member_function_types.hpp>
0024     #include <boost/contract/detail/debug.hpp>
0025     #include <boost/contract/detail/none.hpp>
0026     #include <boost/contract/detail/name.hpp>
0027     #include <boost/type_traits/add_pointer.hpp>
0028     #include <boost/mpl/fold.hpp>
0029     #include <boost/mpl/contains.hpp>
0030     #include <boost/mpl/empty.hpp>
0031     #include <boost/mpl/push_back.hpp>
0032     #include <boost/mpl/eval_if.hpp>
0033     #include <boost/mpl/identity.hpp>
0034     #include <boost/mpl/placeholders.hpp>
0035     #ifndef BOOST_CONTRACT_PERMISSIVE
0036         #include <boost/type_traits/is_same.hpp>
0037         #include <boost/mpl/or.hpp>
0038         #include <boost/mpl/not.hpp>
0039         #include <boost/static_assert.hpp>
0040     #endif
0041     #include <boost/preprocessor/punctuation/comma_if.hpp>
0042     #include <boost/config.hpp>
0043 #endif
0044 #include <boost/mpl/vector.hpp>
0045 #if     !defined(BOOST_CONTRACT_NO_INVARIANTS) || \
0046         !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
0047         !defined(BOOST_CONTRACT_NO_EXCEPTS)
0048     #include <boost/mpl/for_each.hpp>
0049 #endif
0050 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
0051     #include <boost/mpl/pop_front.hpp>
0052     #include <boost/mpl/front.hpp>
0053 #endif
0054 #if     !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
0055         !defined(BOSOT_CONTRACT_NO_EXCEPTS)
0056     #include <boost/any.hpp>
0057     #include <boost/optional.hpp>
0058     #include <boost/type_traits/remove_reference.hpp>
0059     #include <boost/utility/enable_if.hpp>
0060     #include <typeinfo>
0061 #endif
0062 
0063 namespace boost { namespace contract { namespace detail {
0064 
0065 namespace cond_subcontracting_ {
0066     // Exception signals (must not inherit).
0067     class signal_no_error {};
0068     class signal_not_checked {};
0069 }
0070 
0071 // O, VR, F, and Args-i can be none types (but C cannot).
0072 BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1,
0073         /* is_friend = */ 0, O, VR, F, C, Args) : public cond_inv<VR, C>
0074 { // Non-copyable base.
0075     #ifndef BOOST_CONTRACT_NO_CONDITIONS
0076         template<class Class, typename Result = boost::mpl::vector<> >
0077         class overridden_bases_of {
0078             struct search_bases {
0079                 typedef typename boost::mpl::fold<
0080                     typename boost::contract::access::base_types_of<Class>::
0081                             type,
0082                     Result,
0083                     // Fold: _1 = result, _2 = current base from base_types.
0084                     boost::mpl::eval_if<boost::mpl::contains<boost::mpl::_1,
0085                             boost::add_pointer<boost::mpl::_2> >,
0086                         boost::mpl::_1 // Base in result, do not add it again.
0087                     ,
0088                         boost::mpl::eval_if<
0089                             typename O::template BOOST_CONTRACT_DETAIL_NAME1(
0090                                     has_member_function)<
0091                                 boost::mpl::_2,
0092                                 typename member_function_types<C, F>::
0093                                         result_type,
0094                                 typename member_function_types<C, F>::
0095                                         virtual_argument_types,
0096                                 typename member_function_types<C, F>::
0097                                         property_tag
0098                             >
0099                         ,
0100                             boost::mpl::push_back<
0101                                 overridden_bases_of<boost::mpl::_2,
0102                                         boost::mpl::_1>,
0103                                 // Bases as * since for_each constructs them.
0104                                 boost::add_pointer<boost::mpl::_2>
0105                             >
0106                         ,
0107                             overridden_bases_of<boost::mpl::_2, boost::mpl::_1>
0108                         >
0109                     >
0110                 >::type type;
0111             };
0112         public:
0113             typedef typename boost::mpl::eval_if<
0114                     boost::contract::access::has_base_types<Class>,
0115                 search_bases
0116             ,
0117                 boost::mpl::identity<Result> // Return result (stop recursion).
0118             >::type type;
0119         };
0120         
0121         typedef typename boost::mpl::eval_if<boost::is_same<O, none>,
0122             boost::mpl::vector<>
0123         ,
0124             overridden_bases_of<C>
0125         >::type overridden_bases;
0126 
0127         #ifndef BOOST_CONTRACT_PERMISSIVE
0128             BOOST_STATIC_ASSERT_MSG(
0129                 (boost::mpl::or_<
0130                     boost::is_same<O, none>,
0131                     boost::mpl::not_<boost::mpl::empty<overridden_bases> >
0132                 >::value),
0133                 "subcontracting function specified as 'override' but does not "
0134                 "override any contracted member function"
0135             );
0136         #endif
0137     #else
0138         typedef boost::mpl::vector<> overridden_bases;
0139     #endif
0140 
0141 public:
0142     explicit cond_subcontracting(
0143         boost::contract::from from,
0144         boost::contract::virtual_* v,
0145         C* obj,
0146         VR&
0147         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS // Avoid unused param warning.
0148             r
0149         #endif
0150         BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS)
0151         BOOST_CONTRACT_DETAIL_TVARIADIC_FPARAMS_Z(1,
0152                 BOOST_CONTRACT_MAX_ARGS, Args, &, args)
0153     ) :
0154         cond_inv<VR, C>(from, obj)
0155         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
0156             , r_(r)
0157         #endif
0158         #ifndef BOOST_CONTRACT_NO_CONDITIONS
0159             BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS)
0160             BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INIT_Z(1,
0161                     BOOST_CONTRACT_MAX_ARGS, args_, args)
0162         #endif
0163     {
0164         #ifndef BOOST_CONTRACT_NO_CONDITIONS
0165             if(v) {
0166                 base_call_ = true;
0167                 v_ = v; // Invariant: v_ never null if base_call_.
0168                 BOOST_CONTRACT_DETAIL_DEBUG(v_);
0169             } else {
0170                 base_call_ = false;
0171                 if(!boost::mpl::empty<overridden_bases>::value) {
0172                     v_ = new boost::contract::virtual_(
0173                             boost::contract::virtual_::no_action);
0174                     #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
0175                         v_->result_ptr_ = &r_;
0176                         v_->result_type_name_ = typeid(VR).name();
0177                         v_->result_optional_ = is_optional<VR>::value;
0178                     #endif
0179                 } else v_ = 0;
0180             }
0181         #endif
0182     }
0183 
0184     #ifndef BOOST_CONTRACT_NO_CONDITIONS
0185         virtual ~cond_subcontracting() BOOST_NOEXCEPT_IF(false) {
0186             if(!base_call_) delete v_;
0187         }
0188     #endif
0189 
0190 protected:
0191     #ifndef BOOST_CONTRACT_NO_OLDS
0192         void init_subcontracted_old() {
0193             // Old values of overloaded func on stack (so no `f` param here).
0194             exec_and(boost::contract::virtual_::push_old_init_copy);
0195         }
0196     #endif
0197     
0198     #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
0199         void check_subcontracted_entry_inv() {
0200             exec_and(boost::contract::virtual_::check_entry_inv,
0201                     &cond_subcontracting::check_entry_inv);
0202         }
0203     #endif
0204     
0205     #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
0206         void check_subcontracted_pre() {
0207             exec_or(
0208                 boost::contract::virtual_::check_pre,
0209                 &cond_subcontracting::check_pre,
0210                 &boost::contract::precondition_failure
0211             );
0212         }
0213     #endif
0214 
0215     #ifndef BOOST_CONTRACT_NO_OLDS
0216         void copy_subcontracted_old() {
0217             exec_and(boost::contract::virtual_::call_old_ftor,
0218                     &cond_subcontracting::copy_virtual_old);
0219         }
0220     #endif
0221 
0222     #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
0223         void check_subcontracted_exit_inv() {
0224             exec_and(boost::contract::virtual_::check_exit_inv,
0225                     &cond_subcontracting::check_exit_inv);
0226         }
0227     #endif
0228 
0229     #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
0230         void check_subcontracted_post() {
0231             exec_and(boost::contract::virtual_::check_post,
0232                     &cond_subcontracting::check_virtual_post);
0233         }
0234     #endif
0235 
0236     #ifndef BOOST_CONTRACT_NO_EXCEPTS
0237         void check_subcontracted_except() {
0238             exec_and(boost::contract::virtual_::check_except,
0239                     &cond_subcontracting::check_virtual_except);
0240         }
0241     #endif
0242 
0243     #ifndef BOOST_CONTRACT_NO_CONDITIONS
0244         bool base_call() const { return base_call_; }
0245 
0246         bool failed() const /* override */ {
0247             if(v_) return v_->failed_;
0248             else return cond_base::failed();
0249         }
0250 
0251         void failed(bool value) /* override */ {
0252             if(v_) v_->failed_ = value;
0253             else cond_base::failed(value);
0254         }
0255     #endif
0256 
0257 private:
0258     #ifndef BOOST_CONTRACT_NO_OLDS
0259         void copy_virtual_old() {
0260             boost::contract::virtual_::action_enum a;
0261             if(base_call_) {
0262                 a = v_->action_;
0263                 v_->action_ = boost::contract::virtual_::push_old_ftor_copy;
0264             }
0265             this->copy_old();
0266             if(base_call_) v_->action_ = a;
0267         }
0268             
0269         void pop_base_old() {
0270             if(base_call_) {
0271                 boost::contract::virtual_::action_enum a = v_->action_;
0272                 v_->action_ = boost::contract::virtual_::pop_old_ftor_copy;
0273                 this->copy_old();
0274                 v_->action_ = a;
0275             } // Else, do nothing (for base calls only).
0276         }
0277     #endif
0278 
0279     #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
0280         void check_virtual_post() {
0281             pop_base_old();
0282             typedef typename boost::remove_reference<typename
0283                     optional_value_type<VR>::type>::type r_type;
0284             boost::optional<r_type const&> r; // No result copy in this code.
0285             if(!base_call_) r = optional_get(r_);
0286             else if(v_->result_optional_) {
0287                 try {
0288                     r = **boost::any_cast<boost::optional<r_type>*>(
0289                             v_->result_ptr_);
0290                 } catch(boost::bad_any_cast const&) {
0291                     try { // Handle optional<...&>.
0292                         r = **boost::any_cast<boost::optional<r_type&>*>(
0293                                 v_->result_ptr_);
0294                     } catch(boost::bad_any_cast const&) {
0295                         try {
0296                             throw boost::contract::bad_virtual_result_cast(v_->
0297                                     result_type_name_, typeid(r_type).name());
0298                         } catch(...) {
0299                             this->fail(&boost::contract::postcondition_failure);
0300                         }
0301                     }
0302                 }
0303             } else {
0304                 try {
0305                     r = *boost::any_cast<r_type*>(v_->result_ptr_);
0306                 } catch(boost::bad_any_cast const&) {
0307                     try {
0308                         throw boost::contract::bad_virtual_result_cast(
0309                                 v_->result_type_name_, typeid(r_type).name());
0310                     } catch(...) {
0311                         this->fail(&boost::contract::postcondition_failure);
0312                     }
0313                 }
0314             }
0315             check_virtual_post_with_result<VR>(r);
0316         }
0317 
0318         template<typename R_, typename Result>
0319         typename boost::enable_if<is_optional<R_> >::type
0320         check_virtual_post_with_result(Result const& r) {
0321             this->check_post(r);
0322         }
0323         
0324         template<typename R_, typename Result>
0325         typename boost::disable_if<is_optional<R_> >::type
0326         check_virtual_post_with_result(Result const& r) {
0327             BOOST_CONTRACT_DETAIL_DEBUG(r);
0328             this->check_post(*r);
0329         }
0330     #endif
0331     
0332     #ifndef BOOST_CONTRACT_NO_EXCEPTS
0333         void check_virtual_except() {
0334             pop_base_old();
0335             this->check_except();
0336         }
0337     #endif
0338 
0339     #if     !defined(BOOST_CONTRACT_NO_INVARIANTS) || \
0340             !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
0341             !defined(BOOST_CONTRACT_NO_EXCEPTS)
0342         void exec_and( // Execute action in short-circuit logic-and with bases.
0343             boost::contract::virtual_::action_enum a,
0344             void (cond_subcontracting::* f)() = 0
0345         ) {
0346             if(failed()) return;
0347             if(!base_call_ || v_->action_ == a) {
0348                 if(!base_call_ && v_) {
0349                     v_->action_ = a;
0350                     boost::mpl::for_each<overridden_bases>(call_base(*this));
0351                 }
0352                 if(f) (this->*f)();
0353                 if(base_call_) {
0354                     throw cond_subcontracting_::signal_no_error();
0355                 }
0356             }
0357         }
0358     #endif
0359 
0360     #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
0361         void exec_or( // Execute action in short-circuit logic-or with bases.
0362             boost::contract::virtual_::action_enum a,
0363             bool (cond_subcontracting::* f)(bool) = 0,
0364             void (*h)(boost::contract::from) = 0
0365         ) {
0366             if(failed()) return;
0367             if(!base_call_ || v_->action_ == a) {
0368                 if(!base_call_ && v_) {
0369                     v_->action_ = a;
0370                     try { 
0371                         exec_or_bases<overridden_bases>();
0372                         return; // A base checked with no error (done).
0373                     } catch(...) {
0374                         bool checked =  f ? (this->*f)(
0375                                 /* throw_on_failure = */ false) : false;
0376                         if(!checked) {
0377                             try { throw; } // Report latest exception found.
0378                             catch(...) { this->fail(h); }
0379                         }
0380                         return; // Checked and no exception (done).
0381                     }
0382                 }
0383                 bool checked = f ?
0384                         (this->*f)(/* throw_on_failure = */ base_call_) : false;
0385                 if(base_call_) {
0386                     if(!checked) {
0387                         throw cond_subcontracting_::signal_not_checked();
0388                     }
0389                     throw cond_subcontracting_::signal_no_error();
0390                 }
0391             }
0392         }
0393         
0394         template<typename Bases>
0395         typename boost::enable_if<boost::mpl::empty<Bases>, bool>::type
0396         exec_or_bases() { return false; }
0397 
0398         template<typename Bases>
0399         typename boost::disable_if<boost::mpl::empty<Bases>, bool>::type
0400         exec_or_bases() {
0401             if(boost::mpl::empty<Bases>::value) return false;
0402             try {
0403                 call_base(*this)(typename boost::mpl::front<Bases>::type());
0404             } catch(cond_subcontracting_::signal_not_checked const&) {
0405                 return exec_or_bases<
0406                         typename boost::mpl::pop_front<Bases>::type>();
0407             } catch(...) {
0408                 bool checked = false;
0409                 try {
0410                     checked = exec_or_bases<
0411                             typename boost::mpl::pop_front<Bases>::type>();
0412                 } catch(...) { checked = false; }
0413                 if(!checked) throw;
0414             }
0415             return true;
0416         }
0417     #endif
0418     
0419     #ifndef BOOST_CONTRACT_NO_CONDITIONS
0420         class call_base { // Copyable (as &).
0421         public:
0422             explicit call_base(cond_subcontracting& me) : me_(me) {}
0423 
0424             template<class B>
0425             void operator()(B*) {
0426                 BOOST_CONTRACT_DETAIL_DEBUG(me_.object());
0427                 BOOST_CONTRACT_DETAIL_DEBUG(me_.v_);
0428                 BOOST_CONTRACT_DETAIL_DEBUG(me_.v_->action_ !=
0429                         boost::contract::virtual_::no_action);
0430                 try {
0431                     call<B>(BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_OF(
0432                             Args));
0433                 } catch(cond_subcontracting_::signal_no_error const&) {
0434                     // No error (do not throw).
0435                 }
0436             }
0437 
0438         private:
0439             template<
0440                 class B
0441                 // Can't use TVARIADIC_COMMA here.
0442                 BOOST_PP_COMMA_IF(BOOST_CONTRACT_DETAIL_TVARIADIC)
0443                 BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_TPARAM(I)
0444             >
0445             void call(
0446                     BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_FPARAM(I)) {
0447                 O::template BOOST_CONTRACT_DETAIL_NAME1(call_base)<B>(
0448                     me_.v_,
0449                     me_.object()
0450                     BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(
0451                             BOOST_CONTRACT_MAX_ARGS)
0452                     BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_ELEMS_Z(1,
0453                             BOOST_CONTRACT_MAX_ARGS, I, me_.args_)
0454                 );
0455             }
0456             
0457             cond_subcontracting& me_;
0458         };
0459     #endif
0460 
0461     #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
0462         VR& r_;
0463     #endif
0464     #ifndef BOOST_CONTRACT_NO_CONDITIONS
0465         boost::contract::virtual_* v_;
0466         bool base_call_;
0467         BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_Z(1,
0468                 BOOST_CONTRACT_MAX_ARGS, Args, &, args_)
0469     #endif
0470 };
0471 
0472 } } } // namespace
0473 
0474 #endif // #include guard
0475