check.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #ifndef BOOST_CONTRACT_CHECK_HPP_
  2. #define BOOST_CONTRACT_CHECK_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. /** @file
  8. RAII object that checks contracts.
  9. */
  10. #include <boost/contract/core/config.hpp>
  11. #include <boost/contract/core/check_macro.hpp>
  12. #include <boost/contract/core/specify.hpp>
  13. #include <boost/contract/core/exception.hpp> // For set_... (if always in code).
  14. #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
  15. defined(BOOST_CONTRACT_STATIC_LINK)
  16. #include <boost/contract/detail/condition/cond_base.hpp>
  17. #include <boost/contract/detail/auto_ptr.hpp>
  18. #include <boost/contract/detail/debug.hpp>
  19. #endif
  20. #include <boost/contract/detail/check.hpp>
  21. #include <boost/config.hpp>
  22. /* PRIVATE */
  23. /** @cond */
  24. #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
  25. defined(BOOST_CONTRACT_STATIC_LINK)
  26. #define BOOST_CONTRACT_CHECK_CTOR_DEF_(contract_type) \
  27. : cond_(const_cast<contract_type&>(contract).cond_.release()) \
  28. { \
  29. BOOST_CONTRACT_DETAIL_DEBUG(cond_); \
  30. cond_->initialize(); \
  31. }
  32. #else
  33. #define BOOST_CONTRACT_CHECK_CTOR_DEF_(contract_type) {}
  34. #endif
  35. /** @endcond */
  36. /* CODE */
  37. namespace boost { namespace contract {
  38. /**
  39. RAII object that checks the contracts.
  40. In general, when this object is constructed it checks class invariants at entry,
  41. preconditions, and makes old value copies at body.
  42. When it is destructed, it checks class invariants at exist, postconditions, and
  43. exception guarantees.
  44. This object enforces the following (see
  45. @RefSect{contract_programming_overview, Contract Programming Overview}):
  46. @li Postconditions are checked only if the body does not throw an exception.
  47. @li Exceptions guarantees are checked only if the body throws an exception.
  48. @li Constructor entry never checks class invariants.
  49. @li Destructor exit checks class invariants only if the body throws an
  50. exception (even if destructors should usually not be programmed to throw
  51. exceptions in C++).
  52. @li Static invariants are always checked at entry and exit (and regardless of
  53. the body throwing exceptions or not).
  54. When used this way, this object is usually constructed and initialized to the
  55. return value of one of the contract functions
  56. @RefFunc{boost::contract::function}, @RefFunc{boost::contract::constructor},
  57. @RefFunc{boost::contract::destructor}, or
  58. @RefFunc{boost::contract::public_function}.
  59. In addition, this object can be constructed from a nullary functor that is used
  60. to program implementation checks.
  61. @see @RefSect{tutorial, Tutorial},
  62. @RefSect{advanced.implementation_checks, Implementation Checks}
  63. */
  64. class check { // Copy ctor only (as move via ptr release).
  65. public:
  66. // NOTE: Unfortunately, Apple compilers define a `check(...)` macro that
  67. // clashes with the name of this class. In the following code,
  68. // BOOST_PREVENT_MACRO_SUBSTITUTION is used to workaround these name
  69. // clashes. In user code, `check c = ...` syntax is typically used also
  70. // avoiding clashes.
  71. /**
  72. Construct this object for implementation checks.
  73. This can be used to program checks within implementation code (body, etc.).
  74. This constructor is not declared @c explicit so initializations can use
  75. assignment syntax @c =.
  76. @b Throws: This can throw in case programmers specify contract failure
  77. handlers that throw exceptions instead of terminating the
  78. program (see
  79. @RefSect{advanced.throw_on_failures__and__noexcept__,
  80. Throw on Failure}).
  81. @param f Nullary functor that asserts implementation checks. @c f() will
  82. be called as soon as this object is constructed at the point it
  83. is declared within the implementation code (see
  84. @RefSect{advanced.implementation_checks,
  85. Implementation Checks}).
  86. */
  87. template<typename F> // Cannot check `if(f) ...` as f can be a lambda.
  88. // f must be a valid callable object (not null func ptr, empty ftor, etc.
  89. /* implicit */ check
  90. /** @cond **/ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
  91. F const& f) {
  92. BOOST_CONTRACT_DETAIL_CHECK({ f(); })
  93. }
  94. /**
  95. Construct this object copying it from the specified one.
  96. This object will check the contract, the copied-from object will not (i.e.,
  97. contract check ownership is transferred from the copied object to the new
  98. object being created by this constructor).
  99. @param other Copied-from object.
  100. */
  101. check /** @cond **/ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
  102. check const& other)
  103. #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
  104. defined(BOOST_CONTRACT_STATIC_LINK)
  105. // Copy ctor moves cond_ pointer to dest.
  106. : cond_(const_cast<check&>(other).cond_.release())
  107. #endif
  108. {}
  109. /**
  110. Construct this object to check the specified contract.
  111. This checks class invariants at entry (if those apply to the specified
  112. contract).
  113. This constructor is not declared @c explicit so initializations can use
  114. assignment syntax @c =.
  115. @b Throws: This can throw in case programmers specify contract failure
  116. handlers that throw exceptions instead of terminating the
  117. program (see
  118. @RefSect{advanced.throw_on_failures__and__noexcept__,
  119. Throw on Failure}).
  120. @param contract Contract to be checked (usually the return value of
  121. @RefFunc{boost::contract::function} or
  122. @RefFunc{boost::contract::public_function}).
  123. @tparam VirtualResult Return type of the enclosing function declaring the
  124. contract if that is either a virtual or an
  125. overriding public function.
  126. Otherwise, this is always @c void.
  127. */
  128. template<typename VirtualResult>
  129. /* implicit */ check
  130. /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
  131. specify_precondition_old_postcondition_except<VirtualResult> const&
  132. contract
  133. )
  134. #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
  135. BOOST_CONTRACT_CHECK_CTOR_DEF_(
  136. specify_precondition_old_postcondition_except<VirtualResult>)
  137. #else
  138. ;
  139. #endif
  140. /**
  141. Construct this object to check the specified contract.
  142. This checks class invariants at entry and preconditions (if any of those
  143. apply to the specified contract).
  144. This constructor is not declared @c explicit so initializations can use
  145. assignment syntax @c =.
  146. @b Throws: This can throw in case programmers specify contract failure
  147. handlers that throw exceptions instead of terminating the
  148. program (see
  149. @RefSect{advanced.throw_on_failures__and__noexcept__,
  150. Throw on Failure}).
  151. @param contract Contract to be checked (usually the return value of
  152. @RefFunc{boost::contract::function},
  153. @RefFunc{boost::contract::constructor},
  154. @RefFunc{boost::contract::destructor}, or
  155. @RefFunc{boost::contract::public_function}).
  156. @tparam VirtualResult Return type of the enclosing function declaring the
  157. contract if that is either a virtual or an
  158. overriding public function.
  159. Otherwise, this is always @c void.
  160. */
  161. template<typename VirtualResult>
  162. /* implicit */ check
  163. /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
  164. specify_old_postcondition_except<VirtualResult> const& contract)
  165. #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
  166. BOOST_CONTRACT_CHECK_CTOR_DEF_(
  167. specify_old_postcondition_except<VirtualResult>)
  168. #else
  169. ;
  170. #endif
  171. /**
  172. Construct this object to check the specified contract.
  173. This checks class invariants at entry and preconditions then it makes old
  174. value copies at body (if any of those apply to the specified contract).
  175. This constructor is not declared @c explicit so initializations can use
  176. assignment syntax @c =.
  177. @b Throws: This can throw in case programmers specify contract failure
  178. handlers that throw exceptions instead of terminating te
  179. program (see
  180. @RefSect{advanced.throw_on_failures__and__noexcept__,
  181. Throw on Failure}).
  182. @param contract Contract to be checked (usually the return value of
  183. @RefFunc{boost::contract::function},
  184. @RefFunc{boost::contract::constructor},
  185. @RefFunc{boost::contract::destructor}, or
  186. @RefFunc{boost::contract::public_function}).
  187. @tparam VirtualResult Return type of the enclosing function declaring the
  188. contract if that is either a virtual or an
  189. overriding public function.
  190. Otherwise, this is always @c void.
  191. */
  192. template<typename VirtualResult>
  193. /* implicit */ check
  194. /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
  195. specify_postcondition_except<VirtualResult> const& contract)
  196. #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
  197. BOOST_CONTRACT_CHECK_CTOR_DEF_(
  198. specify_postcondition_except<VirtualResult>)
  199. #else
  200. ;
  201. #endif
  202. /**
  203. Construct this object to check the specified contract.
  204. This checks class invariants at entry and preconditions then it makes old
  205. value copies at body, plus the destructor of this object will check
  206. postconditions in this case (if any of those apply to the specified
  207. contract).
  208. This constructor is not declared @c explicit so initializations can use
  209. assignment syntax @c =.
  210. @b Throws: This can throw in case programmers specify contract failure
  211. handlers that throw exceptions instead of terminating the
  212. program (see
  213. @RefSect{advanced.throw_on_failures__and__noexcept__,
  214. Throw on Failure}).
  215. @param contract Contract to be checked (usually the return value of
  216. @RefFunc{boost::contract::function},
  217. @RefFunc{boost::contract::constructor},
  218. @RefFunc{boost::contract::destructor}, or
  219. @RefFunc{boost::contract::public_function}).
  220. @tparam VirtualResult Return type of the enclosing function declaring the
  221. contract if that is either a virtual or an
  222. overriding public function.
  223. Otherwise, this is always @c void.
  224. */
  225. /* implicit */ check
  226. /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
  227. specify_except const& contract)
  228. #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
  229. BOOST_CONTRACT_CHECK_CTOR_DEF_(specify_except)
  230. #else
  231. ;
  232. #endif
  233. /**
  234. Construct this object to check the specified contract.
  235. This checks class invariants at entry and preconditions then it makes old
  236. value copies at body, plus the destructor of this object will check
  237. postconditions and exception guarantees in this case (if any of those apply
  238. to the specified contract).
  239. This constructor is not declared @c explicit so initializations can use
  240. assignment syntax @c =.
  241. @b Throws: This can throw in case programmers specify contract failure
  242. handlers that throw exceptions instead of terminating the
  243. program (see
  244. @RefSect{advanced.throw_on_failures__and__noexcept__,
  245. Throw on Failure}).
  246. @param contract Contract to be checked (usually the return value of
  247. @RefFunc{boost::contract::function},
  248. @RefFunc{boost::contract::constructor},
  249. @RefFunc{boost::contract::destructor}, or
  250. @RefFunc{boost::contract::public_function}).
  251. @tparam VirtualResult Return type of the enclosing function declaring the
  252. contract if that is either a virtual or an
  253. overriding public function.
  254. Otherwise, this is always @c void.
  255. */
  256. /* implicit */ check
  257. /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
  258. specify_nothing const& contract)
  259. #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
  260. BOOST_CONTRACT_CHECK_CTOR_DEF_(specify_nothing)
  261. #else
  262. ;
  263. #endif
  264. /**
  265. Destruct this object.
  266. This checks class invariants at exit and either postconditions when the
  267. enclosing function body did not throw an exception, or exception guarantees
  268. when the function body threw an exception (that is if class invariants,
  269. postconditions, and exception guarantees respectively apply to the contract
  270. parameter specified when constructing this object).
  271. @b Throws: This can throw in case programmers specify contract failure
  272. handlers that throw exceptions instead of terminating the
  273. program (see
  274. @RefSect{advanced.throw_on_failures__and__noexcept__,
  275. Throw on Failure}).
  276. (This is declared @c noexcept(false) since C++11.)
  277. */
  278. ~check /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ ()
  279. BOOST_NOEXCEPT_IF(false) /* allow auto_ptr dtor to throw */
  280. {}
  281. /** @cond */
  282. private:
  283. check& operator=(check const&); // Cannot copy outside of `check c = ...`.
  284. #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
  285. defined(BOOST_CONTRACT_STATIC_LINK)
  286. boost::contract::detail::auto_ptr<boost::contract::detail::cond_base>
  287. cond_;
  288. #endif
  289. /** @endcond */
  290. };
  291. } } // namespace
  292. #endif // #include guard