cond_base.hpp 5.4 KB

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