diff options
Diffstat (limited to 'boost/contract/detail/condition/cond_base.hpp')
-rw-r--r-- | boost/contract/detail/condition/cond_base.hpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/boost/contract/detail/condition/cond_base.hpp b/boost/contract/detail/condition/cond_base.hpp new file mode 100644 index 0000000000..c3f4090461 --- /dev/null +++ b/boost/contract/detail/condition/cond_base.hpp @@ -0,0 +1,153 @@ + +#ifndef BOOST_CONTRACT_DETAIL_COND_BASE_HPP_ +#define BOOST_CONTRACT_DETAIL_COND_BASE_HPP_ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +// NOTE: It seemed not possible to implement this library without inheritance +// here because some sort of base type needs to be used to hold contract objects +// in instances of boost::contract::check while polymorphically calling +// init and destructor functions to check contracts at entry and exit. This +// could be possible without inheritance only if boost::contract::check was made +// a template type but that would complicate user code. In any case, early +// experimentation with removing this base class and its virtual methods did not +// seem to reduce compilation and/or run time. + +#include <boost/contract/core/exception.hpp> +#include <boost/contract/core/config.hpp> +#if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_OLDS) || \ + !defined(BOOST_CONTRACT_NO_EXEPTS) + #include <boost/function.hpp> +#endif +#include <boost/noncopyable.hpp> +#ifndef BOOST_CONTRACT_ON_MISSING_CHECK_DECL + #include <boost/assert.hpp> +#endif +#include <boost/config.hpp> + +namespace boost { namespace contract { namespace detail { + +class cond_base : // Base to hold all contract objects for RAII. + private boost::noncopyable // Avoid copying possible user's ftor captures. +{ +public: + explicit cond_base(boost::contract::from from) : + BOOST_CONTRACT_ERROR_missing_check_object_declaration(false) + , init_asserted_(false) + #ifndef BOOST_CONTRACT_NO_CONDITIONS + , from_(from) + , failed_(false) + #endif + {} + + // Can override for checking on exit, but should call assert_initialized(). + virtual ~cond_base() BOOST_NOEXCEPT_IF(false) { + // Catch error (but later) even if overrides miss assert_initialized(). + if(!init_asserted_) assert_initialized(); + } + + void initialize() { // Must be called by owner ctor (i.e., check class). + BOOST_CONTRACT_ERROR_missing_check_object_declaration = true; + this->init(); // So all inits (pre, old, post) done after owner decl. + } + + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + template<typename F> + void set_pre(F const& f) { pre_ = f; } + #endif + + #ifndef BOOST_CONTRACT_NO_OLDS + template<typename F> + void set_old(F const& f) { old_ = f; } + #endif + + #ifndef BOOST_CONTRACT_NO_EXCEPTS + template<typename F> + void set_except(F const& f) { except_ = f; } + #endif + +protected: + void assert_initialized() { // Derived dtors must assert this at entry. + init_asserted_ = true; + #ifdef BOOST_CONTRACT_ON_MISSING_CHECK_DECL + if(!BOOST_CONTRACT_ERROR_missing_check_object_declaration) { + BOOST_CONTRACT_ON_MISSING_CHECK_DECL; + } + #else + // Cannot use a macro instead of this ERROR_... directly here + // because assert will not expand it in the error message. + BOOST_ASSERT(BOOST_CONTRACT_ERROR_missing_check_object_declaration); + #endif + } + + virtual void init() {} // Override for checking on entry. + + // Return true if actually checked calling user ftor. + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + bool check_pre(bool throw_on_failure = false) { + if(failed()) return true; + try { if(pre_) pre_(); else return false; } + catch(...) { + // Subcontracted pre must throw on failure (instead of + // calling failure handler) so to be checked in logic-or. + if(throw_on_failure) throw; + fail(&boost::contract::precondition_failure); + } + return true; + } + #endif + + #ifndef BOOST_CONTRACT_NO_OLDS + void copy_old() { + if(failed()) return; + try { if(old_) old_(); } + catch(...) { fail(&boost::contract::old_failure); } + } + #endif + + #ifndef BOOST_CONTRACT_NO_EXCEPTS + void check_except() { + if(failed()) return; + try { if(except_) except_(); } + catch(...) { fail(&boost::contract::except_failure); } + } + #endif + + #ifndef BOOST_CONTRACT_NO_CONDITIONS + void fail(void (*h)(boost::contract::from)) { + failed(true); + if(h) h(from_); + } + + // Virtual so overriding pub func can use virtual_::failed_ instead. + virtual bool failed() const { return failed_; } + virtual void failed(bool value) { failed_ = value; } + #endif + +private: + bool BOOST_CONTRACT_ERROR_missing_check_object_declaration; + bool init_asserted_; // Avoid throwing twice from dtors (undef behavior). + #ifndef BOOST_CONTRACT_NO_CONDITIONS + boost::contract::from from_; + bool failed_; + #endif + // Following use Boost.Function to handle also lambdas, binds, etc. + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + boost::function<void ()> pre_; + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + boost::function<void ()> old_; + #endif + #ifndef BOOST_CONTRACT_NO_EXCEPTS + boost::function<void ()> except_; + #endif +}; + +} } } // namespace + +#endif // #include guard + |