diff --git a/include/boost/contract/aux_/base_function.hpp b/include/boost/contract/aux_/base_function.hpp deleted file mode 100644 index dcb60ee..0000000 --- a/include/boost/contract/aux_/base_function.hpp +++ /dev/null @@ -1,103 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_BASE_FUNCTION_HPP_ -#define BOOST_CONTRACT_AUX_BASE_FUNCTION_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { namespace contract { namespace aux { - -template -class base_function { - typedef typename boost::function_types::result_type::type - result_type; - typedef typename boost::mpl::pop_front::type>::type arg_types; - typedef typename boost::mpl::eval_if::type, boost::contract::virtual_body>, - boost::mpl::identity - , - boost::mpl::push_back - >::type virtual_arg_types; - -public: - base_function() : virt_(boost::contract::virtual_body::user_call) {} - - void derived_function(DerivedFunction* derived_func) { - derived_func_ = derived_func; - } - - base_function& action(boost::contract::virtual_body const virt) { - virt_ = virt; - return *this; - } - - template - void operator()(Base*) { - call(boost::mpl::bool_::value>()); - } - -private: - template void call(boost::mpl::false_ const&) {} - template void call(boost::mpl::true_ const&) { - typedef typename boost::mpl::push_front< - typename boost::mpl::push_front::type, - result_type - >::type base_virtual_func_types; - typedef typename boost::function_types::member_function_pointer< - base_virtual_func_types>::type base_virtual_func_ptr; - base_virtual_func_ptr base_virtual_func = Intro::template - member_function_address(); - BOOST_CONTRACT_AUX_DEBUG(base_virtual_func); - - BOOST_CONTRACT_AUX_DEBUG(derived_func_); - Base* const base = derived_func_->obj_; - BOOST_CONTRACT_AUX_DEBUG(base); - - try { - (base->*base_virtual_func)(derived_func_->arg0_, virt_); - } catch(boost::contract::aux::no_error const&) { - if(virt_.action == boost::contract::virtual_body::check_pre_only) { - throw; // Pre logic-or: Stop at 1st no_error (throw to caller). - } - } catch(...) { - if(virt_.action == boost::contract::virtual_body::check_pre_only) { - // Pre logic-or: Ignore errors, possibly checking up to caller. - } - } - } - - DerivedFunction* derived_func_; - boost::contract::virtual_body virt_; -}; - -template -struct base_function { // Dummy implementation that does nothing. - base_function() {} - - void derived_function(DerivedFunction*) {} - base_function& action(boost::contract::virtual_body const) { return *this; } - - template // Should never actually be called at runtime. - void operator()(Base*) { BOOST_CONTRACT_AUX_DEBUG(false); } -}; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/bases.hpp b/include/boost/contract/aux_/bases.hpp deleted file mode 100644 index 49484dc..0000000 --- a/include/boost/contract/aux_/bases.hpp +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_BASES_HPP_ -#define BOOST_CONTRACT_AUX_BASES_HPP_ - -#include -#include - -namespace boost { namespace contract { namespace aux { - -BOOST_CONTRACT_AUX_TTI_TRAIT_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_/basic_function.hpp b/include/boost/contract/aux_/basic_function.hpp deleted file mode 100644 index abb837b..0000000 --- a/include/boost/contract/aux_/basic_function.hpp +++ /dev/null @@ -1,165 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_BASIC_FUNCTION_HPP_ -#define BOOST_CONTRACT_AUX_BASIC_FUNCTION_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// TODO: Modelling after Clang message for assert() failure: -// assertion "(Key != boost::contract::aux::constructor)" failed: file "..\include/boost/contract/aux_/function.hpp", line 156 -// This library should say: -// precondition/postcondition/invariant/... "..." failed: file "...", line ... -// for exception classes precondition/postcondition/..._failure (inheriting from -// assertion_failure base exception to be thrown by CONTRACT_ASSERT) and failure -// handlers [set_]precondition_failed. - -// TODO: Consider splitting this class into aux_/constructor, aux_/destructor, -// etc. bases on Key while keeping all check_... functions in a -// aux_/basic_function base class (or even in contract::type directly). The code -// might be more clear without all the switch on Key. - -namespace boost { namespace contract { namespace aux { - -template< - class Class = boost::contract::aux::none, - class Intro = boost::contract::aux::none, - typename Func = boost::contract::aux::none, - typename Arg0 = boost::contract::aux::none -> class basic_function : public boost::contract::type, - private boost::noncopyable { - friend class boost::contract::aux::base_function< - basic_function, Intro, Func>; - - // Base types as pointers because mpl::for_each will construct them. - typedef typename boost::mpl::transform< - typename boost::mpl::eval_if, - boost::contract::aux::bases_of - , - boost::mpl::identity > - >::type, - boost::add_pointer - >::type base_ptrs; - -#if !BOOST_CONTRACT_CONFIG_PERMISSIVE - // TODO: Fix those. - //BOOST_STATIC_ASSERT_MSG(!boost::contract::aux::has_mutable_invariant< - // Class>::value, "class invariant function must be const"); - //BOOST_STATIC_ASSERT_MSG( - // (!boost::mpl::and_< - // boost::contract::aux::has_bases, - // boost::mpl::or_< - // boost::is_same, - // boost::is_same - // > - // >::value), - // "must specify introspection type, function type, and function " - // "arguments for member contract of class with bases" - //); - // TODO: static_assert(Func == none || class::type == Class) -#endif - -public: - explicit basic_function(Class* const obj, Arg0 arg0) : base_func_(), - obj_(obj), arg0_(arg0) { - BOOST_CONTRACT_AUX_DEBUG(obj_); - base_func_.derived_function(this); - } - - explicit basic_function(Class* const obj) : base_func_(), obj_(obj) { - BOOST_CONTRACT_AUX_DEBUG(obj_); - base_func_.derived_function(this); - } - - explicit basic_function() : base_func_(), obj_(0) { - base_func_.derived_function(this); - } - -protected: - void check_subcontracted_inv(bool const static_inv_only = false) { - if(!boost::mpl::empty::value && obj_) { - boost::mpl::for_each(base_func_.action( - static_inv_only ? - boost::contract::virtual_body::check_static_inv_only - : - boost::contract::virtual_body::check_inv_only - )); - } - check_inv(static_inv_only); - } - - void check_inv(bool const static_inv_only = false) { - check_static_inv(boost::mpl::bool_::value>()); - if(!static_inv_only && obj_) { - check_cv_inv(boost::mpl::bool_::value>()); - } - } - - void check_subcontracted_pre() { - try { - if(!boost::mpl::empty::value && obj_) { - boost::mpl::for_each(base_func_.action( - boost::contract::virtual_body::check_pre_only)); - } - check_pre(); // Pre logic-or: Last check, error if also throws. - } catch(boost::contract::aux::no_error const&) { - // Pre logic-or: Stop at 1st no_error (thrown by callee). - } - } - - void check_pre() { if(pre_) pre_(); } - - void check_subcontracted_post() { - if(!boost::mpl::empty::value && obj_) { - boost::mpl::for_each(base_func_.action( - boost::contract::virtual_body::check_post_only)); - } - check_post(); - } - - void check_post() { if(post_) post_(); } - -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_cv_inv(boost::mpl::false_ const&) {} - void check_cv_inv(boost::mpl::true_ const&) { - typename boost::add_const::type* const const_obj = obj_; - BOOST_CONTRACT_AUX_DEBUG(const_obj); - const_obj->BOOST_CONTRACT_CONFIG_INVARIANT(); - } - - boost::contract::aux::base_function base_func_; - Class* const obj_; - // TODO: add_reference/perfect fwd to all these Arg-i types. - // TODO: Support 0-to-n args. - Arg0 arg0_; -}; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/check/pre_post.hpp b/include/boost/contract/aux_/check/pre_post.hpp new file mode 100644 index 0000000..d81fe20 --- /dev/null +++ b/include/boost/contract/aux_/check/pre_post.hpp @@ -0,0 +1,22 @@ + +#ifndef BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ +#define BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ + +#include + +// TODO: Consider moving this to an aux_/check/ dir and namespace. + +namespace boost { namespace contract { namespace aux { namespace check { + +// TODO: check_pre/post should probably just be made protected members of +// class containing pre_/post_ so those can be made private data members. +class pre_post : public boost::contract::type { +protected: + void check_pre() { if(pre_) pre_(); } + void check_post() { if(post_) 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 new file mode 100644 index 0000000..af6a8b3 --- /dev/null +++ b/include/boost/contract/aux_/check/pre_post_inv.hpp @@ -0,0 +1,51 @@ + +#ifndef BOOST_CONTRACT_AUX_CHECK_PRE_POST_INV_HPP_ +#define BOOST_CONTRACT_AUX_CHECK_PRE_POST_INV_HPP_ + +#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(Class* const obj = 0) : obj_(obj) {} + +protected: + void check_inv(bool const static_inv_only = false) { + check_static_inv(boost::mpl::bool_::value>()); + if(!static_inv_only) { + check_cv_inv(boost::mpl::bool_::value>()); + } + } + + // 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_cv_inv(boost::mpl::false_ const&) {} + void check_cv_inv(boost::mpl::true_ const&) { + typename boost::add_const::type* const const_obj = obj_; + BOOST_CONTRACT_AUX_DEBUG(const_obj); + const_obj->BOOST_CONTRACT_CONFIG_INVARIANT(); + } + + 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 new file mode 100644 index 0000000..bfa74f5 --- /dev/null +++ b/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp @@ -0,0 +1,189 @@ + +#ifndef BOOST_CONTRACT_AUX_CHECK_SUBCONTRACTED_PRE_POST_INV_HPP_ +#define BOOST_CONTRACT_AUX_CHECK_SUBCONTRACTED_PRE_POST_INV_HPP_ + +#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 + +// TODO: Modelling after Clang message for assert() failure: +// assertion "(Key != boost::contract::aux::constructor)" failed: file "..\include/boost/contract/aux_/function.hpp", line 156 +// This library should say: +// precondition/postcondition/invariant/... "..." failed: file "...", line ... +// for exception classes precondition/postcondition/..._failure (inheriting from +// assertion_failure base exception to be thrown by CONTRACT_ASSERT) and failure +// handlers [set_]precondition_failed. + +namespace boost { namespace contract { namespace aux { namespace check { + +template< + class Class, + class Intro = boost::contract::aux::none, + typename Func = boost::contract::aux::none, + typename Arg0 = boost::contract::aux::none +> class subcontracted_pre_post_inv : + public boost::contract::aux::check::pre_post_inv, + 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; + +#if !BOOST_CONTRACT_CONFIG_PERMISSIVE + // TODO: Fix those. + //BOOST_STATIC_ASSERT_MSG(!boost::contract::aux::has_mutable_invariant< + // Class>::value, "class invariant function must be const"); + //BOOST_STATIC_ASSERT_MSG( + // (!boost::mpl::and_< + // boost::contract::aux::has_bases, + // boost::mpl::or_< + // boost::is_same, + // boost::is_same + // > + // >::value), + // "must specify introspection type, function type, and function " + // "arguments for member contract of class with bases" + //); + // TODO: static_assert(Func == none || class::type == Class) +#endif + +public: + explicit subcontracted_pre_post_inv(Class* const obj, Arg0 arg0) : + boost::contract::aux::check::pre_post_inv(obj), + arg0_(arg0) + {} + + explicit subcontracted_pre_post_inv(Class* const obj) : boost::contract:: + aux::check::pre_post_inv(obj) { + } + +protected: + void check_subcontracted_inv(bool const static_inv_only = false) { + boost::mpl::for_each(check_base(*this, + static_inv_only ? + boost::contract::virtual_body::check_static_inv_only + : + boost::contract::virtual_body::check_inv_only + )); + this->check_inv(static_inv_only); + } + + void check_subcontracted_pre() { + try { + boost::mpl::for_each(check_base(*this, + boost::contract::virtual_body::check_pre_only)); + this->check_pre(); // Pre logic-or: Last check, error also throws. + } catch(boost::contract::aux::no_error const&) { + // Pre logic-or: Stop at 1st no_error (thrown by callee). + } + } + + void check_subcontracted_post() { + boost::mpl::for_each(check_base(*this, + boost::contract::virtual_body::check_post_only)); + this->check_post(); + } + + class check_base { + public: + explicit check_base(subcontracted_pre_post_inv& outer, + boost::contract::virtual_body const virt) : + outer_(outer), virt_(virt) + {} + + template + void operator()(Base*) { + typedef typename boost::function_types::result_type::type + result_type; + typedef typename boost::mpl::pop_front< + typename boost::function_types::parameter_types::type + >::type arg_types; + typedef typename boost::mpl::eval_if::type, boost::contract::virtual_body>, + boost::mpl::identity + , + boost::mpl::push_back + >::type virtual_arg_types; + + call_base_function( + boost::mpl::bool_::value>() + ); + } + + private: + template + void call_base_function(boost::mpl::false_ const&) {} + template + void call_base_function(boost::mpl::true_ const&) { + typedef typename boost::mpl::push_front< + typename boost::mpl::push_front::type, + ResultType + >::type base_virtual_func_types; + typedef typename boost::function_types::member_function_pointer< + base_virtual_func_types>::type base_virtual_func_ptr; + + base_virtual_func_ptr base_virtual_func = Intro::template + member_function_address(); + BOOST_CONTRACT_AUX_DEBUG(base_virtual_func); + + 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) { + throw; // Pre logic-or: 1st no_err stops (throw to caller). + } + } catch(...) { + if(virt_.action == boost::contract::virtual_body:: + check_pre_only) { + // Pre logic-or: Ignore err, possibly checks up to caller. + } + } + } + + subcontracted_pre_post_inv& outer_; + boost::contract::virtual_body virt_; + }; + + // TODO: add_reference/perfect fwd to all these Arg-i types. + // TODO: Support 0-to-n args. + Arg0 arg0_; +}; + +} } } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/constructor.hpp b/include/boost/contract/aux_/function/constructor.hpp similarity index 70% rename from include/boost/contract/aux_/constructor.hpp rename to include/boost/contract/aux_/function/constructor.hpp index bffdf53..3cc41de 100644 --- a/include/boost/contract/aux_/constructor.hpp +++ b/include/boost/contract/aux_/function/constructor.hpp @@ -1,19 +1,17 @@ -#ifndef BOOST_CONTRACT_AUX_CONSTRUCTOR_HPP_ -#define BOOST_CONTRACT_AUX_CONSTRUCTOR_HPP_ +#ifndef BOOST_CONTRACT_AUX_FUNCTION_CONSTRUCTOR_HPP_ +#define BOOST_CONTRACT_AUX_FUNCTION_CONSTRUCTOR_HPP_ -#include -#include +#include #include -namespace boost { namespace contract { namespace aux { +namespace boost { namespace contract { namespace aux { namespace function { template -class constructor : public boost::contract::aux::basic_function { +class constructor : public boost::contract::aux::check::pre_post_inv { public: explicit constructor(Class* const obj) : - boost::contract::aux::basic_function(obj) { - BOOST_CONTRACT_AUX_DEBUG(obj); + boost::contract::aux::check::pre_post_inv(obj) { entry(); } @@ -41,7 +39,7 @@ private: }; -} } } // namespace +} } } } // namespace #endif // #include guard diff --git a/include/boost/contract/aux_/destructor.hpp b/include/boost/contract/aux_/function/destructor.hpp similarity index 79% rename from include/boost/contract/aux_/destructor.hpp rename to include/boost/contract/aux_/function/destructor.hpp index 831c468..12a4426 100644 --- a/include/boost/contract/aux_/destructor.hpp +++ b/include/boost/contract/aux_/function/destructor.hpp @@ -1,19 +1,18 @@ -#ifndef BOOST_CONTRACT_AUX_DESTRUCTOR_HPP_ -#define BOOST_CONTRACT_AUX_DESTRUCTOR_HPP_ +#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 boost { namespace contract { namespace aux { namespace function { template -class destructor : public boost::contract::aux::basic_function { +class destructor : public boost::contract::aux::check::pre_post_inv { public: explicit destructor(Class* const obj) : - boost::contract::aux::basic_function(obj) { - BOOST_CONTRACT_AUX_DEBUG(obj); + boost::contract::aux::check::pre_post_inv(obj) { entry(); } @@ -47,7 +46,7 @@ private: } }; -} } } // namespace +} } } } // namespace #endif // #include guard diff --git a/include/boost/contract/aux_/free_function.hpp b/include/boost/contract/aux_/function/free_function.hpp similarity index 63% rename from include/boost/contract/aux_/free_function.hpp rename to include/boost/contract/aux_/function/free_function.hpp index 0f422e7..ee8cd6a 100644 --- a/include/boost/contract/aux_/free_function.hpp +++ b/include/boost/contract/aux_/function/free_function.hpp @@ -1,13 +1,13 @@ -#ifndef BOOST_CONTRACT_AUX_FREE_FUNCTION_HPP_ -#define BOOST_CONTRACT_AUX_FREE_FUNCTION_HPP_ +#ifndef BOOST_CONTRACT_AUX_FUNCTION_FREE_FUNCTION_HPP_ +#define BOOST_CONTRACT_AUX_FUNCTION_FREE_FUNCTION_HPP_ -#include +#include #include -namespace boost { namespace contract { namespace aux { +namespace boost { namespace contract { namespace aux { namespace function { -class free_function : public boost::contract::aux::basic_function<> { +class free_function : public boost::contract::aux::check::pre_post { public: explicit free_function() { entry(); } @@ -18,7 +18,7 @@ private: void entry() {} // Check pre (as soon as related functor set). - void pre_available() { this->check_pre(); } + void pre_available() { check_pre(); } // Post always checked after body, at exit (see below). void post_available() {} @@ -31,7 +31,7 @@ private: } }; -} } } // 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 new file mode 100644 index 0000000..ee0efc8 --- /dev/null +++ b/include/boost/contract/aux_/function/private_member.hpp @@ -0,0 +1,18 @@ + +#ifndef BOOST_CONTRACT_AUX_FUNCTION_PRIVATE_MEMBER_HPP_ +#define BOOST_CONTRACT_AUX_FUNCTION_PRIVATE_MEMBER_HPP_ + +#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. +typedef boost::contract::aux::function::free_function 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 new file mode 100644 index 0000000..a145f70 --- /dev/null +++ b/include/boost/contract/aux_/function/protected_member.hpp @@ -0,0 +1,18 @@ + +#ifndef BOOST_CONTRACT_AUX_FUNCTION_PROTECTED_MEMBER_HPP_ +#define BOOST_CONTRACT_AUX_FUNCTION_PROTECTED_MEMBER_HPP_ + +#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. +typedef boost::contract::aux::function::free_function protected_member; + +} } } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/public_member.hpp b/include/boost/contract/aux_/function/public_member.hpp similarity index 72% rename from include/boost/contract/aux_/public_member.hpp rename to include/boost/contract/aux_/function/public_member.hpp index 89149ba..a400e3e 100644 --- a/include/boost/contract/aux_/public_member.hpp +++ b/include/boost/contract/aux_/function/public_member.hpp @@ -1,32 +1,29 @@ -#ifndef BOOST_CONTRACT_AUX_PUBLIC_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_PUBLIC_MEMBER_HPP_ +#ifndef BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_MEMBER_HPP_ +#define BOOST_CONTRACT_AUX_FUNCTION_PUBLIC_MEMBER_HPP_ -#include +#include #include #include #include #include #include -namespace boost { namespace contract { namespace aux { +namespace boost { namespace contract { namespace aux { namespace function { template< class Class, class Intro = boost::contract::aux::none, typename Func = boost::contract::aux::none, typename Arg0 = boost::contract::aux::none -> class public_member : public boost::contract::aux::basic_function< - Class, Intro, Func, Arg0> { +> class public_member : public boost::contract::aux::check:: + subcontracted_pre_post_inv { public: // Must be used when bases and virtual body (but can also always be used). - explicit public_member( - boost::contract::virtual_body const virt, - Class* const obj, - Arg0 arg0 - ) : - boost::contract::aux::basic_function(obj, - arg0), + explicit public_member(boost::contract::virtual_body const virt, + Class* const obj, Arg0 arg0) : + boost::contract::aux::check::subcontracted_pre_post_inv(obj, arg0), virt_(virt) { BOOST_CONTRACT_AUX_DEBUG((!boost::is_same(obj, - arg0), + explicit public_member(Class* const obj, Arg0 arg0) : + boost::contract::aux::check::subcontracted_pre_post_inv(obj, arg0), virt_(boost::contract::virtual_body::user_call) { BOOST_CONTRACT_AUX_DEBUG((!boost::is_same(obj), + explicit public_member(boost::contract::virtual_body const virt, + Class* const obj) : + boost::contract::aux::check::subcontracted_pre_post_inv(obj), virt_(virt) { BOOST_CONTRACT_AUX_DEBUG((boost::is_same(obj), - virt_(boost::contract::virtual_body::user_call) - { - BOOST_CONTRACT_AUX_DEBUG((boost::is_same::value)); - BOOST_CONTRACT_AUX_DEBUG((boost::is_same::value)); - entry(); - } - - // Must be used for static members. - explicit public_member() : - boost::contract::aux::basic_function(), + explicit public_member(Class* const obj) : + boost::contract::aux::check::subcontracted_pre_post_inv(obj), virt_(boost::contract::virtual_body::user_call) { BOOST_CONTRACT_AUX_DEBUG((boost::is_same +#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() { + 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_inv(/* static_inv_only = */ true); } + + // Check pre (as soon as related functor set). + void pre_available() { this->check_pre(); } + + // Post always checked after body, at exit (see below). + void post_available() {} + + // 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_inv(/* static_inv_only = */ true); + if(!body_threw) this->check_post(); + } +}; + +} } } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/private_member.hpp b/include/boost/contract/aux_/private_member.hpp deleted file mode 100644 index 4ae5a6d..0000000 --- a/include/boost/contract/aux_/private_member.hpp +++ /dev/null @@ -1,18 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_PRIVATE_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_PRIVATE_MEMBER_HPP_ - -#include - -namespace boost { namespace contract { namespace aux { - -// 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. -typedef free_function private_member; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/protected_member.hpp b/include/boost/contract/aux_/protected_member.hpp deleted file mode 100644 index c2728a2..0000000 --- a/include/boost/contract/aux_/protected_member.hpp +++ /dev/null @@ -1,18 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_PROTECTED_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_PROTECTED_MEMBER_HPP_ - -#include - -namespace boost { namespace contract { namespace aux { - -// 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. -typedef free_function protected_member; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/type_traits/bases.hpp b/include/boost/contract/aux_/type_traits/bases.hpp new file mode 100644 index 0000000..a99c1b8 --- /dev/null +++ b/include/boost/contract/aux_/type_traits/bases.hpp @@ -0,0 +1,19 @@ + +#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_/tti.hpp b/include/boost/contract/aux_/type_traits/introspection.hpp similarity index 62% rename from include/boost/contract/aux_/tti.hpp rename to include/boost/contract/aux_/type_traits/introspection.hpp index c7af7ce..5b6e3fa 100644 --- a/include/boost/contract/aux_/tti.hpp +++ b/include/boost/contract/aux_/type_traits/introspection.hpp @@ -1,6 +1,6 @@ -#ifndef BOOST_CONTRACT_AUX_TTI_HPP_ -#define BOOST_CONTRACT_AUX_TTI_HPP_ +#ifndef BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HPP_ +#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HPP_ #include #include @@ -19,29 +19,32 @@ /* PUBLIC */ -#define BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_TYPE(trait, type_name) \ +#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_TYPE(trait, type_name)\ template \ class trait { \ template \ - static boost::contract::aux::tti::yes& check(typename \ - BOOST_CONTRACT_AUX_NAME1(C)::type_name*); \ + static boost::contract::aux::type_traits::introspection::yes& check( \ + typename BOOST_CONTRACT_AUX_NAME1(C)::type_name*); \ \ - BOOST_CONTRACT_AUX_TTI_TRAIT_END_(BOOST_CONTRACT_AUX_NAME1(T)) \ + BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_END_( \ + BOOST_CONTRACT_AUX_NAME1(T)) \ }; -#define BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_MEMBER_FUNCTION(trait, func_name) \ - BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_MEMBER_FUNCTION_(/* is_static = */ 0, \ - trait, func_name) +#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION( \ + trait, func_name) \ + BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION_( \ + /* is_static = */ 0, trait, func_name) -#define BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_STATIC_MEMBER_FUNCTION(trait, \ +#define \ +BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_STATIC_MEMBER_FUNCTION(trait, \ func_name) \ - BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_MEMBER_FUNCTION_(/* is_static = */ 1, \ - trait, func_name) + BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION_( \ + /* is_static = */ 1, trait, func_name) /* PRIVATE */ -#define BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_MEMBER_FUNCTION_(is_static, trait, \ - func_name) \ +#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION_( \ + is_static, trait, func_name) \ template< \ typename BOOST_CONTRACT_AUX_NAME1(T), \ typename BOOST_CONTRACT_AUX_NAME1(R), \ @@ -50,8 +53,8 @@ > \ class trait { \ template \ - static boost::contract::aux::tti::yes& check( \ - boost::contract::aux::tti::check_function< \ + static boost::contract::aux::type_traits::introspection::yes& check( \ + boost::contract::aux::type_traits::introspection::check_function< \ typename \ BOOST_PP_IIF(is_static, \ boost::function_types::function_pointer \ @@ -79,21 +82,24 @@ >* \ ); \ \ - BOOST_CONTRACT_AUX_TTI_TRAIT_END_(BOOST_CONTRACT_AUX_NAME1(T)) \ + BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_END_( \ + BOOST_CONTRACT_AUX_NAME1(T)) \ }; -#define BOOST_CONTRACT_AUX_TTI_TRAIT_END_(tparam) \ +#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_END_(tparam) \ template \ - static boost::contract::aux::tti::no& check(...); \ + static boost::contract::aux::type_traits::introspection::no& check( \ + ...); \ \ public: \ static bool const value = sizeof(check(0)) == \ - sizeof(boost::contract::aux::tti::yes); \ + sizeof(boost::contract::aux::type_traits::introspection::yes); \ typedef boost::mpl::bool_ type; /* CODE */ -namespace boost { namespace contract { namespace aux { namespace tti { +namespace boost { namespace contract { namespace aux { namespace type_traits { + namespace introspection { typedef struct {} yes; typedef yes no[2]; @@ -101,7 +107,7 @@ typedef yes no[2]; template struct check_function; -} } } } // namespace +} } } } } // namespace #endif // #include guard diff --git a/include/boost/contract/aux_/invariant.hpp b/include/boost/contract/aux_/type_traits/invariant.hpp similarity index 69% rename from include/boost/contract/aux_/invariant.hpp rename to include/boost/contract/aux_/type_traits/invariant.hpp index 9603458..6ad4b93 100644 --- a/include/boost/contract/aux_/invariant.hpp +++ b/include/boost/contract/aux_/type_traits/invariant.hpp @@ -1,22 +1,22 @@ -#ifndef BOOST_CONTRACT_AUX_INVARIANT_HPP_ -#define BOOST_CONTRACT_AUX_INVARIANT_HPP_ +#ifndef BOOST_CONTRACT_AUX_TYPE_TRAITS_INVARIANT_HPP_ +#define BOOST_CONTRACT_AUX_TYPE_TRAITS_INVARIANT_HPP_ #include -#include +#include #include #include -namespace boost { namespace contract { namespace aux { +namespace boost { namespace contract { namespace aux { namespace type_traits { namespace invariant_ { - BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_MEMBER_FUNCTION(has_invariant, - BOOST_CONTRACT_CONFIG_INVARIANT) + BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION( + has_invariant, BOOST_CONTRACT_CONFIG_INVARIANT) - BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_MEMBER_FUNCTION( + BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION( has_non_static_invariant, BOOST_CONTRACT_CONFIG_STATIC_INVARIANT) - BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_STATIC_MEMBER_FUNCTION( + BOOST_CONTRACT_AUX_TYPE_TRAITS_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 index af8d1e7..4327d86 100644 --- a/include/boost/contract/base_types.hpp +++ b/include/boost/contract/base_types.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/contract/constructor.hpp b/include/boost/contract/constructor.hpp index 847280c..91608a6 100644 --- a/include/boost/contract/constructor.hpp +++ b/include/boost/contract/constructor.hpp @@ -3,7 +3,7 @@ #define BOOST_CONTRACT_CONSTRUCTOR_HPP_ #include -#include +#include #include namespace boost { namespace contract { @@ -11,7 +11,7 @@ namespace boost { namespace contract { template boost::contract::type constructor(Class* const object) { return boost::contract::type(boost::make_shared >(object)); + function::constructor >(object)); } // Uses Class tparam to avoid multiple inheritance from same type. diff --git a/include/boost/contract/destructor.hpp b/include/boost/contract/destructor.hpp index 5930310..f26f4dc 100644 --- a/include/boost/contract/destructor.hpp +++ b/include/boost/contract/destructor.hpp @@ -3,7 +3,7 @@ #define BOOST_CONTRACT_DESTRUCTOR_HPP_ #include -#include +#include #include namespace boost { namespace contract { @@ -11,7 +11,7 @@ namespace boost { namespace contract { template boost::contract::type destructor(Class* const object) { return boost::contract::type(boost::make_shared >(object)); + function::destructor >(object)); } } } // namespace diff --git a/include/boost/contract/free_function.hpp b/include/boost/contract/free_function.hpp index a7c58b8..07c866a 100644 --- a/include/boost/contract/free_function.hpp +++ b/include/boost/contract/free_function.hpp @@ -3,14 +3,14 @@ #define BOOST_CONTRACT_FREE_FUNCTION_HPP_ #include -#include +#include #include namespace boost { namespace contract { boost::contract::type free_function() { return boost::contract::type(boost::make_shared()); + function::free_function>()); } } } // namespace diff --git a/include/boost/contract/introspect.hpp b/include/boost/contract/introspect.hpp index 9b36767..b8af212 100644 --- a/include/boost/contract/introspect.hpp +++ b/include/boost/contract/introspect.hpp @@ -2,20 +2,20 @@ #ifndef BOOST_CONTRACT_INTROSPECT_HPP_ #define BOOST_CONTRACT_INTROSPECT_HPP_ -#include +#include #include #include /* PUBLIC */ #define BOOST_CONTRACT_INTROSPECT(function_name) \ - BOOST_CONTRACT_TRAIT_INTROSPECT(BOOST_PP_CAT(introspect_, function_name), \ + BOOST_CONTRACT_INTROSPECT_TRAIT(BOOST_PP_CAT(introspect_, function_name), \ function_name) -#define BOOST_CONTRACT_TRAIT_INTROSPECT(trait_name, function_name) \ +#define BOOST_CONTRACT_INTROSPECT_TRAIT(trait_name, function_name) \ struct trait_name { \ - BOOST_CONTRACT_AUX_TTI_TRAIT_HAS_MEMBER_FUNCTION(has_member_function, \ - function_name) \ + BOOST_CONTRACT_AUX_TYPE_TRAITS_INTROSPECTION_HAS_MEMBER_FUNCTION( \ + has_member_function, function_name) \ \ template \ diff --git a/include/boost/contract/private_member.hpp b/include/boost/contract/private_member.hpp index 3dcc34a..3f9849a 100644 --- a/include/boost/contract/private_member.hpp +++ b/include/boost/contract/private_member.hpp @@ -3,7 +3,7 @@ #define BOOST_CONTRACT_PRIVATE_MEMBER_HPP_ #include -#include +#include #include // TOOD: On C++11 Clang... these could static_assert enclosing func is not pub? @@ -12,7 +12,7 @@ namespace boost { namespace contract { boost::contract::type private_member() { return boost::contract::type(boost::make_shared()); + function::private_member>()); } } } // namespace diff --git a/include/boost/contract/protected_member.hpp b/include/boost/contract/protected_member.hpp index a38c81f..359fe13 100644 --- a/include/boost/contract/protected_member.hpp +++ b/include/boost/contract/protected_member.hpp @@ -3,7 +3,7 @@ #define BOOST_CONTRACT_PROTECTED_MEMBER_HPP_ #include -#include +#include #include // TOOD: On C++11 Clang... these could static_assert enclosing func is not pub? @@ -12,7 +12,7 @@ namespace boost { namespace contract { boost::contract::type protected_member() { return boost::contract::type(boost::make_shared()); + function::protected_member>()); } } } // namespace diff --git a/include/boost/contract/public_member.hpp b/include/boost/contract/public_member.hpp index 78f066a..d1986b8 100644 --- a/include/boost/contract/public_member.hpp +++ b/include/boost/contract/public_member.hpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include #include // TODO: On C++11 Clang... these could static_assert enclosing func is pub? @@ -42,7 +43,7 @@ template >( + function::public_member >( v, object, argument0) ); } @@ -56,7 +57,7 @@ template >( + function::public_member >( object, argument0) ); } @@ -67,7 +68,7 @@ template boost::contract::type public_member(Class* const object, boost::contract::virtual_body const v) { return boost::contract::type(boost::make_shared >(v, object)); + function::public_member >(v, object)); } // Contract for public member functions with a non-virtual body and members of a @@ -75,14 +76,14 @@ boost::contract::type public_member(Class* const object, template boost::contract::type public_member(Class* const object) { return boost::contract::type(boost::make_shared >(object)); + function::public_member >(object)); } // Contract for public static member functions. template boost::contract::type public_member() { return boost::contract::type(boost::make_shared >()); + function::public_static_member >()); } } } // namespace diff --git a/include/boost/contract/virtual_body.hpp b/include/boost/contract/virtual_body.hpp index 1796186..1b8bc42 100644 --- a/include/boost/contract/virtual_body.hpp +++ b/include/boost/contract/virtual_body.hpp @@ -5,9 +5,14 @@ namespace boost { namespace contract { namespace aux { - template class base_function; - template class basic_function; - template class public_member; + namespace check { + template + class subcontracted_pre_post_inv; + } + namespace function { + template + class public_member; + } } // Must be efficient to pass this as value param (to limit user API verbosity). @@ -23,12 +28,10 @@ private: // they make the impl hard to follow). These ones are necessary because // they are between public and private APIs of the lib. But maybe // the ones among some of the private APIs of the lib could be reduced... - template friend class - boost::contract::aux::base_function; template friend class - boost::contract::aux::basic_function; + boost::contract::aux::check::subcontracted_pre_post_inv; template friend class - boost::contract::aux::public_member; + boost::contract::aux::function::public_member; enum action_type { user_call, diff --git a/test/has_bases.cpp b/test/has_bases.cpp index 9141a4b..d915d1f 100644 --- a/test/has_bases.cpp +++ b/test/has_bases.cpp @@ -1,5 +1,5 @@ -#include +#include #include #include @@ -11,10 +11,10 @@ struct x : y, z { }; int main() { - BOOST_TEST(!boost::contract::aux::has_bases::value); - BOOST_TEST(boost::contract::aux::has_bases::value); - BOOST_TEST((boost::is_same::type, - boost::mpl::vector >::value)); + BOOST_TEST(!boost::contract::aux::type_traits::has_bases::value); + BOOST_TEST(boost::contract::aux::type_traits::has_bases::value); + BOOST_TEST((boost::is_same:: + type, boost::mpl::vector >::value)); return boost::report_errors(); } diff --git a/test/has_invariant.cpp b/test/has_invariant.cpp index 711f895..c1b45c8 100644 --- a/test/has_invariant.cpp +++ b/test/has_invariant.cpp @@ -1,5 +1,5 @@ -#include +#include #include struct x {}; // Test no invariants. @@ -29,35 +29,37 @@ struct ns { }; int main() { - BOOST_TEST(!boost::contract::aux::has_const_invariant::value); - BOOST_TEST(!boost::contract::aux::has_const_volatile_invariant::value); - BOOST_TEST(!boost::contract::aux::has_invariant::value); - BOOST_TEST(!boost::contract::aux::has_static_invariant::value); - BOOST_TEST(!boost::contract::aux::has_non_static_invariant::value); + using namespace boost::contract::aux::type_traits; + + BOOST_TEST(!has_const_invariant::value); + BOOST_TEST(!has_const_volatile_invariant::value); + BOOST_TEST(!has_invariant::value); + BOOST_TEST(!has_static_invariant::value); + BOOST_TEST(!has_non_static_invariant::value); - BOOST_TEST( boost::contract::aux::has_const_invariant::value); - BOOST_TEST(!boost::contract::aux::has_const_volatile_invariant::value); - BOOST_TEST(!boost::contract::aux::has_invariant::value); - BOOST_TEST(!boost::contract::aux::has_static_invariant::value); - BOOST_TEST(!boost::contract::aux::has_non_static_invariant::value); + BOOST_TEST( has_const_invariant::value); + BOOST_TEST(!has_const_volatile_invariant::value); + BOOST_TEST(!has_invariant::value); + BOOST_TEST(!has_static_invariant::value); + BOOST_TEST(!has_non_static_invariant::value); - BOOST_TEST(!boost::contract::aux::has_const_invariant::value); - BOOST_TEST( boost::contract::aux::has_const_volatile_invariant::value); - BOOST_TEST(!boost::contract::aux::has_invariant::value); - BOOST_TEST(!boost::contract::aux::has_static_invariant::value); - BOOST_TEST(!boost::contract::aux::has_non_static_invariant::value); + BOOST_TEST(!has_const_invariant::value); + BOOST_TEST( has_const_volatile_invariant::value); + BOOST_TEST(!has_invariant::value); + BOOST_TEST(!has_static_invariant::value); + BOOST_TEST(!has_non_static_invariant::value); - BOOST_TEST(!boost::contract::aux::has_const_invariant::value); - BOOST_TEST(!boost::contract::aux::has_const_volatile_invariant::value); - BOOST_TEST( boost::contract::aux::has_invariant::value); - BOOST_TEST(!boost::contract::aux::has_static_invariant::value); - BOOST_TEST(!boost::contract::aux::has_non_static_invariant::value); + BOOST_TEST(!has_const_invariant::value); + BOOST_TEST(!has_const_volatile_invariant::value); + BOOST_TEST( has_invariant::value); + BOOST_TEST(!has_static_invariant::value); + BOOST_TEST(!has_non_static_invariant::value); - BOOST_TEST(!boost::contract::aux::has_const_invariant::value); - BOOST_TEST(!boost::contract::aux::has_const_volatile_invariant::value); - BOOST_TEST(!boost::contract::aux::has_invariant::value); - BOOST_TEST(!boost::contract::aux::has_static_invariant::value); - BOOST_TEST( boost::contract::aux::has_non_static_invariant::value); + BOOST_TEST(!has_const_invariant::value); + BOOST_TEST(!has_const_volatile_invariant::value); + BOOST_TEST(!has_invariant::value); + BOOST_TEST(!has_static_invariant::value); + BOOST_TEST( has_non_static_invariant::value); return boost::report_errors(); }