File indexing completed on 2025-01-18 09:30:26
0001
0002 #ifndef BOOST_CONTRACT_DETAIL_COND_INV_HPP_
0003 #define BOOST_CONTRACT_DETAIL_COND_INV_HPP_
0004
0005
0006
0007
0008
0009
0010 #include <boost/contract/core/exception.hpp>
0011 #include <boost/contract/core/config.hpp>
0012 #include <boost/contract/detail/condition/cond_post.hpp>
0013 #ifndef BOOST_CONTRACT_NO_INVARIANTS
0014 #include <boost/contract/core/access.hpp>
0015 #include <boost/type_traits/add_pointer.hpp>
0016 #include <boost/type_traits/is_volatile.hpp>
0017 #include <boost/mpl/vector.hpp>
0018 #include <boost/mpl/transform.hpp>
0019 #include <boost/mpl/for_each.hpp>
0020 #include <boost/mpl/copy_if.hpp>
0021 #include <boost/mpl/eval_if.hpp>
0022 #include <boost/mpl/not.hpp>
0023 #include <boost/mpl/and.hpp>
0024 #include <boost/mpl/placeholders.hpp>
0025 #include <boost/utility/enable_if.hpp>
0026 #ifndef BOOST_CONTRACT_PERMISSIVE
0027 #include <boost/function_types/property_tags.hpp>
0028 #include <boost/static_assert.hpp>
0029 #endif
0030 #endif
0031
0032 namespace boost { namespace contract { namespace detail {
0033
0034 template<typename VR, class C>
0035 class cond_inv : public cond_post<VR> {
0036 #if !defined(BOOST_CONTRACT_NO_INVARIANTS) && \
0037 !defined(BOOST_CONTRACT_PERMISSIVE)
0038 BOOST_STATIC_ASSERT_MSG(
0039 (!boost::contract::access::has_static_invariant_f<
0040 C, void, boost::mpl:: vector<>
0041 >::value),
0042 "static invariant member function cannot be mutable "
0043 "(it must be static instead)"
0044 );
0045 BOOST_STATIC_ASSERT_MSG(
0046 (!boost::contract::access::has_static_invariant_f<
0047 C, void, boost::mpl::vector<>,
0048 boost::function_types::const_non_volatile
0049 >::value),
0050 "static invariant member function cannot be const qualified "
0051 "(it must be static instead)"
0052 );
0053 BOOST_STATIC_ASSERT_MSG(
0054 (!boost::contract::access::has_static_invariant_f<
0055 C, void, boost::mpl::vector<>,
0056 boost::function_types::volatile_non_const
0057 >::value),
0058 "static invariant member function cannot be volatile qualified "
0059 "(it must be static instead)"
0060 );
0061 BOOST_STATIC_ASSERT_MSG(
0062 (!boost::contract::access::has_static_invariant_f<
0063 C, void, boost::mpl::vector<>,
0064 boost::function_types::cv_qualified
0065 >::value),
0066 "static invariant member function cannot be const volatile "
0067 "qualified (it must be static instead)"
0068 );
0069
0070 BOOST_STATIC_ASSERT_MSG(
0071 (!boost::contract::access::has_invariant_s<
0072 C, void, boost::mpl::vector<>
0073 >::value),
0074 "non-static invariant member function cannot be static "
0075 "(it must be either const or const volatile qualified instead)"
0076 );
0077 BOOST_STATIC_ASSERT_MSG(
0078 (!boost::contract::access::has_invariant_f<
0079 C, void, boost::mpl::vector<>,
0080 boost::function_types::non_cv
0081 >::value),
0082 "non-static invariant member function cannot be mutable "
0083 "(it must be either const or const volatile qualified instead)"
0084 );
0085 BOOST_STATIC_ASSERT_MSG(
0086 (!boost::contract::access::has_invariant_f<
0087 C, void, boost::mpl::vector<>,
0088 boost::function_types::volatile_non_const
0089 >::value),
0090 "non-static invariant member function cannot be volatile qualified "
0091 "(it must be const or const volatile qualified instead)"
0092 );
0093 #endif
0094
0095 public:
0096
0097 explicit cond_inv(boost::contract::from from, C* obj) :
0098 cond_post<VR>(from)
0099 #ifndef BOOST_CONTRACT_NO_CONDITIONS
0100 , obj_(obj)
0101 #endif
0102 {}
0103
0104 protected:
0105 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
0106 void check_entry_inv() { check_inv(true, false, false); }
0107 void check_entry_static_inv() { check_inv(true, true, false); }
0108 void check_entry_all_inv() { check_inv(true, false, true); }
0109 #endif
0110
0111 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
0112 void check_exit_inv() { check_inv(false, false, false); }
0113 void check_exit_static_inv() { check_inv(false, true, false); }
0114 void check_exit_all_inv() { check_inv(false, false, true); }
0115 #endif
0116
0117 #ifndef BOOST_CONTRACT_NO_CONDITIONS
0118 C* object() { return obj_; }
0119 #endif
0120
0121 private:
0122 #ifndef BOOST_CONTRACT_NO_INVARIANTS
0123
0124 void check_inv(bool on_entry, bool static_only, bool const_and_cv) {
0125 if(this->failed()) return;
0126 try {
0127
0128 check_static_inv<C>();
0129 if(!static_only) {
0130 if(const_and_cv) {
0131 check_cv_inv<C>();
0132 check_const_inv<C>();
0133 } else if(boost::is_volatile<C>::value) {
0134 check_cv_inv<C>();
0135 } else {
0136 check_const_inv<C>();
0137 }
0138 }
0139 } catch(...) {
0140 if(on_entry) {
0141 this->fail(&boost::contract::entry_invariant_failure);
0142 } else this->fail(&boost::contract::exit_invariant_failure);
0143 }
0144 }
0145
0146 template<class C_>
0147 typename boost::disable_if<
0148 boost::contract::access::has_const_invariant<C_> >::type
0149 check_const_inv() {}
0150
0151 template<class C_>
0152 typename boost::enable_if<
0153 boost::contract::access::has_const_invariant<C_> >::type
0154 check_const_inv() { boost::contract::access::const_invariant(obj_); }
0155
0156 template<class C_>
0157 typename boost::disable_if<
0158 boost::contract::access::has_cv_invariant<C_> >::type
0159 check_cv_inv() {}
0160
0161 template<class C_>
0162 typename boost::enable_if<
0163 boost::contract::access::has_cv_invariant<C_> >::type
0164 check_cv_inv() { boost::contract::access::cv_invariant(obj_); }
0165
0166 template<class C_>
0167 typename boost::disable_if<
0168 boost::contract::access::has_static_invariant<C_> >::type
0169 check_static_inv() {}
0170
0171 template<class C_>
0172 typename boost::enable_if<
0173 boost::contract::access::has_static_invariant<C_> >::type
0174 check_static_inv() {
0175
0176
0177 if(!inherited<boost::contract::access::has_static_invariant,
0178 boost::contract::access::static_invariant_addr>::apply()) {
0179 boost::contract::access::static_invariant<C_>();
0180 }
0181 }
0182
0183
0184 template<template<class> class HasFunc, template<class> class FuncAddr>
0185 struct inherited {
0186 static bool apply() {
0187 try {
0188 boost::mpl::for_each<
0189
0190
0191 typename boost::mpl::transform<
0192 typename boost::mpl::copy_if<
0193 typename boost::mpl::eval_if<boost::contract::
0194 access::has_base_types<C>,
0195 typename boost::contract::access::
0196 base_types_of<C>
0197 ,
0198 boost::mpl::vector<>
0199 >::type,
0200 HasFunc<boost::mpl::_1>
0201 >::type,
0202 boost::add_pointer<boost::mpl::_1>
0203 >::type
0204 >(compare_func_addr());
0205 } catch(signal_equal const&) { return true; }
0206 return false;
0207 }
0208
0209 private:
0210 class signal_equal {};
0211
0212 struct compare_func_addr {
0213 template<typename B>
0214 void operator()(B*) {
0215
0216 if(FuncAddr<C>::apply() == FuncAddr<B>::apply()) {
0217 throw signal_equal();
0218 }
0219 }
0220 };
0221 };
0222 #endif
0223
0224 #ifndef BOOST_CONTRACT_NO_CONDITIONS
0225 C* obj_;
0226 #endif
0227 };
0228
0229 } } }
0230
0231 #endif
0232