123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- #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 <boost/contract/core/exception.hpp>
- #include <boost/contract/core/config.hpp>
- #include <boost/contract/detail/condition/cond_post.hpp>
- #ifndef BOOST_CONTRACT_NO_INVARIANTS
- #include <boost/contract/core/access.hpp>
- #include <boost/type_traits/add_pointer.hpp>
- #include <boost/type_traits/is_volatile.hpp>
- #include <boost/mpl/vector.hpp>
- #include <boost/mpl/transform.hpp>
- #include <boost/mpl/for_each.hpp>
- #include <boost/mpl/copy_if.hpp>
- #include <boost/mpl/eval_if.hpp>
- #include <boost/mpl/not.hpp>
- #include <boost/mpl/and.hpp>
- #include <boost/mpl/placeholders.hpp>
- #include <boost/utility/enable_if.hpp>
- #ifndef BOOST_CONTRACT_PERMISSIVE
- #include <boost/function_types/property_tags.hpp>
- #include <boost/static_assert.hpp>
- #endif
- #endif
- namespace boost { namespace contract { namespace detail {
- template<typename VR, class C>
- class cond_inv : public cond_post<VR> { // 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<VR>(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<C>();
- if(!static_only) {
- if(const_and_cv) {
- check_cv_inv<C>();
- check_const_inv<C>();
- } else if(boost::is_volatile<C>::value) {
- check_cv_inv<C>();
- } else {
- check_const_inv<C>();
- }
- }
- } catch(...) {
- if(on_entry) {
- this->fail(&boost::contract::entry_invariant_failure);
- } else this->fail(&boost::contract::exit_invariant_failure);
- }
- }
-
- template<class C_>
- typename boost::disable_if<
- boost::contract::access::has_const_invariant<C_> >::type
- check_const_inv() {}
-
- template<class C_>
- typename boost::enable_if<
- boost::contract::access::has_const_invariant<C_> >::type
- check_const_inv() { boost::contract::access::const_invariant(obj_); }
-
- template<class C_>
- typename boost::disable_if<
- boost::contract::access::has_cv_invariant<C_> >::type
- check_cv_inv() {}
- template<class C_>
- typename boost::enable_if<
- boost::contract::access::has_cv_invariant<C_> >::type
- check_cv_inv() { boost::contract::access::cv_invariant(obj_); }
-
- template<class C_>
- typename boost::disable_if<
- boost::contract::access::has_static_invariant<C_> >::type
- check_static_inv() {}
-
- template<class C_>
- typename boost::enable_if<
- boost::contract::access::has_static_invariant<C_> >::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<boost::contract::access::has_static_invariant,
- boost::contract::access::static_invariant_addr>::apply()) {
- boost::contract::access::static_invariant<C_>();
- }
- }
- // Check if class's func is inherited from its base types or not.
- template<template<class> class HasFunc, template<class> 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<boost::contract::
- access::has_base_types<C>,
- typename boost::contract::access::
- base_types_of<C>
- ,
- boost::mpl::vector<>
- >::type,
- HasFunc<boost::mpl::_1>
- >::type,
- boost::add_pointer<boost::mpl::_1>
- >::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<typename B>
- void operator()(B*) {
- // Inherited func has same addr as in its base.
- if(FuncAddr<C>::apply() == FuncAddr<B>::apply()) {
- throw signal_equal();
- }
- }
- };
- };
- #endif
- #ifndef BOOST_CONTRACT_NO_CONDITIONS
- C* obj_;
- #endif
- };
- } } } // namespace
- #endif // #include guard
|