added failure handlers and re-run all tests

This commit is contained in:
Lorenzo Caminiti
2015-04-27 20:54:30 -07:00
parent 3146d3fa3d
commit 2d4cf6bfdf
22 changed files with 328 additions and 161 deletions

View File

@@ -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_;
};

View File

@@ -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_;
};

View File

@@ -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.
}
}

View File

@@ -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();
}

View File

@@ -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();
}
};

View File

@@ -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).

View File

@@ -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

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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();
}
};

View File

@@ -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

View File

@@ -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);

View File

@@ -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.

View File

@@ -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