#ifndef BOOST_CONTRACT_DETAIL_COND_INV_HPP_ #define BOOST_CONTRACT_DETAIL_COND_INV_HPP_ // Copyright (C) 2008-2018 Lorenzo Caminiti // Distributed under the Boost Software License, Version 1.0 (see accompanying // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html #include #include #include #ifndef BOOST_CONTRACT_NO_INVARIANTS #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BOOST_CONTRACT_PERMISSIVE #include #include #endif #endif namespace boost { namespace contract { namespace detail { template class cond_inv : public cond_post { // Non-copyable base. #if !defined(BOOST_CONTRACT_NO_INVARIANTS) && \ !defined(BOOST_CONTRACT_PERMISSIVE) BOOST_STATIC_ASSERT_MSG( (!boost::contract::access::has_static_invariant_f< C, void, boost::mpl:: vector<> >::value), "static invariant member function cannot be mutable " "(it must be static instead)" ); BOOST_STATIC_ASSERT_MSG( (!boost::contract::access::has_static_invariant_f< C, void, boost::mpl::vector<>, boost::function_types::const_non_volatile >::value), "static invariant member function cannot be const qualified " "(it must be static instead)" ); BOOST_STATIC_ASSERT_MSG( (!boost::contract::access::has_static_invariant_f< C, void, boost::mpl::vector<>, boost::function_types::volatile_non_const >::value), "static invariant member function cannot be volatile qualified " "(it must be static instead)" ); BOOST_STATIC_ASSERT_MSG( (!boost::contract::access::has_static_invariant_f< C, void, boost::mpl::vector<>, boost::function_types::cv_qualified >::value), "static invariant member function cannot be const volatile " "qualified (it must be static instead)" ); BOOST_STATIC_ASSERT_MSG( (!boost::contract::access::has_invariant_s< C, void, boost::mpl::vector<> >::value), "non-static invariant member function cannot be static " "(it must be either const or const volatile qualified instead)" ); BOOST_STATIC_ASSERT_MSG( (!boost::contract::access::has_invariant_f< C, void, boost::mpl::vector<>, boost::function_types::non_cv >::value), "non-static invariant member function cannot be mutable " "(it must be either const or const volatile qualified instead)" ); BOOST_STATIC_ASSERT_MSG( (!boost::contract::access::has_invariant_f< C, void, boost::mpl::vector<>, boost::function_types::volatile_non_const >::value), "non-static invariant member function cannot be volatile qualified " "(it must be const or const volatile qualified instead)" ); #endif public: // obj can be 0 for static member functions. explicit cond_inv(boost::contract::from from, C* obj) : cond_post(from) #ifndef BOOST_CONTRACT_NO_CONDITIONS , obj_(obj) #endif {} protected: #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS void check_entry_inv() { check_inv(true, false, false); } void check_entry_static_inv() { check_inv(true, true, false); } void check_entry_all_inv() { check_inv(true, false, true); } #endif #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS void check_exit_inv() { check_inv(false, false, false); } void check_exit_static_inv() { check_inv(false, true, false); } void check_exit_all_inv() { check_inv(false, false, true); } #endif #ifndef BOOST_CONTRACT_NO_CONDITIONS C* object() { return obj_; } #endif private: #ifndef BOOST_CONTRACT_NO_INVARIANTS // Static, cv, and const inv in that order as strongest qualifier first. void check_inv(bool on_entry, bool static_only, bool const_and_cv) { if(this->failed()) return; try { // Static members only check static inv. check_static_inv(); if(!static_only) { if(const_and_cv) { check_cv_inv(); check_const_inv(); } else if(boost::is_volatile::value) { check_cv_inv(); } else { check_const_inv(); } } } catch(...) { if(on_entry) { this->fail(&boost::contract::entry_invariant_failure); } else this->fail(&boost::contract::exit_invariant_failure); } } template typename boost::disable_if< boost::contract::access::has_const_invariant >::type check_const_inv() {} template typename boost::enable_if< boost::contract::access::has_const_invariant >::type check_const_inv() { boost::contract::access::const_invariant(obj_); } template typename boost::disable_if< boost::contract::access::has_cv_invariant >::type check_cv_inv() {} template typename boost::enable_if< boost::contract::access::has_cv_invariant >::type check_cv_inv() { boost::contract::access::cv_invariant(obj_); } template typename boost::disable_if< boost::contract::access::has_static_invariant >::type check_static_inv() {} template typename boost::enable_if< boost::contract::access::has_static_invariant >::type check_static_inv() { // SFINAE HAS_STATIC_... returns true even when member is inherited // so extra run-time check here (not the same for non static). if(!inherited::apply()) { boost::contract::access::static_invariant(); } } // Check if class's func is inherited from its base types or not. template class HasFunc, template class FuncAddr> struct inherited { static bool apply() { try { boost::mpl::for_each< // For now, no reason to deeply search inheritance tree // (SFINAE HAS_STATIC_... already fails in that case). typename boost::mpl::transform< typename boost::mpl::copy_if< typename boost::mpl::eval_if, typename boost::contract::access:: base_types_of , boost::mpl::vector<> >::type, HasFunc >::type, boost::add_pointer >::type >(compare_func_addr()); } catch(signal_equal const&) { return true; } return false; } private: class signal_equal {}; // Except. to stop for_each as soon as found. struct compare_func_addr { template void operator()(B*) { // Inherited func has same addr as in its base. if(FuncAddr::apply() == FuncAddr::apply()) { throw signal_equal(); } } }; }; #endif #ifndef BOOST_CONTRACT_NO_CONDITIONS C* obj_; #endif }; } } } // namespace #endif // #include guard