diff --git a/include/boost/contract.hpp b/include/boost/contract.hpp index ac7ad15..72b8728 100644 --- a/include/boost/contract.hpp +++ b/include/boost/contract.hpp @@ -2,18 +2,19 @@ #ifndef BOOST_CONTRACT_HPP_ #define BOOST_CONTRACT_HPP_ -// TODO: Include all public headers here. Consider moving non-independent -// headers in a sudir like core/. - -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include #include +#include #endif // #include guard diff --git a/include/boost/contract/assert.hpp b/include/boost/contract/assert.hpp index 2c0c457..b42f28e 100644 --- a/include/boost/contract/assert.hpp +++ b/include/boost/contract/assert.hpp @@ -2,7 +2,7 @@ #ifndef BOOST_CONTRACT_ASSERT_HPP_ #define BOOST_CONTRACT_ASSERT_HPP_ -#include +#include #include /* PUBLIC */ diff --git a/include/boost/contract/aux_/check/pre_post.hpp b/include/boost/contract/aux_/check/pre_post.hpp index d31eb6c..de05c64 100644 --- a/include/boost/contract/aux_/check/pre_post.hpp +++ b/include/boost/contract/aux_/check/pre_post.hpp @@ -2,7 +2,6 @@ #ifndef BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ #define BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ -#include #include #include diff --git a/include/boost/contract/aux_/check/pre_post_inv.hpp b/include/boost/contract/aux_/check/pre_post_inv.hpp index 26ed2c6..61429c1 100644 --- a/include/boost/contract/aux_/check/pre_post_inv.hpp +++ b/include/boost/contract/aux_/check/pre_post_inv.hpp @@ -2,9 +2,9 @@ #ifndef BOOST_CONTRACT_AUX_CHECK_PRE_POST_INV_HPP_ #define BOOST_CONTRACT_AUX_CHECK_PRE_POST_INV_HPP_ -#include -#include +#include #include +#include #include #include #include diff --git a/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp b/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp index 119a911..6bdd100 100644 --- a/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp +++ b/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp @@ -2,18 +2,22 @@ #ifndef BOOST_CONTRACT_AUX_CHECK_SUBCONTRACTED_PRE_POST_INV_HPP_ #define BOOST_CONTRACT_AUX_CHECK_SUBCONTRACTED_PRE_POST_INV_HPP_ -#include -#include -#include +// TODO: Double check that this lib header should only #include from core/* +// and aux_/*, while headers directly from contract/* should NOT be #included +// by other headers of this lib (so they remain 100% for user's #inclusion). +// Consider generating a Doxygen #include diagram... + +#include +#include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -29,31 +33,11 @@ #include #include -// TODO: Fix !CONFIG_PERMISSIVE static assertions. -//#if !BOOST_CONTRACT_CONFIG_PERMISSIVE -// BOOST_STATIC_ASSERT_MSG(!boost::contract::aux::has_mutable_invariant< -// Class>::value, "class invariant function must be const"); -// BOOST_STATIC_ASSERT_MSG( -// (!boost::mpl::and_< -// boost::contract::aux::has_bases, -// boost::mpl::or_< -// boost::is_same, -// boost::is_same -// > -// >::value), -// "must specify introspection type, function type, and function " -// "arguments for member contract of class with bases" -// ); -// // TODO: static_assert(Func == none || class::type == Class) -//#endif - - namespace boost { namespace contract { namespace aux { namespace check { template< class Class, class Intro = boost::contract::aux::none, - typename Func = boost::contract::aux::none, typename Arg0 = boost::contract::aux::none > class subcontracted_pre_post_inv : public boost::contract::aux::check::pre_post_inv, @@ -71,34 +55,26 @@ template< >::type base_ptrs; public: - explicit subcontracted_pre_post_inv( - boost::contract::from const from, - boost::contract::virtual_body const virt, Class* const obj, - Arg0 arg0 + explicit subcontracted_pre_post_inv(boost::contract::from const from, + boost::contract::virtual_* const virt, Class* const obj, Arg0& arg0 ) : boost::contract::aux::check::pre_post_inv(from, obj), virt_(virt), arg0_(arg0) { init(); } - explicit subcontracted_pre_post_inv(boost::contract::from const from, - boost::contract::virtual_body const virt, Class* const obj) : - boost::contract::aux::check::pre_post_inv(from, obj), - virt_(virt) - { init(); } - - virtual ~subcontracted_pre_post_inv() {} + virtual ~subcontracted_pre_post_inv() { if(own_virt_) delete virt_; } protected: void copy_subcontracted_oldof() { boost::mpl::for_each(check_base_.action( - boost::contract::aux::virtual_call::copy_oldof)); + boost::contract::virtual_::copy_oldof)); // Old-of values always copied on stack for derived func being called. } void check_subcontracted_entry_inv() { boost::mpl::for_each(check_base_.action( - boost::contract::aux::virtual_call::check_entry_inv)); + boost::contract::virtual_::check_entry_inv)); this->check_entry_inv(); } @@ -106,7 +82,7 @@ protected: void check_subcontracted_pre(bool const throw_on_failure = false) { try { boost::mpl::for_each(check_base_.action( - boost::contract::aux::virtual_call::check_pre)); + boost::contract::virtual_::check_pre)); // Pre logic-or: Last check, error also throws. this->check_pre(throw_on_failure); } catch(boost::contract::aux::no_error const&) { @@ -116,23 +92,28 @@ protected: void check_subcontracted_exit_inv() { boost::mpl::for_each(check_base_.action( - boost::contract::aux::virtual_call::check_exit_inv)); + boost::contract::virtual_::check_exit_inv)); this->check_exit_inv(); } void check_subcontracted_post() { boost::mpl::for_each(check_base_.action( - boost::contract::aux::virtual_call::check_post)); - this->check_post(); + boost::contract::virtual_::check_post)); + std::clog << "post checking" << std::endl; + check_base_.action(boost::contract::virtual_::check_this_post)(this->object()); + std::clog << "post checked" << std::endl; + //this->check_post(); } - boost::contract::virtual_body virtual_call() { return virt_; } + // Invariant: virt_ never null after init (so can always deref it here). + boost::contract::virtual_& virtual_call() { return *virt_; } private: void init() { - if(!virt_) { - virt_ = boost::contract::virtual_body( - new boost::contract::aux::virtual_call()); + if(virt_) own_virt_ = false; + else { + virt_ = new boost::contract::virtual_(); + own_virt_ = true; } check_base_.nest(this); } @@ -140,87 +121,93 @@ private: class check_base { public: explicit check_base() : nest_(0), - action_(boost::contract::aux::virtual_call::user_call) {} + action_(boost::contract::virtual_::user_call) {} void nest(subcontracted_pre_post_inv* n) { nest_ = n; } - check_base& action( - boost::contract::aux::virtual_call::action_type const a) { + check_base& action(boost::contract::virtual_::action_enum const a) { action_ = a; return *this; } template void operator()(Base*) { - typedef typename boost::function_types::result_type::type - result_type; - typedef typename boost::mpl::pop_front< - typename boost::function_types::parameter_types::type - >::type arg_types; - typedef typename boost::mpl::eval_if< - boost::is_same::type, - boost::contract::virtual_body> - , - boost::mpl::identity - , - boost::mpl::push_back - >::type virtual_arg_types; + typedef boost::contract::var result_type; + typedef boost::mpl::vector + virtual_arg_types; + //std::clog << "*** func: " << + // typeid(result_type).name() << " " << + // typeid(Base).name() << " " << + // typeid(virtual_arg_types).name() << + //std::endl; call_base_function( - boost::mpl::bool_::value>() + boost::mpl::bool_< + Intro::template has_member_function< + Base, + result_type, + virtual_arg_types, + boost::function_types::const_qualified + >::value + >() ); } private: template - void call_base_function(boost::mpl::false_ const&) {} + void call_base_function(boost::mpl::false_ const&) { + //std::clog << "*** base function not found" << std::endl; + } template void call_base_function(boost::mpl::true_ const&) { + //std::clog << "*** base function found" << std::endl; + typedef typename boost::mpl::push_front< typename boost::mpl::push_front::type, ResultType >::type base_virtual_func_types; typedef typename boost::function_types::member_function_pointer< - base_virtual_func_types>::type base_virtual_func_ptr; + base_virtual_func_types, + boost::function_types::const_qualified + >::type base_virtual_func_ptr; base_virtual_func_ptr base_virtual_func = Intro::template member_function_address(); BOOST_CONTRACT_AUX_DEBUG(base_virtual_func); BOOST_CONTRACT_AUX_DEBUG(nest_); - Base* const base = nest_->object(); + Base const* const base = nest_->object(); BOOST_CONTRACT_AUX_DEBUG(base); - boost::contract::aux::virtual_call::action_type a = - nest_->virt_->action; - nest_->virt_->action = action_; + boost::contract::virtual_::action_enum reset_action = + nest_->virtual_call().action_; + nest_->virtual_call().action_ = action_; try { (base->*base_virtual_func)(nest_->arg0_, nest_->virt_); } catch(boost::contract::aux::no_error const&) { - if(nest_->virt_->action == - boost::contract::aux::virtual_call::check_pre) { - nest_->virt_->action = a; + if(nest_->virtual_call().action_ == + boost::contract::virtual_::check_pre) { + nest_->virtual_call().action_ = reset_action; throw; // Pre logic-or: 1st no_err stops (throw to caller). } } catch(...) { - if(nest_->virt_->action == - boost::contract::aux::virtual_call::check_pre) { + if(nest_->virtual_call().action_ == + boost::contract::virtual_::check_pre) { // Pre logic-or: Ignore err, possibly checks up to caller. } } - nest_->virt_->action = a; + nest_->virtual_call().action_ = reset_action; } subcontracted_pre_post_inv* nest_; - boost::contract::aux::virtual_call::action_type action_; + boost::contract::virtual_::action_enum action_; }; + bool own_virt_; + boost::contract::virtual_* virt_; check_base check_base_; - boost::contract::virtual_body virt_; - // TODO: add_reference/perfect fwd to all these Arg-i types. // TODO: Support 0-to-n args. - Arg0 arg0_; + Arg0& arg0_; // TODO: Should this be & or perfect fwd? }; } } } } // namespace diff --git a/include/boost/contract/aux_/exception.hpp b/include/boost/contract/aux_/exception.hpp index 26cfe34..32d1933 100644 --- a/include/boost/contract/aux_/exception.hpp +++ b/include/boost/contract/aux_/exception.hpp @@ -2,10 +2,87 @@ #ifndef BOOST_CONTRACT_AUX_EXCEPTION_HPP_ #define BOOST_CONTRACT_AUX_EXCEPTION_HPP_ +#include +#include +#include +#include + namespace boost { namespace contract { namespace aux { struct no_error {}; // Do not inherit from anything (this is internal only). +namespace exception_ { + enum failure_handler_key { + pre_key, + post_key, + const_entry_inv_key, + const_volatile_entry_inv_key, + static_entry_inv_key, + const_exit_inv_key, + const_volatile_exit_inv_key, + static_exit_inv_key, + }; + + template + void default_failure_handler(From const) { + std::string s = ""; + switch(Key) { + case pre_key: + s = "precondition "; break; + case post_key: + s = "postcondition "; break; + case const_entry_inv_key: + s = "const entry invariant "; break; + case const_volatile_entry_inv_key: + s = "const volatile entry invariant "; break; + case static_entry_inv_key: + s = "static entry invariant "; break; + case const_exit_inv_key: + s= "const exit invariant "; break; + case const_volatile_exit_inv_key: + s= "const volatile exit invariant "; break; + case static_exit_inv_key: + s = "static exit invariant "; break; + // No default (so compiler warning/error on missing enum case). + } + try { + throw; + } catch(boost::contract::assertion_failure const& error) { + // what = 'assertion "..." failed: ...'. + std::cerr << s << error.what() << std::endl; + } catch(std::exception const& error) { + std::cerr << s << "checking threw standard exception with " << + "what(): " << error.what() << std::endl; + } catch(...) { + std::cerr << s << "checking threw unknown exception" << + std::endl; + } + std::terminate(); // Default handlers log and call terminate. + } +} + +// TODO: These are part of the lib state. They should prob be put in a .cpp and +// exported (so they are the same across DLL, etc.), plus they should be +// protected by mutexes. +failure_handler pre_failure_handler = &exception_:: + default_failure_handler; +failure_handler post_failure_handler = &exception_:: + default_failure_handler; + +failure_handler const_entry_inv_failure_handler = &exception_:: + default_failure_handler; +failure_handler const_volatile_entry_inv_failure_handler = &exception_:: + default_failure_handler; +failure_handler static_entry_inv_failure_handler = &exception_:: + default_failure_handler; + +failure_handler const_exit_inv_failure_handler = &exception_:: + default_failure_handler; +failure_handler const_volatile_exit_inv_failure_handler = &exception_:: + default_failure_handler; +failure_handler static_exit_inv_failure_handler = &exception_:: + default_failure_handler; + } } } // namespace #endif // #include guard diff --git a/include/boost/contract/aux_/function/constructor.hpp b/include/boost/contract/aux_/function/constructor.hpp index 6ce7b0e..64b6b45 100644 --- a/include/boost/contract/aux_/function/constructor.hpp +++ b/include/boost/contract/aux_/function/constructor.hpp @@ -2,7 +2,7 @@ #ifndef BOOST_CONTRACT_AUX_FUNCTION_CONSTRUCTOR_HPP_ #define BOOST_CONTRACT_AUX_FUNCTION_CONSTRUCTOR_HPP_ -#include +#include #include #include diff --git a/include/boost/contract/aux_/function/destructor.hpp b/include/boost/contract/aux_/function/destructor.hpp index 872a97c..eac02c5 100644 --- a/include/boost/contract/aux_/function/destructor.hpp +++ b/include/boost/contract/aux_/function/destructor.hpp @@ -2,7 +2,7 @@ #ifndef BOOST_CONTRACT_AUX_FUNCTION_DESTRUCTOR_HPP_ #define BOOST_CONTRACT_AUX_FUNCTION_DESTRUCTOR_HPP_ -#include +#include #include #include #include diff --git a/include/boost/contract/aux_/function/free_function.hpp b/include/boost/contract/aux_/function/free_function.hpp index 6da7094..b504aea 100644 --- a/include/boost/contract/aux_/function/free_function.hpp +++ b/include/boost/contract/aux_/function/free_function.hpp @@ -2,7 +2,7 @@ #ifndef BOOST_CONTRACT_AUX_FUNCTION_FREE_FUNCTION_HPP_ #define BOOST_CONTRACT_AUX_FUNCTION_FREE_FUNCTION_HPP_ -#include +#include #include #include diff --git a/include/boost/contract/aux_/function/private_member.hpp b/include/boost/contract/aux_/function/private_member.hpp index b3ca1dc..f1bbf1a 100644 --- a/include/boost/contract/aux_/function/private_member.hpp +++ b/include/boost/contract/aux_/function/private_member.hpp @@ -2,7 +2,7 @@ #ifndef BOOST_CONTRACT_AUX_FUNCTION_PRIVATE_MEMBER_HPP_ #define BOOST_CONTRACT_AUX_FUNCTION_PRIVATE_MEMBER_HPP_ -#include +#include #include namespace boost { namespace contract { namespace aux { namespace function { diff --git a/include/boost/contract/aux_/function/protected_member.hpp b/include/boost/contract/aux_/function/protected_member.hpp index 9cabdda..0fba547 100644 --- a/include/boost/contract/aux_/function/protected_member.hpp +++ b/include/boost/contract/aux_/function/protected_member.hpp @@ -2,7 +2,7 @@ #ifndef BOOST_CONTRACT_AUX_FUNCTION_PROTECTED_MEMBER_HPP_ #define BOOST_CONTRACT_AUX_FUNCTION_PROTECTED_MEMBER_HPP_ -#include +#include #include namespace boost { namespace contract { namespace aux { namespace function { diff --git a/include/boost/contract/aux_/function/public_member.hpp b/include/boost/contract/aux_/function/public_member.hpp index 3b24b4f..b285d59 100644 --- a/include/boost/contract/aux_/function/public_member.hpp +++ b/include/boost/contract/aux_/function/public_member.hpp @@ -2,113 +2,94 @@ #ifndef BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_MEMBER_HPP_ #define BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_MEMBER_HPP_ -#include -#include +#include +#include #include -#include #include #include #include #include -namespace boost { namespace contract { namespace aux { namespace function { +// TODO: Consider passing params as in (by mutable value or const&), inout +// (by & or *). +namespace boost { namespace contract { namespace aux { namespace function { + template< class Class, class Intro = boost::contract::aux::none, - typename Func = boost::contract::aux::none, typename Arg0 = boost::contract::aux::none > class public_member : public boost::contract::aux::check:: - subcontracted_pre_post_inv { + subcontracted_pre_post_inv { public: // Must be used when bases and virtual body (but can also always be used). - explicit public_member(boost::contract::virtual_body const virt, - Class* const obj, Arg0 arg0) : - boost::contract::aux::check::subcontracted_pre_post_inv< - Class, Intro, Func, Arg0 - >(boost::contract::from_public_member, virt, obj, arg0) - { - BOOST_CONTRACT_AUX_DEBUG((!boost::is_same::value)); - BOOST_CONTRACT_AUX_DEBUG((!boost::is_same::value)); - entry(); - } + explicit public_member(boost::contract::virtual_* const virt, + Class* const obj, Arg0& arg0) : + boost::contract::aux::check::subcontracted_pre_post_inv(boost::contract::from_public_member, virt, obj, + arg0 + ) + { entry(); } // Can be used when bases and no virtual body. - explicit public_member(Class* const obj, Arg0 arg0) : - boost::contract::aux::check::subcontracted_pre_post_inv< - Class, Intro, Func, Arg0 - >(boost::contract::from_public_member, /* virt = */ 0, obj, arg0) - { - BOOST_CONTRACT_AUX_DEBUG((!boost::is_same::value)); - BOOST_CONTRACT_AUX_DEBUG((!boost::is_same::value)); - entry(); - } + explicit public_member(Class* const obj, Arg0& arg0) : + boost::contract::aux::check::subcontracted_pre_post_inv(boost::contract::from_public_member, /* virt = */ 0, obj, + arg0 + ) + { entry(); } // Can be used when no bases and virtual body. - explicit public_member(boost::contract::virtual_body const virt, + explicit public_member(boost::contract::virtual_* const virt, Class* const obj) : - boost::contract::aux::check::subcontracted_pre_post_inv< - Class, Intro, Func, Arg0 - >(boost::contract::from_public_member, virt, obj) - { - BOOST_CONTRACT_AUX_DEBUG((boost::is_same::value)); - BOOST_CONTRACT_AUX_DEBUG((boost::is_same::value)); - entry(); - } + boost::contract::aux::check::subcontracted_pre_post_inv(boost::contract::from_public_member, virt, obj, + boost::contract::aux::none::value + ) + { entry(); } // Can be used when no bases and no virtual body. explicit public_member(Class* const obj) : - boost::contract::aux::check::subcontracted_pre_post_inv< - Class, Intro, Func, Arg0 - >(boost::contract::from_public_member, /* virt = */ 0, obj) - { - BOOST_CONTRACT_AUX_DEBUG((boost::is_same::value)); - BOOST_CONTRACT_AUX_DEBUG((boost::is_same::value)); - entry(); - } + boost::contract::aux::check::subcontracted_pre_post_inv(boost::contract::from_public_member, /* virt = */ 0, obj, + boost::contract::aux::none() + ) + { entry(); } ~public_member() { exit(); } - + private: // Check static and non-static subcontracted inv. void entry() { if( - this->virtual_call()->action == - boost::contract::aux::virtual_call::user_call || - this->virtual_call()->action == - boost::contract::aux::virtual_call::copy_oldof + this->virtual_call().action_ == + boost::contract::virtual_::user_call || + this->virtual_call().action_ == + boost::contract::virtual_::copy_oldof ) { this->copy_subcontracted_oldof(); - if(this->virtual_call()->action != - boost::contract::aux::virtual_call::user_call) { + if(this->virtual_call().action_ != + boost::contract::virtual_::user_call) { throw boost::contract::aux::no_error(); } } if( // When inv only, also must check exit inv here to skip body. - this->virtual_call()->action == - boost::contract::aux::virtual_call::user_call || - this->virtual_call()->action == - boost::contract::aux::virtual_call::check_entry_inv || - this->virtual_call()->action == - boost::contract::aux::virtual_call::check_exit_inv + this->virtual_call().action_ == + boost::contract::virtual_::user_call || + this->virtual_call().action_ == + boost::contract::virtual_::check_entry_inv || + this->virtual_call().action_ == + boost::contract::virtual_::check_exit_inv ) { - if(this->virtual_call()->action == - boost::contract::aux::virtual_call::check_exit_inv) { + if(this->virtual_call().action_ == + boost::contract::virtual_::check_exit_inv) { this->check_subcontracted_exit_inv(); } else { // For both user call and entry inv only. this->check_subcontracted_entry_inv(); } - if(this->virtual_call()->action != - boost::contract::aux::virtual_call::user_call) { + if(this->virtual_call().action_ != + boost::contract::virtual_::user_call) { throw boost::contract::aux::no_error(); } } // Else (check only pre, post, etc.) do nothing. @@ -117,17 +98,17 @@ private: // Check subcontracted pre (as soon as related functor set). void pre_available() /* override */ { if( - this->virtual_call()->action == - boost::contract::aux::virtual_call::user_call || - this->virtual_call()->action == - boost::contract::aux::virtual_call::check_pre + this->virtual_call().action_ == + boost::contract::virtual_::user_call || + this->virtual_call().action_ == + boost::contract::virtual_::check_pre ) { this->check_subcontracted_pre( - /* throw_on_failure = */ this->virtual_call()->action != - boost::contract::aux::virtual_call::user_call + /* throw_on_failure = */ this->virtual_call().action_ != + boost::contract::virtual_::user_call ); - if(this->virtual_call()->action != - boost::contract::aux::virtual_call::user_call) { + if(this->virtual_call().action_ != + boost::contract::virtual_::user_call) { throw boost::contract::aux::no_error(); } } // Else (check only inv, post, etc.) do nothing. @@ -135,19 +116,25 @@ private: // Check post here only if check-post-only mode (otherwise check at exit). void post_available() /* override */ { - if(this->virtual_call()->action == - boost::contract::aux::virtual_call::check_post) { + if(this->virtual_call().action_ == + boost::contract::virtual_::check_post) { this->check_subcontracted_post(); throw boost::contract::aux::no_error(); } // Else (check only inv, pre, etc.) do nothing. + if(this->virtual_call().action_ == + boost::contract::virtual_::check_this_post) { + std::clog << "****************" << std::endl; + this->check_post(); + throw boost::contract::aux::no_error(); + } // Else (check only inv, pre, etc.) do nothing. } // Check static and non-static subcontracted invariant and, if body did not // throw, also check subcontracted post. void exit() { bool const body_threw = std::uncaught_exception(); - if(this->virtual_call()->action == - boost::contract::aux::virtual_call::user_call) { + if(this->virtual_call().action_ == + boost::contract::virtual_::user_call) { this->check_subcontracted_exit_inv(); if(!body_threw) this->check_subcontracted_post(); } diff --git a/include/boost/contract/aux_/function/public_static_member.hpp b/include/boost/contract/aux_/function/public_static_member.hpp index 7eb6c49..52cb5b7 100644 --- a/include/boost/contract/aux_/function/public_static_member.hpp +++ b/include/boost/contract/aux_/function/public_static_member.hpp @@ -2,7 +2,7 @@ #ifndef BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_STATIC_MEMBER_HPP_ #define BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_STATIC_MEMBER_HPP_ -#include +#include #include #include diff --git a/include/boost/contract/aux_/none.hpp b/include/boost/contract/aux_/none.hpp index f2839f6..39c7d3c 100644 --- a/include/boost/contract/aux_/none.hpp +++ b/include/boost/contract/aux_/none.hpp @@ -4,7 +4,8 @@ namespace boost { namespace contract { namespace aux { -struct none {}; +struct none { static none value; }; +none none::value; } } } // namespace diff --git a/include/boost/contract/aux_/oldof.hpp b/include/boost/contract/aux_/oldof.hpp index 7b2a675..64129ec 100644 --- a/include/boost/contract/aux_/oldof.hpp +++ b/include/boost/contract/aux_/oldof.hpp @@ -2,17 +2,18 @@ #ifndef BOOST_CONTRACT_AUX_OLDOF_HPP_ #define BOOST_CONTRACT_AUX_OLDOF_HPP_ -#include +#include #include #include #include namespace boost { namespace contract { namespace aux { -struct oldof { +class oldof { // Must allow copies (shallow pointer copies). +public: oldof() : virt_(), value_() {} // Null value ptr when no oldof. - explicit oldof(boost::contract::virtual_body const virt, oldof const& old) : + explicit oldof(boost::contract::virtual_* const virt, oldof const& old) : virt_(virt), value_(old.value_) {} template @@ -30,18 +31,22 @@ struct oldof { boost::static_pointer_cast(value_); BOOST_CONTRACT_AUX_DEBUG(result); return result; - } else if(virt_->action == - boost::contract::aux::virtual_call::copy_oldof) { + } else if( + virt_->action_ == boost::contract::virtual_::user_call || + virt_->action_ == boost::contract::virtual_::copy_oldof + ) { BOOST_CONTRACT_AUX_DEBUG(value_); - virt_->old_values.push_back(value_); + virt_->old_values_.push(value_); + std::clog << "pushed" << std::endl; return boost::shared_ptr(); } else if( - virt_->action == boost::contract::aux::virtual_call::user_call || - virt_->action == boost::contract::aux::virtual_call::check_post + virt_->action_ == boost::contract::virtual_::check_post || + virt_->action_ == boost::contract::virtual_::check_this_post ) { BOOST_CONTRACT_AUX_DEBUG(!value_); - boost::shared_ptr value = virt_->old_values.front(); - virt_->old_values.pop_front(); + boost::shared_ptr value = virt_->old_values_.front(); + virt_->old_values_.pop(); + std::clog << "popped" << std::endl; BOOST_CONTRACT_AUX_DEBUG(value); boost::shared_ptr result = boost::static_pointer_cast(value); @@ -53,7 +58,7 @@ struct oldof { } private: - boost::contract::virtual_body virt_; + boost::contract::virtual_* virt_; boost::shared_ptr value_; // Type erased to `void*`. }; diff --git a/include/boost/contract/aux_/type_traits/bases.hpp b/include/boost/contract/aux_/type_traits/bases.hpp index a99c1b8..ef963cf 100644 --- a/include/boost/contract/aux_/type_traits/bases.hpp +++ b/include/boost/contract/aux_/type_traits/bases.hpp @@ -2,7 +2,7 @@ #ifndef BOOST_CONTRACT_AUX_TYPE_TRAITS_BASES_HPP_ #define BOOST_CONTRACT_AUX_TYPE_TRAITS_BASES_HPP_ -#include +#include #include namespace boost { namespace contract { namespace aux { namespace type_traits { diff --git a/include/boost/contract/aux_/type_traits/invariant.hpp b/include/boost/contract/aux_/type_traits/invariant.hpp index 6ad4b93..2bf9a46 100644 --- a/include/boost/contract/aux_/type_traits/invariant.hpp +++ b/include/boost/contract/aux_/type_traits/invariant.hpp @@ -2,7 +2,7 @@ #ifndef BOOST_CONTRACT_AUX_TYPE_TRAITS_INVARIANT_HPP_ #define BOOST_CONTRACT_AUX_TYPE_TRAITS_INVARIANT_HPP_ -#include +#include #include #include #include diff --git a/include/boost/contract/aux_/virtual_call.hpp b/include/boost/contract/aux_/virtual_call.hpp deleted file mode 100644 index 63e55d1..0000000 --- a/include/boost/contract/aux_/virtual_call.hpp +++ /dev/null @@ -1,32 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_VIRTUAL_CALL_HPP_ -#define BOOST_CONTRACT_AUX_VIRTUAL_CALL_HPP_ - -#include -#include - -namespace boost { namespace contract { namespace aux { - -// Contain state/data passed across virtual function contract calls (so struct). -struct virtual_call { - enum action_type { - user_call, // TODO: Can I use v == 0 instead of this? - copy_oldof, - check_entry_inv, - check_pre, - check_post, - check_exit_inv - }; - - action_type action; - - // TODO: Is this the most efficient STL FIFO? - std::deque > old_values; - - explicit virtual_call() : action(user_call), old_values() {} -}; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/constructor.hpp b/include/boost/contract/constructor.hpp index 81b0f2e..5d7a447 100644 --- a/include/boost/contract/constructor.hpp +++ b/include/boost/contract/constructor.hpp @@ -2,16 +2,17 @@ #ifndef BOOST_CONTRACT_CONSTRUCTOR_HPP_ #define BOOST_CONTRACT_CONSTRUCTOR_HPP_ -#include -#include +#include // Here so user can store contract. +#include +#include #include #include namespace boost { namespace contract { template -boost::contract::set::postcondition_only constructor(Class* const object) { - return boost::contract::set::postcondition_only(boost::make_shared< +boost::contract::set_postcondition_only constructor(Class* const object) { + return boost::contract::set_postcondition_only(boost::make_shared< boost::contract::aux::function::constructor >(object)); } diff --git a/include/boost/contract/config.hpp b/include/boost/contract/core/config.hpp similarity index 100% rename from include/boost/contract/config.hpp rename to include/boost/contract/core/config.hpp diff --git a/include/boost/contract/exception.hpp b/include/boost/contract/core/exception.hpp similarity index 57% rename from include/boost/contract/exception.hpp rename to include/boost/contract/core/exception.hpp index c8cd68d..1a63db4 100644 --- a/include/boost/contract/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -4,9 +4,7 @@ #include #include -#include #include -#include namespace boost { namespace contract { @@ -63,78 +61,17 @@ enum from { typedef void (*failure_handler)(from); -// TODO: These are part of the lib state. They should prob be put in a .cpp and -// exported (so they are the same across DLL, etc.), plus they should be -// protected by mutexes. namespace aux { - namespace exception_ { - enum failure_handler_key { - pre_key, - post_key, - const_entry_inv_key, - const_volatile_entry_inv_key, - static_entry_inv_key, - const_exit_inv_key, - const_volatile_exit_inv_key, - static_exit_inv_key, - }; + extern failure_handler pre_failure_handler; + extern failure_handler post_failure_handler; - template - void default_failure_handler(from const) { - std::string s = ""; - switch(Key) { - case pre_key: - s = "precondition "; break; - case post_key: - s = "postcondition "; break; - case const_entry_inv_key: - s = "const entry invariant "; break; - case const_volatile_entry_inv_key: - s = "const volatile entry invariant "; break; - case static_entry_inv_key: - s = "static entry invariant "; break; - case const_exit_inv_key: - s= "const exit invariant "; break; - case const_volatile_exit_inv_key: - s= "const volatile exit invariant "; break; - case static_exit_inv_key: - s = "static exit invariant "; break; - // No default (so compiler warning/error on missing enum case). - } - try { - throw; - } catch(boost::contract::assertion_failure const& error) { - // what = 'assertion "..." failed: ...'. - std::cerr << s << error.what() << std::endl; - } catch(std::exception const& error) { - std::cerr << s << "checking threw standard exception with " << - "what(): " << error.what() << std::endl; - } catch(...) { - std::cerr << s << "checking threw unknown exception" << - std::endl; - } - std::terminate(); // Default handlers log and call terminate. - } - } + extern failure_handler const_entry_inv_failure_handler; + extern failure_handler const_volatile_entry_inv_failure_handler; + extern failure_handler static_entry_inv_failure_handler; - failure_handler pre_failure_handler = &exception_:: - default_failure_handler; - failure_handler post_failure_handler = &exception_:: - default_failure_handler; - - failure_handler const_entry_inv_failure_handler = &exception_:: - default_failure_handler; - failure_handler const_volatile_entry_inv_failure_handler = &exception_:: - default_failure_handler; - failure_handler static_entry_inv_failure_handler = &exception_:: - default_failure_handler; - - failure_handler const_exit_inv_failure_handler = &exception_:: - default_failure_handler; - failure_handler const_volatile_exit_inv_failure_handler = &exception_:: - default_failure_handler; - failure_handler static_exit_inv_failure_handler = &exception_:: - default_failure_handler; + extern failure_handler const_exit_inv_failure_handler; + extern failure_handler const_volatile_exit_inv_failure_handler; + extern failure_handler static_exit_inv_failure_handler; } failure_handler set_precondition_failure(failure_handler f) diff --git a/include/boost/contract/core/set_nothing.hpp b/include/boost/contract/core/set_nothing.hpp new file mode 100644 index 0000000..9aa8937 --- /dev/null +++ b/include/boost/contract/core/set_nothing.hpp @@ -0,0 +1,29 @@ + +#ifndef BOOST_CONTRACT_SET_NOTHING_HPP_ +#define BOOST_CONTRACT_SET_NOTHING_HPP_ + +#include +#include + +namespace boost { namespace contract { + +class set_nothing { // Allow (shallow ptr) copy for `auto c = ...`. +public: + // Allow to set nothing (neither precondition, nor postcondition). + +private: + // Use friendship and deleted constructors to limit public API. + friend class var; + friend class set_precondition_only; + friend class set_postcondition_only; + + explicit set_nothing(boost::shared_ptr const contract) : contract_(contract) {} + + boost::shared_ptr contract_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/core/set_postcondition_only.hpp b/include/boost/contract/core/set_postcondition_only.hpp new file mode 100644 index 0000000..40b83af --- /dev/null +++ b/include/boost/contract/core/set_postcondition_only.hpp @@ -0,0 +1,39 @@ + +#ifndef BOOST_CONTRACT_SET_POSTCONDITION_ONLY_HPP_ +#define BOOST_CONTRACT_SET_POSTCONDITION_ONLY_HPP_ + +#include +#include +#include + +namespace boost { namespace contract { + +class set_postcondition_only { // Allow (shallow ptr) copy for `auto c = ...`. +public: + template + boost::contract::set_nothing postcondition(Postcondition const& f) { + contract_->set_post(f); + return boost::contract::set_nothing(contract_); + } + +private: + // Use friendship and deleted constructors to limit public API. + friend class var; + friend class set_precondition_postcondition; + + template + friend set_postcondition_only constructor(Class* const); + + template + friend set_postcondition_only destructor(Class* const); + + explicit set_postcondition_only(boost::shared_ptr const contract) : contract_(contract) {} + + boost::shared_ptr contract_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/core/set_precondition_only.hpp b/include/boost/contract/core/set_precondition_only.hpp new file mode 100644 index 0000000..db17075 --- /dev/null +++ b/include/boost/contract/core/set_precondition_only.hpp @@ -0,0 +1,33 @@ + +#ifndef BOOST_CONTRACT_SET_PRECONDITION_ONLY_HPP_ +#define BOOST_CONTRACT_SET_PRECONDITION_ONLY_HPP_ + +#include +#include +#include + +namespace boost { namespace contract { + +class set_precondition_only { // Allow (shallow ptr) copy for `auto c = ...`. +public: + template + boost::contract::set_nothing precondition(Precondition const& f) { + contract_->set_pre(f); + return boost::contract::set_nothing(contract_); + } + +private: + // Use friendship and deleted constructors to limit public API. + friend class var; + friend class set_precondition_postcondition; + + explicit set_precondition_only(boost::shared_ptr const contract) : contract_(contract) {} + + boost::shared_ptr contract_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/core/set_precondition_postcondition.hpp b/include/boost/contract/core/set_precondition_postcondition.hpp new file mode 100644 index 0000000..ee1f930 --- /dev/null +++ b/include/boost/contract/core/set_precondition_postcondition.hpp @@ -0,0 +1,65 @@ + +#ifndef BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ +#define BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ + +#include +#include +#include +#include +#include + +namespace boost { namespace contract { + +// This type allows (shallow ptr) copies for `auto c = ...`. +class set_precondition_postcondition { +public: + template + boost::contract::set_postcondition_only precondition( + Precondition const& f) { + contract_->set_pre(f); + return boost::contract::set_postcondition_only(contract_); + } + + template + boost::contract::set_precondition_only postcondition( + Postcondition const& f) { + contract_->set_post(f); + return boost::contract::set_precondition_only(contract_); + } + +private: + // Use friendship and deleted constructors to limit public API. + friend class var; + + template + friend set_precondition_postcondition public_member(boost::contract:: + virtual_* const, Class* const, Argument0&); + + template + friend set_precondition_postcondition public_member(Class *const, + Argument0&); + + template + friend set_precondition_postcondition public_member(boost::contract:: + virtual_* const, Class* const); + + template + friend set_precondition_postcondition public_member(Class* const); + + template + friend set_precondition_postcondition public_member(); + + friend set_precondition_postcondition protected_member(); + friend set_precondition_postcondition private_member(); + friend set_precondition_postcondition free_function(); + + explicit set_precondition_postcondition(boost::shared_ptr const contract) : contract_(contract) {} + + boost::shared_ptr contract_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/core/var.hpp b/include/boost/contract/core/var.hpp new file mode 100644 index 0000000..6656442 --- /dev/null +++ b/include/boost/contract/core/var.hpp @@ -0,0 +1,35 @@ + +#ifndef BOOST_CONTRACT_VAR_HPP_ +#define BOOST_CONTRACT_VAR_HPP_ + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace contract { + +class var { // Allow (shallow ptr) copy for `var c = ...`. +public: + /* implicit */ var(boost::contract::set_precondition_postcondition + const& c) : contract_(c.contract_) {} + + /* implicit */ var(boost::contract::set_precondition_only + const& c) : contract_(c.contract_) {} + + /* implicit */ var(boost::contract::set_postcondition_only + const& c) : contract_(c.contract_) {} + + /* implicit */ var(boost::contract::set_nothing + const& c) : contract_(c.contract_) {} + +private: + boost::shared_ptr contract_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/core/virtual.hpp b/include/boost/contract/core/virtual.hpp new file mode 100644 index 0000000..23317bb --- /dev/null +++ b/include/boost/contract/core/virtual.hpp @@ -0,0 +1,68 @@ + +#ifndef BOOST_CONTRACT_VIRTUAL_HPP_ +#define BOOST_CONTRACT_VIRTUAL_HPP_ + +#include +#include +#include + +namespace boost { + namespace contract { + namespace aux { + class oldof; + + namespace function { + template + class public_member; + } + namespace check { + template + class subcontracted_pre_post_inv; + } + + namespace test { + class friend_; + } + } + } +} + +namespace boost { namespace contract { + +class virtual_ : private boost::noncopyable { // To avoid copying queue. + // No public operation (users can only assign pointer to this type to null. +//private: +public: + // Friendship used to limit public library API. + template + friend class boost::contract::aux::function::public_member; + + template + friend class boost::contract::aux::check::subcontracted_pre_post_inv; + + friend class boost::contract::aux::oldof; + friend bool copy_oldof(virtual_* const); + + friend class boost::contract::aux::test::friend_; // For regression tests. + + enum action_enum { + user_call, // User call if either v == null || v->action == user_call. + copy_oldof, + check_entry_inv, + check_pre, + check_post, + check_this_post, + check_exit_inv + }; + + explicit virtual_() : action_(user_call), old_values_() {} + + // State passed across virtual calls (friends access data members directly). + action_enum action_; + std::queue > old_values_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/destructor.hpp b/include/boost/contract/destructor.hpp index 8dbbaf3..541b96f 100644 --- a/include/boost/contract/destructor.hpp +++ b/include/boost/contract/destructor.hpp @@ -2,15 +2,16 @@ #ifndef BOOST_CONTRACT_DESTRUCTOR_HPP_ #define BOOST_CONTRACT_DESTRUCTOR_HPP_ -#include +#include // Here so user can store contract. +#include #include #include namespace boost { namespace contract { template -boost::contract::set::postcondition_only destructor(Class* const object) { - return boost::contract::set::postcondition_only(boost::make_shared< +boost::contract::set_postcondition_only destructor(Class* const object) { + return boost::contract::set_postcondition_only(boost::make_shared< boost::contract::aux::function::destructor >(object)); } diff --git a/include/boost/contract/free_function.hpp b/include/boost/contract/free_function.hpp index 4d634b4..f271946 100644 --- a/include/boost/contract/free_function.hpp +++ b/include/boost/contract/free_function.hpp @@ -2,14 +2,15 @@ #ifndef BOOST_CONTRACT_FREE_FUNCTION_HPP_ #define BOOST_CONTRACT_FREE_FUNCTION_HPP_ -#include +#include // Here so user can store contract. +#include #include #include namespace boost { namespace contract { -boost::contract::set::precondition_postcondition free_function() { - return boost::contract::set::precondition_postcondition(boost::make_shared< +boost::contract::set_precondition_postcondition free_function() { + return boost::contract::set_precondition_postcondition(boost::make_shared< boost::contract::aux::function::free_function>()); } diff --git a/include/boost/contract/oldof.hpp b/include/boost/contract/oldof.hpp index 6b3c631..64f6dd4 100644 --- a/include/boost/contract/oldof.hpp +++ b/include/boost/contract/oldof.hpp @@ -2,29 +2,17 @@ #ifndef BOOST_CONTRACT_OLDOF_HPP_ #define BOOST_CONTRACT_OLDOF_HPP_ -#include -#include +#include +#include #include -#include #include #include #include #include -// TODO: There is a problem with old-of of virtual body functions for which -// old-of of the base function are evaluated *after* the derived virtual -// function body is executed (so invalidating old-of values)... Can I fix this? -// Maybe passing a (mutable) pointer v and implementing a "stack" (like a map -// of boost::any indexed by old-of #) inside the mutable object pointed by v... - -// IMPORTANT: Following old-of templates and macros ensure that: -// 1. Old-value expressions are evaluated only once and only when old-of -// should not be skipped. -// 2. Old-values are copied only once (using old-value type copy constructor) -// and only when old-of should not be skipped. -// Old-of are skipped if either postconditions are disabled all together (see -// also CONFIG_NO_POSTCONDITONS), or if virtual-body functions are called to -// not check postconditions (as controlled by the "v" extra parameter). +// IMPORTANT: The following makes sure old values expressions are evaluated +// only once, they are copied only once, and only when preconditions are +// enabled. #if !BOOST_PP_VARIADICS @@ -75,13 +63,13 @@ BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_2( \ namespace boost { namespace contract { -bool copy_oldof(boost::contract::virtual_body v = 0) { +bool copy_oldof(boost::contract::virtual_* const v = 0) { #ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS return false; // Never check post, so old-of never copied. #else - // Copy if user call (also !v) or virtual contract call for copy. - return !v || v->action == boost::contract::aux::virtual_call::user_call || - v->action == boost::contract::aux::virtual_call::copy_oldof; + // Copy if user call (so also if !v) or virtual contract call for copy. + return !v || v->action_ == boost::contract::virtual_::user_call || + v->action_ == boost::contract::virtual_::copy_oldof; #endif } @@ -90,13 +78,13 @@ boost::contract::aux::oldof oldof() { return boost::contract::aux::oldof(); } // Un-erasure via explicit type T so to allow to use C++11 auto decl. template boost::shared_ptr::type const> -oldof(boost::contract::virtual_body v, +oldof(boost::contract::virtual_* const v, boost::contract::aux::oldof const& old) { return boost::contract::aux::oldof(v, old); } // Un-erasure will be done based on explicit decl type (no auto allowed). -boost::contract::aux::oldof oldof(boost::contract::virtual_body const v, +boost::contract::aux::oldof oldof(boost::contract::virtual_* const v, boost::contract::aux::oldof const& old) { return boost::contract::aux::oldof(v, old); } diff --git a/include/boost/contract/private_member.hpp b/include/boost/contract/private_member.hpp index 762fb17..d180837 100644 --- a/include/boost/contract/private_member.hpp +++ b/include/boost/contract/private_member.hpp @@ -2,7 +2,8 @@ #ifndef BOOST_CONTRACT_PRIVATE_MEMBER_HPP_ #define BOOST_CONTRACT_PRIVATE_MEMBER_HPP_ -#include +#include // Here so user can store contract. +#include #include #include @@ -10,8 +11,8 @@ namespace boost { namespace contract { -boost::contract::set::precondition_postcondition private_member() { - return boost::contract::set::precondition_postcondition(boost::make_shared< +boost::contract::set_precondition_postcondition private_member() { + return boost::contract::set_precondition_postcondition(boost::make_shared< boost::contract::aux::function::private_member>()); } diff --git a/include/boost/contract/protected_member.hpp b/include/boost/contract/protected_member.hpp index b5c44fe..33c2f4d 100644 --- a/include/boost/contract/protected_member.hpp +++ b/include/boost/contract/protected_member.hpp @@ -2,7 +2,8 @@ #ifndef BOOST_CONTRACT_PROTECTED_MEMBER_HPP_ #define BOOST_CONTRACT_PROTECTED_MEMBER_HPP_ -#include +#include // Here so user can store contract. +#include #include #include @@ -10,8 +11,8 @@ namespace boost { namespace contract { -boost::contract::set::precondition_postcondition protected_member() { - return boost::contract::set::precondition_postcondition(boost::make_shared< +boost::contract::set_precondition_postcondition protected_member() { + return boost::contract::set_precondition_postcondition(boost::make_shared< boost::contract::aux::function::protected_member>()); } diff --git a/include/boost/contract/public_member.hpp b/include/boost/contract/public_member.hpp index 59025d7..6a89087 100644 --- a/include/boost/contract/public_member.hpp +++ b/include/boost/contract/public_member.hpp @@ -2,89 +2,61 @@ #ifndef BOOST_CONTRACT_PUBLIC_MEMBER_HPP_ #define BOOST_CONTRACT_PUBLIC_MEMBER_HPP_ -#include -#include +#include // Here so user can store contract. +#include +#include #include #include #include -// TODO: On C++11 Clang... these could static_assert enclosing func is pub? - -// TODO: Consider providing also macros like: -// void push_back(T const& value, boost::contract::virtual_back v = 0) { -// unsigned const old_size = v.oldof_(size()); -// BOOST_CONTRACT_PUBLIC_MEMBER(this, &vector::push_back, value, v) -// .precondition(...) -// .postcondition(...) -// ; -// ... -// } -// These macros should take the exact same params as their related functions -// (allowing param overloading via variadic macros) so to avoid confusion for -// the user in using macros instead of function-based APIs. -// The real benefit of these macros is that with C++14 generic lambdas they -// do not require users to also call BOOST_CONTRACT_INTROSPECT(push_back)! -// Also, with C++11 constexpr and __func__ (but also __FUNCTION__), these macros -// can check the specified function name is correct (matching -// `&.*::__func__` == `&vector::push_back`). -// So these macros could be always provided, they will double check the function -// name only on C++11 constexpr + __func__, and the will not require the -// external call to BOOST_CONTRACT_INTROSPECT only on C++14 generic lambdas (so -// even if they are always provided, they become truly useful and more prowerful -// on on C++14 generic lambdas when compared to the function-base APIs). - namespace boost { namespace contract { // Contract for public member functions with a virtual body and members of a // class that inherits from one or more base classes (optionally, it can be used // also if there are no base classes). -template -boost::contract::set::precondition_postcondition public_member( - boost::contract::virtual_body const v, Class* const object, - Function const&, Argument0 argument0 -) { - return boost::contract::set::precondition_postcondition(boost::make_shared< - boost::contract::aux::function::public_member >(v, object, argument0) +template +boost::contract::set_precondition_postcondition public_member(boost::contract:: + virtual_* const v, Class* const object, Argument0& argument0) { + return boost::contract::set_precondition_postcondition(boost::make_shared< + boost::contract::aux::function::public_member >(v, object, argument0) ); } // Contract for public member functions with a non-virtual body and members of a // class that inherits from one or more base classes (optionally, it can be used // also if there are no base classes). -template -boost::contract::set::precondition_postcondition public_member( - Class* const object, Function const&, Argument0 argument0) { - return boost::contract::set::precondition_postcondition(boost::make_shared< +template +boost::contract::set_precondition_postcondition public_member( + Class* const object, Argument0& argument0) { + return boost::contract::set_precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_member >(object, argument0) + Argument0> >(object, argument0) ); } // Contract for public member functions with a virtual body and members of a // class that does not inherits from any base class. template -boost::contract::set::precondition_postcondition public_member( - boost::contract::virtual_body const v, Class* const object) { - return boost::contract::set::precondition_postcondition(boost::make_shared< +boost::contract::set_precondition_postcondition public_member( + boost::contract::virtual_* const v, Class* const object) { + return boost::contract::set_precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_member >(v, object)); } // Contract for public member functions with a non-virtual body and members of a // class that does not inherits from any base class. template -boost::contract::set::precondition_postcondition public_member( +boost::contract::set_precondition_postcondition public_member( Class* const object) { - return boost::contract::set::precondition_postcondition(boost::make_shared< + return boost::contract::set_precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_member >(object)); } // Contract for public static member functions. template -boost::contract::set::precondition_postcondition public_member() { - return boost::contract::set::precondition_postcondition(boost::make_shared< +boost::contract::set_precondition_postcondition public_member() { + return boost::contract::set_precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_static_member >()); } diff --git a/include/boost/contract/scoped.hpp b/include/boost/contract/scoped.hpp deleted file mode 100644 index bb514af..0000000 --- a/include/boost/contract/scoped.hpp +++ /dev/null @@ -1,35 +0,0 @@ - -#ifndef BOOST_CONTRACT_SCOPED_HPP_ -#define BOOST_CONTRACT_SCOPED_HPP_ - -#include -#include -#include -#include -#include -#include - -namespace boost { namespace contract { - -class scoped { // Allow (shallow ptr) copy for `scoped c = ...`. -public: - /* implicit */ scoped(boost::contract::set::precondition_postcondition - const& c) : contract_(c.contract_) {} - - /* implicit */ scoped(boost::contract::set::precondition_only - const& c) : contract_(c.contract_) {} - - /* implicit */ scoped(boost::contract::set::postcondition_only - const& c) : contract_(c.contract_) {} - - /* implicit */ scoped(boost::contract::set::nothing - const& c) : contract_(c.contract_) {} - -private: - boost::shared_ptr contract_; -}; - -} } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/set/nothing.hpp b/include/boost/contract/set/nothing.hpp deleted file mode 100644 index 57f3860..0000000 --- a/include/boost/contract/set/nothing.hpp +++ /dev/null @@ -1,40 +0,0 @@ - -#ifndef BOOST_CONTRACT_SET_NOTHING_HPP_ -#define BOOST_CONTRACT_SET_NOTHING_HPP_ - -#include -#include - -namespace boost { - namespace contract { - class scoped; - - namespace set { - class precondition_only; - class postcondition_only; - } - } -} - -namespace boost { namespace contract { namespace set { - -class nothing { // Allow (shallow ptr) copy for `auto c = ...`. -public: - // Allow to set nothing (neither precondition, nor postcondition). - -private: - // Use friendship and deleted constructors to limit public API. - friend class boost::contract::scoped; - friend class boost::contract::set::precondition_only; - friend class boost::contract::set::postcondition_only; - - explicit nothing(boost::shared_ptr - const contract) : contract_(contract) {} - - boost::shared_ptr contract_; -}; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/set/postcondition_only.hpp b/include/boost/contract/set/postcondition_only.hpp deleted file mode 100644 index b9a9260..0000000 --- a/include/boost/contract/set/postcondition_only.hpp +++ /dev/null @@ -1,55 +0,0 @@ - -#ifndef BOOST_CONTRACT_SET_POSTCONDITION_ONLY_HPP_ -#define BOOST_CONTRACT_SET_POSTCONDITION_ONLY_HPP_ - -#include -#include -#include - -namespace boost { - namespace contract { - class scoped; - - template - boost::contract::set::postcondition_only constructor(Class* const); - - template - boost::contract::set::postcondition_only destructor(Class* const); - - namespace set { - class precondition_postcondition; - } - } -} - -namespace boost { namespace contract { namespace set { - -class postcondition_only { // Allow (shallow ptr) copy for `auto c = ...`. -public: - template - boost::contract::set::nothing postcondition(Postcondition const& f) { - contract_->set_post(f); - return boost::contract::set::nothing(contract_); - } - -private: - // Use friendship and deleted constructors to limit public API. - friend class boost::contract::scoped; - friend class boost::contract::set::precondition_postcondition; - - template - friend postcondition_only boost::contract::constructor(Class* const); - - template - friend postcondition_only boost::contract::destructor(Class* const); - - explicit postcondition_only(boost::shared_ptr const contract) : contract_(contract) {} - - boost::shared_ptr contract_; -}; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/set/precondition_only.hpp b/include/boost/contract/set/precondition_only.hpp deleted file mode 100644 index 7de4cf1..0000000 --- a/include/boost/contract/set/precondition_only.hpp +++ /dev/null @@ -1,43 +0,0 @@ - -#ifndef BOOST_CONTRACT_SET_PRECONDITION_ONLY_HPP_ -#define BOOST_CONTRACT_SET_PRECONDITION_ONLY_HPP_ - -#include -#include -#include - -namespace boost { - namespace contract { - class scoped; - - namespace set { - class precondition_postcondition; - } - } -} - -namespace boost { namespace contract { namespace set { - -class precondition_only { // Allow (shallow ptr) copy for `auto c = ...`. -public: - template - boost::contract::set::nothing precondition(Precondition const& f) { - contract_->set_pre(f); - return boost::contract::set::nothing(contract_); - } - -private: - // Use friendship and deleted constructors to limit public API. - friend class boost::contract::scoped; - friend class boost::contract::set::precondition_postcondition; - - explicit precondition_only(boost::shared_ptr const contract) : contract_(contract) {} - - boost::shared_ptr contract_; -}; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/set/precondition_postcondition.hpp b/include/boost/contract/set/precondition_postcondition.hpp deleted file mode 100644 index ae0aca0..0000000 --- a/include/boost/contract/set/precondition_postcondition.hpp +++ /dev/null @@ -1,102 +0,0 @@ - -#ifndef BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ -#define BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ - -#include -#include -#include -#include -#include - -namespace boost { - namespace contract { - class scoped; - - template - boost::contract::set::precondition_postcondition public_member( - boost::contract::virtual_body const, Class* const, - Function const&, Argument0 - ); - - template - boost::contract::set::precondition_postcondition public_member( - Class* const, Function const&, Argument0); - - template - boost::contract::set::precondition_postcondition public_member( - boost::contract::virtual_body const, Class* const); - - template - boost::contract::set::precondition_postcondition public_member( - Class* const); - - template - boost::contract::set::precondition_postcondition public_member(); - - boost::contract::set::precondition_postcondition protected_member(); - boost::contract::set::precondition_postcondition private_member(); - boost::contract::set::precondition_postcondition free_function(); - } -} - -namespace boost { namespace contract { namespace set { - -class precondition_postcondition { // Allow (shallow ptr) copy for auto c = ... -public: - template - boost::contract::set::postcondition_only precondition( - Precondition const& f) { - contract_->set_pre(f); - return boost::contract::set::postcondition_only(contract_); - } - - template - boost::contract::set::precondition_only postcondition( - Postcondition const& f) { - contract_->set_post(f); - return boost::contract::set::precondition_only(contract_); - } - -private: - // Use friendship and deleted constructors to limit public API. - friend class boost::contract::scoped; - - template - friend precondition_postcondition boost::contract::public_member( - boost::contract::virtual_body const, Class* const, - Function const&, Argument0 - ); - - template - friend precondition_postcondition boost::contract::public_member( - Class* const, Function const&, Argument0); - - template - friend precondition_postcondition boost::contract::public_member( - boost::contract::virtual_body const, Class* const); - - template - friend precondition_postcondition boost::contract::public_member( - Class* const); - - template - friend precondition_postcondition boost::contract::public_member(); - - friend precondition_postcondition boost::contract::protected_member(); - friend precondition_postcondition boost::contract::private_member(); - friend precondition_postcondition boost::contract::free_function(); - - explicit precondition_postcondition(boost::shared_ptr const contract) : contract_(contract) {} - - boost::shared_ptr contract_; -}; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/always.hpp b/include/boost/contract/utility/always.hpp similarity index 100% rename from include/boost/contract/always.hpp rename to include/boost/contract/utility/always.hpp diff --git a/include/boost/contract/call_if.hpp b/include/boost/contract/utility/call_if.hpp similarity index 100% rename from include/boost/contract/call_if.hpp rename to include/boost/contract/utility/call_if.hpp diff --git a/include/boost/contract/virtual_body.hpp b/include/boost/contract/virtual_body.hpp deleted file mode 100644 index 06aecd1..0000000 --- a/include/boost/contract/virtual_body.hpp +++ /dev/null @@ -1,18 +0,0 @@ - -#ifndef BOOST_CONTRACT_VIRTUAL_BODY_HPP_ -#define BOOST_CONTRACT_VIRTUAL_BODY_HPP_ - -#include - -namespace boost { namespace contract { - -// TODO: Can I use a straight pointer * instead of a smart pointer? - -// This type must be initialized when assigned to `0` and it must be efficient -// to pass it as a function parameter and to copy it (like a pointer). -typedef boost::shared_ptr virtual_body; - -} } // namespace - -#endif // #include guard - diff --git a/test/aux_/friend.hpp b/test/aux_/friend.hpp new file mode 100644 index 0000000..74d3c69 --- /dev/null +++ b/test/aux_/friend.hpp @@ -0,0 +1,21 @@ + +#ifndef BOOST_CONTRACT_AUX_TEST_FRIEND_HPP_ +#define BOOST_CONTRACT_AUX_TEST_FRIEND_HPP_ + +#include + +namespace boost { namespace contract { namespace aux { namespace test { + +// Made friend by a few library's types to access them to test them. +class friend_ { +public: + static bool checking_post(boost::contract::virtual_* v) { + return !v || v->action_ == boost::contract::virtual_::check_post || + v->action_ == boost::contract::virtual_::check_this_post; + } +}; + +} } } } // namespace + +#endif // #include guard + diff --git a/test/const/free_function.cpp b/test/const/free_function.cpp new file mode 100644 index 0000000..c519c35 --- /dev/null +++ b/test/const/free_function.cpp @@ -0,0 +1,61 @@ + +#include "../aux_/oteststream.hpp" +#include +#include +#include + +// Test free-function. + +boost::contract::aux::test::oteststream out; + +void inv1_contract(int const& x, int const& result, + boost::contract::decl c = 0) { + boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF(c, x); + boost::contract::free_function(c) + .precondition([&] { BOOST_CONTRACT_ASSERT(x >= 0); }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(-x == *old_x); + BOOST_CONTRACT_ASSERT(result == *old_x); + }) + ; +} +int inv1(int& x) { + int result; + boost::contract::var contract(inv1_contract, x, result); + result = x; + x = -x; + return result; +} + +int inv2(int& x) { + int result; + boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF(x); + boost::contract::var contract = boost::contract::free_function() + .precondition([&] { BOOST_CONTRACT_ASSERT(x >= 0); }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(-x == *old_x); + BOOST_CONTRACT_ASSERT(result == *old_x); + }) + ; + result = x; + x = -x; + return result; +} + + +int main() { + std::ostringstream ok; + + out.str(""); + f(); + ok.str(""); + ok + << "f::pre" << std::endl + << "f::body" << std::endl + << "f::post" << std::endl + ; + BOOST_TEST(out.check(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/function/public_member.cpp b/test/function/public_member.cpp index 29e45f5..5e52fa3 100644 --- a/test/function/public_member.cpp +++ b/test/function/public_member.cpp @@ -15,62 +15,54 @@ boost::contract::aux::test::oteststream out; // Test inheritance level 0 (no bases). template struct e { - void invariant() const { - out << "e::inv" << std::endl; - } - - static void static_invariant() { - out << "e::static_inv" << std::endl; - } + void invariant() const { out << "e::inv" << std::endl; } + static void static_invariant() { out << "e::static_inv" << std::endl; } virtual ~e() {} // Test contract allows (but does not require) extra introspection, // function pointer, etc. parameter because class has no bases. - void f(T& x, boost::contract::virtual_body v = 0) { - auto c = boost::contract::public_member(v, this, &e::f, x) - .precondition([&]() { + boost::contract::var f_contract(T const& x, + boost::contract::virtual_* v = 0) const { + return boost::contract::public_member(v, this, x) + .precondition([&] { out << "e::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(false); // To check subcontracted pre. }) - .postcondition([&]() { - out << "e::f::post" << std::endl; - }) + .postcondition([&] { out << "e::f::post" << std::endl; }) ; - f_body(x); } - virtual void f_body(T& x) = 0; - BOOST_CONTRACT_INTROSPECT(f) + virtual void f(T const& x) = 0; + BOOST_CONTRACT_INTROSPECT(f_contract) }; // Test inheritance level 0 (no bases). template struct d { - void invariant() const { - out << "d::inv" << std::endl; - } - - static void static_invariant() { - out << "d::static_inv" << std::endl; - } + void invariant() const { out << "d::inv" << std::endl; } + static void static_invariant() { out << "d::static_inv" << std::endl; } virtual ~d() {} // Test contract does not require (but allows) extra introspection, // function pointer, etc. parameter because class has no bases. - void f(T& x, boost::contract::virtual_body v = 0) { - auto c = boost::contract::public_member(v, this) - .precondition([&]() { + boost::contract::var f_contract(T const& x, + boost::contract::virtual_* v = 0) const { + return boost::contract::public_member(v, this) + .precondition([&] { out << "d::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(false); // To check subcontracted pre. }) - .postcondition([&]() { - out << "d::f::post" << std::endl; - }) + .postcondition([&] { out << "d::f::post" << std::endl; }) ; - f_body(x); } - virtual void f_body(T& x) = 0; + virtual void f(T const& x) { + boost::contract::var contract = f_contract(x); + out << "d::f::body" << std::endl; + } + + // Test non-contracted virtual function in contracted base. + virtual void k() = 0; }; // Test inheritance level 1 and multiple inheritance (both contracted bases). @@ -82,34 +74,29 @@ struct c typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES - void invariant() const { - out << "c::inv" << std::endl; - } - - static void static_invariant() { - out << "c::static_inv" << std::endl; - } + void invariant() const { out << "c::inv" << std::endl; } + static void static_invariant() { out << "c::static_inv" << std::endl; } virtual ~c() {} - - // Test virtual overrides virtual function. - void f(T& x, boost::contract::virtual_body v = 0) { - auto c = boost::contract::public_member(v, this, &c::f, x) - .precondition([&]() { - out << "c::f::pre" << std::endl; - BOOST_CONTRACT_ASSERT(false); // To check subcontracted pre. - }) - .postcondition([&]() { - out << "c::f::post" << std::endl; - }) - ; - f_body(x); - } - virtual void f_body(T& x) {} - BOOST_CONTRACT_INTROSPECT(f) - // Test non-contracted virtual function in contracted base. - virtual void k() = 0; + // Test virtual overrides virtual function. + boost::contract::var f_contract(T const& x, + boost::contract::virtual_* v = 0) const { + return boost::contract::public_member(v, this, x) + .precondition([&] { + out << "c::f::pre" << std::endl; + BOOST_CONTRACT_ASSERT(x < 0); // To check subcontracted pre. + }) + .postcondition([&] { out << "c::f::post" << std::endl; }) + ; + } + virtual void f(T const& x) { + boost::contract::var contract = f_contract(x); + out << "c::f::body" << std::endl; + } + BOOST_CONTRACT_INTROSPECT(f_contract) + + void k() {} }; // Test a non-contracted base. @@ -130,33 +117,21 @@ struct a typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES - void invariant() const { - out << "a::inv" << std::endl; - } - - static void static_invariant() { - out << "a::static_inv" << std::endl; - } + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } virtual ~a() {} // Test non-virtual overrides virtual function. - void f(T& x) { - auto c = boost::contract::public_member( - this, &a::f, x) - .precondition([&]() { - out << "a::f::pre" << std::endl; - }) - .postcondition([&]() { - out << "a::f::post" << std::endl; - }) + void f(T const& x) { + boost::contract::var contract = boost::contract::public_member< + introspect_f_contract>(this, x) + .precondition([&] { out << "a::f::pre" << std::endl; }) + .postcondition([&] { out << "a::f::post" << std::endl; }) ; - f_body(x); + out << "a::f::body" << std::endl; } - void f_body(T& x) { out << "a::f::body" << std::endl; } - BOOST_CONTRACT_INTROSPECT(f) - - void k() {} + BOOST_CONTRACT_INTROSPECT(f_contract) private: void g() {} @@ -164,12 +139,6 @@ private: int main() { std::ostringstream ok; - - a aa; - int x = 123; - - out.str(""); - aa.f(x); ok.str(""); ok << "e::static_inv" << std::endl @@ -202,6 +171,69 @@ int main() { << "c::f::post" << std::endl << "a::f::post" << std::endl ; + + typedef int i; + typedef unsigned int u; + i x = 123; + + // Test virtual call via derived class. + a ai; + out.str(""); + ai.f(x); + BOOST_TEST(out.check(ok.str())); + + // Test virtual call via base class reference. + out << std::endl; + c& ci = ai; + out.str(""); + ci.f(x); + BOOST_TEST(out.check(ok.str())); + + // Test virtual call via base class pointer. + out << std::endl; + d* di = &ai; + out.str(""); + di->f(x); + BOOST_TEST(out.check(ok.str())); + + // Test pure virtual call via abstract base class (reference). + out << std::endl; + e& ei = ci; + out.str(""); + ei.f(x); + BOOST_TEST(out.check(ok.str())); + + // Test virtual call to derived class c (to double check no a's contracts). + out << std::endl; + c cii; + out.str(""); + cii.f(-x); // Negative x so c::f pre will pass this time (not base anymore). + ok.str(""); + ok + << "e::static_inv" << std::endl + << "e::inv" << std::endl + << "d::static_inv" << std::endl + << "d::inv" << std::endl + << "c::static_inv" << std::endl + << "c::inv" << std::endl + + << "e::f::pre" << std::endl + << "d::f::pre" << std::endl + << "c::f::pre" << std::endl + + << "c::f::body" << std::endl + + << "e::static_inv" << std::endl + << "e::inv" << std::endl + << "d::static_inv" << std::endl + << "d::inv" << std::endl + << "c::static_inv" << std::endl + << "c::inv" << std::endl + + << "e::f::post" << std::endl + << "d::f::post" << std::endl + << "c::f::post" << std::endl + ; BOOST_TEST(out.check(ok.str())); return boost::report_errors(); diff --git a/test/oldof/oldof.cpp b/test/oldof/oldof.cpp index 2575421..62aa14d 100644 --- a/test/oldof/oldof.cpp +++ b/test/oldof/oldof.cpp @@ -1,7 +1,6 @@ -#include #include -#include +#include #include // Test old-values evaluated and copied only once. @@ -16,14 +15,14 @@ private: num& operator=(num const&); }; -num& eval(num& n) { ++eval_count; return n; } +num const& eval(num const& n) { ++eval_count; return n; } void swap(num& a, num& b) { // Test explicit type declaration. boost::shared_ptr old_a = BOOST_CONTRACT_OLDOF(eval(a)); // Test auto type declaration (C++11). auto old_b = BOOST_CONTRACT_OLDOF(eval(b)); - auto c = boost::contract::free_function() + boost::contract::var contract = boost::contract::free_function() .precondition([&] {}) .postcondition([&] { BOOST_TEST_EQ(a.i, old_b->i); diff --git a/test/oldof/oldof_v.cpp b/test/oldof/oldof_v.cpp index 213d45b..4d78093 100644 --- a/test/oldof/oldof_v.cpp +++ b/test/oldof/oldof_v.cpp @@ -1,9 +1,10 @@ +#include +#include "../aux_/friend.hpp" #include #include #include #include -#include #include #include @@ -19,7 +20,7 @@ private: str& operator=(str const&); }; -str& eval(str& s) { ++eval_count; return s; } +str const& eval(str const& s) { ++eval_count; return s; } struct d { str s; @@ -29,22 +30,25 @@ struct d { void invariant() const {} static void static_invariant() {} - void f(char const z, boost::contract::virtual_body v = 0) { + boost::contract::var f_contract(char const& z, + boost::contract::virtual_* v = 0) const { // Test explicit type declaration. boost::shared_ptr old_s = BOOST_CONTRACT_OLDOF(v, eval(s)); - if(!v || v->action == boost::contract::aux::virtual_call::check_post) { + if(boost::contract::aux::test::friend_::checking_post(v)) { BOOST_TEST(old_s); BOOST_TEST_EQ(old_s->x, "d"); } else { BOOST_TEST(!old_s); } - auto c = boost::contract::public_member(v, this) + return boost::contract::public_member(v, this) .precondition([&] {}) .postcondition([&] { BOOST_TEST_EQ(old_s->x, "d"); }) ; - f_body(z); } - virtual void f_body(char const z) { s.x += z; } + virtual void f(char const z) { + boost::contract::var contract = f_contract(z); + s.x += z; + } }; struct c @@ -61,23 +65,23 @@ struct c void invariant() const {} static void static_invariant() {} - void f(char const z, boost::contract::virtual_body v = 0) { + boost::contract::var f_contract(char const& z, + boost::contract::virtual_* v = 0) const { // Test auto type declaration (C++11). auto old_s = BOOST_CONTRACT_OLDOF(v, eval(s)); - if(!v || v->action == boost::contract::aux::virtual_call::check_post) { + if(boost::contract::aux::test::friend_::checking_post(v)) { BOOST_TEST(old_s); BOOST_TEST_EQ(old_s->x, "c"); } else { BOOST_TEST(!old_s); } - auto c = boost::contract::public_member(v, this, &c::f, z) + return boost::contract::public_member(v, this, z) .precondition([&] {}) .postcondition([&] { BOOST_TEST_EQ(old_s->x, "c"); }) ; - f_body(z); } - virtual void f_body(char const z) = 0; - BOOST_CONTRACT_INTROSPECT(f) + virtual void f(char const z) = 0; + BOOST_CONTRACT_INTROSPECT(f_contract) }; struct b { @@ -88,21 +92,21 @@ struct b { void invariant() const {} static void static_invariant() {} - void f(char const z, boost::contract::virtual_body v = 0) { + boost::contract::var f_contract(char const& z, + boost::contract::virtual_* v = 0) const { boost::shared_ptr old_s = BOOST_CONTRACT_OLDOF(v, eval(s)); - if(!v || v->action == boost::contract::aux::virtual_call::check_post) { + if(boost::contract::aux::test::friend_::checking_post(v)) { BOOST_TEST(old_s); BOOST_TEST_EQ(old_s->x, "b"); } else { BOOST_TEST(!old_s); } - auto c = boost::contract::public_member(v, this) + return boost::contract::public_member(v, this) .precondition([&] {}) .postcondition([&] { BOOST_TEST_EQ(old_s->x, "b"); }) ; - f_body(z); } - virtual void f_body(char const z) = 0; + virtual void f(char const z) = 0; }; struct a @@ -119,22 +123,35 @@ struct a void invariant() const {} static void static_invariant() {} - void f(char const z, boost::contract::virtual_body v = 0) { + boost::contract::var f_contract(char const& z, + boost::contract::virtual_* v = 0) const { auto old_s = BOOST_CONTRACT_OLDOF(v, eval(s)); - if(!v || v->action == boost::contract::aux::virtual_call::check_post) { + if(boost::contract::aux::test::friend_::checking_post(v)) { BOOST_TEST(old_s); BOOST_TEST_EQ(old_s->x, "a"); } else { BOOST_TEST(!old_s); } - auto c = boost::contract::public_member(v, this, &a::f, z) - .precondition([&] {}) - .postcondition([&] { BOOST_TEST_EQ(old_s->x, "a"); }) + return boost::contract::public_member(v, this, z) + .precondition([&] { + // std::clog << "pre>>>" << old_s->x << "<<<" << std::endl; + }) + .postcondition([&] { + std::clog << "post>>> " << old_s->x << "<<<" << std::endl; + BOOST_TEST_EQ(old_s->x, "a"); + }) ; - f_body(z); } - virtual void f_body(char const z) { s.x += z; } - BOOST_CONTRACT_INTROSPECT(f) + virtual void f(char const z) { + boost::shared_ptr v = + boost::make_shared(); + boost::contract::var contract = f_contract(z, v.get()); + std::clog << v->old_values_.size() << std::endl; + std::clog << "body start" << std::endl; + s.x += z; + std::clog << "body finish" << std::endl; + } + BOOST_CONTRACT_INTROSPECT(f_contract) }; int main() { @@ -150,17 +167,17 @@ int main() { BOOST_TEST_EQ(eval_count, 0); #endif - // Test with `v` but without bases. - copy_count = eval_count = 0; - d dd; - dd.f('z'); -#ifndef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS - BOOST_TEST_EQ(copy_count, 1); - BOOST_TEST_EQ(eval_count, 1); -#else - BOOST_TEST_EQ(copy_count, 0); - BOOST_TEST_EQ(eval_count, 0); -#endif +// // Test with `v` but without bases. +// copy_count = eval_count = 0; +// d dd; +// dd.f('z'); +//#ifndef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS +// BOOST_TEST_EQ(copy_count, 1); +// BOOST_TEST_EQ(eval_count, 1); +//#else +// BOOST_TEST_EQ(copy_count, 0); +// BOOST_TEST_EQ(eval_count, 0); +//#endif return boost::report_errors(); }