• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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