1 2 #ifndef BOOST_CONTRACT_DETAIL_COND_BASE_HPP_ 3 #define BOOST_CONTRACT_DETAIL_COND_BASE_HPP_ 4 5 // Copyright (C) 2008-2018 Lorenzo Caminiti 6 // Distributed under the Boost Software License, Version 1.0 (see accompanying 7 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). 8 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html 9 10 // NOTE: It seemed not possible to implement this library without inheritance 11 // here because some sort of base type needs to be used to hold contract objects 12 // in instances of boost::contract::check while polymorphically calling 13 // init and destructor functions to check contracts at entry and exit. This 14 // could be possible without inheritance only if boost::contract::check was made 15 // a template type but that would complicate user code. In any case, early 16 // experimentation with removing this base class and its virtual methods did not 17 // seem to reduce compilation and/or run time. 18 19 #include <boost/contract/core/exception.hpp> 20 #include <boost/contract/core/config.hpp> 21 #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ 22 !defined(BOOST_CONTRACT_NO_OLDS) || \ 23 !defined(BOOST_CONTRACT_NO_EXEPTS) 24 #include <boost/function.hpp> 25 #endif 26 #include <boost/noncopyable.hpp> 27 #ifndef BOOST_CONTRACT_ON_MISSING_CHECK_DECL 28 #include <boost/assert.hpp> 29 #endif 30 #include <boost/config.hpp> 31 32 namespace boost { namespace contract { namespace detail { 33 34 class cond_base : // Base to hold all contract objects for RAII. 35 private boost::noncopyable // Avoid copying possible user's ftor captures. 36 { 37 public: cond_base(boost::contract::from from)38 explicit cond_base(boost::contract::from from) : 39 BOOST_CONTRACT_ERROR_missing_check_object_declaration(false) 40 , init_asserted_(false) 41 #ifndef BOOST_CONTRACT_NO_CONDITIONS 42 , from_(from) 43 , failed_(false) 44 #endif 45 {} 46 47 // Can override for checking on exit, but should call assert_initialized(). BOOST_NOEXCEPT_IF(false)48 virtual ~cond_base() BOOST_NOEXCEPT_IF(false) { 49 // Catch error (but later) even if overrides miss assert_initialized(). 50 if(!init_asserted_) assert_initialized(); 51 } 52 initialize()53 void initialize() { // Must be called by owner ctor (i.e., check class). 54 BOOST_CONTRACT_ERROR_missing_check_object_declaration = true; 55 this->init(); // So all inits (pre, old, post) done after owner decl. 56 } 57 58 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS 59 template<typename F> set_pre(F const & f)60 void set_pre(F const& f) { pre_ = f; } 61 #endif 62 63 #ifndef BOOST_CONTRACT_NO_OLDS 64 template<typename F> set_old(F const & f)65 void set_old(F const& f) { old_ = f; } 66 #endif 67 68 #ifndef BOOST_CONTRACT_NO_EXCEPTS 69 template<typename F> set_except(F const & f)70 void set_except(F const& f) { except_ = f; } 71 #endif 72 73 protected: assert_initialized()74 void assert_initialized() { // Derived dtors must assert this at entry. 75 init_asserted_ = true; 76 #ifdef BOOST_CONTRACT_ON_MISSING_CHECK_DECL 77 if(!BOOST_CONTRACT_ERROR_missing_check_object_declaration) { 78 BOOST_CONTRACT_ON_MISSING_CHECK_DECL; 79 } 80 #else 81 // Cannot use a macro instead of this ERROR_... directly here 82 // because assert will not expand it in the error message. 83 BOOST_ASSERT(BOOST_CONTRACT_ERROR_missing_check_object_declaration); 84 #endif 85 } 86 init()87 virtual void init() {} // Override for checking on entry. 88 89 // Return true if actually checked calling user ftor. 90 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS check_pre(bool throw_on_failure=false)91 bool check_pre(bool throw_on_failure = false) { 92 if(failed()) return true; 93 try { if(pre_) pre_(); else return false; } 94 catch(...) { 95 // Subcontracted pre must throw on failure (instead of 96 // calling failure handler) so to be checked in logic-or. 97 if(throw_on_failure) throw; 98 fail(&boost::contract::precondition_failure); 99 } 100 return true; 101 } 102 #endif 103 104 #ifndef BOOST_CONTRACT_NO_OLDS copy_old()105 void copy_old() { 106 if(failed()) return; 107 try { if(old_) old_(); } 108 catch(...) { fail(&boost::contract::old_failure); } 109 } 110 #endif 111 112 #ifndef BOOST_CONTRACT_NO_EXCEPTS check_except()113 void check_except() { 114 if(failed()) return; 115 try { if(except_) except_(); } 116 catch(...) { fail(&boost::contract::except_failure); } 117 } 118 #endif 119 120 #ifndef BOOST_CONTRACT_NO_CONDITIONS fail(void (* h)(boost::contract::from))121 void fail(void (*h)(boost::contract::from)) { 122 failed(true); 123 if(h) h(from_); 124 } 125 126 // Virtual so overriding pub func can use virtual_::failed_ instead. failed() const127 virtual bool failed() const { return failed_; } failed(bool value)128 virtual void failed(bool value) { failed_ = value; } 129 #endif 130 131 private: 132 bool BOOST_CONTRACT_ERROR_missing_check_object_declaration; 133 bool init_asserted_; // Avoid throwing twice from dtors (undef behavior). 134 #ifndef BOOST_CONTRACT_NO_CONDITIONS 135 boost::contract::from from_; 136 bool failed_; 137 #endif 138 // Following use Boost.Function to handle also lambdas, binds, etc. 139 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS 140 boost::function<void ()> pre_; 141 #endif 142 #ifndef BOOST_CONTRACT_NO_OLDS 143 boost::function<void ()> old_; 144 #endif 145 #ifndef BOOST_CONTRACT_NO_EXCEPTS 146 boost::function<void ()> except_; 147 #endif 148 }; 149 150 } } } // namespace 151 152 #endif // #include guard 153 154