diff --git a/include/boost/contract/assert.hpp b/include/boost/contract/assert.hpp index b42f28e..c39eb84 100644 --- a/include/boost/contract/assert.hpp +++ b/include/boost/contract/assert.hpp @@ -8,8 +8,10 @@ /* PUBLIC */ #define BOOST_CONTRACT_ASSERT(condition) \ - if(!(condition)) throw boost::contract::assertion_failure( \ - __FILE__, __LINE__, BOOST_PP_STRINGIZE(condition)); + if(!(condition)) { \ + throw boost::contract::assertion_failure(__FILE__, __LINE__, \ + BOOST_PP_STRINGIZE(cond)); \ + } #endif // #include guard diff --git a/include/boost/contract/aux_/call.hpp b/include/boost/contract/aux_/call.hpp new file mode 100644 index 0000000..657a07f --- /dev/null +++ b/include/boost/contract/aux_/call.hpp @@ -0,0 +1,30 @@ + +#ifndef BOOST_CONTRACT_AUX_CALL_HPP_ +#define BOOST_CONTRACT_AUX_CALL_HPP_ + +#include +#include +#include + +namespace boost { namespace contract { namespace aux { + +struct call : private boost::noncopyable { // Do not copy queue. + enum action_enum { + // Call always hold by ptr so null ptr (not enum) used for user-call. + copy_oldof, + check_entry_inv, + check_pre, + check_post, + check_exit_inv + }; + + explicit call() : action() {} + + action_enum action; + std::queue > old_values; +}; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/check/pre_post.hpp b/include/boost/contract/aux_/check/pre_post.hpp deleted file mode 100644 index de05c64..0000000 --- a/include/boost/contract/aux_/check/pre_post.hpp +++ /dev/null @@ -1,55 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ -#define BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ - -#include -#include - -namespace boost { namespace contract { namespace aux { namespace check { - -class pre_post { -public: - explicit pre_post(boost::contract::from const& from) : from_(from) {} - - virtual ~pre_post() {} - - template - void set_pre(Pre const& pre) { pre_ = pre; pre_available(); } - - template - void set_post(Post const& post) { post_ = post; post_available(); } - -protected: - // Allow to throw on failure for relaxing subcontracted pre. - void check_pre(bool const throw_on_failure = false) { - if(pre_) { - try { pre_(); } - catch(...) { - if(throw_on_failure) throw; - boost::contract::aux::pre_failure_handler(from()); - } - } - } - - void check_post() { - if(post_) { - try { post_(); } - catch(...) { boost::contract::aux::post_failure_handler(from()); } - } - } - - virtual void pre_available() {} - virtual void post_available() {} - - boost::contract::from from() { return from_; } - -private: - boost::contract::from const from_; - boost::function pre_; - boost::function post_; -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/check/pre_post_inv.hpp b/include/boost/contract/aux_/check/pre_post_inv.hpp deleted file mode 100644 index 61429c1..0000000 --- a/include/boost/contract/aux_/check/pre_post_inv.hpp +++ /dev/null @@ -1,83 +0,0 @@ - -#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 - -namespace boost { namespace contract { namespace aux { namespace check { - -template -class pre_post_inv : public boost::contract::aux::check::pre_post { -public: - // Allow object to be 0 (i.e., no object), for static members. - explicit pre_post_inv(boost::contract::from const& from, - Class* const obj = 0) : - boost::contract::aux::check::pre_post(from), - obj_(obj) - {} - - virtual ~pre_post_inv() {} - -protected: - void check_entry_inv(bool const static_inv_only = false) { - check_inv(/* on_entry = */ true, static_inv_only); - } - - void check_exit_inv(bool const static_inv_only = false) { - check_inv(/* on_entry = */ false, static_inv_only); - } - - // Could return null pointer (for static members). - Class* const object() const { return obj_; } - -private: - void check_inv(bool const on_entry, bool const static_inv_only = false) { - check_static_inv(on_entry, boost::mpl::bool_::value>()); - if(!static_inv_only) { - check_cv_inv(on_entry, boost::mpl::bool_::value>()); - } - } - - // TODO: Add const volatile invariant checking here. - - void check_static_inv(bool const on_entry, boost::mpl::false_ const&) {} - void check_static_inv(bool const on_entry, boost::mpl::true_ const&) { - try { Class::BOOST_CONTRACT_CONFIG_STATIC_INVARIANT(); } - catch(...) { - if(on_entry) { - boost::contract::aux::static_entry_inv_failure_handler(from()); - } else { - boost::contract::aux::static_entry_inv_failure_handler(from()); - } - } - } - - void check_cv_inv(bool const on_entry, boost::mpl::false_ const&) {} - void check_cv_inv(bool const on_entry, boost::mpl::true_ const&) { - typename boost::add_const::type* const const_obj = obj_; - BOOST_CONTRACT_AUX_DEBUG(const_obj); - try { const_obj->BOOST_CONTRACT_CONFIG_INVARIANT(); } - catch(...) { - if(on_entry) { - boost::contract::aux::const_entry_inv_failure_handler(from()); - } else { - boost::contract::aux::const_exit_inv_failure_handler(from()); - } - } - } - - Class* const obj_; -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp b/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp deleted file mode 100644 index 6bdd100..0000000 --- a/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp +++ /dev/null @@ -1,216 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_CHECK_SUBCONTRACTED_PRE_POST_INV_HPP_ -#define BOOST_CONTRACT_AUX_CHECK_SUBCONTRACTED_PRE_POST_INV_HPP_ - -// 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { namespace contract { namespace aux { namespace check { - -template< - class Class, - class Intro = boost::contract::aux::none, - typename Arg0 = boost::contract::aux::none -> class subcontracted_pre_post_inv : - public boost::contract::aux::check::pre_post_inv, - private boost::noncopyable // Avoid copying captured function arguments. -{ - // Base types as pointers because mpl::for_each will construct them. - typedef typename boost::mpl::transform< - typename boost::mpl::eval_if, - boost::contract::aux::type_traits::bases_of - , - boost::mpl::identity > - >::type, - boost::add_pointer - >::type base_ptrs; - -public: - 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(); } - - virtual ~subcontracted_pre_post_inv() { if(own_virt_) delete virt_; } - -protected: - void copy_subcontracted_oldof() { - boost::mpl::for_each(check_base_.action( - 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::virtual_::check_entry_inv)); - this->check_entry_inv(); - } - - // Allow to throw on failure for relaxing subcontracted pre. - void check_subcontracted_pre(bool const throw_on_failure = false) { - try { - boost::mpl::for_each(check_base_.action( - 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&) { - // Pre logic-or: Stop at 1st no_error (thrown by callee). - } - } - - void check_subcontracted_exit_inv() { - boost::mpl::for_each(check_base_.action( - boost::contract::virtual_::check_exit_inv)); - this->check_exit_inv(); - } - - void check_subcontracted_post() { - boost::mpl::for_each(check_base_.action( - 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(); - } - - // Invariant: virt_ never null after init (so can always deref it here). - boost::contract::virtual_& virtual_call() { return *virt_; } - -private: - void init() { - if(virt_) own_virt_ = false; - else { - virt_ = new boost::contract::virtual_(); - own_virt_ = true; - } - check_base_.nest(this); - } - - class check_base { - public: - explicit check_base() : nest_(0), - action_(boost::contract::virtual_::user_call) {} - - void nest(subcontracted_pre_post_inv* n) { nest_ = n; } - - check_base& action(boost::contract::virtual_::action_enum const a) { - action_ = a; - return *this; - } - - template - void operator()(Base*) { - 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_< - 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&) { - //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, - 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* const base = nest_->object(); - BOOST_CONTRACT_AUX_DEBUG(base); - - 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_->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_->virtual_call().action_ == - boost::contract::virtual_::check_pre) { - // Pre logic-or: Ignore err, possibly checks up to caller. - } - } - nest_->virtual_call().action_ = reset_action; - } - - subcontracted_pre_post_inv* nest_; - boost::contract::virtual_::action_enum action_; - }; - - bool own_virt_; - boost::contract::virtual_* virt_; - check_base check_base_; - // TODO: Support 0-to-n args. - Arg0& arg0_; // TODO: Should this be & or perfect fwd? -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/condition/check_nothing.hpp b/include/boost/contract/aux_/condition/check_nothing.hpp new file mode 100644 index 0000000..0e8b1dc --- /dev/null +++ b/include/boost/contract/aux_/condition/check_nothing.hpp @@ -0,0 +1,15 @@ + +#ifndef BOOST_CONTRACT_AUX_CHECK_NOTHING_HPP_ +#define BOOST_CONTRACT_AUX_CHECK_NOTHING_HPP_ + +namespace boost { namespace contract { namespace aux { + +class check_nothing { // Used as base for all contracts (and holder for RAII). +public: + virtual ~check_nothing() {} +}; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/condition/check_pre_post.hpp b/include/boost/contract/aux_/condition/check_pre_post.hpp new file mode 100644 index 0000000..e613ee6 --- /dev/null +++ b/include/boost/contract/aux_/condition/check_pre_post.hpp @@ -0,0 +1,94 @@ + +#ifndef BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ +#define BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace contract { namespace aux { + +// TODO: Does this need to be copied? Copying function<> could copy captures +// (if function is a lambda) and it could be expensive... check all classes +// that MUST be copiable, make sure their copies are effecient, make all other +// calsses noncopyable. +class check_pre_post : public boost::contract::aux::check_nothing { +public: + explicit check_pre_post(boost::contract::from from) : from_(from) {} + + explicit check_pre_post(boost::contract::from from, boost::shared_ptr< + boost::contract::aux::call> call) : from_(from), call_(call) {} + + virtual ~check_pre_post() {} + + template + void set_pre(F f) { pre_ = f; pre_available(); } + + template + void set_post(F f) { post_ = f; post_available(); } + +protected: + void check_pre(bool throw_on_failure = false) { + if(!call_ || call_->action == boost::contract::aux::call::check_pre) { + if(pre_) { + try { pre_(); } + catch(...) { + // Subcontracted pre must throw on failure (instead of + // calling failure handler) so to be checked in logic-or. + if(throw_on_failure) throw; + boost::contract::precondition_failed(from_); + } + } + if(call_) throw boost::contract::aux::no_error(); + } + } + + // TODO: I should be able to get rid of throw no_error everywhere (because + // the checking call_ allows the rest of the code to just do nothing). That + // way post and exit_inv checking can go in dtor also when bind is used. + // That will require to use scoped contract = ... also in contract decl + // functions. + // Then I should be able to set a state in c to false when a + // contract decl func is first called and then to true after the + // scoped contract = ... assignment is done. OLDOF can check that state so + // if I add from bind a call with action coped_entry_oldof and + // copy_oldof_after_pre_and_inv, I can then support copying old values + // after pre/inv have been checked also in contract decl func when users + // simply assign old values old_x = OLDOF(c, ...) after the contract decl + // (old_x variable will always have to be decl before the contract decl, but + // assigned before the contract decl to be copied before pre/inv, or after + // the contract decl to be copied after pre/inv). The same syntax, assigned + // before/after contract decl, can be used when bind is not used (that + // should work without changing current impl). + + // If call(), can't call from a dtor (as throw no_error on OK). + void check_post() { + if(!call_ || call_->action == boost::contract::aux::call::check_post) { + if(post_) { + try { post_(); } + catch(...) { boost::contract::postcondition_failed(from_); } + } + if(call_) throw boost::contract::aux::no_error(); + } + } + + virtual void pre_available() {} + virtual void post_available() {} + + boost::contract::from from() const { return from_; } + boost::shared_ptr call() { return call_; } + +private: + boost::function pre_; + boost::function post_; + boost::contract::from from_; + boost::shared_ptr call_; +}; + +} } } + +#endif // #include guard + diff --git a/include/boost/contract/aux_/condition/check_pre_post_inv.hpp b/include/boost/contract/aux_/condition/check_pre_post_inv.hpp new file mode 100644 index 0000000..b4ca150 --- /dev/null +++ b/include/boost/contract/aux_/condition/check_pre_post_inv.hpp @@ -0,0 +1,92 @@ + +#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 + +namespace boost { namespace contract { namespace aux { + +template +class check_pre_post_inv : // Copyable (as shallow ptr). + public boost::contract::aux::check_pre_post { +public: + explicit check_pre_post_inv(boost::contract::from from, C const* obj) : + boost::contract::aux::check_pre_post(from), obj_(obj) {} + + explicit check_pre_post_inv(boost::contract::from from, boost::shared_ptr< + boost::contract::aux::call> call, C const* obj) : + boost::contract::aux::check_pre_post(from, call), obj_(obj) + {} + + virtual ~check_pre_post_inv() {} + +protected: + void check_entry_inv(bool static_inv_only = false) { + if(!this->call() || this->call()->action == + boost::contract::aux::call::check_entry_inv) { + check_inv(/* on_entry = */ true, static_inv_only); + if(this->call()) throw no_error(); + } + } + + // If call(), can't call from dtor (as throw no_error on OK). + void check_exit_inv(bool static_inv_only = false) { + if(!this->call() || this->call()->action == + boost::contract::aux::call::check_exit_inv) { + check_inv(/* on_entry = */ false, static_inv_only); + if(this->call()) throw no_error(); + } + } + + C const* object() const { return obj_; } + +private: + void check_inv(bool on_entry, bool static_inv_only) { + check_static_inv(on_entry, boost::mpl::bool_::value>()); + if(!static_inv_only) { + check_const_inv(on_entry, boost::mpl::bool_::value>()); + } + } + + void check_static_inv(bool, boost::mpl::false_ const&) {} + void check_static_inv(bool on_entry, boost::mpl::true_ const&) { + try { C::BOOST_CONTRACT_CONFIG_STATIC_INVARIANT(); } + catch(...) { + if(on_entry) { + boost::contract::static_entry_invariant_failed(from()); + } else { + boost::contract::static_exit_invariant_failed(from()); + } + } + } + + void check_const_inv(bool, boost::mpl::false_ const&) {} + void check_const_inv(bool on_entry, boost::mpl::true_ const&) { + try { obj_->BOOST_CONTRACT_CONFIG_INVARIANT(); } + catch(...) { + if(on_entry) { + boost::contract::const_entry_invariant_failed(from()); + } else { + boost::contract::const_exit_invariant_failed(from()); + } + } + } + + // TODO: Add volatile inv here... + + C const* obj_; +}; + +} } } + +#endif // #include guard + diff --git a/include/boost/contract/aux_/config.hpp b/include/boost/contract/aux_/config.hpp index a82e9b1..9f7a63a 100644 --- a/include/boost/contract/aux_/config.hpp +++ b/include/boost/contract/aux_/config.hpp @@ -2,8 +2,13 @@ #ifndef BOOST_CONTRACT_AUX_CONFIG_HPP_ #define BOOST_CONTRACT_AUX_CONFIG_HPP_ -#ifndef BOOST_CONTRACT_AUX_CONFIG_DEBUG -# define BOOST_CONTRACT_AUX_CONFIG_DEBUG 1 +// Disable lib's implementation assertions to check against internal errors. +// #define BOOST_CONTRACT_AUX_CONFIG_NDEBUG + +// IMPORTANT: Cannot use '_' infix to prevent forming reserved C++ names +// (containing "__" if user `name` starts/ends with '_' already) so using 'X'. +#ifndef BOOST_CONTRACT_AUX_CONFIG_NAME_PREFIX +# define BOOST_CONTRACT_AUX_CONFIG_NAME_PREFIX boost_contract_auxX #endif #endif // #include guard diff --git a/include/boost/contract/aux_/debug.hpp b/include/boost/contract/aux_/debug.hpp index 925190f..c6dbb04 100644 --- a/include/boost/contract/aux_/debug.hpp +++ b/include/boost/contract/aux_/debug.hpp @@ -3,11 +3,12 @@ #define BOOST_CONTRACT_AUX_DEBUG_HPP_ #include -#if BOOST_CONTRACT_AUX_CONFIG_DEBUG -# include -# define BOOST_CONTRACT_AUX_DEBUG(cond) assert(cond) + +#ifdef BOOST_CONTRACT_AUX_CONFIG_NDEBUG +# define BOOST_CONTRACT_AUX_DEBUG(cond) #else -# define BOOST_COTNRACT_AUX_DEBUG(cond) +# include +# define BOOST_CONTRACT_AUX_DEBUG(cond) (assert(cond)) #endif #endif // #include guard diff --git a/include/boost/contract/aux_/exception.hpp b/include/boost/contract/aux_/exception.hpp index 32d1933..f3f0622 100644 --- a/include/boost/contract/aux_/exception.hpp +++ b/include/boost/contract/aux_/exception.hpp @@ -3,85 +3,11 @@ #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; +class no_error {}; // Must have no bases (just a tag type to signal no error). } } } // namespace diff --git a/include/boost/contract/aux_/function/bind.hpp b/include/boost/contract/aux_/function/bind.hpp new file mode 100644 index 0000000..e99d9f6 --- /dev/null +++ b/include/boost/contract/aux_/function/bind.hpp @@ -0,0 +1,62 @@ + +#ifndef BOOST_CONTRACT_AUX_BIND_HPP_ +#define BOOST_CONTRACT_AUX_BIND_HPP_ + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace contract { namespace aux { + +template +class bind : // Shallow ptr copies or &. + public boost::contract::aux::check_nothing { +public: + explicit bind(F f, A0 const& a0, A1 const& a1) : + c_(boost::make_shared()), + f_(f), a0_(a0), a1_(a1) + { + execute(boost::contract::aux::call::copy_oldof); + execute(boost::contract::aux::call::check_entry_inv); + execute(boost::contract::aux::call::check_pre); + } + + ~bind() { + if(!std::uncaught_exception()) { // Body did not throw. + execute(boost::contract::aux::call::check_exit_inv); + execute(boost::contract::aux::call::check_post); + } + } + +private: + void execute(boost::contract::aux::call::action_enum a) { + c_.call_->action = a; + try { // Call contract decl func for given action. + call(boost::mpl::bool_::value>()); + } catch(boost::contract::aux::no_error&) { + // no_error exception used to signal OK (so just continue). + } // Else: If other exceptions, throw them to caller. + } + + void call(boost::mpl::false_ const&) { + (*f_)(a0_, a1_, c_); + } + void call(boost::mpl::true_ const&) { + (a0_->*f_)(a1_, c_); + } + + boost::contract::call c_; // Copy as ptr. + F f_; // Copy as func. ptr. + A0 const& a0_; // Object for member func ptrs, 1st func arg otherwise. + A1 const& a1_; +}; + + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/function/constructor.hpp b/include/boost/contract/aux_/function/constructor.hpp deleted file mode 100644 index 64b6b45..0000000 --- a/include/boost/contract/aux_/function/constructor.hpp +++ /dev/null @@ -1,46 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_FUNCTION_CONSTRUCTOR_HPP_ -#define BOOST_CONTRACT_AUX_FUNCTION_CONSTRUCTOR_HPP_ - -#include -#include -#include - -namespace boost { namespace contract { namespace aux { namespace function { - -template -class constructor : public boost::contract::aux::check::pre_post_inv { -public: - explicit constructor(Class* const obj) : boost::contract::aux::check:: - pre_post_inv(boost::contract::from_constructor, obj) { - entry(); - } - - ~constructor() { exit(); } - -private: - // No object before ctor body so only static inv at entry. - void entry() { this->check_entry_inv(/* static_inv_only = */ true); } - - // Ctor pre checked by constructor_precondition at start of init list. - void pre_available() /* override */ { BOOST_CONTRACT_AUX_DEBUG(false); } - - // Ctor post always checked later, at exit (see below). - void post_available() /* override */ {} - - // If ctor body threw, only check static inv, otherwise obj constructed so - // check also non-static inv and post (subcontracting implemented - // automatically via C++ object constructor mechanism, so no calls to - // check_subcontracted_... in this case). - void exit() { - bool const body_threw = std::uncaught_exception(); - this->check_exit_inv(/* static_inv_only = */ body_threw); - if(!body_threw) this->check_post(); - } - -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/function/destructor.hpp b/include/boost/contract/aux_/function/destructor.hpp deleted file mode 100644 index eac02c5..0000000 --- a/include/boost/contract/aux_/function/destructor.hpp +++ /dev/null @@ -1,53 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_FUNCTION_DESTRUCTOR_HPP_ -#define BOOST_CONTRACT_AUX_FUNCTION_DESTRUCTOR_HPP_ - -#include -#include -#include -#include - -namespace boost { namespace contract { namespace aux { namespace function { - -template -class destructor : public boost::contract::aux::check::pre_post_inv { -public: - explicit destructor(Class* const obj) : boost::contract::aux::check:: - pre_post_inv(boost::contract::from_destructor, obj) { - entry(); - } - - ~destructor() { exit(); } - -private: - // Obj still exists (before dtor body) so check static and non-static inv - // (subcontracting implemented automatically via C++ object destruction - // mechanism, so no calls to check_subcontracted_... in this case). - void entry() { this->check_entry_inv(); } - - // Dtor cannot have pre because it has no parameters. - void pre_available() /* override */ { BOOST_CONTRACT_AUX_DEBUG(false); } - - // Ctor post always checked after body, at exit (see below). - // NOTE: Even if there is no obj after dtor body, this library allows for - // dtor post (e.g., to check static members for an instance counter class). - void post_available() /* override */ {} - - // If dtor body threw, obj still exists so check subcontracted static and - // non-static inv (but no post because of throw), otherwise obj destructed - // so check static static inv and post (subcontracting implemented - // automatically via C++ object destruction mechanism, so no calls to - // check_subcontracted_... in this case). - // NOTE: In theory C++ destructors should not throw, but the language allows - // for that so this library must handle such a case. - void exit() { - bool const body_threw = std::uncaught_exception(); - this->check_exit_inv(/* static_inv_only = */ !body_threw); - if(!body_threw) this->check_post(); - } -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/function/free_function.hpp b/include/boost/contract/aux_/function/free_function.hpp index b504aea..b0efe7b 100644 --- a/include/boost/contract/aux_/function/free_function.hpp +++ b/include/boost/contract/aux_/function/free_function.hpp @@ -1,41 +1,43 @@ -#ifndef BOOST_CONTRACT_AUX_FUNCTION_FREE_FUNCTION_HPP_ -#define BOOST_CONTRACT_AUX_FUNCTION_FREE_FUNCTION_HPP_ +#ifndef BOOST_CONTRACT_AUX_FREE_FUNCTION_HPP_ +#define BOOST_CONTRACT_AUX_FREE_FUNCTION_HPP_ #include -#include +#include +#include +#include #include -namespace boost { namespace contract { namespace aux { namespace function { +namespace boost { namespace contract { namespace aux { -class free_function : public boost::contract::aux::check::pre_post { +class free_function : public boost::contract::aux::check_pre_post { public: - explicit free_function(boost::contract::from const from = - boost::contract::from_free_function) : - boost::contract::aux::check::pre_post(from) - { entry(); } + explicit free_function() : + boost::contract::aux::check_pre_post( + boost::contract::from_free_function) + {} + + explicit free_function(boost::shared_ptr call) : + boost::contract::aux::check_pre_post( + boost::contract::from_free_function, call) + {} - virtual ~free_function() { exit(); } - private: - // Do nothing (not a public member so no inv to check, nor subcontracting). - void entry() {} - - // Check pre (as soon as related functor set). void pre_available() /* override */ { check_pre(); } + + void post_available() /* override */ { + if(call()) check_post(); // Throw (so not in dtor). + } - // Post always checked after body, at exit (see below). - void post_available() /* override */ {} - - // If body did not throw, check post (not a public member so no inv to - // check, nor subcontracting). - void exit() { - bool const body_threw = std::uncaught_exception(); - if(!body_threw) check_post(); +public: + ~free_function() { + if(!call() && !std::uncaught_exception()) { // Body didn't throw. + check_post(); + } } }; -} } } } // namespace +} } } // namespace #endif // #include guard diff --git a/include/boost/contract/aux_/function/private_member.hpp b/include/boost/contract/aux_/function/private_member.hpp deleted file mode 100644 index f1bbf1a..0000000 --- a/include/boost/contract/aux_/function/private_member.hpp +++ /dev/null @@ -1,23 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_FUNCTION_PRIVATE_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_FUNCTION_PRIVATE_MEMBER_HPP_ - -#include -#include - -namespace boost { namespace contract { namespace aux { namespace function { - -// Not public members (i.e., private members) are allowed to fail class -// invariants (so no inv) and they do not participate in virtual function -// polymorphism according to substitution principle (so no subcontracting). -// Therefore, their contracts behave like contracts of free functions. -class private_member : public free_function { -public: - explicit private_member() : - free_function(boost::contract::from_private_member) {} -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/function/protected_member.hpp b/include/boost/contract/aux_/function/protected_member.hpp deleted file mode 100644 index 0fba547..0000000 --- a/include/boost/contract/aux_/function/protected_member.hpp +++ /dev/null @@ -1,23 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_FUNCTION_PROTECTED_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_FUNCTION_PROTECTED_MEMBER_HPP_ - -#include -#include - -namespace boost { namespace contract { namespace aux { namespace function { - -// Not public members (i.e., protected members) are allowed to fail class -// invariants (so no inv) and they do not participate in virtual function -// polymorphism according to substitution principle (so no subcontracting). -// Therefore, their contracts behave like contracts of free functions. -class protected_member : public free_function { -public: - explicit protected_member() : - free_function(boost::contract::from_protected_member) {} -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/function/public_member.hpp b/include/boost/contract/aux_/function/public_member.hpp index b285d59..16ecde1 100644 --- a/include/boost/contract/aux_/function/public_member.hpp +++ b/include/boost/contract/aux_/function/public_member.hpp @@ -1,147 +1,50 @@ -#ifndef BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_MEMBER_HPP_ +#ifndef BOOST_CONTRACT_AUX_PUBLIC_MEMBER_HPP_ +#define BOOST_CONTRACT_AUX_PUBLIC_MEMBER_HPP_ -#include -#include -#include -#include -#include -#include +#include +#include +#include #include -// TODO: Consider passing params as in (by mutable value or const&), inout -// (by & or *). +namespace boost { namespace contract { namespace aux { -namespace boost { namespace contract { namespace aux { namespace function { - -template< - class Class, - class Intro = boost::contract::aux::none, - typename Arg0 = boost::contract::aux::none -> class public_member : public boost::contract::aux::check:: - subcontracted_pre_post_inv { +template +class public_member : public boost::contract::aux::check_pre_post_inv { public: - // Must be used when bases and virtual body (but can also always be used). - 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(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_* const virt, - Class* const obj) : - 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(boost::contract::from_public_member, /* virt = */ 0, obj, - boost::contract::aux::none() - ) - { entry(); } - - ~public_member() { exit(); } + explicit public_member(C const* obj) : + boost::contract::aux::check_pre_post_inv( + boost::contract::from_public_member, obj) + { init(); } + + explicit public_member(boost::shared_ptr call, + C const* obj) : + boost::contract::aux::check_pre_post_inv( + boost::contract::from_public_member, call, obj) + { init(); } private: - // Check static and non-static subcontracted inv. - void entry() { - if( - 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::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::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::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::virtual_::user_call) { - throw boost::contract::aux::no_error(); - } - } // Else (check only pre, post, etc.) do nothing. + void init() { + this->check_entry_inv(); + if(this->call()) this->check_exit_inv(); // Throw (so not in dtor). } - // Check subcontracted pre (as soon as related functor set). - void pre_available() /* override */ { - if( - 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::virtual_::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. - } - - // Check post here only if check-post-only mode (otherwise check at exit). + void pre_available() /* override */ { this->check_pre(); } + void post_available() /* override */ { - 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. + if(this->call()) this->check_post(); // Throw (so not in dtor). } - // 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::virtual_::user_call) { - this->check_subcontracted_exit_inv(); - if(!body_threw) this->check_subcontracted_post(); +public: + ~public_member() { + if(!this->call() && !std::uncaught_exception()) { // Body didn't throw. + this->check_exit_inv(); + this->check_post(); } } }; -} } } } // namespace +} } } // namespace #endif // #include guard diff --git a/include/boost/contract/aux_/function/public_static_member.hpp b/include/boost/contract/aux_/function/public_static_member.hpp deleted file mode 100644 index 52cb5b7..0000000 --- a/include/boost/contract/aux_/function/public_static_member.hpp +++ /dev/null @@ -1,47 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_STATIC_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_STATIC_MEMBER_HPP_ - -#include -#include -#include - -namespace boost { namespace contract { namespace aux { namespace function { - -template class public_static_member : - public boost::contract::aux::check::pre_post_inv { -public: - explicit public_static_member() : boost::contract::aux::check:: - pre_post_inv(boost::contract::from_public_member) { - entry(); - } - - ~public_static_member() { exit(); } - -private: - // Static members have no object so they do not participate in virtual - // function polymorphism according to substitution principle (so no - // subcontracting for any of the checks below). - - // Static so no object so check static inv only. - void entry() { this->check_entry_inv(/* static_inv_only = */ true); } - - // Check pre (as soon as related functor set). - void pre_available() /* override */ { this->check_pre(); } - - // Post always checked after body, at exit (see below). - void post_available() /* override */ {} - - // Static so no object and only static inv checked, plus check post but - // only if body did not throw. - void exit() { - bool const body_threw = std::uncaught_exception(); - this->check_exit_inv(/* static_inv_only = */ true); - if(!body_threw) this->check_post(); - } -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/name.hpp b/include/boost/contract/aux_/name.hpp index c0288b1..680e0ca 100644 --- a/include/boost/contract/aux_/name.hpp +++ b/include/boost/contract/aux_/name.hpp @@ -2,18 +2,16 @@ #ifndef BOOST_CONTRACT_AUX_NAME_HPP_ #define BOOST_CONTRACT_AUX_NAME_HPP_ +#include #include /* PUBLIC */ -// IMPORTANT: Cannot use '_' infix to prevent forming reserved C++ names -// (containing "__" if user `name` starts/ends with '_' already) so using 'X'. - // NOTE: Explicitly list number of names to concatenate using ..._NAME-n // (instead of using ..._SEQ_CAT or similar) for optimal speed and reentrancy. #define BOOST_CONTRACT_AUX_NAME1(name1) \ - BOOST_PP_CAT(boost_contract_auxX, name1) + BOOST_PP_CAT(BOOST_CONTRACT_AUX_CONFIG_NAME_PREFIX, name1) #endif // #include guard diff --git a/include/boost/contract/aux_/none.hpp b/include/boost/contract/aux_/none.hpp index 39c7d3c..401a37c 100644 --- a/include/boost/contract/aux_/none.hpp +++ b/include/boost/contract/aux_/none.hpp @@ -4,7 +4,12 @@ namespace boost { namespace contract { namespace aux { -struct none { static none value; }; +struct none { // Tag for "no type". + static none value; // Tag for "no value". + + // Must contain no functionality (so it cannot actually be used by mistake). +}; + none none::value; } } } // namespace diff --git a/include/boost/contract/aux_/oldof.hpp b/include/boost/contract/aux_/oldof.hpp deleted file mode 100644 index 64129ec..0000000 --- a/include/boost/contract/aux_/oldof.hpp +++ /dev/null @@ -1,68 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_OLDOF_HPP_ -#define BOOST_CONTRACT_AUX_OLDOF_HPP_ - -#include -#include -#include -#include - -namespace boost { namespace contract { namespace aux { - -class oldof { // Must allow copies (shallow pointer copies). -public: - oldof() : virt_(), value_() {} // Null value ptr when no oldof. - - explicit oldof(boost::contract::virtual_* const virt, oldof const& old) : - virt_(virt), value_(old.value_) {} - - template - /* implicit */ oldof(T const& old_value) : - value_(boost::make_shared(old_value)) {} // One single copy of T. - - // Pointer so it can be null (for when no post) and shared because owned by - // this lib for virtual calls (stored in v) but owned by user's stack value - // for non-virtual calls (so shared ownership to handle both cases). - template - operator boost::shared_ptr() { - if(!virt_) { - BOOST_CONTRACT_AUX_DEBUG(value_); - boost::shared_ptr result = - boost::static_pointer_cast(value_); - BOOST_CONTRACT_AUX_DEBUG(result); - return result; - } 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(value_); - std::clog << "pushed" << std::endl; - return boost::shared_ptr(); - } else if( - 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(); - std::clog << "popped" << std::endl; - BOOST_CONTRACT_AUX_DEBUG(value); - boost::shared_ptr result = - boost::static_pointer_cast(value); - BOOST_CONTRACT_AUX_DEBUG(result); - return result; - } - BOOST_CONTRACT_AUX_DEBUG(!value_); - return boost::shared_ptr(); - } - -private: - boost::contract::virtual_* virt_; - boost::shared_ptr value_; // Type erased to `void*`. -}; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/preprocessor/keyword/private.hpp b/include/boost/contract/aux_/preprocessor/keyword/private.hpp deleted file mode 100644 index 9f4d805..0000000 --- a/include/boost/contract/aux_/preprocessor/keyword/private.hpp +++ /dev/null @@ -1,29 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_PP_KEYWORD_PRIVATE_HPP_ -#define BOOST_CONTRACT_AUX_PP_KEYWORD_PRIVATE_HPP_ - -#include -#include - -/* PUBLIC */ - -// Precondition: tokens must start with a token concatenable to a macro name -// (e.g., a literal or integral token). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_IS_PRIVATE(tokens) \ - BOOST_CONTRACT_AUX_PP_KEYWORD_UTILITY_IS( \ - BOOST_CONTRACT_AUX_PP_KEYWORD_PRIVATE_CAT_TO_COMMA, tokens) - -// Precondition: tokens must start with `private` (this can be -// checked with `..._IS_PRIVATE` macro above). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_REMOVE_PRIVATE(tokens) \ - BOOST_PP_CAT(BOOST_CONTRACT_AUX_PP_KEYWORD_PRIVATE_CAT_TO_EMPTY, tokens) - -/* PRIVATE */ - -// Must expand to a single comma `,` (not local macros, do not #undefine). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_PRIVATE_CAT_TO_COMMAprivate , -// Must expand to empty `` (not local macros, do not #undefine). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_PRIVATE_CAT_TO_EMPTYprivate - -#endif // #include guard - diff --git a/include/boost/contract/aux_/preprocessor/keyword/protected.hpp b/include/boost/contract/aux_/preprocessor/keyword/protected.hpp deleted file mode 100644 index 1d309d0..0000000 --- a/include/boost/contract/aux_/preprocessor/keyword/protected.hpp +++ /dev/null @@ -1,29 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_PP_KEYWORD_PROTECTED_HPP_ -#define BOOST_CONTRACT_AUX_PP_KEYWORD_PROTECTED_HPP_ - -#include -#include - -/* PUBLIC */ - -// Precondition: tokens must start with a token concatenable to a macro name -// (e.g., a literal or integral token). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_IS_PROTECTED(tokens) \ - BOOST_CONTRACT_AUX_PP_KEYWORD_UTILITY_IS( \ - BOOST_CONTRACT_AUX_PP_KEYWORD_PROTECTED_CAT_TO_COMMA, tokens) - -// Precondition: tokens must start with `protected` (this can be -// checked with `..._IS_PROTECTED` macro above). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_REMOVE_PROTECTED(tokens) \ - BOOST_PP_CAT(BOOST_CONTRACT_AUX_PP_KEYWORD_PROTECTED_CAT_TO_EMPTY, tokens) - -/* PRIVATE */ - -// Must expand to a single comma `,` (not local macros, do not #undefine). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_PROTECTED_CAT_TO_COMMAprotected , -// Must expand to empty `` (not local macros, do not #undefine). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_PROTECTED_CAT_TO_EMPTYprotected - -#endif // #include guard - diff --git a/include/boost/contract/aux_/preprocessor/keyword/public.hpp b/include/boost/contract/aux_/preprocessor/keyword/public.hpp deleted file mode 100644 index 2c3f9ca..0000000 --- a/include/boost/contract/aux_/preprocessor/keyword/public.hpp +++ /dev/null @@ -1,29 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_PP_KEYWORD_PUBLIC_HPP_ -#define BOOST_CONTRACT_AUX_PP_KEYWORD_PUBLIC_HPP_ - -#include -#include - -/* PUBLIC */ - -// Precondition: tokens must start with a token concatenable to a macro name -// (e.g., a literal or integral token). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_IS_PUBLIC(tokens) \ - BOOST_CONTRACT_AUX_PP_KEYWORD_UTILITY_IS( \ - BOOST_CONTRACT_AUX_PP_KEYWORD_PUBLIC_CAT_TO_COMMA, tokens) - -// Precondition: tokens must start with `public` (this can be -// checked with `..._IS_PUBLIC` macro above). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_REMOVE_PUBLIC(tokens) \ - BOOST_PP_CAT(BOOST_CONTRACT_AUX_PP_KEYWORD_PUBLIC_CAT_TO_EMPTY, tokens) - -/* PRIVATE */ - -// Must expand to a single comma `,` (not local macros, do not #undefine). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_PUBLIC_CAT_TO_COMMApublic , -// Must expand to empty `` (not local macros, do not #undefine). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_PUBLIC_CAT_TO_EMPTYpublic - -#endif // #include guard - diff --git a/include/boost/contract/aux_/preprocessor/keyword/utility/is.hpp b/include/boost/contract/aux_/preprocessor/keyword/utility/is.hpp deleted file mode 100644 index d851ec5..0000000 --- a/include/boost/contract/aux_/preprocessor/keyword/utility/is.hpp +++ /dev/null @@ -1,24 +0,0 @@ - -#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS_HPP_ -#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS_HPP_ - -#include -#include - -/* PUBLIC */ - -// Precondition: A macro named `cat_to_comma_prefix ## token-to-check` must be -// #defined to expand to `,`. -// Precondition: tokens must start with a token concatenable to a macro name -// (e.g., a literal or integral token). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_UTILITY_IS(cat_to_comma_prefix, tokens) \ - BOOST_PP_CAT(BOOST_CONTRACT_AUX_PP_KEYWORD_UTILITY_IS_, \ - BOOST_PP_VARIADIC_SIZE(BOOST_PP_CAT(cat_to_comma_prefix, tokens))) - -/* PRIVATE */ - -#define BOOST_CONTRACT_AUX_PP_KEYWORD_UTILITY_IS_1 0 -#define BOOST_CONTRACT_AUX_PP_KEYWORD_UTILITY_IS_2 1 - -#endif // #include guard - diff --git a/include/boost/contract/aux_/preprocessor/keyword/virtual.hpp b/include/boost/contract/aux_/preprocessor/keyword/virtual.hpp deleted file mode 100644 index 0af327d..0000000 --- a/include/boost/contract/aux_/preprocessor/keyword/virtual.hpp +++ /dev/null @@ -1,28 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_PP_KEYWORD_VIRTUAL_HPP_ -#define BOOST_CONTRACT_AUX_PP_KEYWORD_VIRTUAL_HPP_ - -#include - -/* PUBLIC */ - -// Precondition: tokens must start with a token concatenable to a macro name -// (e.g., a literal or integral token). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_IS_VIRTUAL(tokens) \ - BOOST_CONTRACT_AUX_PP_KEYWORD_UTILITY_IS( \ - BOOST_CONTRACT_AUX_PP_KEYWORD_VIRTUAL_CAT_TO_COMMA, tokens) - -// Precondition: tokens must start with `virtual` (this can be -// checked with `..._IS_VIRTUAL` macro above). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_REMOVE_VIRTUAL(tokens) \ - BOOST_PP_CAT(BOOST_CONTRACT_AUX_PP_KEYWORD_VIRTUAL_CAT_TO_EMPTY, tokens) - -/* PRIVATE */ - -// Must expand to a single comma `,` (not local macros, do not #undefine). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_VIRTUAL_CAT_TO_COMMAvirtual , -// Must expand to empty `` (not local macros, do not #undefine). -#define BOOST_CONTRACT_AUX_PP_KEYWORD_VIRTUAL_CAT_TO_EMPTYvirtual - -#endif // #include guard - diff --git a/include/boost/contract/aux_/type_traits/bases.hpp b/include/boost/contract/aux_/type_traits/bases.hpp deleted file mode 100644 index ef963cf..0000000 --- a/include/boost/contract/aux_/type_traits/bases.hpp +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_TYPE_TRAITS_BASES_HPP_ -#define BOOST_CONTRACT_AUX_TYPE_TRAITS_BASES_HPP_ - -#include -#include - -namespace boost { namespace contract { namespace aux { namespace type_traits { - -BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_TYPE(has_bases, - BOOST_CONTRACT_CONFIG_BASE_TYPES) - -template< class C > -struct bases_of { typedef typename C::BOOST_CONTRACT_CONFIG_BASE_TYPES type; }; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/type_traits/introspection.hpp b/include/boost/contract/aux_/type_traits/introspection.hpp index 5b6e3fa..89ac1bc 100644 --- a/include/boost/contract/aux_/type_traits/introspection.hpp +++ b/include/boost/contract/aux_/type_traits/introspection.hpp @@ -1,6 +1,6 @@ -#ifndef BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HPP_ -#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HPP_ +#ifndef BOOST_CONTRACT_AUX_INTROSPECTION_HPP_ +#define BOOST_CONTRACT_AUX_INTROSPECTION_HPP_ #include #include @@ -19,32 +19,29 @@ /* PUBLIC */ -#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_TYPE(trait, type_name)\ +#define BOOST_CONTRACT_AUX_INTROSPECTION_HAS_TYPE(trait, type_name)\ template \ class trait { \ template \ - static boost::contract::aux::type_traits::introspection::yes& check( \ + static boost::contract::aux::introspection::yes& check( \ typename BOOST_CONTRACT_AUX_NAME1(C)::type_name*); \ - \ - BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_END_( \ - BOOST_CONTRACT_AUX_NAME1(T)) \ + BOOST_CONTRACT_AUX_INTROSPECTION_END_(BOOST_CONTRACT_AUX_NAME1(T)) \ }; -#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION( \ +#define BOOST_CONTRACT_AUX_INTROSPECTION_HAS_MEMBER_FUNCTION( \ trait, func_name) \ - BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION_( \ - /* is_static = */ 0, trait, func_name) + BOOST_CONTRACT_AUX_INTROSPECTION_HAS_MEMBER_FUNCTION_(/* is_static = */ 0, \ + trait, func_name) -#define \ -BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_STATIC_MEMBER_FUNCTION(trait, \ +#define BOOST_CONTRACT_AUX_INTROSPECTION_HAS_STATIC_MEMBER_FUNCTION(trait, \ func_name) \ - BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION_( \ - /* is_static = */ 1, trait, func_name) + BOOST_CONTRACT_AUX_INTROSPECTION_HAS_MEMBER_FUNCTION_(/* is_static = */ 1, \ + trait, func_name) /* PRIVATE */ -#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION_( \ - is_static, trait, func_name) \ +#define BOOST_CONTRACT_AUX_INTROSPECTION_HAS_MEMBER_FUNCTION_(is_static, \ + trait, func_name) \ template< \ typename BOOST_CONTRACT_AUX_NAME1(T), \ typename BOOST_CONTRACT_AUX_NAME1(R), \ @@ -53,8 +50,8 @@ BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_STATIC_MEMBER_FUNCTION(trait, \ > \ class trait { \ template \ - static boost::contract::aux::type_traits::introspection::yes& check( \ - boost::contract::aux::type_traits::introspection::check_function< \ + static boost::contract::aux::introspection::yes& check( \ + boost::contract::aux::introspection::check_function< \ typename \ BOOST_PP_IIF(is_static, \ boost::function_types::function_pointer \ @@ -81,33 +78,27 @@ BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_STATIC_MEMBER_FUNCTION(trait, \ &BOOST_CONTRACT_AUX_NAME1(C)::func_name \ >* \ ); \ - \ - BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_END_( \ - BOOST_CONTRACT_AUX_NAME1(T)) \ + BOOST_CONTRACT_AUX_INTROSPECTION_END_(BOOST_CONTRACT_AUX_NAME1(T)) \ }; -#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_END_(tparam) \ +#define BOOST_CONTRACT_AUX_INTROSPECTION_END_(tparam) \ template \ - static boost::contract::aux::type_traits::introspection::no& check( \ - ...); \ - \ + static boost::contract::aux::introspection::no& check(...); \ public: \ static bool const value = sizeof(check(0)) == \ - sizeof(boost::contract::aux::type_traits::introspection::yes); \ + sizeof(boost::contract::aux::introspection::yes); \ typedef boost::mpl::bool_ type; /* CODE */ -namespace boost { namespace contract { namespace aux { namespace type_traits { - namespace introspection { +namespace boost { namespace contract { namespace aux { namespace introspection { typedef struct {} yes; typedef yes no[2]; -template -struct check_function; +template struct check_function; -} } } } } // namespace +} } } } // namespace #endif // #include guard diff --git a/include/boost/contract/aux_/type_traits/invariant.hpp b/include/boost/contract/aux_/type_traits/invariant.hpp index 2bf9a46..97fabc6 100644 --- a/include/boost/contract/aux_/type_traits/invariant.hpp +++ b/include/boost/contract/aux_/type_traits/invariant.hpp @@ -1,22 +1,22 @@ -#ifndef BOOST_CONTRACT_AUX_TYPE_TRAITS_INVARIANT_HPP_ -#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INVARIANT_HPP_ +#ifndef BOOST_CONTRACT_AUX_INVARIANT_HPP_ +#define BOOST_CONTRACT_AUX_INVARIANT_HPP_ #include #include #include #include -namespace boost { namespace contract { namespace aux { namespace type_traits { +namespace boost { namespace contract { namespace aux { namespace invariant_ { - BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION( + BOOST_CONTRACT_AUX_INTROSPECTION_HAS_MEMBER_FUNCTION( has_invariant, BOOST_CONTRACT_CONFIG_INVARIANT) - BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION( + BOOST_CONTRACT_AUX_INTROSPECTION_HAS_MEMBER_FUNCTION( has_non_static_invariant, BOOST_CONTRACT_CONFIG_STATIC_INVARIANT) - BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_STATIC_MEMBER_FUNCTION( + BOOST_CONTRACT_AUX_INTROSPECTION_HAS_STATIC_MEMBER_FUNCTION( has_static_invariant, BOOST_CONTRACT_CONFIG_STATIC_INVARIANT) } @@ -45,7 +45,7 @@ template struct has_non_static_invariant : invariant_::has_non_static_invariant > {}; -} } } } // namespace +} } } // namespace #endif // #include guard diff --git a/include/boost/contract/base_types.hpp b/include/boost/contract/base_types.hpp deleted file mode 100644 index 6595cab..0000000 --- a/include/boost/contract/base_types.hpp +++ /dev/null @@ -1,142 +0,0 @@ - -#ifndef BOOST_CONTRACT_BASE_TYPES_HPP_ -#define BOOST_CONTRACT_BASE_TYPES_HPP_ - -#include -#if !BOOST_PP_VARIADICS - -#define BOOST_CONTRACT_BASE_TYPES BOOST_CONTRACT_ERROR_variadic_macros_required_by_BOOST_CONTRACT_BASE_TYPES_otherwise_manually_program_base_types - -#else - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* PUBLIC */ - -#define BOOST_CONTRACT_BASE_TYPES(...) \ - BOOST_CONTRACT_BASE_TYPES_CHECK_((__VA_ARGS__), \ - BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) - -/* PRIVATE */ - -// Cannot check that all base types have access specifiers (unless users have to -// specify bases using pp-seq, because user specified base list can have -// unwrapped commas between bases but also within a given base type, when base -// types are templates), but at least check the very first base type explicitly -// specifies access `[virtual] public | protected | private [virtual] ...`. -#define BOOST_CONTRACT_BASE_TYPES_CHECK_(bases_tuple, bases_seq) \ - BOOST_PP_IIF(BOOST_CONTRACT_BASE_TYPES_IS_ACCESS_( \ - BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_(BOOST_PP_SEQ_HEAD( \ - bases_seq))), \ - BOOST_CONTRACT_BASE_TYPES_OK_ \ - , \ - BOOST_CONTRACT_BASE_TYPES_ERR_ \ - )(bases_tuple, bases_seq) - -#define BOOST_CONTRACT_BASE_TYPES_ERR_(bases_tuple, bases_seq) \ - BOOST_CONTRACT_ERROR_all_bases_must_explicitly_specify_public_protected_or_private base_tuple - -#define BOOST_CONTRACT_BASE_TYPES_OK_(base_tuple, bases_seq) \ - boost::mpl::vector< \ - BOOST_CONTRACT_BASE_TYPES_RETURN_(BOOST_PP_TUPLE_ELEM(2, 1, \ - BOOST_PP_SEQ_FOLD_LEFT( \ - BOOST_CONTRACT_BASE_TYPES_, \ - (0, (BOOST_PP_NIL)), \ - bases_seq \ - ) \ - )) \ - > - -#define BOOST_CONTRACT_BASE_TYPES_RETURN_(types_nilseq) \ - BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE(types_nilseq), 1), \ - BOOST_PP_TUPLE_EAT(1) \ - , \ - BOOST_CONTRACT_BASE_TYPES_RETURN_YES_ \ - )(types_nilseq) - -#define BOOST_CONTRACT_BASE_TYPES_RETURN_YES_(types_nilseq) \ - BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TAIL(types_nilseq)) - -#define BOOST_CONTRACT_BASE_TYPES_(s, public_types, base) \ - BOOST_CONTRACT_BASE_TYPES_ACCESS_( \ - BOOST_PP_TUPLE_ELEM(2, 0, public_types), \ - BOOST_PP_TUPLE_ELEM(2, 1, public_types), \ - BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_(base) \ - ) - -#define BOOST_CONTRACT_BASE_TYPES_ACCESS_(is_public, types_nilseq, base) \ - BOOST_PP_IIF(BOOST_CONTRACT_AUX_PP_KEYWORD_IS_PUBLIC(base), \ - BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_PUBLIC_ \ - , BOOST_PP_IIF(BOOST_CONTRACT_AUX_PP_KEYWORD_IS_PROTECTED(base), \ - BOOST_CONTRACT_BASE_TYPES_SKIP_NOT_PUBLIC_ \ - , BOOST_PP_IIF(BOOST_CONTRACT_AUX_PP_KEYWORD_IS_PRIVATE(base), \ - BOOST_CONTRACT_BASE_TYPES_SKIP_NOT_PUBLIC_ \ - , \ - BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_IF_ \ - )))(is_public, types_nilseq, base) - -// Precondition: base = `public [virtual] ...`. -#define BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_PUBLIC_(is_public, types_nilseq, \ - base) \ - ( \ - 1, \ - BOOST_PP_SEQ_PUSH_BACK(types_nilseq, \ - BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_( \ - BOOST_CONTRACT_AUX_PP_KEYWORD_REMOVE_PUBLIC(base)) \ - ) \ - ) - -#define BOOST_CONTRACT_BASE_TYPES_SKIP_NOT_PUBLIC_(is_public, types_nilseq, \ - base) \ - (0, types_nilseq) - -#define BOOST_CONTRACT_BASE_TYPES_PUSH_BACK_IF_(is_public, types_nilseq, base) \ - ( \ - is_public, \ - BOOST_PP_IIF(is_public, \ - BOOST_PP_SEQ_PUSH_BACK \ - , \ - types_nilseq BOOST_PP_TUPLE_EAT(2) \ - )(types_nilseq, base) \ - ) - -#define BOOST_CONTRACT_BASE_TYPES_REMOVE_VIRTUAL_(base) \ - BOOST_PP_EXPAND( \ - BOOST_PP_IIF(BOOST_CONTRACT_AUX_PP_KEYWORD_IS_VIRTUAL(base), \ - BOOST_CONTRACT_AUX_PP_KEYWORD_REMOVE_VIRTUAL \ - , \ - BOOST_PP_TUPLE_REM(1) \ - )(base) \ - ) - -#define BOOST_CONTRACT_BASE_TYPES_IS_ACCESS_(base) \ - BOOST_PP_IIF(BOOST_CONTRACT_AUX_PP_KEYWORD_IS_PUBLIC(base), \ - 1 \ - , BOOST_PP_IIF(BOOST_CONTRACT_AUX_PP_KEYWORD_IS_PROTECTED(base), \ - 1 \ - , BOOST_PP_IIF(BOOST_CONTRACT_AUX_PP_KEYWORD_IS_PRIVATE(base), \ - 1 \ - , \ - 0 \ - ))) - -#endif // BOOST_PP_VARIADICS - -#endif // #include guard - diff --git a/include/boost/contract/bind.hpp b/include/boost/contract/bind.hpp new file mode 100644 index 0000000..afc7714 --- /dev/null +++ b/include/boost/contract/bind.hpp @@ -0,0 +1,22 @@ + +#ifndef BOOST_CONTRACT_BIND_HPP_ +#define BOOST_CONTRACT_BIND_HPP_ + +#include +#include +#include + +namespace boost { namespace contract { + +// A0 is object ptr if F is member func ptr, 1st func arg otherwise. + +template +boost::contract::set_nothing bind(F f, A0 const& a0, A1 const& a1) { + return boost::contract::set_nothing(boost::make_shared >(f, a0, a1)); +} + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/constructor.hpp b/include/boost/contract/constructor.hpp deleted file mode 100644 index 5d7a447..0000000 --- a/include/boost/contract/constructor.hpp +++ /dev/null @@ -1,37 +0,0 @@ - -#ifndef BOOST_CONTRACT_CONSTRUCTOR_HPP_ -#define BOOST_CONTRACT_CONSTRUCTOR_HPP_ - -#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::aux::function::constructor >(object)); -} - -// Uses Class tparam to avoid multiple inheritance from same type. -template -struct constructor_precondition { - constructor_precondition() {} // For overloaded constructors with no pre. - - template - explicit constructor_precondition(Precondition const& f) { - try { f(); } - catch(...) { - boost::contract::aux::pre_failure_handler( - boost::contract::from_constructor); - } - } -}; - -} } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/core/call.hpp b/include/boost/contract/core/call.hpp new file mode 100644 index 0000000..e83facc --- /dev/null +++ b/include/boost/contract/core/call.hpp @@ -0,0 +1,51 @@ + +#ifndef BOOST_CONTRACT_CALL_HPP_ +#define BOOST_CONTRACT_CALL_HPP_ + +#include +#include + +namespace boost { + namespace contract { + class set_precondition_postcondition; + + namespace aux { + template + class bind; + } + } +} + +namespace boost { namespace contract { + +class call { +public: + // Nothing here (opaque object that users cannot directly use or create). + +private: // Friendship to minimize lib's public API. + friend bool copy_oldof(call const&); + friend class oldof; + + template + friend class boost::contract::aux::bind; + + friend boost::contract::set_precondition_postcondition free_function( + call const&); + + template + friend boost::contract::set_precondition_postcondition public_member( + boost::contract::call const&, C const*); + + explicit call(boost::shared_ptr _call) : + call_(_call) {} + + call(call const& other) : call_(other.call_) {} // Shallow ptr copy. + call& operator=(call const&); // No copy operator. + + boost::shared_ptr call_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/core/config.hpp b/include/boost/contract/core/config.hpp index 2c78594..0ff9f92 100644 --- a/include/boost/contract/core/config.hpp +++ b/include/boost/contract/core/config.hpp @@ -2,30 +2,15 @@ #ifndef BOOST_CONTRACT_CONFIG_HPP_ #define BOOST_CONTRACT_CONFIG_HPP_ -// TODO: Implement NO_... macros to disable pre/post/inv-entry/inv-exit/etc. - -// The name of the invariant member function ("invariant" by default). #ifndef BOOST_CONTRACT_CONFIG_INVARIANT # define BOOST_CONTRACT_CONFIG_INVARIANT invariant #endif -// The name of the static invariant member function ("static invariant" by -// default). -// NOTE: C++ forbids function overload based on static classifier so a new -// function name, different from invariant's function name, had to be used. +// C++ does not allow to overload member functions based on static classifier, +// so a name different from the non-static class invariant member must be used. #ifndef BOOST_CONTRACT_CONFIG_STATIC_INVARIANT # define BOOST_CONTRACT_CONFIG_STATIC_INVARIANT static_invariant #endif -// The name of the base types type-def ("base_types" by default). -#ifndef BOOST_CONTRACT_CONFIG_BASE_TYPES -# define BOOST_CONTRACT_CONFIG_BASE_TYPES base_types -#endif - -// Disable some sanity checks on usage of APIs (0 by default). -#ifndef BOOST_CONTRACT_CONFIG_PERMISSIVE -# define BOOST_CONTRACT_CONFIG_PERMISSIVE 0 -#endif - #endif // #include guard diff --git a/include/boost/contract/core/exception.hpp b/include/boost/contract/core/exception.hpp index 1a63db4..8eec4d3 100644 --- a/include/boost/contract/core/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -2,14 +2,15 @@ #ifndef BOOST_CONTRACT_EXCEPTION_HPP_ #define BOOST_CONTRACT_EXCEPTION_HPP_ +//#include #include #include #include +#include +#include namespace boost { namespace contract { -// Exceptions. - struct assertion_failure : public std::exception { explicit assertion_failure(char const* const file = "", unsigned long const line = 0, char const* const code = "") : @@ -36,7 +37,7 @@ private: if(std::string(code_) != "") text << " \"" << code_ << "\""; text << " failed"; if(std::string(file_) != "") { - text << ": \"" << file_ << "\""; + text << ": file \"" << file_ << "\""; if(line_ != 0) text << ", line " << line_; } what_ = text.str(); @@ -48,8 +49,6 @@ private: std::string what_; }; -// Handlers. - enum from { from_constructor, from_destructor, @@ -59,104 +58,241 @@ enum from { from_free_function }; -typedef void (*failure_handler)(from); +typedef void (*assertion_failed_handler)(from); -namespace aux { - extern failure_handler pre_failure_handler; - extern failure_handler post_failure_handler; +namespace exception_ { + enum failed_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 const_entry_inv_failure_handler; - extern failure_handler const_volatile_entry_inv_failure_handler; - extern failure_handler static_entry_inv_failure_handler; + template + void default_handler(from) { + 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_exit_inv_failure_handler; - extern failure_handler const_volatile_exit_inv_failure_handler; - extern failure_handler static_exit_inv_failure_handler; + // TODO: These (and some of the related def code) should be moved in a .cpp. + //boost::mutex pre_failed_mutex; + assertion_failed_handler pre_failed_handler = + &default_handler; + + //boost::mutex post_failed_mutex; + assertion_failed_handler post_failed_handler = + &default_handler; + + //boost::mutex const_entry_inv_failed_mutex; + assertion_failed_handler const_entry_inv_failed_handler = + &default_handler; + + //boost::mutex const_volatile_entry_inv_failed_mutex; + assertion_failed_handler const_volatile_entry_inv_failed_handler = + &default_handler; + + //boost::mutex static_entry_inv_failed_mutex; + assertion_failed_handler static_entry_inv_failed_handler = + &default_handler; + + //boost::mutex const_exit_inv_failed_mutex; + assertion_failed_handler const_exit_inv_failed_handler = + &default_handler; + + //boost::mutex const_volatile_exit_inv_failed_mutex; + assertion_failed_handler const_volatile_exit_inv_failed_handler = + &default_handler; + + //boost::mutex static_exit_inv_failed_mutex; + assertion_failed_handler static_exit_inv_failed_handler = + &default_handler; } -failure_handler set_precondition_failure(failure_handler f) - BOOST_NOEXCEPT_OR_NOTHROW { - failure_handler result = boost::contract::aux::pre_failure_handler; - boost::contract::aux::pre_failure_handler = f; +#define BOOST_CONTRACT_EXCEPTION_SET_HANDLER_(_mutex, handler, f) \ + /*boost::mutex::scoped_lock lock(exception_::_mutex);*/ \ + assertion_failed_handler result = exception_::handler; \ + exception_::handler = f; \ return result; -} + +#define BOOST_CONTRACT_EXCEPTION_GET_HANDLER_(_mutex, handler) \ + /*boost::mutex::scoped_lock lock(exception_::_mutex)*/; \ + return exception_::handler; + +#define BOOST_CONTRACT_EXCEPTION_CALL_HANDLER_(_mutex, handler, where) \ + /*boost::mutex::scoped_lock lock(exception_::_mutex);*/ \ + exception_::handler(where); -failure_handler set_postcondition_failure(failure_handler f) +assertion_failed_handler set_precondition_failed(assertion_failed_handler f) BOOST_NOEXCEPT_OR_NOTHROW { - failure_handler result = boost::contract::aux::post_failure_handler; - boost::contract::aux::post_failure_handler = f; - return result; + BOOST_CONTRACT_EXCEPTION_SET_HANDLER_(pre_failed_mutex, pre_failed_handler, + f) +} +assertion_failed_handler get_precondition_failed() BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_CONTRACT_EXCEPTION_GET_HANDLER_(pre_failed_mutex, pre_failed_handler) +} +void precondition_failed(from where) /* can throw */ { + BOOST_CONTRACT_EXCEPTION_CALL_HANDLER_(pre_failed_mutex, pre_failed_handler, + where) } -// Entry invariants. - -failure_handler set_const_entry_invariant_failure(failure_handler f) +assertion_failed_handler set_postcondition_failed(assertion_failed_handler f) BOOST_NOEXCEPT_OR_NOTHROW { - failure_handler result = boost::contract::aux:: - const_entry_inv_failure_handler; - boost::contract::aux::const_entry_inv_failure_handler = f; - return result; + BOOST_CONTRACT_EXCEPTION_SET_HANDLER_(post_failed_mutex, + post_failed_handler, f) +} +assertion_failed_handler get_postcondition_failed() BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_CONTRACT_EXCEPTION_GET_HANDLER_(post_failed_mutex, + post_failed_handler) +} +void postcondition_failed(from where) /* can throw */ { + BOOST_CONTRACT_EXCEPTION_CALL_HANDLER_(post_failed_mutex, + post_failed_handler, where) } -failure_handler set_const_volatile_entry_invariant_failure(failure_handler f) +assertion_failed_handler set_const_entry_invariant_failed( + assertion_failed_handler f) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_CONTRACT_EXCEPTION_SET_HANDLER_(const_entry_inv_failed_mutex, + const_entry_inv_failed_handler, f) +} +assertion_failed_handler get_const_entry_invariant_failed() BOOST_NOEXCEPT_OR_NOTHROW { - failure_handler result = boost::contract::aux:: - const_volatile_entry_inv_failure_handler; - boost::contract::aux::const_volatile_entry_inv_failure_handler = f; - return result; + BOOST_CONTRACT_EXCEPTION_GET_HANDLER_(const_entry_inv_failed_mutex, + const_entry_inv_failed_handler) +} +void const_entry_invariant_failed(from where) /* can throw */ { + BOOST_CONTRACT_EXCEPTION_CALL_HANDLER_(const_entry_inv_failed_mutex, + const_entry_inv_failed_handler, where) } -failure_handler set_static_entry_invariant_failure(failure_handler f) +assertion_failed_handler set_const_volatile_entry_invariant_failed( + assertion_failed_handler f) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_CONTRACT_EXCEPTION_SET_HANDLER_(const_volatile_entry_inv_failed_mutex, + const_volatile_entry_inv_failed_handler, f) +} +assertion_failed_handler get_const_volatile_entry_invariant_failed() BOOST_NOEXCEPT_OR_NOTHROW { - failure_handler result = boost::contract::aux:: - static_entry_inv_failure_handler; - boost::contract::aux::static_entry_inv_failure_handler = f; - return result; + BOOST_CONTRACT_EXCEPTION_GET_HANDLER_(const_volatile_entry_inv_failed_mutex, + const_volatile_entry_inv_failed_handler) +} +void const_volatile_entry_invariant_failed(from where) /* can throw */ { + BOOST_CONTRACT_EXCEPTION_CALL_HANDLER_( + const_volatile_entry_inv_failed_mutex, + const_volatile_entry_inv_failed_handler, + where + ) } -void set_entry_invariant_failure(failure_handler f) BOOST_NOEXCEPT_OR_NOTHROW { - set_const_entry_invariant_failure(f); - set_const_volatile_entry_invariant_failure(f); - set_static_entry_invariant_failure(f); +assertion_failed_handler set_static_entry_invariant_failed( + assertion_failed_handler f) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_CONTRACT_EXCEPTION_SET_HANDLER_(static_entry_inv_failed_mutex, + static_entry_inv_failed_handler, f) } - -// Exit invariants. - -failure_handler set_const_exit_invariant_failure(failure_handler f) +assertion_failed_handler get_static_entry_invariant_failed() BOOST_NOEXCEPT_OR_NOTHROW { - failure_handler result = boost::contract::aux:: - const_exit_inv_failure_handler; - boost::contract::aux::const_exit_inv_failure_handler = f; - return result; + BOOST_CONTRACT_EXCEPTION_GET_HANDLER_(static_entry_inv_failed_mutex, + static_entry_inv_failed_handler) +} +void static_entry_invariant_failed(from where) /* can throw */ { + BOOST_CONTRACT_EXCEPTION_CALL_HANDLER_(static_entry_inv_failed_mutex, + static_entry_inv_failed_handler, where) } -failure_handler set_const_volatile_exit_invariant_failure(failure_handler f) +assertion_failed_handler set_const_exit_invariant_failed( + assertion_failed_handler f) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_CONTRACT_EXCEPTION_SET_HANDLER_(const_exit_inv_failed_mutex, + const_exit_inv_failed_handler, f) +} +assertion_failed_handler get_const_exit_invariant_failed() BOOST_NOEXCEPT_OR_NOTHROW { - failure_handler result = boost::contract::aux:: - const_volatile_exit_inv_failure_handler; - boost::contract::aux::const_volatile_exit_inv_failure_handler = f; - return result; + BOOST_CONTRACT_EXCEPTION_GET_HANDLER_(const_exit_inv_failed_mutex, + const_exit_inv_failed_handler) +} +void const_exit_invariant_failed(from where) /* can throw */ { + BOOST_CONTRACT_EXCEPTION_CALL_HANDLER_(const_exit_inv_failed_mutex, + const_exit_inv_failed_handler, where) } -failure_handler set_static_exit_invariant_failure(failure_handler f) +assertion_failed_handler set_const_volatile_exit_invariant_failed( + assertion_failed_handler f) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_CONTRACT_EXCEPTION_SET_HANDLER_(const_volatile_exit_inv_failed_mutex, + const_volatile_exit_inv_failed_handler, f) +} +assertion_failed_handler get_const_volatile_exit_invariant_failed() BOOST_NOEXCEPT_OR_NOTHROW { - failure_handler result = boost::contract::aux:: - static_exit_inv_failure_handler; - boost::contract::aux::static_exit_inv_failure_handler = f; - return result; + BOOST_CONTRACT_EXCEPTION_GET_HANDLER_(const_volatile_exit_inv_failed_mutex, + const_volatile_exit_inv_failed_handler) +} +void const_volatile_exit_invariant_failed(from where) /* can throw */ { + BOOST_CONTRACT_EXCEPTION_CALL_HANDLER_(const_volatile_exit_inv_failed_mutex, + const_volatile_exit_inv_failed_handler, where) } -void set_exit_invariant_failure(failure_handler f) BOOST_NOEXCEPT_OR_NOTHROW { - set_const_exit_invariant_failure(f); - set_const_volatile_exit_invariant_failure(f); - set_static_exit_invariant_failure(f); +assertion_failed_handler set_static_exit_invariant_failed( + assertion_failed_handler f) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_CONTRACT_EXCEPTION_SET_HANDLER_(static_exit_inv_failed_mutex, + static_exit_inv_failed_handler, f) +} +assertion_failed_handler get_static_exit_invariant_failed() + BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_CONTRACT_EXCEPTION_GET_HANDLER_(static_exit_inv_failed_mutex, + static_exit_inv_failed_handler) +} +void static_exit_invariant_failed(from where) /* can throw */ { + BOOST_CONTRACT_EXCEPTION_CALL_HANDLER_(static_exit_inv_failed_mutex, + static_exit_inv_failed_handler, where) } -// All invariants. - -void set_invariant_failure(failure_handler f) BOOST_NOEXCEPT_OR_NOTHROW { - set_entry_invariant_failure(f); - set_exit_invariant_failure(f); +void set_entry_invariant_failed(assertion_failed_handler f) + BOOST_NOEXCEPT_OR_NOTHROW { + set_const_entry_invariant_failed(f); + set_const_volatile_entry_invariant_failed(f); + set_static_entry_invariant_failed(f); +} +void set_exit_invariant_failed(assertion_failed_handler f) + BOOST_NOEXCEPT_OR_NOTHROW { + set_const_exit_invariant_failed(f); + set_const_volatile_exit_invariant_failed(f); + set_static_exit_invariant_failed(f); +} +void set_invariant_failed(assertion_failed_handler f) + BOOST_NOEXCEPT_OR_NOTHROW { + set_entry_invariant_failed(f); + set_exit_invariant_failed(f); } } } // namespace diff --git a/include/boost/contract/core/set_nothing.hpp b/include/boost/contract/core/set_nothing.hpp index 9aa8937..fbfd343 100644 --- a/include/boost/contract/core/set_nothing.hpp +++ b/include/boost/contract/core/set_nothing.hpp @@ -2,25 +2,27 @@ #ifndef BOOST_CONTRACT_SET_NOTHING_HPP_ #define BOOST_CONTRACT_SET_NOTHING_HPP_ -#include +#include #include namespace boost { namespace contract { -class set_nothing { // Allow (shallow ptr) copy for `auto c = ...`. +class set_nothing { public: - // Allow to set nothing (neither precondition, nor postcondition). + // No set function member here. -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) {} +private: // Friendship to minimize lib's public API. + friend class scoped; + friend class set_precondition; + friend class set_postcondition; - boost::shared_ptr contract_; + template + friend set_nothing bind(F, A0 const&, A1 const&); + + explicit set_nothing(boost::shared_ptr check) : check_(check) {} + + boost::shared_ptr check_; }; } } // namespace diff --git a/include/boost/contract/core/set_postcondition.hpp b/include/boost/contract/core/set_postcondition.hpp new file mode 100644 index 0000000..08b0c4a --- /dev/null +++ b/include/boost/contract/core/set_postcondition.hpp @@ -0,0 +1,32 @@ + +#ifndef BOOST_CONTRACT_SET_POSTCONDITION_HPP_ +#define BOOST_CONTRACT_SET_POSTCONDITION_HPP_ + +#include +#include +#include + +namespace boost { namespace contract { + +class set_postcondition { +public: + template + set_nothing postcondition(F f) { + check_->set_post(f); + return set_nothing(check_); + } + +private: // Friendship to minimize lib's public API. + friend class scoped; + friend class set_precondition_postcondition; + + explicit set_postcondition(boost::shared_ptr check) : check_(check) {} + + boost::shared_ptr check_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/core/set_postcondition_only.hpp b/include/boost/contract/core/set_postcondition_only.hpp deleted file mode 100644 index 40b83af..0000000 --- a/include/boost/contract/core/set_postcondition_only.hpp +++ /dev/null @@ -1,39 +0,0 @@ - -#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.hpp b/include/boost/contract/core/set_precondition.hpp new file mode 100644 index 0000000..68adda4 --- /dev/null +++ b/include/boost/contract/core/set_precondition.hpp @@ -0,0 +1,32 @@ + +#ifndef BOOST_CONTRACT_SET_PRECONDITION_HPP_ +#define BOOST_CONTRACT_SET_PRECONDITION_HPP_ + +#include +#include +#include + +namespace boost { namespace contract { + +class set_precondition { +public: + template + set_nothing precondition(F f) { + check_->set_pre(f); + return set_nothing(check_); + } + +private: // Friendship to minimize lib's public API. + friend class scoped; + friend class set_precondition_postcondition; + + explicit set_precondition(boost::shared_ptr check) : check_(check) {} + + boost::shared_ptr check_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/core/set_precondition_only.hpp b/include/boost/contract/core/set_precondition_only.hpp deleted file mode 100644 index db17075..0000000 --- a/include/boost/contract/core/set_precondition_only.hpp +++ /dev/null @@ -1,33 +0,0 @@ - -#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 index ee1f930..97032ad 100644 --- a/include/boost/contract/core/set_precondition_postcondition.hpp +++ b/include/boost/contract/core/set_precondition_postcondition.hpp @@ -2,61 +2,43 @@ #ifndef BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ #define BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ -#include -#include -#include -#include +#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_); + template + boost::contract::set_postcondition precondition(F f) { + check_->set_pre(f); + return boost::contract::set_postcondition(check_); } -private: - // Use friendship and deleted constructors to limit public API. - friend class var; + template + boost::contract::set_precondition postcondition(F f) { + check_->set_post(f); + return boost::contract::set_precondition(check_); + } - 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(); +private: // Friendship to minimize lib's public API. + friend class scoped; + + friend set_precondition_postcondition free_function( + boost::contract::call const&); friend set_precondition_postcondition free_function(); + template + friend set_precondition_postcondition public_member( + boost::contract::call const&, C const*); + explicit set_precondition_postcondition(boost::shared_ptr const contract) : contract_(contract) {} + aux::check_pre_post> check) : check_(check) {} - boost::shared_ptr contract_; + boost::shared_ptr check_; }; } } // namespace diff --git a/include/boost/contract/core/var.hpp b/include/boost/contract/core/var.hpp deleted file mode 100644 index 6656442..0000000 --- a/include/boost/contract/core/var.hpp +++ /dev/null @@ -1,35 +0,0 @@ - -#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 deleted file mode 100644 index 23317bb..0000000 --- a/include/boost/contract/core/virtual.hpp +++ /dev/null @@ -1,68 +0,0 @@ - -#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 deleted file mode 100644 index 541b96f..0000000 --- a/include/boost/contract/destructor.hpp +++ /dev/null @@ -1,21 +0,0 @@ - -#ifndef BOOST_CONTRACT_DESTRUCTOR_HPP_ -#define BOOST_CONTRACT_DESTRUCTOR_HPP_ - -#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::aux::function::destructor >(object)); -} - -} } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/free_function.hpp b/include/boost/contract/free_function.hpp index f271946..4d0c44b 100644 --- a/include/boost/contract/free_function.hpp +++ b/include/boost/contract/free_function.hpp @@ -2,16 +2,22 @@ #ifndef BOOST_CONTRACT_FREE_FUNCTION_HPP_ #define BOOST_CONTRACT_FREE_FUNCTION_HPP_ -#include // Here so user can store contract. +#include #include #include #include namespace boost { namespace contract { +boost::contract::set_precondition_postcondition free_function( + boost::contract::call const& c) { + return boost::contract::set_precondition_postcondition(boost::make_shared< + boost::contract::aux::free_function>(c.call_)); +} + boost::contract::set_precondition_postcondition free_function() { return boost::contract::set_precondition_postcondition(boost::make_shared< - boost::contract::aux::function::free_function>()); + boost::contract::aux::free_function>()); } } } // namespace diff --git a/include/boost/contract/introspect.hpp b/include/boost/contract/introspect.hpp deleted file mode 100644 index b8af212..0000000 --- a/include/boost/contract/introspect.hpp +++ /dev/null @@ -1,28 +0,0 @@ - -#ifndef BOOST_CONTRACT_INTROSPECT_HPP_ -#define BOOST_CONTRACT_INTROSPECT_HPP_ - -#include -#include -#include - -/* PUBLIC */ - -#define BOOST_CONTRACT_INTROSPECT(function_name) \ - BOOST_CONTRACT_INTROSPECT_TRAIT(BOOST_PP_CAT(introspect_, function_name), \ - function_name) - -#define BOOST_CONTRACT_INTROSPECT_TRAIT(trait_name, function_name) \ - struct trait_name { \ - BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION( \ - has_member_function, function_name) \ - \ - template \ - static BOOST_CONTRACT_AUX_NAME1(F) member_function_address() { \ - return &BOOST_CONTRACT_AUX_NAME1(C)::function_name; \ - } \ - }; - -#endif // #include guard - diff --git a/include/boost/contract/oldof.hpp b/include/boost/contract/oldof.hpp index 64f6dd4..e61b469 100644 --- a/include/boost/contract/oldof.hpp +++ b/include/boost/contract/oldof.hpp @@ -2,59 +2,55 @@ #ifndef BOOST_CONTRACT_OLDOF_HPP_ #define BOOST_CONTRACT_OLDOF_HPP_ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include + #include -#include - -// 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 - -#define BOOST_CONTRACT_OLDOF BOOST_CONTRACT_ERROR_variadic_macros_required_by_BOOST_CONTRACT_OLDOF_otherwise_manually_program_old_values - +# define BOOST_CONTRACT_OLDOF \ +BOOST_CONTRACT_ERROR_variadic_macros_required_by_BOOST_CONTRACT_OLDOF_otherwise_manually_program_old_values #else +#include #include +#include #include /* PUBLIC */ #define BOOST_CONTRACT_OLDOF(...) \ - BOOST_PP_CAT(BOOST_PP_OVERLOAD( /* CAT(... EMPTY()) workaround for MSVC */ \ -BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_, \ - __VA_ARGS__)(__VA_ARGS__), BOOST_PP_EMPTY()) + BOOST_PP_CAT( /* CAT(..., EMTPY()) required on MSVC */ \ + BOOST_PP_OVERLOAD( \ +BOOST_CONTRACT_ERROR_invoked_macro_BOOST_CONTRACT_OLDOF_with_invalid_number_of_arguments_, \ + __VA_ARGS__ \ + )(__VA_ARGS__), \ + BOOST_PP_EMPTY() \ + ) /* PRIVATE */ -// NOTE: Following are not local macros, do NOT #undef them. These macro names -// are use so all variadic macro argument numbers > 2 will generate appropriate -// ERROR symbols. - #define \ -BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_1( \ - value) \ - (boost::contract::oldof BOOST_CONTRACT_OLDOF_TYPEOF_(value) ( \ - boost::contract::copy_oldof() ? value : boost::contract::oldof() \ +BOOST_CONTRACT_ERROR_invoked_macro_BOOST_CONTRACT_OLDOF_with_invalid_number_of_arguments_1(value) \ + BOOST_CONTRACT_OLDOF_AUTO_(value)(boost::contract::oldof( \ + boost::contract::copy_oldof() ? (value) : boost::contract::oldof() \ )) #define \ -BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_2( \ - v, value) \ - (boost::contract::oldof BOOST_CONTRACT_OLDOF_TYPEOF_(value) ( \ - v, boost::contract::copy_oldof(v) ? value : boost::contract::oldof() \ +BOOST_CONTRACT_ERROR_invoked_macro_BOOST_CONTRACT_OLDOF_with_invalid_number_of_arguments_2(c, value) \ + BOOST_CONTRACT_OLDOF_AUTO_(value)(boost::contract::oldof(c, \ + boost::contract::copy_oldof(c) ? (value) : boost::contract::oldof() \ )) #ifdef BOOST_NO_CXX11_AUTO_DECLARATIONS -# define BOOST_CONTRACT_OLDOF_TYPEOF_(value) /* nothing */ +# define BOOST_CONTRACT_OLDOF_AUTO_(value) /* nothing */ #else # include -# define BOOST_CONTRACT_OLDOF_TYPEOF_(value) +// Explicitly force shared_ptr conversion to allow for C++11 auto decl. +# define BOOST_CONTRACT_OLDOF_AUTO_(value) \ + boost::shared_ptr #endif #endif // VARIADICS @@ -63,43 +59,72 @@ BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_2( \ namespace boost { namespace contract { -bool copy_oldof(boost::contract::virtual_* const v = 0) { +bool copy_oldof() { #ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS - return false; // Never check post, so old-of never copied. + return false; // Post checking disabled, so never copy old values. #else - // 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; + return true; #endif } -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_* const v, - boost::contract::aux::oldof const& old) { - return boost::contract::aux::oldof(v, old); +bool copy_oldof(boost::contract::call const& c) { +#ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS + return false; // Post checking disabled, so never copy old values. +#else + return c.call_ && c.call_->action == boost::contract::aux::call::copy_oldof; +#endif } -// Un-erasure will be done based on explicit decl type (no auto allowed). -boost::contract::aux::oldof oldof(boost::contract::virtual_* const v, - boost::contract::aux::oldof const& old) { - return boost::contract::aux::oldof(v, old); -} +class oldof { +public: + explicit oldof() : call_(), value_() {} -// Un-erasure via explicit type T so to allow to use C++11 auto decl. -template -boost::shared_ptr::type const> oldof( - boost::contract::aux::oldof const& old) { - return boost::contract::aux::oldof(0, old); -} + explicit oldof(boost::contract::call const& c, oldof const& old) : + call_(c.call_), value_(old.value_) {} -// Un-erasure will be done based on explicit decl type (no auto allowed). -boost::contract::aux::oldof oldof(boost::contract::aux::oldof const& old) { - return boost::contract::aux::oldof(0, old); -} + template + /* implicit */ oldof(T const& old_value) : + value_(boost::make_shared(old_value)) { // T's one single copy. + std::clog << "oldof copy" << std::endl; + } + + // TODO: I might be able to use unique_ptr here instead of shared_ptr. That + // might be the true for the pointer that holds contract and call as well... + // do some testing to figure that out (unique_ptr adds less overhead). + + template + operator boost::shared_ptr() { + if(!call_) { + BOOST_CONTRACT_AUX_DEBUG(value_); + boost::shared_ptr old_value = + boost::static_pointer_cast(value_); + BOOST_CONTRACT_AUX_DEBUG(old_value); + std::clog << "oldof un-erased: " << *old_value << std::endl; + return old_value; + } else if(call_->action == boost::contract::aux::call::copy_oldof) { + BOOST_CONTRACT_AUX_DEBUG(value_); + call_->old_values.push(value_); + std::clog << "oldof push" << std::endl; + return boost::shared_ptr(); + } else if(call_->action == boost::contract::aux::call::check_post) { + BOOST_CONTRACT_AUX_DEBUG(!value_); + boost::shared_ptr value = call_->old_values.front(); + BOOST_CONTRACT_AUX_DEBUG(value); + call_->old_values.pop(); + boost::shared_ptr old_value = + boost::static_pointer_cast(value); + BOOST_CONTRACT_AUX_DEBUG(old_value); + std::clog << "oldof pop: " << *old_value << std::endl; + return old_value; + } + BOOST_CONTRACT_AUX_DEBUG(!value_); + return boost::shared_ptr(); + } + +private: + boost::shared_ptr call_; + boost::shared_ptr value_; +}; } } // namespace diff --git a/include/boost/contract/private_member.hpp b/include/boost/contract/private_member.hpp deleted file mode 100644 index d180837..0000000 --- a/include/boost/contract/private_member.hpp +++ /dev/null @@ -1,22 +0,0 @@ - -#ifndef BOOST_CONTRACT_PRIVATE_MEMBER_HPP_ -#define BOOST_CONTRACT_PRIVATE_MEMBER_HPP_ - -#include // Here so user can store contract. -#include -#include -#include - -// TOOD: On C++11 Clang... these could static_assert enclosing func is not pub? - -namespace boost { namespace contract { - -boost::contract::set_precondition_postcondition private_member() { - return boost::contract::set_precondition_postcondition(boost::make_shared< - boost::contract::aux::function::private_member>()); -} - -} } // namespace - -#endif // - diff --git a/include/boost/contract/protected_member.hpp b/include/boost/contract/protected_member.hpp deleted file mode 100644 index 33c2f4d..0000000 --- a/include/boost/contract/protected_member.hpp +++ /dev/null @@ -1,22 +0,0 @@ - -#ifndef BOOST_CONTRACT_PROTECTED_MEMBER_HPP_ -#define BOOST_CONTRACT_PROTECTED_MEMBER_HPP_ - -#include // Here so user can store contract. -#include -#include -#include - -// TOOD: On C++11 Clang... these could static_assert enclosing func is not pub? - -namespace boost { namespace contract { - -boost::contract::set_precondition_postcondition protected_member() { - return boost::contract::set_precondition_postcondition(boost::make_shared< - boost::contract::aux::function::protected_member>()); -} - -} } // namespace - -#endif // - diff --git a/include/boost/contract/public_member.hpp b/include/boost/contract/public_member.hpp index 6a89087..01039f2 100644 --- a/include/boost/contract/public_member.hpp +++ b/include/boost/contract/public_member.hpp @@ -2,62 +2,24 @@ #ifndef BOOST_CONTRACT_PUBLIC_MEMBER_HPP_ #define BOOST_CONTRACT_PUBLIC_MEMBER_HPP_ -#include // Here so user can store contract. +#include #include -#include -#include #include #include 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_* 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 +template boost::contract::set_precondition_postcondition public_member( - Class* const object, Argument0& argument0) { + boost::contract::call const& c, C const* obj) { return boost::contract::set_precondition_postcondition(boost::make_shared< - boost::contract::aux::function::public_member >(object, argument0) - ); + boost::contract::aux::public_member >(c.call_, obj)); } -// 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_* const v, Class* const object) { +template +boost::contract::set_precondition_postcondition public_member(C const* obj) { 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( - Class* const object) { - 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::aux::function::public_static_member >()); + boost::contract::aux::public_member >(obj)); } } } // namespace diff --git a/include/boost/contract/scoped.hpp b/include/boost/contract/scoped.hpp new file mode 100644 index 0000000..d26336a --- /dev/null +++ b/include/boost/contract/scoped.hpp @@ -0,0 +1,37 @@ + +#ifndef BOOST_CONTRACT_SCOPED_HPP_ +#define BOOST_CONTRACT_SCOPED_HPP_ + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace contract { + +class scoped { // Copyable (shallow shared ptr copies). +public: + // All implicit to allow `scoped c = ...`. + + /* implicit */ scoped(boost::contract::set_precondition_postcondition + const& contract) : check_(contract.check_) {} + + /* implicit */ scoped(boost::contract::set_precondition + const& contract) : check_(contract.check_) {} + + /* implicit */ scoped(boost::contract::set_postcondition + const& contract) : check_(contract.check_) {} + + /* implicit */ scoped(boost::contract::set_nothing + const& contract) : check_(contract.check_) {} + +private: + boost::shared_ptr check_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/utility/always.hpp b/include/boost/contract/utility/always.hpp deleted file mode 100644 index 2ac079f..0000000 --- a/include/boost/contract/utility/always.hpp +++ /dev/null @@ -1,30 +0,0 @@ - -#ifndef BOOST_CONTRACT_ALWAYS_HPP_ -#define BOOST_CONTRACT_ALWAYS_HPP_ - -#include -#include - -namespace boost { namespace contract { - -// Result must be copy constructible (always true for func. result types). -template< typename Result > -struct always { - typedef Result result_type; - - explicit always ( Result const& result ) : - result_(boost::make_shared(result)) {} - - // No matter if functor called with 0 to n args, it always returns result. - Result operator() ( ... ) const { return *result_; } - -private: - // Pointer so copies of this object do not keep copying result (above - // operator() already returns new copies for result to users). - boost::shared_ptr const result_; -}; - -} } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/utility/call_if.hpp b/include/boost/contract/utility/call_if.hpp deleted file mode 100644 index 1cbff04..0000000 --- a/include/boost/contract/utility/call_if.hpp +++ /dev/null @@ -1,94 +0,0 @@ - -#ifndef BOOST_CONTRACT_CALL_IF_HPP_ -#define BOOST_CONTRACT_CALL_IF_HPP_ - -#include -#include -#include - -// TODO: Once I get this to work 100% right... then consider using it instead -// of the extra mpl::bool_ param inside the lib impl too. - -namespace boost { namespace contract { - -namespace call_if_ { - // Result must be copy constructible (always true for func. result types). - - template< bool Cond, typename Result > - struct call_if_c { - template< typename Then > - explicit call_if_c ( Then const& t ) : - result_(boost::make_shared(t())) {} - - operator Result ( ) const { return *result_; } - - template< typename Else > - Result else_ ( Else const& ) const { return *result_; } - - private: - // Pointer so copies of this object do not keep copying result (above - // operator() already returns new copies of result to users). - boost::shared_ptr const result_; - }; - - template< typename Result > - struct call_if_c { - template< typename Then > - explicit call_if_c ( Then const& ) {} - - // Result must be default constructible when else_ is not used. - operator Result ( ) { return Result(); } - - template< typename Else > - Result else_ ( Else const& e ) const { return e(); } - }; - - // Specializations (optimized) for void result type. - - template< > - struct call_if_c { - template< typename Then > - explicit call_if_c ( Then const& t ) { t(); } - - template< typename Else > - void else_ ( Else const& ) const {} - }; - - template< > - struct call_if_c { - template< typename Then > - explicit call_if_c ( Then const& ) {} - - template< typename Else > - void else_ ( Else const& e ) const { e(); } - }; -} - -template< bool Cond, typename Result, typename Then > -call_if_::call_if_c call_if_c ( Then const& t ) { - return call_if_::call_if_c(t); -} - -template< bool Cond, typename Then > -call_if_::call_if_c::type> call_if_c ( - Then const& t ) { - return call_if_::call_if_c::type>(t); -} - -template< class Cond, typename Result, typename Then > -call_if_::call_if_c call_if ( Then const& t ) { - return call_if_::call_if_c(t); -} - -template< class Cond, typename Then > -call_if_::call_if_c::type> call_if( - Then const& t ) { - return call_if_::call_if_c::type>(t); -} - -} } // namespace - -#endif // #include guard - diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d66dba9..7f8154e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,4 +1,8 @@ +subdir-run const : free_function ; +subdir-run const : public_member ; +subdir-run const : public_virtual_member ; + subdir-run function : constructor ; subdir-run function : destructor ; subdir-run function : public_member ; diff --git a/test/const/free_function.cpp b/test/const/free_function.cpp index c519c35..bd78ffa 100644 --- a/test/const/free_function.cpp +++ b/test/const/free_function.cpp @@ -1,27 +1,33 @@ -#include "../aux_/oteststream.hpp" +#include +#include #include -#include -#include +#include +#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) { +void inv1_contract(int const& x, int const& result, boost::contract::call c) { boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF(c, x); boost::contract::free_function(c) - .precondition([&] { BOOST_CONTRACT_ASSERT(x >= 0); }) + .precondition([&] { + std::clog << "inv1::pre" << std::endl; + BOOST_CONTRACT_ASSERT(x >= 0); + }) .postcondition([&] { + std::clog << "inv1::post" << std::endl; BOOST_CONTRACT_ASSERT(-x == *old_x); BOOST_CONTRACT_ASSERT(result == *old_x); }) ; } int inv1(int& x) { + std::clog << "inv1" << std::endl; int result; - boost::contract::var contract(inv1_contract, x, result); + boost::contract::scoped contract = boost::contract::bind( + &inv1_contract, x, result); + + std::clog << "inv1::body" << std::endl; result = x; x = -x; return result; @@ -30,32 +36,31 @@ int inv1(int& x) { 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); }) + boost::contract::scoped contract = boost::contract::free_function() + .precondition([&] { + std::clog << "inv2::pre" << std::endl; + BOOST_CONTRACT_ASSERT(x >= 0); + }) .postcondition([&] { + std::clog << "inv2::post" << std::endl; BOOST_CONTRACT_ASSERT(-x == *old_x); BOOST_CONTRACT_ASSERT(result == *old_x); }) ; + + std::clog << "inv2::body" << std::endl; result = x; x = -x; return result; } - int main() { - std::ostringstream ok; + int x = 123; + inv1(x); + std::clog << std::endl; - 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(); + x = 456; + inv2(x); + return 0; } diff --git a/test/const/public_member.cpp b/test/const/public_member.cpp new file mode 100644 index 0000000..97b3449 --- /dev/null +++ b/test/const/public_member.cpp @@ -0,0 +1,53 @@ + +#include +#include +#include +#include +#include +#include + +struct a { + int x; + + void invariant() const { + std::clog << "a::inv" << std::endl; + BOOST_CONTRACT_ASSERT(x > 0); + } + static void static_invariant() { + std::clog << "a::static_inv" << std::endl; + } + + void swap_contract(int const& y, boost::contract::call c) const { + boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF(c, x); + boost::shared_ptr old_y = BOOST_CONTRACT_OLDOF(c, y); + boost::contract::public_member(c, this) + .precondition([&] { + std::clog << "a::swap::pre" << std::endl; + BOOST_CONTRACT_ASSERT(x != y); + }) + .postcondition([&] { + std::clog << "a::swap::post" << std::endl; + BOOST_CONTRACT_ASSERT(x == *old_y); + BOOST_CONTRACT_ASSERT(y == *old_x); + }) + ; + } + void swap(int& y) { + boost::contract::scoped contract = boost::contract::bind( + &a::swap_contract, this, y); + + std::clog << "a::swap::body" << std::endl; + int save_x = x; + x = y; + y = save_x; + } +}; + +int main() { + a aa; + aa.x = 10; + int y = 20; + aa.swap(y); + return 0; +} + diff --git a/test/const/public_virtual_member.cpp b/test/const/public_virtual_member.cpp new file mode 100644 index 0000000..d40bd2b --- /dev/null +++ b/test/const/public_virtual_member.cpp @@ -0,0 +1,39 @@ + +#include +#include +#include +#include +#include +#include + +struct a { + std::string x; + a() : x("a") {} + + void invariant() const { std::clog << "a::inv" << std::endl; } + static void static_invariant() { std::clog << "a::static_inv" << std::endl;} + + void f_contract(int const& s, boost::contract::call c) const { + boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF(c, x); + boost::contract::public_member(c, this) + .precondition([&] { std::clog << "a::f::pre" << std::endd; }) + .postcondition([&] { + std::clog << "a::f::post" << std::endl; + BOOST_CONTRACT_ASSERT(x == old_x + s); + }) + ; + } + virtual void f(int s) { + boost::contract::scoped contract = boost::contract::bind( + &a::f, this, s); + std::clog << "a::f::body" << std::endl; + x = x + s; + } +}; + +int main() { + a aa; + aa.f("s"); + return 0; +} +