cond_inv.hpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #ifndef BOOST_CONTRACT_DETAIL_COND_INV_HPP_
  2. #define BOOST_CONTRACT_DETAIL_COND_INV_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. #include <boost/contract/core/exception.hpp>
  8. #include <boost/contract/core/config.hpp>
  9. #include <boost/contract/detail/condition/cond_post.hpp>
  10. #ifndef BOOST_CONTRACT_NO_INVARIANTS
  11. #include <boost/contract/core/access.hpp>
  12. #include <boost/type_traits/add_pointer.hpp>
  13. #include <boost/type_traits/is_volatile.hpp>
  14. #include <boost/mpl/vector.hpp>
  15. #include <boost/mpl/transform.hpp>
  16. #include <boost/mpl/for_each.hpp>
  17. #include <boost/mpl/copy_if.hpp>
  18. #include <boost/mpl/eval_if.hpp>
  19. #include <boost/mpl/not.hpp>
  20. #include <boost/mpl/and.hpp>
  21. #include <boost/mpl/placeholders.hpp>
  22. #include <boost/utility/enable_if.hpp>
  23. #ifndef BOOST_CONTRACT_PERMISSIVE
  24. #include <boost/function_types/property_tags.hpp>
  25. #include <boost/static_assert.hpp>
  26. #endif
  27. #endif
  28. namespace boost { namespace contract { namespace detail {
  29. template<typename VR, class C>
  30. class cond_inv : public cond_post<VR> { // Non-copyable base.
  31. #if !defined(BOOST_CONTRACT_NO_INVARIANTS) && \
  32. !defined(BOOST_CONTRACT_PERMISSIVE)
  33. BOOST_STATIC_ASSERT_MSG(
  34. (!boost::contract::access::has_static_invariant_f<
  35. C, void, boost::mpl:: vector<>
  36. >::value),
  37. "static invariant member function cannot be mutable "
  38. "(it must be static instead)"
  39. );
  40. BOOST_STATIC_ASSERT_MSG(
  41. (!boost::contract::access::has_static_invariant_f<
  42. C, void, boost::mpl::vector<>,
  43. boost::function_types::const_non_volatile
  44. >::value),
  45. "static invariant member function cannot be const qualified "
  46. "(it must be static instead)"
  47. );
  48. BOOST_STATIC_ASSERT_MSG(
  49. (!boost::contract::access::has_static_invariant_f<
  50. C, void, boost::mpl::vector<>,
  51. boost::function_types::volatile_non_const
  52. >::value),
  53. "static invariant member function cannot be volatile qualified "
  54. "(it must be static instead)"
  55. );
  56. BOOST_STATIC_ASSERT_MSG(
  57. (!boost::contract::access::has_static_invariant_f<
  58. C, void, boost::mpl::vector<>,
  59. boost::function_types::cv_qualified
  60. >::value),
  61. "static invariant member function cannot be const volatile "
  62. "qualified (it must be static instead)"
  63. );
  64. BOOST_STATIC_ASSERT_MSG(
  65. (!boost::contract::access::has_invariant_s<
  66. C, void, boost::mpl::vector<>
  67. >::value),
  68. "non-static invariant member function cannot be static "
  69. "(it must be either const or const volatile qualified instead)"
  70. );
  71. BOOST_STATIC_ASSERT_MSG(
  72. (!boost::contract::access::has_invariant_f<
  73. C, void, boost::mpl::vector<>,
  74. boost::function_types::non_cv
  75. >::value),
  76. "non-static invariant member function cannot be mutable "
  77. "(it must be either const or const volatile qualified instead)"
  78. );
  79. BOOST_STATIC_ASSERT_MSG(
  80. (!boost::contract::access::has_invariant_f<
  81. C, void, boost::mpl::vector<>,
  82. boost::function_types::volatile_non_const
  83. >::value),
  84. "non-static invariant member function cannot be volatile qualified "
  85. "(it must be const or const volatile qualified instead)"
  86. );
  87. #endif
  88. public:
  89. // obj can be 0 for static member functions.
  90. explicit cond_inv(boost::contract::from from, C* obj) :
  91. cond_post<VR>(from)
  92. #ifndef BOOST_CONTRACT_NO_CONDITIONS
  93. , obj_(obj)
  94. #endif
  95. {}
  96. protected:
  97. #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
  98. void check_entry_inv() { check_inv(true, false, false); }
  99. void check_entry_static_inv() { check_inv(true, true, false); }
  100. void check_entry_all_inv() { check_inv(true, false, true); }
  101. #endif
  102. #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
  103. void check_exit_inv() { check_inv(false, false, false); }
  104. void check_exit_static_inv() { check_inv(false, true, false); }
  105. void check_exit_all_inv() { check_inv(false, false, true); }
  106. #endif
  107. #ifndef BOOST_CONTRACT_NO_CONDITIONS
  108. C* object() { return obj_; }
  109. #endif
  110. private:
  111. #ifndef BOOST_CONTRACT_NO_INVARIANTS
  112. // Static, cv, and const inv in that order as strongest qualifier first.
  113. void check_inv(bool on_entry, bool static_only, bool const_and_cv) {
  114. if(this->failed()) return;
  115. try {
  116. // Static members only check static inv.
  117. check_static_inv<C>();
  118. if(!static_only) {
  119. if(const_and_cv) {
  120. check_cv_inv<C>();
  121. check_const_inv<C>();
  122. } else if(boost::is_volatile<C>::value) {
  123. check_cv_inv<C>();
  124. } else {
  125. check_const_inv<C>();
  126. }
  127. }
  128. } catch(...) {
  129. if(on_entry) {
  130. this->fail(&boost::contract::entry_invariant_failure);
  131. } else this->fail(&boost::contract::exit_invariant_failure);
  132. }
  133. }
  134. template<class C_>
  135. typename boost::disable_if<
  136. boost::contract::access::has_const_invariant<C_> >::type
  137. check_const_inv() {}
  138. template<class C_>
  139. typename boost::enable_if<
  140. boost::contract::access::has_const_invariant<C_> >::type
  141. check_const_inv() { boost::contract::access::const_invariant(obj_); }
  142. template<class C_>
  143. typename boost::disable_if<
  144. boost::contract::access::has_cv_invariant<C_> >::type
  145. check_cv_inv() {}
  146. template<class C_>
  147. typename boost::enable_if<
  148. boost::contract::access::has_cv_invariant<C_> >::type
  149. check_cv_inv() { boost::contract::access::cv_invariant(obj_); }
  150. template<class C_>
  151. typename boost::disable_if<
  152. boost::contract::access::has_static_invariant<C_> >::type
  153. check_static_inv() {}
  154. template<class C_>
  155. typename boost::enable_if<
  156. boost::contract::access::has_static_invariant<C_> >::type
  157. check_static_inv() {
  158. // SFINAE HAS_STATIC_... returns true even when member is inherited
  159. // so extra run-time check here (not the same for non static).
  160. if(!inherited<boost::contract::access::has_static_invariant,
  161. boost::contract::access::static_invariant_addr>::apply()) {
  162. boost::contract::access::static_invariant<C_>();
  163. }
  164. }
  165. // Check if class's func is inherited from its base types or not.
  166. template<template<class> class HasFunc, template<class> class FuncAddr>
  167. struct inherited {
  168. static bool apply() {
  169. try {
  170. boost::mpl::for_each<
  171. // For now, no reason to deeply search inheritance tree
  172. // (SFINAE HAS_STATIC_... already fails in that case).
  173. typename boost::mpl::transform<
  174. typename boost::mpl::copy_if<
  175. typename boost::mpl::eval_if<boost::contract::
  176. access::has_base_types<C>,
  177. typename boost::contract::access::
  178. base_types_of<C>
  179. ,
  180. boost::mpl::vector<>
  181. >::type,
  182. HasFunc<boost::mpl::_1>
  183. >::type,
  184. boost::add_pointer<boost::mpl::_1>
  185. >::type
  186. >(compare_func_addr());
  187. } catch(signal_equal const&) { return true; }
  188. return false;
  189. }
  190. private:
  191. class signal_equal {}; // Except. to stop for_each as soon as found.
  192. struct compare_func_addr {
  193. template<typename B>
  194. void operator()(B*) {
  195. // Inherited func has same addr as in its base.
  196. if(FuncAddr<C>::apply() == FuncAddr<B>::apply()) {
  197. throw signal_equal();
  198. }
  199. }
  200. };
  201. };
  202. #endif
  203. #ifndef BOOST_CONTRACT_NO_CONDITIONS
  204. C* obj_;
  205. #endif
  206. };
  207. } } } // namespace
  208. #endif // #include guard