diff options
Diffstat (limited to 'boost/contract/detail')
35 files changed, 3296 insertions, 0 deletions
diff --git a/boost/contract/detail/assert.hpp b/boost/contract/detail/assert.hpp new file mode 100644 index 0000000000..e44726733e --- /dev/null +++ b/boost/contract/detail/assert.hpp @@ -0,0 +1,28 @@ + +#ifndef BOOST_CONTRACT_DETAIL_ASSERT_HPP_ +#define BOOST_CONTRACT_DETAIL_ASSERT_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/detail/noop.hpp> +#include <boost/preprocessor/stringize.hpp> + +// In detail because used by both ASSERT and CHECK. +// Use ternary operator `?:` and no trailing `;` here to allow `if(...) ASSERT( +// ...); else ...` (won't compile if expands using an if statement instead even +// if wrapped by {}, and else won't compile if expands trailing `;`). +#define BOOST_CONTRACT_DETAIL_ASSERT(cond) \ + /* no if-statement here */ \ + ((cond) ? \ + BOOST_CONTRACT_DETAIL_NOOP \ + : \ + throw boost::contract::assertion_failure( \ + __FILE__, __LINE__, BOOST_PP_STRINGIZE(cond)) \ + ) /* no ; here */ + +#endif // #include guard + diff --git a/boost/contract/detail/auto_ptr.hpp b/boost/contract/detail/auto_ptr.hpp new file mode 100644 index 0000000000..e76945ce9c --- /dev/null +++ b/boost/contract/detail/auto_ptr.hpp @@ -0,0 +1,53 @@ + +#ifndef BOOST_CONTRACT_DETAIL_AUTO_PTR_HPP_ +#define BOOST_CONTRACT_DETAIL_AUTO_PTR_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/detail/operator_safe_bool.hpp> +#include <boost/contract/detail/debug.hpp> +#include <boost/config.hpp> + +namespace boost { namespace contract { namespace detail { + +// Using this instead of std::auto_ptr because std::auto_ptr will be removed in +// C++17 (this library always uses release() to avoid ownership issues). +template<typename T> +class auto_ptr { // Copyable (using default copy operations). +public: + explicit auto_ptr(T* ptr = 0) : ptr_(ptr) {} + + ~auto_ptr() BOOST_NOEXCEPT_IF(false) { delete ptr_; } + + T* release() { + T* ptr = ptr_; + ptr_ = 0; + return ptr; + } + + T& operator*() { + BOOST_CONTRACT_DETAIL_DEBUG(ptr_); + return *ptr_; + } + + T const& operator*() const { + BOOST_CONTRACT_DETAIL_DEBUG(ptr_); + return *ptr_; + } + + T* operator->() { return ptr_; } + T const* operator->() const { return ptr_; } + + BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(auto_ptr<T>, !!ptr_) + +private: + T* ptr_; +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/check.hpp b/boost/contract/detail/check.hpp new file mode 100644 index 0000000000..49006d92d7 --- /dev/null +++ b/boost/contract/detail/check.hpp @@ -0,0 +1,48 @@ + +#ifndef BOOST_CONTRACT_DETAIL_CHECK_HPP_ +#define BOOST_CONTRACT_DETAIL_CHECK_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/config.hpp> +#ifndef BOOST_CONTRACT_NO_CHECKS + #include <boost/contract/core/exception.hpp> + + /* PRIVATE */ + + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + #include <boost/contract/detail/checking.hpp> + #include <boost/contract/detail/name.hpp> + + #define BOOST_CONTRACT_CHECK_IF_NOT_CHECKING_ALREADY_ \ + if(!boost::contract::detail::checking::already()) + #define BOOST_CONTRACT_CHECK_CHECKING_VAR_(guard) \ + /* this name somewhat unique to min var shadow warnings */ \ + boost::contract::detail::checking BOOST_CONTRACT_DETAIL_NAME2( \ + guard, __LINE__); + #else + #define BOOST_CONTRACT_CHECK_IF_NOT_CHECKING_ALREADY_ /* nothing */ + #define BOOST_CONTRACT_CHECK_CHECKING_VAR_(guard) /* nothing */ + #endif + + /* PUBLIC */ + + #define BOOST_CONTRACT_DETAIL_CHECK(assertion) \ + { \ + try { \ + BOOST_CONTRACT_CHECK_IF_NOT_CHECKING_ALREADY_ \ + { \ + BOOST_CONTRACT_CHECK_CHECKING_VAR_(k) \ + { assertion; } \ + } \ + } catch(...) { boost::contract::check_failure(); } \ + } +#else + #define BOOST_CONTRACT_DETAIL_CHECK(assertion) {} +#endif + +#endif // #include guard + diff --git a/boost/contract/detail/checking.hpp b/boost/contract/detail/checking.hpp new file mode 100644 index 0000000000..765c04f4f8 --- /dev/null +++ b/boost/contract/detail/checking.hpp @@ -0,0 +1,80 @@ + +#ifndef BOOST_CONTRACT_DETAIL_CHECKING_HPP_ +#define BOOST_CONTRACT_DETAIL_CHECKING_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/config.hpp> +#include <boost/contract/detail/static_local_var.hpp> +#include <boost/contract/detail/declspec.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/noncopyable.hpp> + +namespace boost { namespace contract { namespace detail { + +#ifdef BOOST_MSVC + #pragma warning(push) + #pragma warning(disable: 4251) // Member w/o DLL spec (mutex_ type). +#endif + +// RAII facility to disable assertions while checking other assertions. +class BOOST_CONTRACT_DETAIL_DECLSPEC checking : + private boost::noncopyable // Non-copyable resource (might use mutex, etc.). +{ +public: + explicit checking() { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + init_locked(); + #else + init_unlocked(); + #endif + } + + ~checking() { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + done_locked(); + #else + done_unlocked(); + #endif + } + + static bool already() { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return already_locked(); + #else + return already_unlocked(); + #endif + } + +private: + void init_unlocked(); + void init_locked(); + + void done_unlocked(); + void done_locked(); + + static bool already_unlocked(); + static bool already_locked(); + + struct mutex_tag; + typedef static_local_var<mutex_tag, boost::mutex> mutex; + + struct checking_tag; + typedef static_local_var_init<checking_tag, bool, bool, false> flag; +}; + +#ifdef BOOST_MSVC + #pragma warning(pop) +#endif + +} } } // namespace + +#ifdef BOOST_CONTRACT_HEADER_ONLY + #include <boost/contract/detail/inlined/detail/checking.hpp> +#endif + +#endif // #include guard + diff --git a/boost/contract/detail/condition/cond_base.hpp b/boost/contract/detail/condition/cond_base.hpp new file mode 100644 index 0000000000..c3f4090461 --- /dev/null +++ b/boost/contract/detail/condition/cond_base.hpp @@ -0,0 +1,153 @@ + +#ifndef BOOST_CONTRACT_DETAIL_COND_BASE_HPP_ +#define BOOST_CONTRACT_DETAIL_COND_BASE_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 + +// NOTE: It seemed not possible to implement this library without inheritance +// here because some sort of base type needs to be used to hold contract objects +// in instances of boost::contract::check while polymorphically calling +// init and destructor functions to check contracts at entry and exit. This +// could be possible without inheritance only if boost::contract::check was made +// a template type but that would complicate user code. In any case, early +// experimentation with removing this base class and its virtual methods did not +// seem to reduce compilation and/or run time. + +#include <boost/contract/core/exception.hpp> +#include <boost/contract/core/config.hpp> +#if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_OLDS) || \ + !defined(BOOST_CONTRACT_NO_EXEPTS) + #include <boost/function.hpp> +#endif +#include <boost/noncopyable.hpp> +#ifndef BOOST_CONTRACT_ON_MISSING_CHECK_DECL + #include <boost/assert.hpp> +#endif +#include <boost/config.hpp> + +namespace boost { namespace contract { namespace detail { + +class cond_base : // Base to hold all contract objects for RAII. + private boost::noncopyable // Avoid copying possible user's ftor captures. +{ +public: + explicit cond_base(boost::contract::from from) : + BOOST_CONTRACT_ERROR_missing_check_object_declaration(false) + , init_asserted_(false) + #ifndef BOOST_CONTRACT_NO_CONDITIONS + , from_(from) + , failed_(false) + #endif + {} + + // Can override for checking on exit, but should call assert_initialized(). + virtual ~cond_base() BOOST_NOEXCEPT_IF(false) { + // Catch error (but later) even if overrides miss assert_initialized(). + if(!init_asserted_) assert_initialized(); + } + + void initialize() { // Must be called by owner ctor (i.e., check class). + BOOST_CONTRACT_ERROR_missing_check_object_declaration = true; + this->init(); // So all inits (pre, old, post) done after owner decl. + } + + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + template<typename F> + void set_pre(F const& f) { pre_ = f; } + #endif + + #ifndef BOOST_CONTRACT_NO_OLDS + template<typename F> + void set_old(F const& f) { old_ = f; } + #endif + + #ifndef BOOST_CONTRACT_NO_EXCEPTS + template<typename F> + void set_except(F const& f) { except_ = f; } + #endif + +protected: + void assert_initialized() { // Derived dtors must assert this at entry. + init_asserted_ = true; + #ifdef BOOST_CONTRACT_ON_MISSING_CHECK_DECL + if(!BOOST_CONTRACT_ERROR_missing_check_object_declaration) { + BOOST_CONTRACT_ON_MISSING_CHECK_DECL; + } + #else + // Cannot use a macro instead of this ERROR_... directly here + // because assert will not expand it in the error message. + BOOST_ASSERT(BOOST_CONTRACT_ERROR_missing_check_object_declaration); + #endif + } + + virtual void init() {} // Override for checking on entry. + + // Return true if actually checked calling user ftor. + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + bool check_pre(bool throw_on_failure = false) { + if(failed()) return true; + try { if(pre_) pre_(); else return false; } + catch(...) { + // Subcontracted pre must throw on failure (instead of + // calling failure handler) so to be checked in logic-or. + if(throw_on_failure) throw; + fail(&boost::contract::precondition_failure); + } + return true; + } + #endif + + #ifndef BOOST_CONTRACT_NO_OLDS + void copy_old() { + if(failed()) return; + try { if(old_) old_(); } + catch(...) { fail(&boost::contract::old_failure); } + } + #endif + + #ifndef BOOST_CONTRACT_NO_EXCEPTS + void check_except() { + if(failed()) return; + try { if(except_) except_(); } + catch(...) { fail(&boost::contract::except_failure); } + } + #endif + + #ifndef BOOST_CONTRACT_NO_CONDITIONS + void fail(void (*h)(boost::contract::from)) { + failed(true); + if(h) h(from_); + } + + // Virtual so overriding pub func can use virtual_::failed_ instead. + virtual bool failed() const { return failed_; } + virtual void failed(bool value) { failed_ = value; } + #endif + +private: + bool BOOST_CONTRACT_ERROR_missing_check_object_declaration; + bool init_asserted_; // Avoid throwing twice from dtors (undef behavior). + #ifndef BOOST_CONTRACT_NO_CONDITIONS + boost::contract::from from_; + bool failed_; + #endif + // Following use Boost.Function to handle also lambdas, binds, etc. + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + boost::function<void ()> pre_; + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + boost::function<void ()> old_; + #endif + #ifndef BOOST_CONTRACT_NO_EXCEPTS + boost::function<void ()> except_; + #endif +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/condition/cond_inv.hpp b/boost/contract/detail/condition/cond_inv.hpp new file mode 100644 index 0000000000..b4c6c03133 --- /dev/null +++ b/boost/contract/detail/condition/cond_inv.hpp @@ -0,0 +1,232 @@ + +#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 + diff --git a/boost/contract/detail/condition/cond_post.hpp b/boost/contract/detail/condition/cond_post.hpp new file mode 100644 index 0000000000..aa99a5b9fa --- /dev/null +++ b/boost/contract/detail/condition/cond_post.hpp @@ -0,0 +1,88 @@ + +#ifndef BOOST_CONTRACT_DETAIL_COND_POST_HPP_ +#define BOOST_CONTRACT_DETAIL_COND_POST_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_base.hpp> +#include <boost/contract/detail/none.hpp> +#ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + #include <boost/contract/detail/type_traits/optional.hpp> + #include <boost/optional.hpp> + #include <boost/function.hpp> + #include <boost/type_traits/remove_reference.hpp> + #include <boost/mpl/if.hpp> +#endif + +/* PRIVATE */ + +#define BOOST_CONTRACT_DETAIL_COND_POST_DEF_( \ + result_type, result_param, ftor_type, ftor_var, ftor_call) \ + public: \ + template<typename F> \ + void set_post(F const& f) { ftor_var = f; } \ + \ + protected: \ + void check_post(result_type const& result_param) { \ + if(failed()) return; \ + try { if(ftor_var) { ftor_call; } } \ + catch(...) { fail(&boost::contract::postcondition_failure); } \ + } \ + \ + private: \ + boost::function<ftor_type> ftor_var; /* Boost.Func for lambdas, etc. */ + +/* CODE */ + +namespace boost { namespace contract { namespace detail { + +template<typename VR> +class cond_post : public cond_base { // Non-copyable base. +public: + explicit cond_post(boost::contract::from from) : cond_base(from) {} + + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + private: typedef typename boost::mpl::if_<is_optional<VR>, + boost::optional<typename boost::remove_reference<typename + optional_value_type<VR>::type>::type const&> const& + , + VR const& + >::type r_type; + + BOOST_CONTRACT_DETAIL_COND_POST_DEF_( + r_type, + r, + void (r_type), + // Won't raise this error if NO_POST (for optimization). + BOOST_CONTRACT_ERROR_postcondition_result_parameter_required, + BOOST_CONTRACT_ERROR_postcondition_result_parameter_required(r) + ) + #endif +}; + +template<> +class cond_post<none> : public cond_base { // Non-copyable base. +public: + explicit cond_post(boost::contract::from from) : cond_base(from) {} + + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + BOOST_CONTRACT_DETAIL_COND_POST_DEF_( + none, + unused, + void (), + // Won't raise this error if NO_POST (for optimization). + BOOST_CONTRACT_ERROR_postcondition_result_parameter_not_allowed, + BOOST_CONTRACT_ERROR_postcondition_result_parameter_not_allowed() + ) + #endif +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/condition/cond_subcontracting.hpp b/boost/contract/detail/condition/cond_subcontracting.hpp new file mode 100644 index 0000000000..17d7a6abaa --- /dev/null +++ b/boost/contract/detail/condition/cond_subcontracting.hpp @@ -0,0 +1,472 @@ + +#ifndef BOOST_CONTRACT_DETAIL_COND_SUBCONTRACTING_HPP_ +#define BOOST_CONTRACT_DETAIL_COND_SUBCONTRACTING_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/config.hpp> +#if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + #include <boost/contract/core/exception.hpp> +#endif +#include <boost/contract/detail/condition/cond_inv.hpp> +#include <boost/contract/detail/decl.hpp> +#include <boost/contract/detail/tvariadic.hpp> +#ifndef BOOST_CONTRACT_NO_CONDITIONS + #include <boost/contract/core/virtual.hpp> + #include <boost/contract/core/access.hpp> + #include <boost/contract/detail/type_traits/optional.hpp> + #include <boost/contract/detail/type_traits/member_function_types.hpp> + #include <boost/contract/detail/debug.hpp> + #include <boost/contract/detail/none.hpp> + #include <boost/contract/detail/name.hpp> + #include <boost/type_traits/add_pointer.hpp> + #include <boost/mpl/fold.hpp> + #include <boost/mpl/contains.hpp> + #include <boost/mpl/empty.hpp> + #include <boost/mpl/push_back.hpp> + #include <boost/mpl/eval_if.hpp> + #include <boost/mpl/identity.hpp> + #include <boost/mpl/placeholders.hpp> + #ifndef BOOST_CONTRACT_PERMISSIVE + #include <boost/type_traits/is_same.hpp> + #include <boost/mpl/or.hpp> + #include <boost/mpl/not.hpp> + #include <boost/static_assert.hpp> + #endif + #include <boost/preprocessor/punctuation/comma_if.hpp> + #include <boost/config.hpp> +#endif +#include <boost/mpl/vector.hpp> +#if !defined(BOOST_CONTRACT_NO_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + #include <boost/mpl/for_each.hpp> +#endif +#ifndef BOOST_CONTRACT_NO_PRECONDITIONS + #include <boost/mpl/pop_front.hpp> + #include <boost/mpl/front.hpp> +#endif +#if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOSOT_CONTRACT_NO_EXCEPTS) + #include <boost/any.hpp> + #include <boost/optional.hpp> + #include <boost/type_traits/remove_reference.hpp> + #include <boost/utility/enable_if.hpp> + #include <typeinfo> +#endif + +namespace boost { namespace contract { namespace detail { + +namespace cond_subcontracting_ { + // Exception signals (must not inherit). + class signal_no_error {}; + class signal_not_checked {}; +} + +// O, VR, F, and Args-i can be none types (but C cannot). +BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1, + /* is_friend = */ 0, O, VR, F, C, Args) : public cond_inv<VR, C> +{ // Non-copyable base. + #ifndef BOOST_CONTRACT_NO_CONDITIONS + template<class Class, typename Result = boost::mpl::vector<> > + class overridden_bases_of { + struct search_bases { + typedef typename boost::mpl::fold< + typename boost::contract::access::base_types_of<Class>:: + type, + Result, + // Fold: _1 = result, _2 = current base from base_types. + boost::mpl::eval_if<boost::mpl::contains<boost::mpl::_1, + boost::add_pointer<boost::mpl::_2> >, + boost::mpl::_1 // Base in result, do not add it again. + , + boost::mpl::eval_if< + typename O::template BOOST_CONTRACT_DETAIL_NAME1( + has_member_function)< + boost::mpl::_2, + typename member_function_types<C, F>:: + result_type, + typename member_function_types<C, F>:: + virtual_argument_types, + typename member_function_types<C, F>:: + property_tag + > + , + boost::mpl::push_back< + overridden_bases_of<boost::mpl::_2, + boost::mpl::_1>, + // Bases as * since for_each constructs them. + boost::add_pointer<boost::mpl::_2> + > + , + overridden_bases_of<boost::mpl::_2, boost::mpl::_1> + > + > + >::type type; + }; + public: + typedef typename boost::mpl::eval_if< + boost::contract::access::has_base_types<Class>, + search_bases + , + boost::mpl::identity<Result> // Return result (stop recursion). + >::type type; + }; + + typedef typename boost::mpl::eval_if<boost::is_same<O, none>, + boost::mpl::vector<> + , + overridden_bases_of<C> + >::type overridden_bases; + + #ifndef BOOST_CONTRACT_PERMISSIVE + BOOST_STATIC_ASSERT_MSG( + (boost::mpl::or_< + boost::is_same<O, none>, + boost::mpl::not_<boost::mpl::empty<overridden_bases> > + >::value), + "subcontracting function specified as 'override' but does not " + "override any contracted member function" + ); + #endif + #else + typedef boost::mpl::vector<> overridden_bases; + #endif + +public: + explicit cond_subcontracting( + boost::contract::from from, + boost::contract::virtual_* v, + C* obj, + VR& r + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS) + BOOST_CONTRACT_DETAIL_TVARIADIC_FPARAMS_Z(1, + BOOST_CONTRACT_MAX_ARGS, Args, &, args) + ) : + cond_inv<VR, C>(from, obj) + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + , r_(r) + #endif + #ifndef BOOST_CONTRACT_NO_CONDITIONS + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS) + BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INIT_Z(1, + BOOST_CONTRACT_MAX_ARGS, args_, args) + #endif + { + #ifndef BOOST_CONTRACT_NO_CONDITIONS + if(v) { + base_call_ = true; + v_ = v; // Invariant: v_ never null if base_call_. + BOOST_CONTRACT_DETAIL_DEBUG(v_); + } else { + base_call_ = false; + if(!boost::mpl::empty<overridden_bases>::value) { + v_ = new boost::contract::virtual_( + boost::contract::virtual_::no_action); + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + v_->result_ptr_ = &r_; + v_->result_type_name_ = typeid(VR).name(); + v_->result_optional_ = is_optional<VR>::value; + #endif + } else v_ = 0; + } + #endif + } + + #ifndef BOOST_CONTRACT_NO_CONDITIONS + virtual ~cond_subcontracting() BOOST_NOEXCEPT_IF(false) { + if(!base_call_) delete v_; + } + #endif + +protected: + #ifndef BOOST_CONTRACT_NO_OLDS + void init_subcontracted_old() { + // Old values of overloaded func on stack (so no `f` param here). + exec_and(boost::contract::virtual_::push_old_init_copy); + } + #endif + + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + void check_subcontracted_entry_inv() { + exec_and(boost::contract::virtual_::check_entry_inv, + &cond_subcontracting::check_entry_inv); + } + #endif + + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + void check_subcontracted_pre() { + exec_or( + boost::contract::virtual_::check_pre, + &cond_subcontracting::check_pre, + &boost::contract::precondition_failure + ); + } + #endif + + #ifndef BOOST_CONTRACT_NO_OLDS + void copy_subcontracted_old() { + exec_and(boost::contract::virtual_::call_old_ftor, + &cond_subcontracting::copy_virtual_old); + } + #endif + + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + void check_subcontracted_exit_inv() { + exec_and(boost::contract::virtual_::check_exit_inv, + &cond_subcontracting::check_exit_inv); + } + #endif + + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + void check_subcontracted_post() { + exec_and(boost::contract::virtual_::check_post, + &cond_subcontracting::check_virtual_post); + } + #endif + + #ifndef BOOST_CONTRACT_NO_EXCEPTS + void check_subcontracted_except() { + exec_and(boost::contract::virtual_::check_except, + &cond_subcontracting::check_virtual_except); + } + #endif + + #ifndef BOOST_CONTRACT_NO_CONDITIONS + bool base_call() const { return base_call_; } + + bool failed() const /* override */ { + if(v_) return v_->failed_; + else return cond_base::failed(); + } + + void failed(bool value) /* override */ { + if(v_) v_->failed_ = value; + else cond_base::failed(value); + } + #endif + +private: + #ifndef BOOST_CONTRACT_NO_OLDS + void copy_virtual_old() { + boost::contract::virtual_::action_enum a; + if(base_call_) { + a = v_->action_; + v_->action_ = boost::contract::virtual_::push_old_ftor_copy; + } + this->copy_old(); + if(base_call_) v_->action_ = a; + } + + void pop_base_old() { + if(base_call_) { + boost::contract::virtual_::action_enum a = v_->action_; + v_->action_ = boost::contract::virtual_::pop_old_ftor_copy; + this->copy_old(); + v_->action_ = a; + } // Else, do nothing (for base calls only). + } + #endif + + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + void check_virtual_post() { + pop_base_old(); + typedef typename boost::remove_reference<typename + optional_value_type<VR>::type>::type r_type; + boost::optional<r_type const&> r; // No result copy in this code. + if(!base_call_) r = optional_get(r_); + else if(v_->result_optional_) { + try { + r = **boost::any_cast<boost::optional<r_type>*>( + v_->result_ptr_); + } catch(boost::bad_any_cast const&) { + try { // Handle optional<...&>. + r = **boost::any_cast<boost::optional<r_type&>*>( + v_->result_ptr_); + } catch(boost::bad_any_cast const&) { + try { + throw boost::contract::bad_virtual_result_cast(v_-> + result_type_name_, typeid(r_type).name()); + } catch(...) { + this->fail(&boost::contract::postcondition_failure); + } + } + } + } else { + try { + r = *boost::any_cast<r_type*>(v_->result_ptr_); + } catch(boost::bad_any_cast const&) { + try { + throw boost::contract::bad_virtual_result_cast( + v_->result_type_name_, typeid(r_type).name()); + } catch(...) { + this->fail(&boost::contract::postcondition_failure); + } + } + } + check_virtual_post_with_result<VR>(r); + } + + template<typename R_, typename Result> + typename boost::enable_if<is_optional<R_> >::type + check_virtual_post_with_result(Result const& r) { + this->check_post(r); + } + + template<typename R_, typename Result> + typename boost::disable_if<is_optional<R_> >::type + check_virtual_post_with_result(Result const& r) { + BOOST_CONTRACT_DETAIL_DEBUG(r); + this->check_post(*r); + } + #endif + + #ifndef BOOST_CONTRACT_NO_EXCEPTS + void check_virtual_except() { + pop_base_old(); + this->check_except(); + } + #endif + + #if !defined(BOOST_CONTRACT_NO_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + void exec_and( // Execute action in short-circuit logic-and with bases. + boost::contract::virtual_::action_enum a, + void (cond_subcontracting::* f)() = 0 + ) { + if(failed()) return; + if(!base_call_ || v_->action_ == a) { + if(!base_call_ && v_) { + v_->action_ = a; + boost::mpl::for_each<overridden_bases>(call_base(*this)); + } + if(f) (this->*f)(); + if(base_call_) { + throw cond_subcontracting_::signal_no_error(); + } + } + } + #endif + + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + void exec_or( // Execute action in short-circuit logic-or with bases. + boost::contract::virtual_::action_enum a, + bool (cond_subcontracting::* f)(bool) = 0, + void (*h)(boost::contract::from) = 0 + ) { + if(failed()) return; + if(!base_call_ || v_->action_ == a) { + if(!base_call_ && v_) { + v_->action_ = a; + try { + exec_or_bases<overridden_bases>(); + return; // A base checked with no error (done). + } catch(...) { + bool checked = f ? (this->*f)( + /* throw_on_failure = */ false) : false; + if(!checked) { + try { throw; } // Report latest exception found. + catch(...) { this->fail(h); } + } + return; // Checked and no exception (done). + } + } + bool checked = f ? + (this->*f)(/* throw_on_failure = */ base_call_) : false; + if(base_call_) { + if(!checked) { + throw cond_subcontracting_::signal_not_checked(); + } + throw cond_subcontracting_::signal_no_error(); + } + } + } + + template<typename Bases> + typename boost::enable_if<boost::mpl::empty<Bases>, bool>::type + exec_or_bases() { return false; } + + template<typename Bases> + typename boost::disable_if<boost::mpl::empty<Bases>, bool>::type + exec_or_bases() { + if(boost::mpl::empty<Bases>::value) return false; + try { + call_base(*this)(typename boost::mpl::front<Bases>::type()); + } catch(cond_subcontracting_::signal_not_checked const&) { + return exec_or_bases< + typename boost::mpl::pop_front<Bases>::type>(); + } catch(...) { + bool checked = false; + try { + checked = exec_or_bases< + typename boost::mpl::pop_front<Bases>::type>(); + } catch(...) { checked = false; } + if(!checked) throw; + } + return true; + } + #endif + + #ifndef BOOST_CONTRACT_NO_CONDITIONS + class call_base { // Copyable (as &). + public: + explicit call_base(cond_subcontracting& me) : me_(me) {} + + template<class B> + void operator()(B*) { + BOOST_CONTRACT_DETAIL_DEBUG(me_.object()); + BOOST_CONTRACT_DETAIL_DEBUG(me_.v_); + BOOST_CONTRACT_DETAIL_DEBUG(me_.v_->action_ != + boost::contract::virtual_::no_action); + try { + call<B>(BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_OF( + Args)); + } catch(cond_subcontracting_::signal_no_error const&) { + // No error (do not throw). + } + } + + private: + template< + class B + // Can't use TVARIADIC_COMMA here. + BOOST_PP_COMMA_IF(BOOST_CONTRACT_DETAIL_TVARIADIC) + BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_TPARAM(I) + > + void call( + BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_FPARAM(I)) { + O::template BOOST_CONTRACT_DETAIL_NAME1(call_base)<B>( + me_.v_, + me_.object() + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA( + BOOST_CONTRACT_MAX_ARGS) + BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_ELEMS_Z(1, + BOOST_CONTRACT_MAX_ARGS, I, me_.args_) + ); + } + + cond_subcontracting& me_; + }; + #endif + + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + VR& r_; + #endif + #ifndef BOOST_CONTRACT_NO_CONDITIONS + boost::contract::virtual_* v_; + bool base_call_; + BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_Z(1, + BOOST_CONTRACT_MAX_ARGS, Args, &, args_) + #endif +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/config.hpp b/boost/contract/detail/config.hpp new file mode 100644 index 0000000000..1bd106e6d0 --- /dev/null +++ b/boost/contract/detail/config.hpp @@ -0,0 +1,26 @@ + +#ifndef BOOST_CONTRACT_DETAIL_CONFIG_HPP_ +#define BOOST_CONTRACT_DETAIL_CONFIG_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/preprocessor/cat.hpp> + +// Turn off BOOST_ASSERT(...) in lib's implementation (always on by default). +// BOOST_CONTRACT_DETAIL_NDEBUG + +#ifndef BOOST_CONTRACT_DETAIL_NAME_INFIX + // Do not use underscore "_" to avoid generating reserved names with "__". + #define BOOST_CONTRACT_DETAIL_NAME_INFIX X +#endif + +#ifndef BOOST_CONTRACT_DETAIL_NAME_PREFIX + #define BOOST_CONTRACT_DETAIL_NAME_PREFIX \ + BOOST_PP_CAT(boost_contract_detail, BOOST_CONTRACT_DETAIL_NAME_INFIX) +#endif + +#endif // #include guard + diff --git a/boost/contract/detail/debug.hpp b/boost/contract/detail/debug.hpp new file mode 100644 index 0000000000..9fa580a5f8 --- /dev/null +++ b/boost/contract/detail/debug.hpp @@ -0,0 +1,20 @@ + +#ifndef BOOST_CONTRACT_DETAIL_DEBUG_HPP_ +#define BOOST_CONTRACT_DETAIL_DEBUG_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 + +// Usually, never #defined (so "debug" assertions always in code). +#ifdef BOOST_CONTRACT_DETAIL_NDEBUG + #define BOOST_CONTRACT_DETAIL_DEBUG(cond) /* nothing */ +#else + #include <boost/assert.hpp> + // Extra parenthesis around BOOST_ASSERT to be safe because its is a macro. + #define BOOST_CONTRACT_DETAIL_DEBUG(cond) (BOOST_ASSERT(cond)) +#endif + +#endif // #include guard + diff --git a/boost/contract/detail/decl.hpp b/boost/contract/detail/decl.hpp new file mode 100644 index 0000000000..aa84e2e16d --- /dev/null +++ b/boost/contract/detail/decl.hpp @@ -0,0 +1,129 @@ + +#ifndef BOOST_CONTRACT_DETAIL_DECL_HPP_ +#define BOOST_CONTRACT_DETAIL_DECL_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 + +// Cannot include core/*.hpp other than config.hpp here (avoid circular incl). +#include <boost/contract/detail/tvariadic.hpp> +#if !BOOST_CONTRACT_DETAIL_TVARIADIC + #include <boost/contract/core/config.hpp> + #include <boost/preprocessor/repetition/repeat.hpp> + #include <boost/preprocessor/tuple/elem.hpp> + #include <boost/preprocessor/arithmetic/inc.hpp> +#endif +#include <boost/preprocessor/control/expr_iif.hpp> +#include <boost/preprocessor/control/iif.hpp> +#include <boost/preprocessor/punctuation/comma_if.hpp> + +/* PUBLIC */ + +#define BOOST_CONTRACT_DETAIL_DECL_OVERRIDING_PUBLIC_FUNCTION_Z(z, \ + arity, is_friend, has_result, \ + O, VR, F, C, Args, \ + v, r, f, obj, args \ +) \ + template< \ + class O \ + BOOST_PP_COMMA_IF(has_result) \ + BOOST_PP_EXPR_IIF(has_result, typename VR) \ + , typename F \ + , class C \ + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(arity) \ + BOOST_CONTRACT_DETAIL_TVARIADIC_TPARAMS_Z(z, arity, Args) \ + > \ + BOOST_PP_EXPR_IIF(is_friend, friend) \ + boost::contract::specify_precondition_old_postcondition_except< \ + BOOST_PP_EXPR_IIF(has_result, VR)> \ + /* no boost::contract:: here for friends (otherwise need fwd decl) */ \ + public_function( \ + boost::contract::virtual_* v \ + BOOST_PP_COMMA_IF(has_result) \ + BOOST_PP_EXPR_IIF(has_result, VR& r) \ + , F f \ + , C* obj \ + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(arity) \ + BOOST_CONTRACT_DETAIL_TVARIADIC_FPARAMS_Z(z, arity, Args, &, args) \ + ) + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTIONS_Z(z, \ + O, VR, F, C, Args, \ + v, r, f, obj, args \ + ) \ + BOOST_CONTRACT_DETAIL_DECL_OVERRIDING_PUBLIC_FUNCTION_Z(z, \ + ~, /* is_friend = */ 1, /* has_result = */ 0, \ + O, VR, F, C, Args, v, r, f, obj, args \ + ); \ + BOOST_CONTRACT_DETAIL_DECL_OVERRIDING_PUBLIC_FUNCTION_Z(z, \ + ~, /* is_friend = */ 1, /* has_result = */ 1, \ + O, VR, F, C, Args, v, r, f, obj, args \ + ); +#else + /* PRIVATE */ + #define BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTION_( \ + z, n, result_O_R_F_C_Args_v_r_f_obj_args) \ + BOOST_CONTRACT_DETAIL_DECL_OVERRIDING_PUBLIC_FUNCTION_Z(z, \ + /* arity = */ n, \ + /* is_friend = */ 1, \ + BOOST_PP_TUPLE_ELEM(11, 0, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 1, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 2, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 3, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 4, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 5, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 6, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 7, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 8, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 9, result_O_R_F_C_Args_v_r_f_obj_args), \ + BOOST_PP_TUPLE_ELEM(11, 10, result_O_R_F_C_Args_v_r_f_obj_args) \ + ); + + /* PUBLIC */ + #define BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTIONS_Z(z, \ + O, VR, F, C, Args, \ + v, r, f, obj, args \ + ) \ + BOOST_PP_REPEAT_ ## z( \ + BOOST_PP_INC(BOOST_CONTRACT_MAX_ARGS), \ + BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTION_, \ + (/* has_result = */ 0, O, VR, F, C, Args, v, r, f, obj, args) \ + ) \ + BOOST_PP_REPEAT_ ## z( \ + BOOST_PP_INC(BOOST_CONTRACT_MAX_ARGS), \ + BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTION_, \ + (/* has_result = */ 1, O, VR, F, C, Args, v, r, f, obj, args) \ + ) +#endif + +#define BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z( \ + z, is_friend, O, VR, F, C, Args) \ + template< \ + class O, typename VR, typename F, class C \ + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS) \ + BOOST_CONTRACT_DETAIL_TVARIADIC_TPARAMS_Z(z, \ + BOOST_CONTRACT_MAX_ARGS, Args) \ + > \ + BOOST_PP_IIF(is_friend, \ + friend class boost::contract::detail:: \ + , \ + class \ + ) \ + cond_subcontracting + +/* CODE */ + +namespace boost { + namespace contract { + class virtual_; + + template<typename VR = void> + class specify_precondition_old_postcondition_except; + } +} + +#endif // #include guard + diff --git a/boost/contract/detail/declspec.hpp b/boost/contract/detail/declspec.hpp new file mode 100644 index 0000000000..a1bfb5ceda --- /dev/null +++ b/boost/contract/detail/declspec.hpp @@ -0,0 +1,51 @@ + +#ifndef BOOST_CONTRACT_DETAIL_DECLSPEC_HPP_ +#define BOOST_CONTRACT_DETAIL_DECLSPEC_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 + +// IMPORTANT: Indirectly included by contract_macro.hpp so trivial headers only. +#include <boost/contract/core/config.hpp> // No compile-time overhead. +#include <boost/config.hpp> + +/* PUBLIC */ + +// IMPORTANT: In general, this library should always and only be compiled and +// used as a shared library. Otherwise, lib's state won't be shared among +// different user programs and user libraries. However, this library can be +// safely compiled and used as a static or header-only library only when it is +// being used by a single program unit (e.g., a single program with only +// statically linked libraries that check contracts). + +#ifdef BOOST_CONTRACT_DYN_LINK + #ifdef BOOST_CONTRACT_SOURCE + #define BOOST_CONTRACT_DETAIL_DECLSPEC BOOST_SYMBOL_EXPORT + #else + #define BOOST_CONTRACT_DETAIL_DECLSPEC BOOST_SYMBOL_IMPORT + #endif +#else + #define BOOST_CONTRACT_DETAIL_DECLSPEC /* nothing */ +#endif + +#ifdef BOOST_CONTRACT_HEADER_ONLY + #define BOOST_CONTRACT_DETAIL_DECLINLINE inline +#else + #define BOOST_CONTRACT_DETAIL_DECLINLINE /* nothing */ + + // Automatically link this lib to correct build variant (for MSVC, etc.). + #if !defined(BOOST_ALL_NO_LIB) && \ + !defined(BOOST_CONTRACT_NO_LIB) && \ + !defined(BOOST_CONTRACT_SOURCE) + #define BOOST_LIB_NAME boost_contract // This lib (static or shared). + #if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTRACT_DYN_LINK) + #define BOOST_DYN_LINK // This lib as shared. + #endif + #include <boost/config/auto_link.hpp> // Also #undef BOOST_LIB_NAME. + #endif +#endif + +#endif // #include guard + diff --git a/boost/contract/detail/inlined.hpp b/boost/contract/detail/inlined.hpp new file mode 100644 index 0000000000..06c7167f10 --- /dev/null +++ b/boost/contract/detail/inlined.hpp @@ -0,0 +1,15 @@ + +#ifndef BOOST_CONTRACT_DETAIL_INLINED_HPP_ +#define BOOST_CONTRACT_DETAIL_INLINED_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/detail/inlined/old.hpp> +#include <boost/contract/detail/inlined/core/exception.hpp> +#include <boost/contract/detail/inlined/detail/checking.hpp> + +#endif // #include guard + diff --git a/boost/contract/detail/inlined/core/exception.hpp b/boost/contract/detail/inlined/core/exception.hpp new file mode 100644 index 0000000000..8c3eb3ff95 --- /dev/null +++ b/boost/contract/detail/inlined/core/exception.hpp @@ -0,0 +1,502 @@ + +#ifndef BOOST_CONTRACT_DETAIL_INLINED_EXCEPTION_HPP_ +#define BOOST_CONTRACT_DETAIL_INLINED_EXCEPTION_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 + +// IMPORTANT: Do NOT use config macros BOOST_CONTRACT_... in this file so lib +// .cpp does not need recompiling if config changes (recompile only user code). + +#include <boost/contract/core/exception.hpp> +#include <boost/contract/detail/static_local_var.hpp> +#include <boost/contract/detail/declspec.hpp> +#include <boost/thread/lock_guard.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/exception/diagnostic_information.hpp> +#include <boost/config.hpp> +#include <string> +#include <sstream> +#include <iostream> +#include <exception> + +namespace boost { namespace contract { + +BOOST_CONTRACT_DETAIL_DECLINLINE +exception::~exception() BOOST_NOEXCEPT_OR_NOTHROW {} + +BOOST_CONTRACT_DETAIL_DECLINLINE +bad_virtual_result_cast::bad_virtual_result_cast(char const* from_type_name, + char const* to_type_name) { + std::ostringstream text; + text + << "incompatible contracted virtual function result type " + << "conversion from '" << from_type_name << "' to '" + << to_type_name << "'" + ; + what_ = text.str(); +} + +BOOST_CONTRACT_DETAIL_DECLINLINE +bad_virtual_result_cast::~bad_virtual_result_cast() BOOST_NOEXCEPT_OR_NOTHROW {} + +BOOST_CONTRACT_DETAIL_DECLINLINE +char const* bad_virtual_result_cast::what() const BOOST_NOEXCEPT_OR_NOTHROW { + return what_.c_str(); +} + +BOOST_CONTRACT_DETAIL_DECLINLINE +assertion_failure::assertion_failure(char const* const file, + unsigned long const line, char const* const code) : + file_(file), line_(line), code_(code) +{ init(); } + +BOOST_CONTRACT_DETAIL_DECLINLINE +assertion_failure::assertion_failure(char const* const code) : + file_(""), line_(0), code_(code) +{ init(); } + +BOOST_CONTRACT_DETAIL_DECLINLINE +assertion_failure::~assertion_failure() BOOST_NOEXCEPT_OR_NOTHROW {} + +BOOST_CONTRACT_DETAIL_DECLINLINE +char const* assertion_failure::what() const BOOST_NOEXCEPT_OR_NOTHROW { + return what_.c_str(); +} + +BOOST_CONTRACT_DETAIL_DECLINLINE +char const* assertion_failure::file() const { return file_; } + +BOOST_CONTRACT_DETAIL_DECLINLINE +unsigned long assertion_failure::line() const { return line_; } + +BOOST_CONTRACT_DETAIL_DECLINLINE +char const* assertion_failure::code() const { return code_; } + +BOOST_CONTRACT_DETAIL_DECLINLINE +void assertion_failure::init() { + std::ostringstream text; + text << "assertion"; + if(std::string(code_) != "") text << " \"" << code_ << "\""; + text << " failed"; + if(std::string(file_) != "") { + text << ": file \"" << file_ << "\""; + if(line_ != 0) text << ", line " << line_; + } + what_ = text.str(); +} + +namespace exception_ { + enum failure_key { + check_failure_key, + pre_failure_key, + post_failure_key, + except_failure_key, + old_failure_key, + entry_inv_failure_key, + exit_inv_failure_key + }; + + template<failure_key Key> + void default_handler() { + std::string k = ""; + switch(Key) { + case check_failure_key: k = "check "; break; + case pre_failure_key: k = "precondition "; break; + case post_failure_key: k = "postcondition "; break; + case except_failure_key: k = "except "; break; + case old_failure_key: k = "old copy "; break; + case entry_inv_failure_key: k = "entry invariant "; break; + case exit_inv_failure_key: k = "exit invariant "; break; + // No default (so compiler warning/error on missing enum case). + } + try { throw; } + catch(boost::contract::assertion_failure const& error) { + // what = "assertion '...' failed: ...". + std::cerr << k << error.what() << std::endl; + } catch(...) { // old_failure_key prints this, not above. + std::cerr << k << "threw following exception:" << std::endl + << boost::current_exception_diagnostic_information(); + } + std::terminate(); // Default handlers log and call terminate. + } + + template<failure_key Key> + void default_from_handler(from) { default_handler<Key>(); } + + // Check failure. + + struct check_failure_mutex_tag; + typedef boost::contract::detail::static_local_var<check_failure_mutex_tag, + boost::mutex> check_failure_mutex; + + struct check_failure_handler_tag; + typedef boost::contract::detail::static_local_var_init< + check_failure_handler_tag, + failure_handler, + void (*)(), + &default_handler<check_failure_key> + > check_failure_handler; + + BOOST_CONTRACT_DETAIL_DECLINLINE + failure_handler const& set_check_failure_unlocked(failure_handler const& f) + BOOST_NOEXCEPT_OR_NOTHROW { + check_failure_handler::ref() = f; + return f; + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + failure_handler const& set_check_failure_locked(failure_handler const& f) + BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(check_failure_mutex::ref()); + return set_check_failure_unlocked(f); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + failure_handler get_check_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW { + return check_failure_handler::ref(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + failure_handler get_check_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(check_failure_mutex::ref()); + return get_check_failure_unlocked(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void check_failure_unlocked() /* can throw */ { + check_failure_handler::ref()(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void check_failure_locked() /* can throw */ { + boost::lock_guard<boost::mutex> lock(check_failure_mutex::ref()); + check_failure_unlocked(); + } + + // Precondition failure. + + struct pre_failure_mutex_tag; + typedef boost::contract::detail::static_local_var<pre_failure_mutex_tag, + boost::mutex> pre_failure_mutex; + + struct pre_failure_handler_tag; + typedef boost::contract::detail::static_local_var_init< + pre_failure_handler_tag, + from_failure_handler, + void (*)(from), + &default_from_handler<pre_failure_key> + > pre_failure_handler; + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_pre_failure_unlocked(from_failure_handler + const& f) BOOST_NOEXCEPT_OR_NOTHROW { + pre_failure_handler::ref() = f; + return f; + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_pre_failure_locked(from_failure_handler + const& f) BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(pre_failure_mutex::ref()); + return set_pre_failure_unlocked(f); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_pre_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW { + return pre_failure_handler::ref(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_pre_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(pre_failure_mutex::ref()); + return get_pre_failure_unlocked(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void pre_failure_unlocked(from where) /* can throw */ { + pre_failure_handler::ref()(where); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void pre_failure_locked(from where) /* can throw */ { + boost::lock_guard<boost::mutex> lock(pre_failure_mutex::ref()); + pre_failure_unlocked(where); + } + + // Postcondition failure. + + struct post_failure_mutex_tag; + typedef boost::contract::detail::static_local_var<post_failure_mutex_tag, + boost::mutex> post_failure_mutex; + + struct post_failure_handler_tag; + typedef boost::contract::detail::static_local_var_init< + post_failure_handler_tag, + from_failure_handler, + void (*)(from), + &default_from_handler<post_failure_key> + > post_failure_handler; + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_post_failure_unlocked(from_failure_handler + const& f) BOOST_NOEXCEPT_OR_NOTHROW { + post_failure_handler::ref() = f; + return f; + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_post_failure_locked(from_failure_handler + const& f) BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(post_failure_mutex::ref()); + return set_post_failure_unlocked(f); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_post_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW { + return post_failure_handler::ref(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_post_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(post_failure_mutex::ref()); + return get_post_failure_unlocked(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void post_failure_unlocked(from where) /* can throw */ { + post_failure_handler::ref()(where); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void post_failure_locked(from where) /* can throw */ { + boost::lock_guard<boost::mutex> lock(post_failure_mutex::ref()); + post_failure_unlocked(where); + } + + // Except failure. + + struct except_failure_mutex_tag; + typedef boost::contract::detail::static_local_var<except_failure_mutex_tag, + boost::mutex> except_failure_mutex; + + struct except_failure_handler_tag; + typedef boost::contract::detail::static_local_var_init< + except_failure_handler_tag, + from_failure_handler, + void (*)(from), + &default_from_handler<except_failure_key> + > except_failure_handler; + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_except_failure_unlocked(from_failure_handler + const& f) BOOST_NOEXCEPT_OR_NOTHROW { + except_failure_handler::ref() = f; + return f; + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_except_failure_locked(from_failure_handler + const& f) BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(except_failure_mutex::ref()); + return set_except_failure_unlocked(f); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_except_failure_unlocked() + BOOST_NOEXCEPT_OR_NOTHROW { + return except_failure_handler::ref(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_except_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(except_failure_mutex::ref()); + return get_except_failure_unlocked(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void except_failure_unlocked(from where) /* can throw */ { + except_failure_handler::ref()(where); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void except_failure_locked(from where) /* can throw */ { + boost::lock_guard<boost::mutex> lock(except_failure_mutex::ref()); + except_failure_unlocked(where); + } + + // Old-copy failure. + + struct old_failure_mutex_tag; + typedef boost::contract::detail::static_local_var<old_failure_mutex_tag, + boost::mutex> old_failure_mutex; + + struct old_failure_handler_tag; + typedef boost::contract::detail::static_local_var_init< + old_failure_handler_tag, + from_failure_handler, + void (*)(from), + &default_from_handler<old_failure_key> + > old_failure_handler; + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_old_failure_unlocked(from_failure_handler + const& f) BOOST_NOEXCEPT_OR_NOTHROW { + old_failure_handler::ref() = f; + return f; + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_old_failure_locked(from_failure_handler + const& f) BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(old_failure_mutex::ref()); + return set_old_failure_unlocked(f); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_old_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW { + return old_failure_handler::ref(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_old_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(old_failure_mutex::ref()); + return get_old_failure_unlocked(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void old_failure_unlocked(from where) /* can throw */ { + old_failure_handler::ref()(where); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void old_failure_locked(from where) /* can throw */ { + boost::lock_guard<boost::mutex> lock(old_failure_mutex::ref()); + old_failure_unlocked(where); + } + + // Entry invariant failure. + + struct entry_inv_failure_mutex_tag; + typedef boost::contract::detail::static_local_var< + entry_inv_failure_mutex_tag, boost::mutex> entry_inv_failure_mutex; + + struct entry_inv_failure_handler_tag; + typedef boost::contract::detail::static_local_var_init< + entry_inv_failure_handler_tag, + from_failure_handler, + void (*)(from), + &default_from_handler<entry_inv_failure_key> + > entry_inv_failure_handler; + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_entry_inv_failure_unlocked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { + entry_inv_failure_handler::ref() = f; + return f; + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_entry_inv_failure_locked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(entry_inv_failure_mutex::ref()); + return set_entry_inv_failure_unlocked(f); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_entry_inv_failure_unlocked() + BOOST_NOEXCEPT_OR_NOTHROW { + return entry_inv_failure_handler::ref(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_entry_inv_failure_locked() + BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(entry_inv_failure_mutex::ref()); + return get_entry_inv_failure_unlocked(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void entry_inv_failure_unlocked(from where) /* can throw */ { + entry_inv_failure_handler::ref()(where); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void entry_inv_failure_locked(from where) /* can throw */ { + boost::lock_guard<boost::mutex> lock(entry_inv_failure_mutex::ref()); + entry_inv_failure_unlocked(where); + } + + // Exit invariant failure. + + struct exit_inv_failure_mutex_tag; + typedef boost::contract::detail::static_local_var< + exit_inv_failure_mutex_tag, boost::mutex> exit_inv_failure_mutex; + + struct exit_inv_failure_handler_tag; + typedef boost::contract::detail::static_local_var_init< + exit_inv_failure_handler_tag, + from_failure_handler, + void (*)(from), + &default_from_handler<exit_inv_failure_key> + > exit_inv_failure_handler; + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_exit_inv_failure_unlocked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { + exit_inv_failure_handler::ref() = f; + return f; + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler const& set_exit_inv_failure_locked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(exit_inv_failure_mutex::ref()); + return set_exit_inv_failure_unlocked(f); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_exit_inv_failure_unlocked() + BOOST_NOEXCEPT_OR_NOTHROW { + return exit_inv_failure_handler::ref(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + from_failure_handler get_exit_inv_failure_locked() + BOOST_NOEXCEPT_OR_NOTHROW { + boost::lock_guard<boost::mutex> lock(exit_inv_failure_mutex::ref()); + return get_exit_inv_failure_unlocked(); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void exit_inv_failure_unlocked(from where) /* can throw */ { + exit_inv_failure_handler::ref()(where); + } + + BOOST_CONTRACT_DETAIL_DECLINLINE + void exit_inv_failure_locked(from where) /* can throw */ { + boost::lock_guard<boost::mutex> lock(exit_inv_failure_mutex::ref()); + exit_inv_failure_unlocked(where); + } +} + +from_failure_handler const& set_entry_invariant_failure( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + +from_failure_handler const& set_exit_invariant_failure( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + +BOOST_CONTRACT_DETAIL_DECLINLINE +from_failure_handler const& set_invariant_failure( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW { + set_entry_invariant_failure(f); + set_exit_invariant_failure(f); + return f; +} + +} } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/inlined/detail/checking.hpp b/boost/contract/detail/inlined/detail/checking.hpp new file mode 100644 index 0000000000..c0557af48b --- /dev/null +++ b/boost/contract/detail/inlined/detail/checking.hpp @@ -0,0 +1,49 @@ + +#ifndef BOOST_CONTRACT_DETAIL_INLINED_DETAIL_CHECKING_HPP_ +#define BOOST_CONTRACT_DETAIL_INLINED_DETAIL_CHECKING_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 + +// IMPORTANT: Do NOT use config macros BOOST_CONTRACT_... in this file so lib +// .cpp does not need recompiling if config changes (recompile only user code). + +#include <boost/contract/detail/checking.hpp> +#include <boost/contract/detail/declspec.hpp> +#include <boost/thread/lock_guard.hpp> + +namespace boost { namespace contract { namespace detail { + +BOOST_CONTRACT_DETAIL_DECLINLINE +void checking::init_unlocked() { flag::ref() = true; } + +BOOST_CONTRACT_DETAIL_DECLINLINE +void checking::init_locked() { + boost::lock_guard<boost::mutex> lock(mutex::ref()); + init_unlocked(); +} + +BOOST_CONTRACT_DETAIL_DECLINLINE +void checking::done_unlocked() { flag::ref() = false; } + +BOOST_CONTRACT_DETAIL_DECLINLINE +void checking::done_locked() { + boost::lock_guard<boost::mutex> lock(mutex::ref()); + done_unlocked(); +} + +BOOST_CONTRACT_DETAIL_DECLINLINE +bool checking::already_unlocked() { return flag::ref(); } + +BOOST_CONTRACT_DETAIL_DECLINLINE +bool checking::already_locked() { + boost::lock_guard<boost::mutex> lock(mutex::ref()); + return already_unlocked(); +} + +} } } // namespace + +#endif + diff --git a/boost/contract/detail/inlined/old.hpp b/boost/contract/detail/inlined/old.hpp new file mode 100644 index 0000000000..aaa2fe7826 --- /dev/null +++ b/boost/contract/detail/inlined/old.hpp @@ -0,0 +1,34 @@ + +#ifndef BOOST_CONTRACT_DETAIL_INLINED_OLD_HPP_ +#define BOOST_CONTRACT_DETAIL_INLINED_OLD_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 + +// IMPORTANT: Do NOT use config macros BOOST_CONTRACT_... in this file so lib +// .cpp does not need recompiling if config changes (recompile only user code). + +#include <boost/contract/old.hpp> +#include <boost/contract/detail/declspec.hpp> + +namespace boost { namespace contract { + +BOOST_CONTRACT_DETAIL_DECLINLINE +old_value null_old() { return old_value(); } + +BOOST_CONTRACT_DETAIL_DECLINLINE +old_pointer make_old(old_value const& old) { + return old_pointer(0, old); +} + +BOOST_CONTRACT_DETAIL_DECLINLINE +old_pointer make_old(virtual_* v, old_value const& old) { + return old_pointer(v, old); +} + +} } // namespacd + +#endif // #include guard + diff --git a/boost/contract/detail/name.hpp b/boost/contract/detail/name.hpp new file mode 100644 index 0000000000..5327357e61 --- /dev/null +++ b/boost/contract/detail/name.hpp @@ -0,0 +1,26 @@ + +#ifndef BOOST_CONTRACT_DETAIL_NAME_HPP_ +#define BOOST_CONTRACT_DETAIL_NAME_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/detail/config.hpp> +#include <boost/preprocessor/cat.hpp> + +/* PUBLIC */ + +// NOTE: Explicitly list number of names to concatenate using ..._NAME-n +// (instead of using ..._SEQ_CAT or similar) for optimal speed and reentrancy. + +#define BOOST_CONTRACT_DETAIL_NAME1(name1) \ + BOOST_PP_CAT(BOOST_CONTRACT_DETAIL_NAME_PREFIX, name1) + +#define BOOST_CONTRACT_DETAIL_NAME2(name1, name2) \ + BOOST_PP_CAT(BOOST_CONTRACT_DETAIL_NAME_PREFIX, BOOST_PP_CAT(name1, \ + BOOST_PP_CAT(BOOST_CONTRACT_DETAIL_NAME_INFIX, name2))) + +#endif // #include guard + diff --git a/boost/contract/detail/none.hpp b/boost/contract/detail/none.hpp new file mode 100644 index 0000000000..afbd3024e8 --- /dev/null +++ b/boost/contract/detail/none.hpp @@ -0,0 +1,28 @@ + +#ifndef BOOST_CONTRACT_DETAIL_NONE_HPP_ +#define BOOST_CONTRACT_DETAIL_NONE_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 + +namespace boost { namespace contract { namespace detail { + +// Tag for "no type". +struct none { + // Some lib code use this to avoid unused local var warnings on #if, etc. + static none& value() { + static none none_value; + return none_value; + } +}; + +// Transform `void` to `none` type (for convenience, instead of using MPL). +template<typename T> struct none_if_void { typedef T type; }; +template<> struct none_if_void<void> { typedef none type; }; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/noop.hpp b/boost/contract/detail/noop.hpp new file mode 100644 index 0000000000..f3beabe246 --- /dev/null +++ b/boost/contract/detail/noop.hpp @@ -0,0 +1,19 @@ + +#ifndef BOOST_CONTRACT_DETAIL_NOOP_HPP_ +#define BOOST_CONTRACT_DETAIL_NOOP_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 + +// Following must be expressions, not statements (as used with if.., etc.). + +#define BOOST_CONTRACT_DETAIL_NOOP ((void)0) + +// Following always compiles but never evaluates cond (so check correct syntax). +#define BOOST_CONTRACT_DETAIL_NOEVAL(cond) \ + (true || (cond) ? BOOST_CONTRACT_DETAIL_NOOP : BOOST_CONTRACT_DETAIL_NOOP) + +#endif // #include guard + diff --git a/boost/contract/detail/operation/constructor.hpp b/boost/contract/detail/operation/constructor.hpp new file mode 100644 index 0000000000..ce4d2de30c --- /dev/null +++ b/boost/contract/detail/operation/constructor.hpp @@ -0,0 +1,95 @@ + +#ifndef BOOST_CONTRACT_DETAIL_CONSTRUCTOR_HPP_ +#define BOOST_CONTRACT_DETAIL_CONSTRUCTOR_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_inv.hpp> +#include <boost/contract/detail/none.hpp> +#if !defined(BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION) && ( \ + !defined(BOOST_CONTRACT_NO_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS)) + #include <boost/contract/detail/checking.hpp> +#endif +#if !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + #include <boost/config.hpp> + #include <exception> +#endif + +namespace boost { namespace contract { namespace detail { + +// Ctor subcontracting impl via C++ obj construction mechanism. +template<class C> // Non-copyable base. +class constructor : public cond_inv</* VR = */ none, C> { +public: + explicit constructor(C* obj) : cond_inv</* VR = */ none, C>( + boost::contract::from_constructor, obj) {} + +private: + #if !defined(BOOST_CONTRACT_NO_ENTRY_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_OLDS) + void init() /* override */ { + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + #endif + + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + { + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + checking k; + #endif + this->check_entry_static_inv(); + // No object before ctor body so check only static inv at + // entry. Ctor pre checked by constructor_precondition. + } + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + this->copy_old(); + #endif + } + #endif + +public: + #if !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + ~constructor() BOOST_NOEXCEPT_IF(false) { + this->assert_initialized(); + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + checking k; + #endif + + // If ctor body threw, no obj so check only static inv. Otherwise, + // obj constructed so check static inv, non-static inv, and post. + if(std::uncaught_exception()) { + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + this->check_exit_static_inv(); + #endif + #ifndef BOOST_CONTRACT_NO_EXCEPTS + this->check_except(); + #endif + } else { + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + this->check_exit_all_inv(); + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + this->check_post(none()); + #endif + } + } + #endif +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/operation/destructor.hpp b/boost/contract/detail/operation/destructor.hpp new file mode 100644 index 0000000000..ea8d8780a1 --- /dev/null +++ b/boost/contract/detail/operation/destructor.hpp @@ -0,0 +1,102 @@ + +#ifndef BOOST_CONTRACT_DETAIL_DESTRUCTOR_HPP_ +#define BOOST_CONTRACT_DETAIL_DESTRUCTOR_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_inv.hpp> +#include <boost/contract/detail/none.hpp> +#if !defined(BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION) && ( \ + !defined(BOOST_CONTRACT_NO_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS)) + #include <boost/contract/detail/checking.hpp> +#endif +#if !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + #include <boost/config.hpp> + #include <exception> +#endif + +namespace boost { namespace contract { namespace detail { + +// Dtor subcontracting impl via C++ obj destruction mechanism. +template<class C> // Non-copyable base. +class destructor : public cond_inv</* VR = */ none, C> { +public: + explicit destructor(C* obj) : cond_inv</* VR = */ none, C>( + boost::contract::from_destructor, obj) {} + +private: + #if !defined(BOOST_CONTRACT_NO_ENTRY_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_OLDS) + void init() /* override */ { + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + #endif + + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + { + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + checking k; + #endif + // Obj exists (before dtor body), check static and non- inv. + this->check_entry_all_inv(); + // Dtor cannot have pre because it has no parameters. + } + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + this->copy_old(); + #endif + } + #endif + +public: + #if !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + ~destructor() BOOST_NOEXCEPT_IF(false) { + this->assert_initialized(); + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + checking k; + #endif + + // If dtor body threw, obj still exists so check subcontracted + // static and non- inv (but no post because of throw). Otherwise, + // obj destructed so check static inv and post (even if there is no + // obj after dtor body, this library allows dtor post, for example + // to check static members for an instance counter class). + // NOTE: In theory C++ destructors should not throw, but the + // language allows for that (even if in C++11 dtors declarations are + // implicitly noexcept(true) unless specified otherwise) so this + // library must handle such a case. + if(std::uncaught_exception()) { + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + this->check_exit_all_inv(); + #endif + #ifndef BOOST_CONTRACT_NO_EXCEPTS + this->check_except(); + #endif + } else { + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + this->check_exit_static_inv(); + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + this->check_post(none()); + #endif + } + } + #endif +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/operation/function.hpp b/boost/contract/detail/operation/function.hpp new file mode 100644 index 0000000000..db0503c33b --- /dev/null +++ b/boost/contract/detail/operation/function.hpp @@ -0,0 +1,82 @@ + +#ifndef BOOST_CONTRACT_DETAIL_FUNCTION_HPP_ +#define BOOST_CONTRACT_DETAIL_FUNCTION_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> +#if !defined(BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION) && ( \ + !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS)) + #include <boost/contract/detail/checking.hpp> +#endif +#if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + #include <boost/config.hpp> + #include <exception> +#endif + +namespace boost { namespace contract { namespace detail { + +// Used for free function, private and protected member functions. +class function : public cond_post</* VR = */ none> { // Non-copyable base. +public: + explicit function() : cond_post</* VR = */ none>( + boost::contract::from_function) {} + +private: + #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_OLDS) + void init() /* override */ { + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + #endif + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + { + #if !defined(BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION) && \ + !defined( \ + BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION) + checking k; + #endif + this->check_pre(); + } + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + this->copy_old(); + #endif + } + #endif + +public: + #if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + ~function() BOOST_NOEXCEPT_IF(false) { + this->assert_initialized(); + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + checking k; + #endif + + if(std::uncaught_exception()) { + #ifndef BOOST_CONTRACT_NO_EXCEPTS + this->check_except(); + #endif + } else { + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + this->check_post(none()); + #endif + } + } + #endif +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/operation/public_function.hpp b/boost/contract/detail/operation/public_function.hpp new file mode 100644 index 0000000000..6392e4ddbe --- /dev/null +++ b/boost/contract/detail/operation/public_function.hpp @@ -0,0 +1,161 @@ + +#ifndef BOOST_CONTRACT_DETAIL_PUBLIC_FUNCTION_HPP_ +#define BOOST_CONTRACT_DETAIL_PUBLIC_FUNCTION_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/virtual.hpp> +#include <boost/contract/core/exception.hpp> +#include <boost/contract/core/config.hpp> +#include <boost/contract/detail/condition/cond_subcontracting.hpp> +#include <boost/contract/detail/tvariadic.hpp> +#include <boost/contract/core/virtual.hpp> +#if !defined(BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION) && ( \ + !defined(BOOST_CONTRACT_NO_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS)) + #include <boost/contract/detail/checking.hpp> +#endif +#if !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + #include <boost/config.hpp> +#endif +#if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + #include <exception> +#endif + +namespace boost { namespace contract { namespace detail { + +template< + class O, typename VR, typename F, class C + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS) + BOOST_CONTRACT_DETAIL_TVARIADIC_TPARAMS_Z(1, BOOST_CONTRACT_MAX_ARGS, Args) +> +class public_function : // Non-copyable base. + public cond_subcontracting< + O, VR, F, C + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS) + BOOST_CONTRACT_DETAIL_TVARIADIC_ARGS_Z(1, BOOST_CONTRACT_MAX_ARGS, Args) + > +{ +public: + explicit public_function( + boost::contract::virtual_* v, C* obj, VR& r + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS) + BOOST_CONTRACT_DETAIL_TVARIADIC_FPARAMS_Z(1, + BOOST_CONTRACT_MAX_ARGS, Args, &, args) + ) : + cond_subcontracting< + O, VR, F, C + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS) + BOOST_CONTRACT_DETAIL_TVARIADIC_ARGS_Z(1, + BOOST_CONTRACT_MAX_ARGS, Args) + >( + boost::contract::from_function, v, obj, r + BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS) + BOOST_CONTRACT_DETAIL_TVARIADIC_ARGS_Z(1, + BOOST_CONTRACT_MAX_ARGS, args) + ) + {} + +private: + #if !defined(BOOST_CONTRACT_NO_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + void init() /* override */ { + #if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + this->init_subcontracted_old(); + #endif + if(!this->base_call()) { + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + #endif + { // Acquire checking guard. + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + checking k; + #endif + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + this->check_subcontracted_entry_inv(); + #endif + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + #ifndef \ + BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION + this->check_subcontracted_pre(); + } // Release checking guard (after pre check). + #else + } // Release checking guard (before pre check). + this->check_subcontracted_pre(); + #endif + #else + } // Release checking guard. + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + this->copy_subcontracted_old(); + #endif + } else { + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + this->check_subcontracted_entry_inv(); + #endif + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + this->check_subcontracted_pre(); + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + this->copy_subcontracted_old(); + #endif + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + this->check_subcontracted_exit_inv(); + #endif + if(std::uncaught_exception()) { + #ifndef BOOST_CONTRACT_NO_EXCEPTS + this->check_subcontracted_except(); + #endif + } else { + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + this->check_subcontracted_post(); + #endif + } + } + } + #endif + +public: + #if !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + ~public_function() BOOST_NOEXCEPT_IF(false) { + this->assert_initialized(); + if(!this->base_call()) { + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + checking k; + #endif + + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + this->check_subcontracted_exit_inv(); + #endif + if(std::uncaught_exception()) { + #ifndef BOOST_CONTRACT_NO_EXCEPTS + this->check_subcontracted_except(); + #endif + } else { + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + this->check_subcontracted_post(); + #endif + } + } + } + #endif +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/operation/static_public_function.hpp b/boost/contract/detail/operation/static_public_function.hpp new file mode 100644 index 0000000000..d49fcd091d --- /dev/null +++ b/boost/contract/detail/operation/static_public_function.hpp @@ -0,0 +1,103 @@ + +#ifndef BOOST_CONTRACT_DETAIL_STATIC_PUBLIC_FUNCTION_HPP_ +#define BOOST_CONTRACT_DETAIL_STATIC_PUBLIC_FUNCTION_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_inv.hpp> +#include <boost/contract/detail/none.hpp> +#if !defined(BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION) && ( \ + !defined(BOOST_CONTRACT_NO_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS)) + #include <boost/contract/detail/checking.hpp> +#endif +#if !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + #include <boost/config.hpp> + #include <exception> +#endif + +namespace boost { namespace contract { namespace detail { + +// No subcontracting because static so no obj and no substitution principle. +template<class C> // Non-copyable base. +class static_public_function : public cond_inv</* VR = */ none, C> { +public: + explicit static_public_function() : cond_inv</* VR = */ none, C>( + boost::contract::from_function, /* obj = */ 0) {} + +private: + #if !defined(BOOST_CONTRACT_NO_ENTRY_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_OLDS) + void init() /* override */ { + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + #endif + #if !defined(BOOST_CONTRACT_NO_ENTRY_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_PRECONDITIONS) + { // Acquire checking guard. + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + checking k; + #endif + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + this->check_entry_static_inv(); + #endif + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + #ifndef \ + BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION + this->check_pre(); + } // Release checking guard (after pre check). + #else + } // Release checking guard (before pre check). + this->check_pre(); + #endif + #else + } // Release checking guard + #endif + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + this->copy_old(); + #endif + } + #endif + +public: + #if !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + ~static_public_function() BOOST_NOEXCEPT_IF(false) { + this->assert_initialized(); + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(checking::already()) return; + checking k; + #endif + + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + this->check_exit_static_inv(); + #endif + if(std::uncaught_exception()) { + #ifndef BOOST_CONTRACT_NO_EXCEPTS + this->check_except(); + #endif + } else { + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + this->check_post(none()); + #endif + } + } + #endif +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/operator_safe_bool.hpp b/boost/contract/detail/operator_safe_bool.hpp new file mode 100644 index 0000000000..65edc32dd8 --- /dev/null +++ b/boost/contract/detail/operator_safe_bool.hpp @@ -0,0 +1,73 @@ + +#ifndef BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL_HPP_ +#define BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL_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/detail/name.hpp> +#include <boost/config.hpp> +#include <boost/detail/workaround.hpp> + +// NOTE: This code is inspired by <boost/shared_ptr/detail/operator_bool.hpp>. + +/* PRIVATE */ + +// operator! is redundant, but some compilers need it. +#define BOOST_CONTRACT_OPERATOR_SAFE_BOOL_NOT_(bool_expr) \ + bool operator!() const BOOST_NOEXCEPT { return !(bool_expr); } + +/* PUBLIC */ + +#if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) && \ + !defined(BOOST_NO_CXX11_NULLPTR) + #define BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(this_type, bool_expr) \ + explicit operator bool() const BOOST_NOEXCEPT { return (bool_expr); } \ + BOOST_CONTRACT_OPERATOR_SAFE_BOOL_NOT_(bool_expr) +#elif (defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, < 0x570) ) || \ + defined(__CINT__) + #define BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(this_type, bool_expr) \ + operator bool() const BOOST_NOEXCEPT { return (bool_expr); } \ + BOOST_CONTRACT_OPERATOR_SAFE_BOOL_NOT_(bool_expr) +#elif defined(_MANAGED) + #define BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(this_type, bool_expr) \ + static void BOOST_CONTRACT_DETAIL_NAME1(operator_safe_bool_func)( \ + this_type***) {} \ + typedef void (*BOOST_CONTRACT_DETAIL_NAME1(operator_safe_bool_type))( \ + this_type***); \ + operator BOOST_CONTRACT_DETAIL_NANE(operator_safe_bool_type)() \ + const BOOST_NOEXCEPT { \ + return (bool_expr) ? \ + &BOOST_CONTRACT_DETAIL_NAME1(operator_safe_bool_func) : 0; \ + } \ + BOOST_CONTRACT_OPERATOR_SAFE_BOOL_NOT_(bool_expr) +#elif (defined(__MWERKS__) && BOOST_WORKAROUND(__MWERKS__, < 0x3200)) || \ + (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 304)) || \ + (defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590)) + #define BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(this_type, bool_expr) \ + void BOOST_CONTRACT_DETAIL_NAME1(operator_safe_bool_func)() const {} \ + typedef void (this_type::*BOOST_CONTRACT_DETAIL_NAME1( \ + operator_safe_bool_type))() const; \ + operator BOOST_CONTRACT_DETAIL_NAME1(operator_safe_bool_type)() \ + const BOOST_NOEXCEPT { \ + return (bool_expr) ? &this_type:: \ + BOOST_CONTRACT_DETAIL_NAME1(operator_safe_bool_func) : 0; \ + } \ + BOOST_CONTRACT_OPERATOR_SAFE_BOOL_NOT_(bool_expr) +#else + #define BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(this_type, bool_expr) \ + void* BOOST_CONTRACT_DETAIL_NAME1(operator_safe_bool_data); \ + typedef void* this_type::*BOOST_CONTRACT_DETAIL_NAME1( \ + operator_safe_bool_type);\ + operator BOOST_CONTRACT_DETAIL_NAME1(operator_safe_bool_type)() \ + const BOOST_NOEXCEPT { \ + return (bool_expr) ? &this_type:: \ + BOOST_CONTRACT_DETAIL_NAME1(operator_safe_bool_data) : 0; \ + } \ + BOOST_CONTRACT_OPERATOR_SAFE_BOOL_NOT_(bool_expr) +#endif + +#endif // #include guard + diff --git a/boost/contract/detail/preprocessor/keyword/private.hpp b/boost/contract/detail/preprocessor/keyword/private.hpp new file mode 100644 index 0000000000..2fc0d853f4 --- /dev/null +++ b/boost/contract/detail/preprocessor/keyword/private.hpp @@ -0,0 +1,35 @@ + +#ifndef BOOST_CONTRACT_DETAIL_PP_KEYWORD_PRIVATE_HPP_ +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_PRIVATE_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/detail/preprocessor/keyword/utility/is.hpp> +#include <boost/preprocessor/cat.hpp> + +/* PRIVATE */ + +// Must expand to a single comma `,` (not local macros, do not #undefine). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_PRIVATE_CAT_TO_COMMAprivate , + +// Must expand to empty `` (not local macros, do not #undefine). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_PRIVATE_CAT_TO_EMPTYprivate + +/* PUBLIC */ + +// Precondition: tokens must start with a token concatenable to a macro name +// (e.g., a literal or integral token). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PRIVATE(tokens) \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS( \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_PRIVATE_CAT_TO_COMMA, tokens) + +// Precondition: tokens must start with `private` (this can be +// checked with `..._IS_PRIVATE` macro above). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_REMOVE_PRIVATE(tokens) \ + BOOST_PP_CAT(BOOST_CONTRACT_DETAIL_PP_KEYWORD_PRIVATE_CAT_TO_EMPTY, tokens) + +#endif // #include guard + diff --git a/boost/contract/detail/preprocessor/keyword/protected.hpp b/boost/contract/detail/preprocessor/keyword/protected.hpp new file mode 100644 index 0000000000..e9ac94e78c --- /dev/null +++ b/boost/contract/detail/preprocessor/keyword/protected.hpp @@ -0,0 +1,36 @@ + +#ifndef BOOST_CONTRACT_DETAIL_PP_KEYWORD_PROTECTED_HPP_ +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_PROTECTED_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/detail/preprocessor/keyword/utility/is.hpp> +#include <boost/preprocessor/cat.hpp> + +/* PRIVATE */ + +// Must expand to a single comma `,` (not local macros, do not #undefine). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_PROTECTED_CAT_TO_COMMAprotected , + +// Must expand to empty `` (not local macros, do not #undefine). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_PROTECTED_CAT_TO_EMPTYprotected + +/* PUBLIC */ + +// Precondition: tokens must start with a token concatenable to a macro name +// (e.g., a literal or integral token). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PROTECTED(tokens) \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS( \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_PROTECTED_CAT_TO_COMMA, tokens) + +// Precondition: tokens must start with `protected` (this can be +// checked with `..._IS_PROTECTED` macro above). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_REMOVE_PROTECTED(tokens) \ + BOOST_PP_CAT(BOOST_CONTRACT_DETAIL_PP_KEYWORD_PROTECTED_CAT_TO_EMPTY, \ + tokens) + +#endif // #include guard + diff --git a/boost/contract/detail/preprocessor/keyword/public.hpp b/boost/contract/detail/preprocessor/keyword/public.hpp new file mode 100644 index 0000000000..b5e7994610 --- /dev/null +++ b/boost/contract/detail/preprocessor/keyword/public.hpp @@ -0,0 +1,35 @@ + +#ifndef BOOST_CONTRACT_DETAIL_PP_KEYWORD_PUBLIC_HPP_ +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_PUBLIC_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/detail/preprocessor/keyword/utility/is.hpp> +#include <boost/preprocessor/cat.hpp> + +/* PRIVATE */ + +// Must expand to a single comma `,` (not local macros, do not #undefine). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_PUBLIC_CAT_TO_COMMApublic , + +// Must expand to empty `` (not local macros, do not #undefine). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_PUBLIC_CAT_TO_EMPTYpublic + +/* PUBLIC */ + +// Precondition: tokens must start with a token concatenable to a macro name +// (e.g., a literal or integral token). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_PUBLIC(tokens) \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS( \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_PUBLIC_CAT_TO_COMMA, tokens) + +// Precondition: tokens must start with `public` (this can be +// checked with `..._IS_PUBLIC` macro above). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_REMOVE_PUBLIC(tokens) \ + BOOST_PP_CAT(BOOST_CONTRACT_DETAIL_PP_KEYWORD_PUBLIC_CAT_TO_EMPTY, tokens) + +#endif // #include guard + diff --git a/boost/contract/detail/preprocessor/keyword/utility/is.hpp b/boost/contract/detail/preprocessor/keyword/utility/is.hpp new file mode 100644 index 0000000000..d786033544 --- /dev/null +++ b/boost/contract/detail/preprocessor/keyword/utility/is.hpp @@ -0,0 +1,30 @@ + +#ifndef BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS_HPP_ +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS_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/preprocessor/cat.hpp> +#include <boost/preprocessor/variadic/size.hpp> + +/* PRIVATE */ + +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS_1 0 +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS_2 1 + +/* PUBLIC */ + +// Precondition: A macro named `cat_to_comma_prefix ## token-to-check` must be +// #defined to expand to `,`. +// Precondition: tokens must start with a token concatenable to a macro name +// (e.g., a literal or integral token). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS( \ + cat_to_comma_prefix, tokens) \ + BOOST_PP_CAT(BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS_, \ + BOOST_PP_VARIADIC_SIZE(BOOST_PP_CAT(cat_to_comma_prefix, tokens))) + +#endif // #include guard + diff --git a/boost/contract/detail/preprocessor/keyword/virtual.hpp b/boost/contract/detail/preprocessor/keyword/virtual.hpp new file mode 100644 index 0000000000..2acfaa1de3 --- /dev/null +++ b/boost/contract/detail/preprocessor/keyword/virtual.hpp @@ -0,0 +1,35 @@ + +#ifndef BOOST_CONTRACT_DETAIL_PP_KEYWORD_VIRTUAL_HPP_ +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_VIRTUAL_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/detail/preprocessor/keyword/utility/is.hpp> +#include <boost/preprocessor/cat.hpp> + +/* PRIVATE */ + +// Must expand to a single comma `,` (not local macros, do not #undefine). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_VIRTUAL_CAT_TO_COMMAvirtual , + +// Must expand to empty `` (not local macros, do not #undefine). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_VIRTUAL_CAT_TO_EMPTYvirtual + +/* PUBLIC */ + +// Precondition: tokens must start with a token concatenable to a macro name +// (e.g., a literal or integral token). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_IS_VIRTUAL(tokens) \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_UTILITY_IS( \ + BOOST_CONTRACT_DETAIL_PP_KEYWORD_VIRTUAL_CAT_TO_COMMA, tokens) + +// Precondition: tokens must start with `virtual` (this can be +// checked with `..._IS_VIRTUAL` macro above). +#define BOOST_CONTRACT_DETAIL_PP_KEYWORD_REMOVE_VIRTUAL(tokens) \ + BOOST_PP_CAT(BOOST_CONTRACT_DETAIL_PP_KEYWORD_VIRTUAL_CAT_TO_EMPTY, tokens) + +#endif // #include guard + diff --git a/boost/contract/detail/static_local_var.hpp b/boost/contract/detail/static_local_var.hpp new file mode 100644 index 0000000000..53495a089a --- /dev/null +++ b/boost/contract/detail/static_local_var.hpp @@ -0,0 +1,41 @@ + +#ifndef BOOST_CONTRACT_DETAIL_STATIC_LOCAL_VAR_HPP_ +#define BOOST_CONTRACT_DETAIL_STATIC_LOCAL_VAR_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 + +namespace boost { namespace contract { namespace detail { + +// This is used to hold the state of this library (already checking assertions, +// failure handers, mutexes, etc.). Local static variables are used instead of +// global or class-level static variables to avoid ODR errors when this library +// is used as header-only. + +// Use T's default constructor to init the local var. +template<typename Tag, typename T> +struct static_local_var { + static T& ref() { + static T data; + return data; + } +}; + +// Use `init` param to init local var (Init same as or convertible to T). +// NOTE: Template specializations could be used to program both this and the +// template above together but some pre-C++11 compilers give errors (e.g., Clang +// without -std=c++11), plus the `_init` postfix is more readable at call site. +template<typename Tag, typename T, typename Init, Init init> +struct static_local_var_init { + static T& ref() { + static T data = init; + return data; + } +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/tvariadic.hpp b/boost/contract/detail/tvariadic.hpp new file mode 100644 index 0000000000..3172d0972b --- /dev/null +++ b/boost/contract/detail/tvariadic.hpp @@ -0,0 +1,190 @@ + +#ifndef BOOST_CONTRACT_DETAIL_TVARIADIC_HPP_ +#define BOOST_CONTRACT_DETAIL_TVARIADIC_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/config.hpp> +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES + #define BOOST_CONTRACT_DETAIL_TVARIADIC 0 +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC 1 +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #include <tuple> + + /* CODE */ + + namespace boost { namespace contract { namespace detail { + namespace tvariadic_ { + template<int...> struct indexes {}; + + template<int N, int... I> struct indexes_of : + indexes_of<N - 1, N - 1, I...> {}; + template<int... I> struct indexes_of<0, I...> + { typedef indexes<I...> type; }; + } } } } // namespace + +#else + #include <boost/preprocessor/repetition/enum.hpp> + #include <boost/preprocessor/repetition/repeat.hpp> + #include <boost/preprocessor/tuple/elem.hpp> + #include <boost/preprocessor/punctuation/comma_if.hpp> + #include <boost/preprocessor/cat.hpp> + + /* PRIVATE */ + + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_ELEM_(z, n, tuple) \ + BOOST_PP_CAT(tuple, n) + + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INIT_(z, n, tuplevar_values) \ + BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, tuplevar_values), n)( \ + BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, tuplevar_values), n)) + + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_(z, n, type_qualifier_name) \ + BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 0, type_qualifier_name), n) \ + BOOST_PP_TUPLE_ELEM(3, 1, type_qualifier_name) \ + BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 2, type_qualifier_name), n) \ + ; + + #define BOOST_CONTRACT_DETAIL_NO_TVARIADIC_ENUM_(z, n, tokens) \ + tokens + + #define BOOST_CONTRACT_DETAIL_TVARIADIC_ARG_(z, n, name) \ + BOOST_PP_CAT(name, n) + + #define BOOST_CONTRACT_DETAIL_TVARIADIC_FPARAM_(z, n, type_qualifier_name) \ + BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 0, type_qualifier_name), n) \ + BOOST_PP_TUPLE_ELEM(3, 1, type_qualifier_name) \ + BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 2, type_qualifier_name), n) + + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TPARAM_(z, n, name) \ + typename BOOST_PP_CAT(name, n) +#endif + +/* PUBLIC */ + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(arity) \ + , +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(arity) \ + BOOST_PP_COMMA_IF(arity) +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_NO_TVARIADIC_COMMA(arity) /* nothing */ +#else + #define BOOST_CONTRACT_DETAIL_NO_TVARIADIC_COMMA(arity) \ + BOOST_PP_COMMA_IF(arity) +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_SIZEOF(arity, name) sizeof...(name) +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_SIZEOF(arity, name) arity +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TPARAMS_Z(z, arity, name) \ + typename... name +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TPARAMS_Z(z, arity, name) \ + BOOST_PP_ENUM_ ## z(arity, BOOST_CONTRACT_DETAIL_TVARIADIC_TPARAM_, \ + name) +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_FPARAMS_Z( \ + z, arity, type, qualifier, name) \ + type qualifier ... name +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_FPARAMS_Z( \ + z, arity, type, qualifier, name) \ + BOOST_PP_ENUM_ ## z(arity, BOOST_CONTRACT_DETAIL_TVARIADIC_FPARAM_, \ + (type, qualifier, name)) +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_ARGS_Z(z, arity, name) \ + name... +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_ARGS_Z(z, arity, name) \ + BOOST_PP_ENUM_ ## z(arity, BOOST_CONTRACT_DETAIL_TVARIADIC_ARG_, name) +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_NO_TVARIADIC_ENUM_Z(z, arity, tokens) \ + /* nothing */ +#else + #define BOOST_CONTRACT_DETAIL_NO_TVARIADIC_ENUM_Z(z, arity, tokens) \ + BOOST_PP_ENUM_ ## z(arity, BOOST_CONTRACT_DETAIL_NO_TVARIADIC_ENUM_, \ + tokens) +#endif + +// Tuple. + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_Z( \ + z, arity, type, qualifier, name) \ + std::tuple<type qualifier ...> name; +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_Z( \ + z, arity, type, qualifier, name) \ + BOOST_PP_REPEAT_ ## z(arity, BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_, \ + (type, qualifier, name)) +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INIT_Z(z, \ + arity, tuple, values) \ + tuple(values...) +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INIT_Z(z, \ + arity, tuple, values) \ + BOOST_PP_ENUM_ ## z(arity, BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INIT_,\ + (tuple, values)) +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_TPARAM(indexes) \ + int... indexes +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_TPARAM(indexes) \ + /* nothing */ +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_FPARAM(_indexes) \ + boost::contract::detail::tvariadic_::indexes<_indexes...> +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_FPARAM(_indexes) \ + /* nothing */ +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_OF(tuple_type) \ + typename boost::contract::detail::tvariadic_::indexes_of< \ + sizeof...(tuple_type)>::type() +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_OF(unused) \ + /* nothing */ +#endif + +#if BOOST_CONTRACT_DETAIL_TVARIADIC + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_ELEMS_Z( \ + z, arity, indexes, tuple) \ + std::get<indexes>(tuple)... +#else + #define BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_ELEMS_Z( \ + z, arity, indexes, tuple) \ + BOOST_PP_ENUM_ ## z(arity, BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_ELEM_,\ + tuple) +#endif + +#endif // #include guard + diff --git a/boost/contract/detail/type_traits/member_function_types.hpp b/boost/contract/detail/type_traits/member_function_types.hpp new file mode 100644 index 0000000000..4966f1db1e --- /dev/null +++ b/boost/contract/detail/type_traits/member_function_types.hpp @@ -0,0 +1,72 @@ + +#ifndef BOOST_CONTRACT_DETAIL_MEMBER_FUNCTION_TYPES_HPP_ +#define BOOST_CONTRACT_DETAIL_MEMBER_FUNCTION_TYPES_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/detail/none.hpp> +#include <boost/function_types/parameter_types.hpp> +#include <boost/function_types/result_type.hpp> +#include <boost/function_types/property_tags.hpp> +#include <boost/type_traits/is_const.hpp> +#include <boost/type_traits/is_volatile.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/mpl/pop_front.hpp> +#include <boost/mpl/push_back.hpp> +#include <boost/mpl/back.hpp> +#include <boost/mpl/and.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/identity.hpp> + +namespace boost { + namespace contract { + class virtual_; + } +} + +namespace boost { namespace contract { namespace detail { + +template<class C, typename F> +struct member_function_types { + typedef typename boost::function_types::result_type<F>::type result_type; + + // Never include leading class type. + typedef typename boost::mpl::pop_front<typename boost::function_types:: + parameter_types<F>::type>::type argument_types; + + // Always include trailing virtual_* type. + typedef typename boost::mpl::if_<boost::is_same<typename boost:: + mpl::back<argument_types>::type, boost::contract::virtual_*>, + boost::mpl::identity<argument_types> + , + boost::mpl::push_back<argument_types, boost::contract::virtual_*> + >::type::type virtual_argument_types; + + typedef typename boost::mpl::if_<boost::mpl::and_<boost::is_const<C>, + boost::is_volatile<C> >, + boost::function_types::cv_qualified + , typename boost::mpl::if_<boost::is_const<C>, + boost::function_types::const_non_volatile + , typename boost::mpl::if_<boost::is_volatile<C>, + boost::function_types::volatile_non_const + , + boost::function_types::null_tag + >::type>::type>::type property_tag; +}; + +// Also handles none type. +template<class C> +struct member_function_types<C, none> { + typedef none result_type; + typedef none argument_types; + typedef none virtual_argument_types; + typedef none property_tag; +}; + +} } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/type_traits/mirror.hpp b/boost/contract/detail/type_traits/mirror.hpp new file mode 100644 index 0000000000..ef71451677 --- /dev/null +++ b/boost/contract/detail/type_traits/mirror.hpp @@ -0,0 +1,111 @@ + +#ifndef BOOST_CONTRACT_DETAIL_MIRROR_HPP_ +#define BOOST_CONTRACT_DETAIL_MIRROR_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/detail/name.hpp> +#include <boost/function_types/member_function_pointer.hpp> +#include <boost/function_types/function_pointer.hpp> +#include <boost/function_types/property_tags.hpp> +#include <boost/mpl/push_front.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/preprocessor/control/iif.hpp> +#include <boost/preprocessor/tuple/rem.hpp> +#include <boost/preprocessor/tuple/eat.hpp> + +// NOTE: Unfortunately, it is not possible to use Boost.TTI because it not +// always works on MSVC (e.g., when the mirror meta-function is invoked +// multiple times, MSVC 2010 gives an internal compiler error). This is a +// simpler mirror implementation that seems to work better on MSVC. + +/* PRIVATE */ + +#define BOOST_CONTRACT_DETAIL_MIRROR_END_(tparam) \ + template<typename> \ + static boost::contract::detail::mirror::no& apply(...); \ + public: \ + static bool const value = sizeof(apply<tparam>(0)) == \ + sizeof(boost::contract::detail::mirror::yes); \ + typedef boost::mpl::bool_<value> type; + +#define BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION_(is_static, \ + trait, func_name) \ + template< \ + typename BOOST_CONTRACT_DETAIL_NAME1(T), \ + typename BOOST_CONTRACT_DETAIL_NAME1(R), \ + class BOOST_CONTRACT_DETAIL_NAME1(P), \ + class BOOST_CONTRACT_DETAIL_NAME1(G) = boost::function_types::null_tag \ + > \ + class trait { \ + template<class BOOST_CONTRACT_DETAIL_NAME1(C)> \ + static boost::contract::detail::mirror::yes& apply( \ + boost::contract::detail::mirror::check_function< \ + typename \ + BOOST_PP_IIF(is_static, \ + boost::function_types::function_pointer \ + , \ + boost::function_types::member_function_pointer \ + ) \ + < \ + typename boost::mpl::push_front< \ + BOOST_PP_IIF(is_static, \ + BOOST_CONTRACT_DETAIL_NAME1(P) \ + BOOST_PP_TUPLE_EAT(2) \ + , \ + BOOST_PP_TUPLE_REM(2) \ + )( \ + typename boost::mpl::push_front< \ + BOOST_CONTRACT_DETAIL_NAME1(P), \ + BOOST_CONTRACT_DETAIL_NAME1(C) \ + >::type \ + ) \ + , BOOST_CONTRACT_DETAIL_NAME1(R) \ + >::type, \ + BOOST_CONTRACT_DETAIL_NAME1(G) \ + >::type, \ + &BOOST_CONTRACT_DETAIL_NAME1(C)::func_name \ + >* \ + ); \ + BOOST_CONTRACT_DETAIL_MIRROR_END_( \ + BOOST_CONTRACT_DETAIL_NAME1(T)) \ + }; + +/* PUBLIC */ + +#define BOOST_CONTRACT_DETAIL_MIRROR_HAS_TYPE(trait, type_name)\ + template<typename BOOST_CONTRACT_DETAIL_NAME1(T)> \ + class trait { \ + template<class BOOST_CONTRACT_DETAIL_NAME1(C)> \ + static boost::contract::detail::mirror::yes& apply( \ + typename BOOST_CONTRACT_DETAIL_NAME1(C)::type_name*); \ + BOOST_CONTRACT_DETAIL_MIRROR_END_( \ + BOOST_CONTRACT_DETAIL_NAME1(T)) \ + }; + +#define BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION( \ + trait, func_name) \ + BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION_( \ + /* is_static = */ 0, trait, func_name) + +#define BOOST_CONTRACT_DETAIL_MIRROR_HAS_STATIC_MEMBER_FUNCTION(trait, \ + func_name) \ + BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION_( \ + /* is_static = */ 1, trait, func_name) + +/* CODE */ + +namespace boost { namespace contract { namespace detail { namespace mirror { + +typedef class {} yes; +typedef yes no[2]; + +template<typename F, F> class check_function; + +} } } } // namespace + +#endif // #include guard + diff --git a/boost/contract/detail/type_traits/optional.hpp b/boost/contract/detail/type_traits/optional.hpp new file mode 100644 index 0000000000..453df2f778 --- /dev/null +++ b/boost/contract/detail/type_traits/optional.hpp @@ -0,0 +1,42 @@ + +#ifndef BOOST_CONTRACT_DETAIL_OPTIONAL_HPP_ +#define BOOST_CONTRACT_DETAIL_OPTIONAL_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/optional.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/type_traits/integral_constant.hpp> + +namespace boost { namespace contract { namespace detail { + +template<typename T> +struct is_optional : boost::false_type {}; +template<typename T> +struct is_optional<boost::optional<T> > : boost::true_type {}; + +template<typename T> +struct optional_value_type { typedef T type; }; +template<typename T> +struct optional_value_type<boost::optional<T> > { typedef T type; }; + +template<typename T> +struct remove_value_reference_if_optional { typedef T type; }; +template<typename T> +struct remove_value_reference_if_optional<boost::optional<T> > + { typedef typename boost::remove_reference<T>::type type; }; + +template<typename T> +T& optional_get(T& x) { return x; } +template<typename T> +T& optional_get(boost::optional<T>& x) { return x.get(); } +template<typename T> +T& optional_get(boost::optional<T&>& x) { return x.get(); } + +} } } // namespace + +#endif // #include guard + |