#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 #include #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ !defined(BOOST_CONTRACT_NO_OLDS) || \ !defined(BOOST_CONTRACT_NO_EXEPTS) #include #endif #include #ifndef BOOST_CONTRACT_ON_MISSING_CHECK_DECL #include #endif #include 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 void set_pre(F const& f) { pre_ = f; } #endif #ifndef BOOST_CONTRACT_NO_OLDS template void set_old(F const& f) { old_ = f; } #endif #ifndef BOOST_CONTRACT_NO_EXCEPTS template 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 pre_; #endif #ifndef BOOST_CONTRACT_NO_OLDS boost::function old_; #endif #ifndef BOOST_CONTRACT_NO_EXCEPTS boost::function except_; #endif }; } } } // namespace #endif // #include guard