mirror of
https://github.com/boostorg/contract.git
synced 2026-02-27 04:52:22 +00:00
added failure handlers and re-run all tests
This commit is contained in:
@@ -2,12 +2,18 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_
|
||||
#define BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_
|
||||
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/aux_/exception.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
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<typename Pre>
|
||||
void set_pre(Pre const& pre) { pre_ = pre; pre_available(); }
|
||||
|
||||
@@ -15,16 +21,31 @@ public:
|
||||
void set_post(Post const& post) { post_ = post; post_available(); }
|
||||
|
||||
protected:
|
||||
pre_post() {}
|
||||
virtual ~pre_post() {}
|
||||
// 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_pre() { if(pre_) pre_(); }
|
||||
void check_post() { if(post_) post_(); }
|
||||
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<void ()> pre_;
|
||||
boost::function<void ()> post_;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_CHECK_PRE_POST_INV_HPP_
|
||||
#define BOOST_CONTRACT_AUX_CHECK_PRE_POST_INV_HPP_
|
||||
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/config.hpp>
|
||||
#include <boost/contract/aux_/check/pre_post.hpp>
|
||||
#include <boost/contract/aux_/type_traits/invariant.hpp>
|
||||
@@ -15,34 +16,64 @@ template<class Class>
|
||||
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(Class* const obj = 0) : obj_(obj) {}
|
||||
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_inv(bool const static_inv_only = false) {
|
||||
check_static_inv(boost::mpl::bool_<boost::contract::aux::type_traits::
|
||||
has_static_invariant<Class>::value>());
|
||||
if(!static_inv_only) {
|
||||
check_cv_inv(boost::mpl::bool_<boost::contract::aux::type_traits::
|
||||
has_const_invariant<Class>::value>());
|
||||
}
|
||||
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_static_inv(boost::mpl::false_ const&) {}
|
||||
void check_static_inv(boost::mpl::true_ const&) {
|
||||
Class::BOOST_CONTRACT_CONFIG_STATIC_INVARIANT();
|
||||
void check_inv(bool const on_entry, bool const static_inv_only = false) {
|
||||
check_static_inv(on_entry, boost::mpl::bool_<boost::contract::aux::
|
||||
type_traits::has_static_invariant<Class>::value>());
|
||||
if(!static_inv_only) {
|
||||
check_cv_inv(on_entry, boost::mpl::bool_<boost::contract::aux::
|
||||
type_traits::has_const_invariant<Class>::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(boost::mpl::false_ const&) {}
|
||||
void check_cv_inv(boost::mpl::true_ const&) {
|
||||
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<Class>::type* const const_obj = obj_;
|
||||
BOOST_CONTRACT_AUX_DEBUG(const_obj);
|
||||
const_obj->BOOST_CONTRACT_CONFIG_INVARIANT();
|
||||
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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_CHECK_SUBCONTRACTED_PRE_POST_INV_HPP_
|
||||
#define BOOST_CONTRACT_AUX_CHECK_SUBCONTRACTED_PRE_POST_INV_HPP_
|
||||
|
||||
#include <boost/contract/config.hpp>
|
||||
#include <boost/contract/virtual_body.hpp>
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/config.hpp>
|
||||
#include <boost/contract/aux_/check/pre_post_inv.hpp>
|
||||
#include <boost/contract/aux_/type_traits/bases.hpp>
|
||||
#include <boost/contract/aux_/exception.hpp>
|
||||
#include <boost/contract/aux_/none.hpp>
|
||||
#include <boost/contract/aux_/debug.hpp>
|
||||
#include <boost/contract/virtual_body.hpp>
|
||||
#include <boost/function_types/result_type.hpp>
|
||||
#include <boost/function_types/parameter_types.hpp>
|
||||
#include <boost/function_types/member_function_pointer.hpp>
|
||||
@@ -69,27 +69,27 @@ template<
|
||||
//#endif
|
||||
|
||||
public:
|
||||
explicit subcontracted_pre_post_inv(Class* const obj, Arg0 arg0) :
|
||||
boost::contract::aux::check::pre_post_inv<Class>(obj),
|
||||
explicit subcontracted_pre_post_inv(boost::contract::from const from,
|
||||
Class* const obj, Arg0 arg0) :
|
||||
boost::contract::aux::check::pre_post_inv<Class>(from, obj),
|
||||
arg0_(arg0)
|
||||
{}
|
||||
|
||||
explicit subcontracted_pre_post_inv(Class* const obj) : boost::contract::
|
||||
aux::check::pre_post_inv<Class>(obj) {
|
||||
}
|
||||
explicit subcontracted_pre_post_inv(boost::contract::from const from,
|
||||
Class* const obj) :
|
||||
boost::contract::aux::check::pre_post_inv<Class>(from, obj)
|
||||
{}
|
||||
|
||||
virtual ~subcontracted_pre_post_inv() {}
|
||||
|
||||
protected:
|
||||
void check_subcontracted_inv() {
|
||||
boost::mpl::for_each<base_ptrs>(check_base(*this,
|
||||
boost::contract::virtual_body::check_inv_only));
|
||||
this->check_inv();
|
||||
}
|
||||
|
||||
void check_subcontracted_pre() {
|
||||
// Allow to throw on failure for relaxing subcontracted pre.
|
||||
void check_subcontracted_pre(bool const throw_on_failure = false) {
|
||||
try {
|
||||
boost::mpl::for_each<base_ptrs>(check_base(*this,
|
||||
boost::contract::virtual_body::check_pre_only));
|
||||
this->check_pre(); // Pre logic-or: Last check, error also throws.
|
||||
// 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).
|
||||
}
|
||||
@@ -100,6 +100,18 @@ protected:
|
||||
boost::contract::virtual_body::check_post_only));
|
||||
this->check_post();
|
||||
}
|
||||
|
||||
void check_subcontracted_entry_inv() {
|
||||
boost::mpl::for_each<base_ptrs>(check_base(*this,
|
||||
boost::contract::virtual_body::check_entry_inv_only));
|
||||
this->check_entry_inv();
|
||||
}
|
||||
|
||||
void check_subcontracted_exit_inv() {
|
||||
boost::mpl::for_each<base_ptrs>(check_base(*this,
|
||||
boost::contract::virtual_body::check_exit_inv_only));
|
||||
this->check_exit_inv();
|
||||
}
|
||||
|
||||
class check_base {
|
||||
public:
|
||||
@@ -147,16 +159,13 @@ protected:
|
||||
Base* const base = outer_.object();
|
||||
BOOST_CONTRACT_AUX_DEBUG(base);
|
||||
|
||||
try {
|
||||
(base->*base_virtual_func)(outer_.arg0_, virt_);
|
||||
} catch(boost::contract::aux::no_error const&) {
|
||||
if(virt_.action == boost::contract::virtual_body::
|
||||
check_pre_only) {
|
||||
try { (base->*base_virtual_func)(outer_.arg0_, virt_); }
|
||||
catch(boost::contract::aux::no_error const&) {
|
||||
if(virt_ == boost::contract::virtual_body::check_pre_only) {
|
||||
throw; // Pre logic-or: 1st no_err stops (throw to caller).
|
||||
}
|
||||
} catch(...) {
|
||||
if(virt_.action == boost::contract::virtual_body::
|
||||
check_pre_only) {
|
||||
if(virt_ == boost::contract::virtual_body::check_pre_only) {
|
||||
// Pre logic-or: Ignore err, possibly checks up to caller.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_FUNCTION_CONSTRUCTOR_HPP_
|
||||
#define BOOST_CONTRACT_AUX_FUNCTION_CONSTRUCTOR_HPP_
|
||||
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/aux_/check/pre_post_inv.hpp>
|
||||
#include <exception>
|
||||
|
||||
@@ -10,8 +11,8 @@ namespace boost { namespace contract { namespace aux { namespace function {
|
||||
template<class Class>
|
||||
class constructor : public boost::contract::aux::check::pre_post_inv<Class> {
|
||||
public:
|
||||
explicit constructor(Class* const obj) :
|
||||
boost::contract::aux::check::pre_post_inv<Class>(obj) {
|
||||
explicit constructor(Class* const obj) : boost::contract::aux::check::
|
||||
pre_post_inv<Class>(boost::contract::from_constructor, obj) {
|
||||
entry();
|
||||
}
|
||||
|
||||
@@ -19,7 +20,7 @@ public:
|
||||
|
||||
private:
|
||||
// No object before ctor body so only static inv at entry.
|
||||
void entry() { this->check_inv(/* static_inv_only = */ true); }
|
||||
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); }
|
||||
@@ -33,7 +34,7 @@ private:
|
||||
// check_subcontracted_... in this case).
|
||||
void exit() {
|
||||
bool const body_threw = std::uncaught_exception();
|
||||
this->check_inv(/* static_inv_only = */ body_threw);
|
||||
this->check_exit_inv(/* static_inv_only = */ body_threw);
|
||||
if(!body_threw) this->check_post();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_FUNCTION_DESTRUCTOR_HPP_
|
||||
#define BOOST_CONTRACT_AUX_FUNCTION_DESTRUCTOR_HPP_
|
||||
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/aux_/check/pre_post_inv.hpp>
|
||||
#include <boost/contract/aux_/debug.hpp>
|
||||
#include <exception>
|
||||
@@ -11,8 +12,8 @@ namespace boost { namespace contract { namespace aux { namespace function {
|
||||
template<class Class>
|
||||
class destructor : public boost::contract::aux::check::pre_post_inv<Class> {
|
||||
public:
|
||||
explicit destructor(Class* const obj) :
|
||||
boost::contract::aux::check::pre_post_inv<Class>(obj) {
|
||||
explicit destructor(Class* const obj) : boost::contract::aux::check::
|
||||
pre_post_inv<Class>(boost::contract::from_destructor, obj) {
|
||||
entry();
|
||||
}
|
||||
|
||||
@@ -22,7 +23,7 @@ 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_inv(); }
|
||||
void entry() { this->check_entry_inv(); }
|
||||
|
||||
// Dtor cannot have pre because it has no parameters.
|
||||
void pre_available() /* override */ { BOOST_CONTRACT_AUX_DEBUG(false); }
|
||||
@@ -41,7 +42,7 @@ private:
|
||||
// for that so this library must handle such a case.
|
||||
void exit() {
|
||||
bool const body_threw = std::uncaught_exception();
|
||||
this->check_inv(/* static_inv_only = */ !body_threw);
|
||||
this->check_exit_inv(/* static_inv_only = */ !body_threw);
|
||||
if(!body_threw) this->check_post();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_FUNCTION_FREE_FUNCTION_HPP_
|
||||
#define BOOST_CONTRACT_AUX_FUNCTION_FREE_FUNCTION_HPP_
|
||||
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/aux_/check/pre_post.hpp>
|
||||
#include <exception>
|
||||
|
||||
@@ -9,9 +10,12 @@ namespace boost { namespace contract { namespace aux { namespace function {
|
||||
|
||||
class free_function : public boost::contract::aux::check::pre_post {
|
||||
public:
|
||||
explicit free_function() { entry(); }
|
||||
explicit free_function(boost::contract::from const from =
|
||||
boost::contract::from_free_function) :
|
||||
boost::contract::aux::check::pre_post(from)
|
||||
{ entry(); }
|
||||
|
||||
~free_function() { exit(); }
|
||||
virtual ~free_function() { exit(); }
|
||||
|
||||
private:
|
||||
// Do nothing (not a public member so no inv to check, nor subcontracting).
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_FUNCTION_PRIVATE_MEMBER_HPP_
|
||||
#define BOOST_CONTRACT_AUX_FUNCTION_PRIVATE_MEMBER_HPP_
|
||||
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/aux_/function/free_function.hpp>
|
||||
|
||||
namespace boost { namespace contract { namespace aux { namespace function {
|
||||
@@ -10,7 +11,11 @@ namespace boost { namespace contract { namespace aux { namespace function {
|
||||
// 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.
|
||||
typedef boost::contract::aux::function::free_function private_member;
|
||||
class private_member : public free_function {
|
||||
public:
|
||||
explicit private_member() :
|
||||
free_function(boost::contract::from_private_member) {}
|
||||
};
|
||||
|
||||
} } } } // namespace
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_FUNCTION_PROTECTED_MEMBER_HPP_
|
||||
#define BOOST_CONTRACT_AUX_FUNCTION_PROTECTED_MEMBER_HPP_
|
||||
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/aux_/function/free_function.hpp>
|
||||
|
||||
namespace boost { namespace contract { namespace aux { namespace function {
|
||||
@@ -10,7 +11,11 @@ namespace boost { namespace contract { namespace aux { namespace function {
|
||||
// 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.
|
||||
typedef boost::contract::aux::function::free_function protected_member;
|
||||
class protected_member : public free_function {
|
||||
public:
|
||||
explicit protected_member() :
|
||||
free_function(boost::contract::from_protected_member) {}
|
||||
};
|
||||
|
||||
} } } } // namespace
|
||||
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_MEMBER_HPP_
|
||||
#define BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_MEMBER_HPP_
|
||||
|
||||
#include <boost/contract/virtual_body.hpp>
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/aux_/check/subcontracted_pre_post_inv.hpp>
|
||||
#include <boost/contract/aux_/exception.hpp>
|
||||
#include <boost/contract/aux_/none.hpp>
|
||||
#include <boost/contract/aux_/debug.hpp>
|
||||
#include <boost/contract/virtual_body.hpp>
|
||||
#include <exception>
|
||||
|
||||
namespace boost { namespace contract { namespace aux { namespace function {
|
||||
@@ -23,7 +24,7 @@ public:
|
||||
explicit public_member(boost::contract::virtual_body const virt,
|
||||
Class* const obj, Arg0 arg0) :
|
||||
boost::contract::aux::check::subcontracted_pre_post_inv<Class, Intro,
|
||||
Func, Arg0>(obj, arg0),
|
||||
Func, Arg0>(boost::contract::from_public_member, obj, arg0),
|
||||
virt_(virt)
|
||||
{
|
||||
BOOST_CONTRACT_AUX_DEBUG((!boost::is_same<Intro,
|
||||
@@ -36,7 +37,7 @@ public:
|
||||
// Can be used when bases and no virtual body.
|
||||
explicit public_member(Class* const obj, Arg0 arg0) :
|
||||
boost::contract::aux::check::subcontracted_pre_post_inv<Class, Intro,
|
||||
Func, Arg0>(obj, arg0),
|
||||
Func, Arg0>(boost::contract::from_public_member, obj, arg0),
|
||||
virt_(boost::contract::virtual_body::user_call)
|
||||
{
|
||||
BOOST_CONTRACT_AUX_DEBUG((!boost::is_same<Intro,
|
||||
@@ -50,7 +51,7 @@ public:
|
||||
explicit public_member(boost::contract::virtual_body const virt,
|
||||
Class* const obj) :
|
||||
boost::contract::aux::check::subcontracted_pre_post_inv<Class, Intro,
|
||||
Func, Arg0>(obj),
|
||||
Func, Arg0>(boost::contract::from_public_member, obj),
|
||||
virt_(virt)
|
||||
{
|
||||
BOOST_CONTRACT_AUX_DEBUG((boost::is_same<Intro,
|
||||
@@ -63,7 +64,7 @@ public:
|
||||
// Can be used when no bases and no virtual body.
|
||||
explicit public_member(Class* const obj) :
|
||||
boost::contract::aux::check::subcontracted_pre_post_inv<Class, Intro,
|
||||
Func, Arg0>(obj),
|
||||
Func, Arg0>(boost::contract::from_public_member, obj),
|
||||
virt_(boost::contract::virtual_body::user_call)
|
||||
{
|
||||
BOOST_CONTRACT_AUX_DEBUG((boost::is_same<Intro,
|
||||
@@ -78,27 +79,35 @@ public:
|
||||
private:
|
||||
// Check static and non-static subcontracted inv.
|
||||
void entry() {
|
||||
if(virt_.action == boost::contract::virtual_body::user_call ||
|
||||
virt_.action == boost::contract::virtual_body::check_inv_only) {
|
||||
this->check_subcontracted_inv();
|
||||
if(virt_.action != boost::contract::virtual_body::user_call)
|
||||
// When inv only, also exit inv in must be checked here so to skip body.
|
||||
if(
|
||||
virt_ == boost::contract::virtual_body::user_call ||
|
||||
virt_ == boost::contract::virtual_body::check_entry_inv_only ||
|
||||
virt_ == boost::contract::virtual_body::check_exit_inv_only
|
||||
) {
|
||||
if(virt_ == boost::contract::virtual_body::check_exit_inv_only)
|
||||
this->check_subcontracted_exit_inv();
|
||||
else // For both user call and entry inv only.
|
||||
this->check_subcontracted_entry_inv();
|
||||
if(virt_ != boost::contract::virtual_body::user_call)
|
||||
throw boost::contract::aux::no_error();
|
||||
} // Else (check only pre, post, etc.) do nothing.
|
||||
}
|
||||
|
||||
// Check subcontracted pre (as soon as related functor set).
|
||||
void pre_available() /* override */ {
|
||||
if(virt_.action == boost::contract::virtual_body::user_call ||
|
||||
virt_.action == boost::contract::virtual_body::check_pre_only) {
|
||||
this->check_subcontracted_pre();
|
||||
if(virt_.action != boost::contract::virtual_body::user_call)
|
||||
if(virt_ == boost::contract::virtual_body::user_call ||
|
||||
virt_ == boost::contract::virtual_body::check_pre_only) {
|
||||
this->check_subcontracted_pre(/* throw_on_failure = */
|
||||
virt_ != boost::contract::virtual_body::user_call);
|
||||
if(virt_ != boost::contract::virtual_body::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 post_available() /* override */ {
|
||||
if(virt_.action == boost::contract::virtual_body::check_post_only) {
|
||||
if(virt_ == boost::contract::virtual_body::check_post_only) {
|
||||
this->check_subcontracted_post();
|
||||
throw boost::contract::aux::no_error();
|
||||
} // Else (check only inv, pre, etc.) do nothing.
|
||||
@@ -108,8 +117,8 @@ private:
|
||||
// throw, also check subcontracted post.
|
||||
void exit() {
|
||||
bool const body_threw = std::uncaught_exception();
|
||||
if(virt_.action == boost::contract::virtual_body::user_call) {
|
||||
this->check_subcontracted_inv();
|
||||
if(virt_ == boost::contract::virtual_body::user_call) {
|
||||
this->check_subcontracted_exit_inv();
|
||||
if(!body_threw) this->check_subcontracted_post();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifndef BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_STATIC_MEMBER_HPP_
|
||||
#define BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_STATIC_MEMBER_HPP_
|
||||
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/aux_/check/pre_post_inv.hpp>
|
||||
#include <exception>
|
||||
|
||||
@@ -10,8 +11,8 @@ namespace boost { namespace contract { namespace aux { namespace function {
|
||||
template<class Class> class public_static_member :
|
||||
public boost::contract::aux::check::pre_post_inv<Class> {
|
||||
public:
|
||||
explicit public_static_member() :
|
||||
boost::contract::aux::check::pre_post_inv<Class>() {
|
||||
explicit public_static_member() : boost::contract::aux::check::
|
||||
pre_post_inv<Class>(boost::contract::from_public_member) {
|
||||
entry();
|
||||
}
|
||||
|
||||
@@ -23,7 +24,7 @@ private:
|
||||
// subcontracting for any of the checks below).
|
||||
|
||||
// Static so no object so check static inv only.
|
||||
void entry() { this->check_inv(/* static_inv_only = */ true); }
|
||||
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(); }
|
||||
@@ -35,7 +36,7 @@ private:
|
||||
// only if body did not throw.
|
||||
void exit() {
|
||||
bool const body_threw = std::uncaught_exception();
|
||||
this->check_inv(/* static_inv_only = */ true);
|
||||
this->check_exit_inv(/* static_inv_only = */ true);
|
||||
if(!body_threw) this->check_post();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#define BOOST_CONTRACT_CONSTRUCTOR_HPP_
|
||||
|
||||
#include <boost/contract/set/postcondition_only.hpp>
|
||||
#include <boost/contract/exception.hpp>
|
||||
#include <boost/contract/aux_/function/constructor.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
@@ -20,7 +21,13 @@ struct constructor_precondition {
|
||||
constructor_precondition() {} // For overloaded constructors with no pre.
|
||||
|
||||
template<typename Precondition>
|
||||
explicit constructor_precondition(Precondition const& f) { f(); }
|
||||
explicit constructor_precondition(Precondition const& f) {
|
||||
try { f(); }
|
||||
catch(...) {
|
||||
boost::contract::aux::pre_failure_handler(
|
||||
boost::contract::from_constructor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} } // namespace
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
// TODO: Implement set_precondition/postcondition/invariant/entry_invariant/
|
||||
// exit_invariant_failed handlers.
|
||||
|
||||
namespace boost { namespace contract {
|
||||
|
||||
// Exceptions.
|
||||
@@ -37,7 +34,7 @@ struct assertion_failure : public std::exception {
|
||||
private:
|
||||
void init() {
|
||||
std::ostringstream text;
|
||||
text.str("assertion");
|
||||
text << "assertion";
|
||||
if(std::string(code_) != "") text << " \"" << code_ << "\"";
|
||||
text << " failed";
|
||||
if(std::string(file_) != "") {
|
||||
@@ -53,48 +50,6 @@ private:
|
||||
std::string what_;
|
||||
};
|
||||
|
||||
struct precondition_failure : public assertion_failure {
|
||||
explicit precondition_failure(assertion_failure const& failure) :
|
||||
assertion_failure(failure) {
|
||||
what_ = std::string("precondition ") + assertion_failure::what();
|
||||
}
|
||||
virtual char const* what() const BOOST_NOEXCEPT { return what_.c_str(); }
|
||||
private:
|
||||
std::string what_;
|
||||
};
|
||||
|
||||
struct postcondition_failure : public assertion_failure {
|
||||
explicit postcondition_failure(assertion_failure const& failure) :
|
||||
assertion_failure(failure) {
|
||||
what_ = std::string("postcondition ") + assertion_failure::what();
|
||||
}
|
||||
virtual char const* what() const BOOST_NOEXCEPT { return what_.c_str(); }
|
||||
private:
|
||||
std::string what_;
|
||||
};
|
||||
|
||||
struct invariant_failure : public assertion_failure {};
|
||||
|
||||
struct entry_invariant_failure : public assertion_failure {
|
||||
explicit entry_invariant_failure(assertion_failure const& failure) :
|
||||
assertion_failure(failure) {
|
||||
what_ = std::string("exit invariant ") + assertion_failure::what();
|
||||
}
|
||||
virtual char const* what() const BOOST_NOEXCEPT { return what_.c_str(); }
|
||||
private:
|
||||
std::string what_;
|
||||
};
|
||||
|
||||
struct exit_invariant_failure : public assertion_failure {
|
||||
explicit exit_invariant_failure(assertion_failure const& failure) :
|
||||
assertion_failure(failure) {
|
||||
what_ = std::string("exit invariant ") + assertion_failure::what();
|
||||
}
|
||||
virtual char const* what() const BOOST_NOEXCEPT { return what_.c_str(); }
|
||||
private:
|
||||
std::string what_;
|
||||
};
|
||||
|
||||
// Handlers.
|
||||
|
||||
enum from {
|
||||
@@ -112,54 +67,156 @@ typedef void (*failure_handler)(from);
|
||||
// exported (so they are the same across DLL, etc.), plus they should be
|
||||
// protected by mutexes.
|
||||
namespace aux {
|
||||
void default_handler(from const) {
|
||||
try {
|
||||
throw;
|
||||
} catch(boost::contract::assertion_failure const& error) {
|
||||
std::cerr << error.what() << std::endl;
|
||||
std::terminate();
|
||||
} catch(...) {
|
||||
std::terminate();
|
||||
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<exception_::failure_handler_key Key>
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
failure_handler precondition_failure_handler = &default_handler;
|
||||
failure_handler postcondition_failure_handler = &default_handler;
|
||||
failure_handler entry_invariant_failure_handler = &default_handler;
|
||||
failure_handler exit_invariant_failure_handler = &default_handler;
|
||||
failure_handler pre_failure_handler = &exception_::
|
||||
default_failure_handler<exception_::pre_key>;
|
||||
failure_handler post_failure_handler = &exception_::
|
||||
default_failure_handler<exception_::post_key>;
|
||||
|
||||
failure_handler const_entry_inv_failure_handler = &exception_::
|
||||
default_failure_handler<exception_::const_entry_inv_key>;
|
||||
failure_handler const_volatile_entry_inv_failure_handler = &exception_::
|
||||
default_failure_handler<exception_::const_volatile_entry_inv_key>;
|
||||
failure_handler static_entry_inv_failure_handler = &exception_::
|
||||
default_failure_handler<exception_::static_entry_inv_key>;
|
||||
|
||||
failure_handler const_exit_inv_failure_handler = &exception_::
|
||||
default_failure_handler<exception_::const_exit_inv_key>;
|
||||
failure_handler const_volatile_exit_inv_failure_handler = &exception_::
|
||||
default_failure_handler<exception_::const_volatile_exit_inv_key>;
|
||||
failure_handler static_exit_inv_failure_handler = &exception_::
|
||||
default_failure_handler<exception_::static_exit_inv_key>;
|
||||
}
|
||||
|
||||
failure_handler set_precondition_failure(failure_handler f)
|
||||
BOOST_NOEXCEPT_OR_NOTHROW {
|
||||
failure_handler result = boost::contract::aux::precondition_failure_handler;
|
||||
boost::contract::aux::precondition_failure_handler = f;
|
||||
failure_handler result = boost::contract::aux::pre_failure_handler;
|
||||
boost::contract::aux::pre_failure_handler = f;
|
||||
return result;
|
||||
}
|
||||
|
||||
failure_handler set_postcondition_failure(failure_handler f)
|
||||
BOOST_NOEXCEPT_OR_NOTHROW {
|
||||
failure_handler result = boost::contract::aux::
|
||||
postcondition_failure_handler;
|
||||
boost::contract::aux::postcondition_failure_handler = f;
|
||||
failure_handler result = boost::contract::aux::post_failure_handler;
|
||||
boost::contract::aux::post_failure_handler = f;
|
||||
return result;
|
||||
}
|
||||
|
||||
failure_handler set_entry_invariant_failure(failure_handler f)
|
||||
// Entry invariants.
|
||||
|
||||
failure_handler set_const_entry_invariant_failure(failure_handler f)
|
||||
BOOST_NOEXCEPT_OR_NOTHROW {
|
||||
failure_handler result = boost::contract::aux::
|
||||
entry_invariant_failure_handler;
|
||||
boost::contract::aux::entry_invariant_failure_handler = f;
|
||||
const_entry_inv_failure_handler;
|
||||
boost::contract::aux::const_entry_inv_failure_handler = f;
|
||||
return result;
|
||||
}
|
||||
|
||||
failure_handler set_exit_invariant_failure(failure_handler f)
|
||||
failure_handler set_const_volatile_entry_invariant_failure(failure_handler f)
|
||||
BOOST_NOEXCEPT_OR_NOTHROW {
|
||||
failure_handler result = boost::contract::aux::
|
||||
exit_invariant_failure_handler;
|
||||
boost::contract::aux::exit_invariant_failure_handler = f;
|
||||
const_volatile_entry_inv_failure_handler;
|
||||
boost::contract::aux::const_volatile_entry_inv_failure_handler = f;
|
||||
return result;
|
||||
}
|
||||
|
||||
failure_handler set_static_entry_invariant_failure(failure_handler f)
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Exit invariants.
|
||||
|
||||
failure_handler set_const_exit_invariant_failure(failure_handler f)
|
||||
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;
|
||||
}
|
||||
|
||||
failure_handler set_const_volatile_exit_invariant_failure(failure_handler f)
|
||||
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;
|
||||
}
|
||||
|
||||
failure_handler set_static_exit_invariant_failure(failure_handler f)
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// All invariants.
|
||||
|
||||
void set_invariant_failure(failure_handler f) BOOST_NOEXCEPT_OR_NOTHROW {
|
||||
set_entry_invariant_failure(f);
|
||||
set_exit_invariant_failure(f);
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
#include <boost/preprocessor/config/config.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
// TODO: There is a problem with old-of of virtual body functions for which
|
||||
// old-of of the base function are evaluated *after* the derived virtual
|
||||
// function body is executed (so invalidating old-of values)... Can I fix this?
|
||||
// Maybe passing a (mutable) pointer v and implementing a "stack" (like a map
|
||||
// of boost::any indexed by old-of #) inside the mutable object pointed by v...
|
||||
|
||||
// IMPORTANT: Following old-of templates and macros ensure that:
|
||||
// 1. Old-value expressions are evaluated only once and only when old-of
|
||||
// should not be skipped.
|
||||
@@ -115,8 +121,8 @@ bool skip_oldof(boost::contract::virtual_body const v) {
|
||||
#ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS
|
||||
return true; // Never check post, so old-of never needed.
|
||||
#else
|
||||
if(v.action == boost::contract::virtual_body::user_call ||
|
||||
v.action == boost::contract::virtual_body::check_post_only) {
|
||||
if(v == boost::contract::virtual_body::user_call ||
|
||||
v == boost::contract::virtual_body::check_post_only) {
|
||||
return false; // Checking post, so old-of needed.
|
||||
}
|
||||
return true; // Not checking post, so old-of not needed.
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace boost { namespace contract {
|
||||
// Must be efficient to pass this as value param (to limit user API verbosity).
|
||||
class virtual_body {
|
||||
public:
|
||||
/* implicit */ virtual_body(int const) : action(user_call) {}
|
||||
/* implicit */ virtual_body(int const) : action_(user_call) {}
|
||||
|
||||
private:
|
||||
// Use friendship to limit public API.
|
||||
@@ -36,15 +36,24 @@ private:
|
||||
|
||||
enum action_type {
|
||||
user_call,
|
||||
check_inv_only,
|
||||
check_pre_only,
|
||||
check_post_only
|
||||
check_post_only,
|
||||
check_entry_inv_only,
|
||||
check_exit_inv_only
|
||||
};
|
||||
|
||||
/* implicit */ virtual_body(action_type const an_action) :
|
||||
action(an_action) {}
|
||||
/* implicit */ virtual_body(action_type const action) :
|
||||
action_(action) {}
|
||||
|
||||
action_type action;
|
||||
bool operator==(action_type const action) const {
|
||||
return action_ == action;
|
||||
}
|
||||
|
||||
bool operator!=(action_type const action) const {
|
||||
return action_ != action;
|
||||
}
|
||||
|
||||
action_type action_;
|
||||
};
|
||||
|
||||
} } // namespace
|
||||
|
||||
Reference in New Issue
Block a user