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
0006
0007
0008
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
0067 class signal_no_error {};
0068 class signal_not_checked {};
0069 }
0070
0071
0072 BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1,
0073 0, O, VR, F, C, Args) : public cond_inv<VR, C>
0074 {
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
0084 boost::mpl::eval_if<boost::mpl::contains<boost::mpl::_1,
0085 boost::add_pointer<boost::mpl::_2> >,
0086 boost::mpl::_1
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
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>
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
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;
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
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 {
0247 if(v_) return v_->failed_;
0248 else return cond_base::failed();
0249 }
0250
0251 void failed(bool value) {
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 }
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;
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 {
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(
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(
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;
0373 } catch(...) {
0374 bool checked = f ? (this->*f)(
0375 false) : false;
0376 if(!checked) {
0377 try { throw; }
0378 catch(...) { this->fail(h); }
0379 }
0380 return;
0381 }
0382 }
0383 bool checked = f ?
0384 (this->*f)( 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 {
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
0435 }
0436 }
0437
0438 private:
0439 template<
0440 class B
0441
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 } } }
0473
0474 #endif
0475