diff options
Diffstat (limited to 'boost/contract/core')
-rw-r--r-- | boost/contract/core/access.hpp | 183 | ||||
-rw-r--r-- | boost/contract/core/check_macro.hpp | 133 | ||||
-rw-r--r-- | boost/contract/core/config.hpp | 797 | ||||
-rw-r--r-- | boost/contract/core/constructor_precondition.hpp | 122 | ||||
-rw-r--r-- | boost/contract/core/exception.hpp | 953 | ||||
-rw-r--r-- | boost/contract/core/specify.hpp | 650 | ||||
-rw-r--r-- | boost/contract/core/virtual.hpp | 161 |
7 files changed, 2999 insertions, 0 deletions
diff --git a/boost/contract/core/access.hpp b/boost/contract/core/access.hpp new file mode 100644 index 0000000000..ba8334ba0d --- /dev/null +++ b/boost/contract/core/access.hpp @@ -0,0 +1,183 @@ + +#ifndef BOOST_CONTRACT_ACCESS_HPP_ +#define BOOST_CONTRACT_ACCESS_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 + +/** @file +Allow to declare invariants, base types, etc all as private members. +*/ + +// IMPORTANT: Included by contract_macro.hpp so must #if-guard all its includes. +#include <boost/contract/core/config.hpp> +#if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \ + defined(BOOST_CONTRACT_STATIC_LINK) + #include <boost/contract/detail/decl.hpp> + #include <boost/contract/detail/type_traits/mirror.hpp> +#endif +#ifndef BOOST_CONTRACT_NO_INVARIANTS + #include <boost/contract/detail/debug.hpp> + #include <boost/function_types/property_tags.hpp> + #include <boost/mpl/vector.hpp> +#endif + +namespace boost { namespace contract { + +#if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \ + defined(BOOST_CONTRACT_STATIC_LINK) + class virtual_; + + namespace detail { + BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1, + /* is_friend = */ 0, OO, RR, FF, CC, AArgs); + } +#endif +#ifndef BOOST_CONTRACT_NO_INVARIANTS + namespace detail { + template<typename RR, class CC> + class cond_inv; + } +#endif + +/** +Friend this class to declare invariants and base types as private members. + +Declare this class a friend of the user-defined class specifying the contracts +in order to declare the invariant functions and the base types @c typedef as +non-public members: + +@code +class u : + #define BASES public b, private w + BASES +{ + friend class boost::contract::access; + + typedef BOOST_CONTRACT_BASES(BASES) base_types; // Private. + #undef BASES + + void invariant() const { ... } // Private. + +public: + ... +}; +@endcode + +In real code, programmers will likely chose to declare this class as friend so +to fully control public interfaces of their user-defined classes. +This class is not intended to be directly used by programmers a part from +declaring it @c friend (and that is why this class does not have any public +member and it is not copyable). + +@warning Not declaring this class friend of user-defined classes will cause + compiler errors on some compilers (e.g., MSVC) because the private + members needed to check the contracts will not be accessible. + On other compilers (e.g., GCC and CLang), the private access will + instead fail SFINAE and no compiler error will be reported while + invariants and subcontracting will be silently skipped at run-time. + Therefore, programmers must make sure to either declare this class + as friend (preferred) or to always declare invariant functions and + base types @c typedef as public members. + +@see @RefSect{advanced.access_specifiers, Access Specifiers} +*/ +class access { // Non-copyable (see below). +/** @cond */ +private: // No public APIs (so users cannot use it directly by mistake). + + access(); // Should never be constructed (not even internally). + ~access(); + + // No boost::noncopyable to avoid its overhead when contracts disabled. + access(access&); + access& operator=(access&); + + #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \ + defined(BOOST_CONTRACT_STATIC_LINK) + BOOST_CONTRACT_DETAIL_MIRROR_HAS_TYPE(has_base_types, + BOOST_CONTRACT_BASES_TYPEDEF) + + template<class C> + struct base_types_of { + typedef typename C::BOOST_CONTRACT_BASES_TYPEDEF type; + }; + #endif + + #ifndef BOOST_CONTRACT_NO_INVARIANTS + BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION( + has_static_invariant_f, BOOST_CONTRACT_STATIC_INVARIANT_FUNC) + + BOOST_CONTRACT_DETAIL_MIRROR_HAS_STATIC_MEMBER_FUNCTION( + has_static_invariant_s, BOOST_CONTRACT_STATIC_INVARIANT_FUNC) + + template<class C> + struct has_static_invariant : has_static_invariant_s<C, void, + boost::mpl::vector<> > {}; + + template<class C> + static void static_invariant() { + C::BOOST_CONTRACT_STATIC_INVARIANT_FUNC(); + } + + template<class C> + class static_invariant_addr { // Class so to pass it as tparam. + typedef void (*func_ptr)(); + public: + static func_ptr apply() { + return &C::BOOST_CONTRACT_STATIC_INVARIANT_FUNC; + } + }; + + BOOST_CONTRACT_DETAIL_MIRROR_HAS_MEMBER_FUNCTION( + has_invariant_f, BOOST_CONTRACT_INVARIANT_FUNC) + + BOOST_CONTRACT_DETAIL_MIRROR_HAS_STATIC_MEMBER_FUNCTION( + has_invariant_s, BOOST_CONTRACT_INVARIANT_FUNC) + + template<class C> + struct has_cv_invariant : has_invariant_f<C, void, boost::mpl::vector<>, + boost::function_types::cv_qualified> {}; + + template<class C> + struct has_const_invariant : has_invariant_f<C, void, boost::mpl:: + vector<>, boost::function_types::const_qualified> {}; + + template<class C> + static void cv_invariant(C const volatile* obj) { + BOOST_CONTRACT_DETAIL_DEBUG(obj); + obj->BOOST_CONTRACT_INVARIANT_FUNC(); + } + + template<class C> + static void const_invariant(C const* obj) { + BOOST_CONTRACT_DETAIL_DEBUG(obj); + obj->BOOST_CONTRACT_INVARIANT_FUNC(); + } + #endif + + // Friends (used to limit library's public API). + // NOTE: Using friends here and in all other places in this library + // does not increase compilation times (I experimented replacing all + // friends with public and got the same compilation times). + #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \ + defined(BOOST_CONTRACT_STATIC_LINK) + BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1, + /* is_friend = */ 1, OO, RR, FF, CC, AArgs); + + BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTIONS_Z(1, + OO, RR, FF, CC, AArgs, vv, rr, ff, oobj, aargs) + #endif + #ifndef BOOST_CONTRACT_NO_INVARIANTS + template<typename RR, class CC> + friend class boost::contract::detail::cond_inv; + #endif +/** @endcond */ +}; + +} } // namespace + +#endif // #include guard + diff --git a/boost/contract/core/check_macro.hpp b/boost/contract/core/check_macro.hpp new file mode 100644 index 0000000000..3ecc93ea82 --- /dev/null +++ b/boost/contract/core/check_macro.hpp @@ -0,0 +1,133 @@ + +#ifndef BOOST_CONTRACT_CHECK_MACRO_HPP_ +#define BOOST_CONTRACT_CHECK_MACRO_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 + +/** @file +Macros for implementation checks. +*/ + +// IMPORTANT: Included by contract_macro.hpp so must #if-guard all its includes. +#include <boost/contract/core/config.hpp> +#include <boost/contract/detail/noop.hpp> + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + Preferred way to assert implementation check conditions. + + It is preferred to use this macro instead of programming implementation + checks in a nullary functor passed to @RefClass{boost::contract::check} + constructor because this macro will completely remove implementation checks + from the code when @RefMacro{BOOST_CONTRACT_NO_CHECKS} is defined: + + @code + void f() { + ... + BOOST_CONTRACT_CHECK(...); + ... + } + @endcode + + @RefMacro{BOOST_CONTRACT_CHECK}, @RefMacro{BOOST_CONTRACT_CHECK_AUDIT}, and + @RefMacro{BOOST_CONTRACT_CHECK_AXIOM} are the three assertion levels + predefined by this library for implementation checks. + + @see @RefSect{advanced.implementation_checks, Implementation Checks} + + @param cond Boolean condition to check within implementation code (function + body, etc.). + (This is not a variadic macro parameter so any comma it might + contain must be protected by round parenthesis, + @c BOOST_CONTRACT_CHECK((cond)) will always work.) + */ + #define BOOST_CONTRACT_CHECK(cond) +#elif !defined(BOOST_CONTRACT_NO_CHECKS) + #include <boost/contract/detail/check.hpp> + #include <boost/contract/detail/assert.hpp> + + #define BOOST_CONTRACT_CHECK(cond) \ + BOOST_CONTRACT_DETAIL_CHECK(BOOST_CONTRACT_DETAIL_ASSERT(cond)) +#else + #define BOOST_CONTRACT_CHECK(cond) /* nothing */ +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + Preferred way to assert implementation check conditions that are + computationally expensive, at least compared to the cost of executing the + function body. + + The specified condition will always be compiled and validated + syntactically, but it will not be evaluated at run-time unless + @RefMacro{BOOST_CONTRACT_AUDITS} is defined (undefined by default). + This macro is defined by code equivalent to: + + @code + #ifdef BOOST_CONTRACT_AUDITS + #define BOOST_CONTRACT_CHECK_AUDIT(cond) \ + BOOST_CONTRACT_CHECK(cond) + #else + #define BOOST_CONTRACT_CHECK_AUDIT(cond) \ + BOOST_CONTRACT_CHECK(true || cond) + #endif + @endcode + + @RefMacro{BOOST_CONTRACT_CHECK}, @RefMacro{BOOST_CONTRACT_CHECK_AUDIT}, and + @RefMacro{BOOST_CONTRACT_CHECK_AXIOM} are the three assertion levels + predefined by this library for implementation checks. + If there is a need, programmers are free to implement their own assertion + levels defining macros similar to the one above. + + @see @RefSect{extras.assertion_levels, Assertion Levels} + + @param cond Boolean condition to check within implementation code (function + body, etc.). + (This is not a variadic macro parameter so any comma it might + contain must be protected by round parenthesis, + @c BOOST_CONTRACT_CHECK_AUDIT((cond)) will always work.) + */ + #define BOOST_CONTRACT_CHECK_AUDIT(cond) +#elif defined(BOOST_CONTRACT_AUDITS) + #define BOOST_CONTRACT_CHECK_AUDIT(cond) \ + BOOST_CONTRACT_CHECK(cond) +#else + #define BOOST_CONTRACT_CHECK_AUDIT(cond) \ + BOOST_CONTRACT_DETAIL_NOEVAL(cond) +#endif + +/** +Preferred way to assert implementation check conditions that are computationally +prohibitive, at least compared to the cost of executing the function body. + +The specified condition will always be compiled and validated +syntactically, but it will never be evaluated at run-time. +This macro is defined by code equivalent to: + +@code +#define BOOST_CONTRACT_CHECK_AXIOM(cond) \ + BOOST_CONTRACT_CHECK(true || cond) +@endcode + +@RefMacro{BOOST_CONTRACT_CHECK}, @RefMacro{BOOST_CONTRACT_CHECK_AUDIT}, and +@RefMacro{BOOST_CONTRACT_CHECK_AXIOM} are the three assertion levels predefined +by this library for implementation checks. +If there is a need, programmers are free to implement their own assertion levels +defining macros similar to the one above. + +@see @RefSect{extras.assertion_levels, Assertion Levels} + +@param cond Boolean condition to check within implementation code (function + body, etc.). + (This is not a variadic macro parameter so any comma it might + contain must be protected by round parenthesis, + @c BOOST_CONTRACT_CHECK_AXIOM((cond)) will always work.) +*/ +#define BOOST_CONTRACT_CHECK_AXIOM(cond) \ + BOOST_CONTRACT_DETAIL_NOEVAL(cond) + +#endif // #include guard + diff --git a/boost/contract/core/config.hpp b/boost/contract/core/config.hpp new file mode 100644 index 0000000000..e33c2bff81 --- /dev/null +++ b/boost/contract/core/config.hpp @@ -0,0 +1,797 @@ + +#ifndef BOOST_CONTRACT_CONFIG_HPP_ +#define BOOST_CONTRACT_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 + +/** @file +Configure this library compile-time and run-time behaviours. +*/ + +// IMPORTANT: This header MUST NOT #include any other header of this lib. +// That way users can #include this header and not #include any of this lib +// headers after that depending on the contract 0/1 macros below ensuring no +// compilation overhead. + +// Export symbols when compiling as shared lib (for internal use only). (Named +// after similar macros in all Boost libs.) +// BOOST_CONTRACT_SOURCE + +// Disable automatic library selection for linking. (Named after similar macros +// in all Boost libs.) +// BOOST_CONTRACT_NO_LIB +// BOOST_ALL_NO_LIB + +#if (!defined(BOOST_CONTRACT_DYN_LINK) && defined(BOOST_ALL_DYN_LINK)) || \ + defined(BOOST_CONTRACT_DETAIL_DOXYGEN) + /** + Define this macro to compile this library as a shared library (recommended). + + If this macro is defined, this library is compiled so it can be linked + as a shared library (a.k.a., Dynamically Linked Library or DLL) to user + code. + Also, this library will automatically define this macro when Boost libraries + are built as dynamic libraries (e.g., defining @c BOOST_ALL_DYN_LINK). + + @warning In general this library will correctly check contracts at + run-time only when compiled as a shared library, unless user + code checks contracts in a single program unit (e.g., a single + program with only statically linked libraries that check + contracts). + Therefore, it is recommended to build and use this library as + a dynamic library by defining this macro (or equivalently by + building all Boost libraries as dynamic libraries and + @c BOOST_ALL_DYN_LINK is defined). + + @see @RefSect{getting_started.compilers_and_platforms, Compilers and + Platforms} + */ + #define BOOST_CONTRACT_DYN_LINK +#elif defined(BOOST_CONTRACT_DYN_LINK) && defined(BOOST_CONTRACT_STATIC_LINK) + #error "DYN_LINK defined with STATIC_LINK" +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + Define this macro to compile this library as a static library (not + recommended). + + If this macro is defined, this library is compiled so it can be linked + statically to user code. + This library build scripts will automatically define this macro when Boost + libraries are being built as static libraries. + + @warning This library is not guaranteed to always work correctly at + run-time when this macro is defined (define + @RefMacro{BOOST_CONTRACT_DYN_LINK} or @c BOOST_ALL_DYN_LINK + instead). + However, this macro can be defined and this library can be + safely used as a static library for user code that checks + contracts in a single program unit (e.g., a single program with + only statically linked libraries that check contracts). + + @see @RefSect{getting_started.compilers_and_platforms, Compilers and + Platforms} + */ + #define BOOST_CONTRACT_STATIC_LINK +#elif defined(BOOST_CONTRACT_STATIC_LINK) && defined(BOOST_CONTRACT_DYN_LINK) + #error "STATIC_LINK defined with DYN_LINK" +#endif + +#ifdef BOOST_CONTRACT_HEADER_ONLY + #error "leave DYN_LINK and STATIC_LINK undefined instead" +#elif (!defined(BOOST_CONTRACT_DYN_LINK) && \ + !defined(BOOST_CONTRACT_STATIC_LINK)) || \ + defined(BOOST_CONTRACT_DETAIL_DOXYGEN) + /** + Automatically defined by this library when it is being used as a header-only + library (not recommended). + + This library will define this macro when users do not define + @RefMacro{BOOST_CONTRACT_DYN_LINK} (or @c BOOST_ALL_DYN_LINK) and + @RefMacro{BOOST_CONTRACT_STATIC_LINK} (this macro is not a configuration + macro and this library will generate a compile-time error if users try to + define it directly). + When used as a header-only library, this library code does not have to be + compiled separately from user code, this library headers are simply included + and compiled as part of the user program. + + @warning This library is not guaranteed to always work correctly at + run-time when this macro is defined (define + @RefMacro{BOOST_CONTRACT_DYN_LINK} or @c BOOST_ALL_DYN_LINK + instead). + However, this macro can be defined and this library can be + safely used as a header-only library for user code that checks + contracts in a single program unit (e.g., a single program with + only statically linked libraries that check contracts). + + @see @RefSect{getting_started.compilers_and_platforms, Compilers and + Platforms} + */ + #define BOOST_CONTRACT_HEADER_ONLY +#endif + +#if (!defined(BOOST_CONTRACT_DISABLE_THREADS) && \ + defined(BOOST_DISABLE_THREADS)) || \ + defined(BOOST_CONTRACT_DETAIL_DOXYGEN) + /** + Define this macro to not lock internal library data for thread safety + (undefined by default). + + Defining this macro will make the library implementation code not thread + safe so this macro should not be defined unless the library is being used by + single-threaded applications only. + This library will automatically define this macro when Boost libraries are + built without threads (e.g., defining @c BOOST_DISABLE_THREADS). + + @note When this macro is left undefined this library needs to internally + use some sort of global lock (to ensure contract checking is + globally disabled when other contracts are being checked and also to + safely access failure handler functors). + That could introduce an undesired amount of synchronization in some + multi-threaded applications. + + @see @RefSect{contract_programming_overview.assertions, Assertions} + */ + #define BOOST_CONTRACT_DISABLE_THREADS +#endif + +#ifndef BOOST_CONTRACT_MAX_ARGS + /** + Maximum number of arguments for public function overrides on compilers that + do not support variadic templates (default to @c 10). + + On compilers that do not support variadic templates, this macro is defined + to the maximum number of arguments that public function overrides can have + and pass to @RefFunc{boost::contract::public_function} (users can redefine + this macro to a different value). + On compilers that support variadic templates, this macro has no effect. + + @note Regardless of the value of this macro and of compiler support for + variadic templates, there is an intrinsic limit of about 18 + arguments for public function overrides (because of similar limits + in Boost.MPL and Boost.FunctionTypes internally used by this + library). + + @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros} + */ + #define BOOST_CONTRACT_MAX_ARGS 10 +#endif + +#ifndef BOOST_CONTRACT_BASES_TYPEDEF + /** + Define the name of the base type @c typedef (@c base_types by default). + + This macro expands to the name of the @c typedef that lists the base + classes for subcontracting via @RefMacro{BOOST_CONTRACT_BASE_TYPES}: + + @code + class u : + #define BASES public b, private w + BASES + { + friend class boost::contract:access; + + typedef BOOST_CONTRACT_BASES(BASES) BOOST_CONTRACT_TYPEDEF; + #undef BASES + + ... + }; + @endcode + + Users can redefine this macro if the @c typedef must have a name different + from @c base_types (because of name clashes in user code, etc.). + + @see @RefSect{tutorial.base_classes__subcontracting_, Base Classes} + */ + #define BOOST_CONTRACT_BASES_TYPEDEF base_types +#endif + +#ifndef BOOST_CONTRACT_INVARIANT_FUNC + /** + Define the name of the class invariant member function (@c invariant by + default). + + This macro expands to the name of the @c const and <c>const volatile</c> + member functions that check class invariants and volatile class invariants + respectively: + + @code + class u { + friend class boost::contract::access; + + void BOOST_CONTRACT_INVARIANT_FUNC() const { + BOOST_CONTRACT_ASSERT(...); + ... + } + + void BOOST_CONTRACT_INVARIANT_FUNC() const volatile { + BOOST_CONTRACT_ASSERT(...); + ... + } + + ... + }; + @endcode + + Users can redefine this macro if the invariant functions must have a name + different from @c invariant (because of name clashes in user code, etc.). + + @note C++ does not allow to overload member functions based on the + @c static classifier, so this macro must always be defined to be + different than the function name defined for + @RefMacro{BOOST_CONTRACT_STATIC_INVARIANT_FUNC}. + + @see @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.volatile_public_functions, + Volatile Public Functions} + */ + #define BOOST_CONTRACT_INVARIANT_FUNC invariant +#endif + +#ifndef BOOST_CONTRACT_STATIC_INVARIANT_FUNC + /** + Define the name of the static invariant member function (@c static_invariant + by default). + + This macro expands to the name of the @c static member function that checks + static class invariants: + + @code + class u { + friend class boost::contract::access; + + static void BOOST_CONTRACT_STATIC_INVARIANT_FUNC() { + BOOST_CONTRACT_ASSERT(...); + ... + } + + ... + }; + @endcode + + Users can redefine this macro if the static invariant function must have a + name different from @c static_invariant (because of name clashes in user + code, etc.). + + @note C++ does not allow to overload member functions based on the + @c static classifier, so this macro must always be defined to be + different than the function name defined for + @RefMacro{BOOST_CONTRACT_INVARIANT_FUNC}. + + @see @RefSect{tutorial.class_invariants, Class Invariants} + */ + #define BOOST_CONTRACT_STATIC_INVARIANT_FUNC static_invariant +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + Disable some compile-time errors generated by this library (undefined by + default). + + Defining this macro disables a number of static checks and related + compile-time errors generated by this library, for example: + + @li The static invariant member @c BOOST_CONTRACT_STATIC_INVARIANT_FUNC + function must be declared @c static. + @li Non-static invariant member functions @c BOOST_CONTRACT_INVARIANT_FUNC + must be declared either @c const, <c>const volatile</c>, or + <c>volatile const</c>. + @li Derived classes that program contracts for one or more public function + overrides via @RefFunc{boost::contract::public_function} must also + define the @RefMacro{BOOST_CONTRACT_BASE_TYPES} @c typedef. + + In general, it is not recommended to define this macro because these + compile-time checks can guard against misuses of this library. + + @see @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{tutorial.base_classes__subcontracting_, Base Classes} + */ + #define BOOST_CONTRACT_PERMISSIVE +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + Code block to execute if contracts are not assigned to a + @RefClass{boost::contract::check} variable (undefined by default and + executes @c BOOST_ASSERT(false)). + + In general, there is a logic error in the program when contracts are not + assigned to a local variable of type @RefClass{boost::contract::check} + (because that is a misuse of this library). + Therefore, by default (i.e., when this macro is not defined) this library + calls <c>BOOST_ASSERT(false)</c> in those cases. + If this macro is defined, this library will execute the code expanded by the + macro instead of calling @c BOOST_ASSERT(false) (if programmers prefer to + throw an exception, etc.). + + This macro can be defined to be any block of code (use empty curly brackets + @c {} to generate no error), for example (on GCC): + @code + -DBOOST_CONTRACT_ON_MISSING_CHECK_DECL='{ throw std::logic_error("missing contract check declaration"); }' + @endcode + + @see @RefSect{tutorial, Tutorial} + */ + #define BOOST_CONTRACT_ON_MISSING_CHECK_DECL +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + Define this macro to not disable other assertions while checking + preconditions (undefined by default). + + Not disabling other assertions while checking preconditions can lead to + infinite recursion in user code so by default this macro is not defined. + + However, the @RefSect{bibliography, [1962]} proposal does not disable + assertions while checking preconditions because arguments can reach the + function body unchecked if assertions are disabled while checking + preconditions (e.g., when these same functions bodies are called to check + the preconditions in question). + This macro can be defined to obtain the behaviour specified in + @RefSect{bibliography, [1962]} (at the risk of infinite recursion). + + @see @RefSect{contract_programming_overview.feature_summary, + Feature Summary} + */ + #define BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + Define this macro to not disable any assertion while checking other + assertions (undefined by default). + + Not disabling assertions while checking other assertions can lead to + infinite recursion in user code so by default this macro is not defined. + (Defining this macro automatically implies that other assertion checking is + disabled while checking preconditions as if + @RefMacro{BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION} was also + defined.) + + @see @RefSect{contract_programming_overview.feature_summary, + Feature Summary} + */ + #define BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + Define this macro to evaluate and check audit assertions at run-time + (undefined by default). + + Audit assertions and implementation checks programmed via + @RefMacro{BOOST_CONTRACT_ASSERT_AUDIT} and + @RefMacro{BOOST_CONTRACT_CHECK_AUDIT} are always compiled and validated + syntactically. + However, they are not evaluated and checked at run-time unless + this macro is defined (because these conditions can be computationally + expensive, at least compared to the cost of executing the function body). + + @see @RefSect{extras.assertion_levels, Assertion Levels} + */ + #define BOOST_CONTRACT_AUDITS +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + If defined, this library does not perform implementation checks (undefined + by default). + + If this macro is defined, this library internal code is also optimized to + reduce compile-time (not just run-time) overhead associated with + implementation checks. + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of implementation checks or use + @RefMacro{BOOST_CONTRACT_CHECK} (recommended). + + @see @RefSect{advanced.implementation_checks, + Implementation Checks}, + @RefSect{extras.disable_contract_checking, + Disable Contract Checking}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_CHECKS +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + If defined, this library does not check preconditions (undefined by + default). + + If this macro is defined, this library internal code is also optimized to + reduce compile-time (not just run-time) overhead associated with + checking preconditions. + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of preconditions or use the macros + defined in @c boost/contract_macro.hpp (recommended only for applications + where it is truly necessary to completely remove contract code compilation + from production code). + + @see @RefSect{tutorial.preconditions, Preconditions}, + @RefSect{extras.disable_contract_checking, + Disable Contract Checking}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_PRECONDITIONS +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + If defined, this library does not check postconditions (undefined by + default). + + If this macro is defined, this library internal code is also optimized to + reduce compile-time (not just run-time) overhead associated with + checking postconditions. + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of postconditions or use the macros + defined in @c boost/contract_macro.hpp (recommended only for applications + where it is truly necessary to completely remove contract code compilation + from production code). + + It is necessary to disable both postconditions and exception guarantees + defining @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS} and + @RefMacro{BOOST_CONTRACT_NO_EXCEPTS} in order to disable old value copies + (see @RefMacro{BOOST_CONTRACT_NO_OLDS}). + + @see @RefSect{tutorial.postconditions, Postconditions}, + @RefSect{extras.disable_contract_checking, + Disable Contract Checking}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_POSTCONDITIONS +#endif + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + /** + If defined, this library does not check exception guarantees (undefined by + default). + + If this macro is defined, this library internal code is also optimized to + reduce compile-time (not just run-time) overhead associated with + checking exception guarantees. + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of exception guarantees or use the + macros defined in @c boost/contract_macro.hpp (recommended only for + applications where it is truly necessary to completely remove contract code + compilation from production code). + + It is necessary to disable both postconditions and exception guarantees + defining @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS} and + @RefMacro{BOOST_CONTRACT_NO_EXCEPTS} in order to disable old value copies + (see @RefMacro{BOOST_CONTRACT_NO_OLDS}). + + @see @RefSect{tutorial.exception_guarantees, Exception Guarantees}, + @RefSect{extras.disable_contract_checking, + Disable Contract Checking}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_EXCEPTS +#endif + +#if defined(BOOST_CONTRACT_DETAIL_DOXYGEN) || \ + ( \ + !defined(BOOST_CONTRACT_NO_ENTRY_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_INVARIANTS) \ + ) + /** + If defined, this library does not check class invariants at entry (undefined + by default). + + If this macro is defined, this library internal code is also optimized to + reduce compile-time (not just run-time) overhead associated with + checking class invariants at entry. + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of entry class invariants or use the + macros defined in @c boost/contract_macro.hpp (recommended only for + applications where it is truly necessary to completely remove contract code + compilation from production code). + + This macro is automatically defined when + @RefMacro{BOOST_CONTRACT_NO_INVARIANTS} is defined. + + @see @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.disable_contract_checking, + Disable Contract Checking}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_ENTRY_INVARIANTS +#endif + +#if defined(BOOST_CONTRACT_DETAIL_DOXYGEN) || \ + ( \ + !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_INVARIANTS) \ + ) + /** + If defined, this library does not check class invariants at exit (undefined + by default). + + If this macro is defined, this library internal code is also optimized to + reduce compile-time (not just run-time) overhead associated with + checking class invariants at exit. + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of exit class invariants or use the + macros defined in @c boost/contract_macro.hpp (recommended only for + applications where it is truly necessary to completely remove contract code + compilation from production code). + + This macro is automatically defined when + @RefMacro{BOOST_CONTRACT_NO_INVARIANTS} is defined. + + @see @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.disable_contract_checking, + Disable Contract Checking}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_EXIT_INVARIANTS +#endif + +#if !defined(BOOST_CONTRACT_NO_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_ENTRY_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) + /** + If defined, this library does not check class invariants (undefined by + default). + + If this macro is defined, this library internal code is also optimized to + reduce compile-time (not just run-time) overhead associated with + checking class invariants. + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of class invariants or use the + macros defined in @c boost/contract_macro.hpp (recommended only for + applications where it is truly necessary to completely remove contract code + compilation from production code). + + Defining this macro is equivalent to defining both + @RefMacro{BOOST_CONTRACT_NO_ENTRY_INVARIANTS} and + @RefMacro{BOOST_CONTRACT_NO_EXIT_INVARIANTS}. + + @see @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.disable_contract_checking, + Disable Contract Checking}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_INVARIANTS +#endif + +#ifdef BOOST_CONTRACT_NO_OLDS + #error "define NO_POSTCONDITIONS and NO_EXCEPTS instead" +#elif defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ + defined(BOOST_CONTRACT_NO_EXCEPTS) + /** + Automatically defined by this library when old value copies are not to be + performed. + + This library will define this macro when users define both + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS} and + @RefMacro{BOOST_CONTRACT_NO_EXCEPTS} (this macro is not a configuration + macro and this library will generate a compile-time error if users try to + define it directly). + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of old value copies or use the + macros defined in @c boost/contract_macro.hpp (recommended only for + applications where it is truly necessary to completely remove contract code + compilation from production code). + + @see @RefSect{tutorial.old_values, Old Values}, + @RefSect{advanced.old_value_copies_at_body, + Old Value Copies at Body}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_OLDS +#endif + +// Ctor pre checked separately and outside RAII so not part of this #define. +#ifdef BOOST_CONTRACT_NO_CONSTRUCTORS + #error "define NO_INVARIANTS, NO_POSTCONDITIONS, and NO_EXCEPTS instead" +#elif defined(BOOST_CONTRACT_NO_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ + defined(BOOST_CONTRACT_NO_EXCEPTS) + /** + Automatically defined by this library when contracts are not checked for + constructors. + + This library will define this macro when users define all + @RefMacro{BOOST_CONTRACT_NO_INVARIANTS}, + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS}, and + @RefMacro{BOOST_CONTRACT_NO_EXCEPTS} (this macro is not a configuration + macro and this library will generate a compile-time error if users try to + define it directly). + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of contracts for constructors or use + the macros defined in @c boost/contract_macro.hpp (recommended only for + applications where it is truly necessary to completely remove contract code + compilation from production code). + + @note Constructor preconditions are checked separately by + @RefClass{boost::contract::constructor_precondition} so they are + disabled by @RefMacro{BOOST_CONTRACT_NO_PRECONDITIONS} instead. + + @see @RefSect{tutorial.constructors, Constructors}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_CONSTRUCTORS +#endif + +#ifdef BOOST_CONTRACT_NO_DESTRUCTORS + #error "define NO_INVARIANTS, NO_POSTCONDITIONS, and NO_EXCEPTS instead" +#elif defined(BOOST_CONTRACT_NO_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ + defined(BOOST_CONTRACT_NO_EXCEPTS) + /** + Automatically defined by this library when contracts are not checked for + destructors. + + This library will define this macro when users define all + @RefMacro{BOOST_CONTRACT_NO_INVARIANTS}, + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS}, and + @RefMacro{BOOST_CONTRACT_NO_EXCEPTS} (this macro is not a configuration + macro and this library will generate a compile-time error if users try to + define it directly). + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of contracts for destructors or use + the macros defined in @c boost/contract_macro.hpp (recommended only for + applications where it is truly necessary to completely remove contract code + compilation from production code). + + @see @RefSect{tutorial.destructors, Destructors}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_DESTRUCTORS +#endif + +#ifdef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + #error "define NO_INVARIANTS, NO_PRECONDITIONS, NO_POSTCONDITIONS, and NO_EXCEPTS instead" +#elif defined(BOOST_CONTRACT_NO_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_PRECONDITIONS) && \ + defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ + defined(BOOST_CONTRACT_NO_EXCEPTS) + /** + Automatically defined by this library when contracts are not checked for + public functions. + + This library will define this macro when users define all + @RefMacro{BOOST_CONTRACT_NO_INVARIANTS}, + @RefMacro{BOOST_CONTRACT_NO_PRECONDITIONS}, + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS}, and + @RefMacro{BOOST_CONTRACT_NO_EXCEPTS} (this macro is not a configuration + macro and this library will generate a compile-time error if users try to + define it directly). + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of contracts for public functions or + use the macros defined in @c boost/contract_macro.hpp (recommended only for + applications where it is truly necessary to completely remove contract code + compilation from production code). + + @see @RefSect{tutorial.public_functions, Public Functions}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS +#endif + +#ifdef BOOST_CONTRACT_NO_FUNCTIONS + #error "define NO_PRECONDITIONS, NO_POSTCONDITIONS, and NO_EXCEPTS instead" +#elif defined(BOOST_CONTRACT_NO_PRECONDITIONS) && \ + defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ + defined(BOOST_CONTRACT_NO_EXCEPTS) + /** + Automatically defined by this library when contracts are not checked for + non-member, private and protected functions. + + This library will define this macro when users define all + @RefMacro{BOOST_CONTRACT_NO_PRECONDITIONS}, + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS}, and + @RefMacro{BOOST_CONTRACT_NO_EXCEPTS} (this macro is not a configuration + macro and this library will generate a compile-time error if users try to + define it directly). + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of contracts for non-member, + private and protected functions, or use the macros defined in + @c boost/contract_macro.hpp (recommended only for applications where it is + truly necessary to completely remove contract code compilation from + production code). + + This macro is also used when contracts are not checked for private and + protected functions, lambda functions, code blocks, loops, etc. + + @see @RefSect{tutorial.non_member_functions, Non-Member Functions}, + @RefSect{advanced.private_and_protected_functions, + Private and Protected Functions}, + @RefSect{advanced.lambdas__loops__code_blocks__and__constexpr__, + Lambdas\, Loops\, Code Blocks}, + @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_FUNCTIONS +#endif + +#ifdef BOOST_CONTRACT_NO_CONDITIONS + #error "define NO_INVARIANTS, NO_PRECONDITIONS, NO_POSTCONDITIONS, and NO_EXCEPTS instead" +#elif defined(BOOST_CONTRACT_NO_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_PRECONDITIONS) && \ + defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ + defined(BOOST_CONTRACT_NO_EXCEPTS) + /** + Automatically defined by this library when contracts are not checked for + preconditions, postconditions, exceptions guarantees, and class invariants + (excluding implementation checks). + + This library will define this macro when users define all + @RefMacro{BOOST_CONTRACT_NO_PRECONDITIONS}, + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS}, + @RefMacro{BOOST_CONTRACT_NO_EXCEPTS}, and + @RefMacro{BOOST_CONTRACT_NO_INVARIANTS} (this macro is not a configuration + macro and this library will generate a compile-time error if users try to + define it directly). + Users can manually program @c \#ifndef statements in their code using this + macro to completely disable compilation of contracts within specifications + or use the macros defined in @c boost/contract_macro.hpp (recommended only + for applications where it is truly necessary to completely remove contract + code compilation from production code). + + @see @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_CONDITIONS +#endif + +#ifdef BOOST_CONTRACT_NO_ALL + #error "define NO_INVARIANTS, NO_PRECONDITIONS, NO_POSTCONDITIONS, NO_EXCEPTS, and NO_CHECKS instead" +#elif defined(BOOST_CONTRACT_NO_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_PRECONDITIONS) && \ + defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ + defined(BOOST_CONTRACT_NO_EXCEPTS) && \ + defined(BOOST_CONTRACT_NO_CHECKS) + /** + Automatically defined by this library when contracts are not checked at all. + + This library will define this macro when users define all + @RefMacro{BOOST_CONTRACT_NO_INVARIANTS}, + @RefMacro{BOOST_CONTRACT_NO_PRECONDITIONS}, + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS}, + @RefMacro{BOOST_CONTRACT_NO_EXCEPTS}, and + @RefMacro{BOOST_CONTRACT_NO_CHECKS} (this macro is not a configuration + macro and this library will generate a compile-time error if users try to + define it directly). + For example, users can manually program @c \#ifndef statements in their code + using this macro to avoid including the @c boost/contract.hpp header all + together: + + @code + #include <boost/contract/core/config.hpp> + #ifndef BOOST_CONTRACT_NO_ALL + #include <boost/contract.hpp> + #endif + @endcode + + Or, use the @c boost/contract_macro.hpp header and related macros instead + (because the @c boost/contract_macro.hpp header is already optimized to not + include other headers from this library when contracts are not checked, but + recommended only for applications where it is truly necessary to completely + remove contract code compilation from production code). + + @see @RefSect{extras.disable_contract_compilation__macro_interface_, + Disable Contract Compilation} + */ + #define BOOST_CONTRACT_NO_ALL +#endif + +#endif // #include guard + diff --git a/boost/contract/core/constructor_precondition.hpp b/boost/contract/core/constructor_precondition.hpp new file mode 100644 index 0000000000..7a7fa753aa --- /dev/null +++ b/boost/contract/core/constructor_precondition.hpp @@ -0,0 +1,122 @@ + +#ifndef BOOST_CONTRACT_CONSTRUCTOR_PRECONDITION_HPP_ +#define BOOST_CONTRACT_CONSTRUCTOR_PRECONDITION_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 + +/** @file +Program preconditions for constructors. +*/ + +// IMPORTANT: Included by contract_macro.hpp so must #if-guard all its includes. +#include <boost/contract/core/config.hpp> +#ifndef BOOST_CONTRACT_NO_PRECONDITIONS + #include <boost/contract/core/exception.hpp> + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + #include <boost/contract/detail/checking.hpp> + #endif +#endif + +namespace boost { namespace contract { + +/** +Program preconditions for constructors. + +This class must be the very first base of the class declaring the +constructor for which preconditions are programmed (that way constructor +arguments can be checked by preconditions even before they are used to +initialize other base classes): + +@code + class u + #define BASES private boost::contract::constructor_precondition<u>, \ + public b + : BASES + { + ... + #undef BASES + + public: + explicit u(unsigned x) : + boost::contract::constructor_precondition<u>([&] { + BOOST_CONTRACT_ASSERT(x != 0); + ... + }), + b(1.0 / float(x)) + { + ... + } + + ... + }; +@endcode + +User-defined classes should inherit privately from this class (to not alter the +public interface of user-defined classes). +In addition, this class should never be declared as a virtual base (because +virtual bases are initialized only once across the entire inheritance hierarchy +preventing preconditions of other base classes from being checked). + +Unions cannot have base classes in C++ so this class can be used to declare a +local object within the constructor definition just before +@RefFunc{boost::contract::constructor} is used (see +@RefSect{extras.unions, Unions}). + +@see @RefSect{tutorial.constructors, Constructors} + +@tparam Class The class type of the constructor for which preconditions are + being programmed. +*/ +template<class Class> +class constructor_precondition { // Copyable (has no data). +public: + /** + Construct this object without specifying constructor preconditions. + + This is implicitly called for those constructors of the contracted class + that do not specify preconditions. + + @note Calling this default constructor should amount to negligible + compile-time and run-time overheads (likely to be optimized away + completely by most compilers). + */ + constructor_precondition() {} + + /** + Construct this object specifying constructor preconditions. + + @param f Nullary functor called by this library to check constructor + preconditions @c f(). + Assertions within this functor call are usually programmed + using @RefMacro{BOOST_CONTRACT_ASSERT}, but any exception thrown + by a call to this functor indicates a contract failure (and will + result in this library calling + @RefFunc{boost::contract::precondition_failure}). + This functor should capture variables by (constant) value, or + better by (constant) reference to avoid extra copies. + */ + template<typename F> + explicit constructor_precondition(F const& f) { + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + try { + #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION + if(boost::contract::detail::checking::already()) return; + #ifndef BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION + boost::contract::detail::checking k; + #endif + #endif + f(); + } catch(...) { precondition_failure(from_constructor); } + #endif + } + + // Default copy operations (so user's derived classes can be copied, etc.). +}; + +} } // namespace + +#endif // #include guard + diff --git a/boost/contract/core/exception.hpp b/boost/contract/core/exception.hpp new file mode 100644 index 0000000000..2a1d144dd2 --- /dev/null +++ b/boost/contract/core/exception.hpp @@ -0,0 +1,953 @@ + +#ifndef BOOST_CONTRACT_EXCEPTION_HPP_ +#define BOOST_CONTRACT_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 + +/** @file +Handle contract assertion failures. +*/ + +// IMPORTANT: Included by contract_macro.hpp so trivial headers only. +#include <boost/contract/core/config.hpp> +#include <boost/contract/detail/declspec.hpp> // No compile-time overhead. +#include <boost/function.hpp> +#include <boost/config.hpp> +#include <exception> +#include <string> + +// NOTE: This code should not change (not even its impl) based on the +// CONTRACT_NO_... macros. For example, preconditions_failure() should still +// all the set precondition failure handler even when NO_PRECONDITIONS is +// #defined, because user code might explicitly call precondition_failure() +// (for whatever reason...). Otherwise, the public API of this lib will change. + +#ifdef BOOST_CONTRACT_DETAIL_DOXYGEN +// Needed for `std::` prefix to show (but removed via `EXCLUDE_SYMBOLS=std`). +namespace std { + class exception {}; + class bad_cast {}; +} +#endif + +namespace boost { namespace contract { + +/** +Public base class for all exceptions directly thrown by this library. + +This class does not inherit from @c std::exception because exceptions deriving +from this class will do that (inheriting from @c std::exception, +@c std::bad_cast, etc.). + +@see @RefClass{boost::contract::assertion_failure}, + @RefClass{boost::contract::bad_virtual_result_cast}, + etc. +*/ +class BOOST_CONTRACT_DETAIL_DECLSPEC exception { +public: + /** + Destruct this object. + + @b Throws: This is declared @c noexcept (or @c throw() before C++11). + */ + virtual ~exception() /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */; +}; + +#ifdef BOOST_MSVC + #pragma warning(push) + #pragma warning(disable: 4275) // Bases w/o DLL spec (bad_cast, etc). + #pragma warning(disable: 4251) // Members w/o DLL spec (string for what_). +#endif + +/** +Exception thrown when inconsistent return values are passed to overridden +virtual public functions. + +This exception is internally thrown by this library when programmers specify +return values for public function overrides in derived classes that are not +consistent with the return types of the virtual public functions being +overridden in the base classes. +This allows this library to give more descriptive error messages in such cases. + +@see @RefSect{tutorial.public_function_overrides__subcontracting_, + Public Function Overrides} +*/ +class BOOST_CONTRACT_DETAIL_DECLSPEC bad_virtual_result_cast : // Copy (as str). + public std::bad_cast, public boost::contract::exception { +public: + /** + Construct this object with the name of the from- and to- result types. + + @param from_type_name Name of the from-type (source of the cast). + @param to_type_name Name of the to-type (destination of the cast). + */ + explicit bad_virtual_result_cast(char const* from_type_name, + char const* to_type_name); + + /** + Destruct this object. + + @b Throws: This is declared @c noexcept (or @c throw() before C++11). + */ + virtual ~bad_virtual_result_cast() + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */; + + /** + Description for this error (containing both from- and to- type names). + + @b Throws: This is declared @c noexcept (or @c throw() before C++11). + */ + virtual char const* what() const + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */; + +/** @cond */ +private: + std::string what_; +/** @endcond */ +}; + +/** +Exception typically used to report a contract assertion failure. + +This exception is thrown by code expanded by @RefMacro{BOOST_CONTRACT_ASSERT} +(but it can also be thrown by user code programmed manually without that macro). +This exception is typically used to report contract assertion failures because +it contains detailed information about the file name, line number, and source +code of the asserted condition (so it can be used by this library to provide +detailed error messages). +However, any other exception can be used to report a contract assertion failure +(including user-defined exceptions). + +This library will call the appropriate contract failure handler function +(@RefFunc{boost::contract::precondition_failure}, etc.) when this or any other +exception is thrown while checking contracts (by default, these failure handler +functions print an error message to @c std::cerr and terminate the program, but +they can be customized to take any other action). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros} +*/ +class BOOST_CONTRACT_DETAIL_DECLSPEC assertion_failure : // Copy (as str, etc.). + public std::exception, public boost::contract::exception { +public: + /** + Construct this object with file name, line number, and source code text of + an assertion condition (all optional). + + This constructor can also be used to specify no information (default + constructor), or to specify only file name and line number but not source + code text (because of the parameter default values). + + @param file Name of the file containing the assertion (usually set using + <c>__FILE__</c>). + @param line Number of the line containing the assertion (usually set using + <c>__LINE__</c>). + @param code Text listing the source code of the assertion condition. + */ + explicit assertion_failure(char const* file = "", unsigned long line = 0, + char const* code = ""); + + /** + Construct this object only with the source code text of the assertion + condition. + @param code Text listing the source code of the assertion condition. + */ + explicit assertion_failure(char const* code); + + /** + Destruct this object. + + @b Throws: This is declared @c noexcept (or @c throw() before C++11). + */ + virtual ~assertion_failure() + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */; + + /** + String describing the failed assertion. + + @b Throws: This is declared @c noexcept (or @c throw() before C++11). + + @return A string formatted similarly to the following: + <c>assertion "`code()`" failed: file "`file()`", line \`line()\`</c>. + File, line, and code will be omitted from this string if they were + not specified when constructing this object. + */ + virtual char const* what() const + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */; + + /** + Name of the file containing the assertion. + + @return File name as specified at construction (or @c "" if no file was + specified). + */ + char const* file() const; + + /** + Number of the line containing the assertion. + + @return Line number as specified at construction (or @c 0 if no line number + was specified). + */ + unsigned long line() const; + + /** + Text listing the source code of the assertion condition. + + @return Assertion condition source code as specified at construction (or + @c "" if no source code text was specified). + */ + char const* code() const; + +/** @cond */ +private: + void init(); + + char const* file_; + unsigned long line_; + char const* code_; + std::string what_; +/** @endcond */ +}; + +#ifdef BOOST_MSVC + #pragma warning(pop) +#endif + +/** +Indicate the kind of operation where the contract assertion failed. + +This is passed as a parameter to the assertion failure handler functions. +For example, it might be necessary to know in which operation an assertion +failed to make sure exceptions are never thrown from destructors, not even +when contract failure handlers are programmed by users to throw exceptions +instead of terminating the program. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure} +*/ +enum from { + /** Assertion failed when checking contracts for constructors. */ + from_constructor, + + /** Assertion failed when checking contracts for destructors . */ + from_destructor, + + /** + Assertion failed when checking contracts for functions (members or not). + */ + from_function +}; + +/** +Type of assertion failure handler functions (with @c from parameter). + +Assertion failure handler functions specified by this type must be functors +returning @c void and taking a single parameter of type +@RefEnum{boost::contract::from}. +For example, this is used to specify contract failure handlers for class +invariants, preconditions, postconditions, and exception guarantees. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure} +*/ +typedef boost::function<void (from)> from_failure_handler; + +/** +Type of assertion failure handler functions (without @c from parameter). + +Assertion failure handler functions specified by this type must be nullary +functors returning @c void. +For example, this is used to specify contract failure handlers for +implementation checks. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure} +*/ +typedef boost::function<void ()> failure_handler; + +/** @cond */ +namespace exception_ { + // Check failure. + + BOOST_CONTRACT_DETAIL_DECLSPEC + failure_handler const& set_check_failure_unlocked(failure_handler const& f) + BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + failure_handler const& set_check_failure_locked(failure_handler const& f) + BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + failure_handler get_check_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + failure_handler get_check_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + void check_failure_unlocked() /* can throw */; + BOOST_CONTRACT_DETAIL_DECLSPEC + void check_failure_locked() /* can throw */; + + // Precondition failure. + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_pre_failure_unlocked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_pre_failure_locked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_pre_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_pre_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + void pre_failure_unlocked(from where) /* can throw */; + BOOST_CONTRACT_DETAIL_DECLSPEC + void pre_failure_locked(from where) /* can throw */; + + // Postcondition failure. + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_post_failure_unlocked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_post_failure_locked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_post_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_post_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + void post_failure_unlocked(from where) /* can throw */; + BOOST_CONTRACT_DETAIL_DECLSPEC + void post_failure_locked(from where) /* can throw */; + + // Except failure. + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_except_failure_unlocked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_except_failure_locked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_except_failure_unlocked() + BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_except_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + void except_failure_unlocked(from where) /* can throw */; + BOOST_CONTRACT_DETAIL_DECLSPEC + void except_failure_locked(from where) /* can throw */; + + // Old-copy failure. + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_old_failure_unlocked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_old_failure_locked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_old_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_old_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + void old_failure_unlocked(from where) /* can throw */; + BOOST_CONTRACT_DETAIL_DECLSPEC + void old_failure_locked(from where) /* can throw */; + + // Entry invariant failure. + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_entry_inv_failure_unlocked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_entry_inv_failure_locked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_entry_inv_failure_unlocked() + BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_entry_inv_failure_locked() + BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + void entry_inv_failure_unlocked(from where) /* can throw */; + BOOST_CONTRACT_DETAIL_DECLSPEC + void entry_inv_failure_locked(from where) /* can throw */; + + // Exit invariant failure. + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_exit_inv_failure_unlocked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const&set_exit_inv_failure_locked( + from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_exit_inv_failure_unlocked() + BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler get_exit_inv_failure_locked() + BOOST_NOEXCEPT_OR_NOTHROW; + + BOOST_CONTRACT_DETAIL_DECLSPEC + void exit_inv_failure_unlocked(from where) /* can throw */; + BOOST_CONTRACT_DETAIL_DECLSPEC + void exit_inv_failure_locked(from where) /* can throw */; +} +/** @endcond */ + +} } // namespace + +/** @cond */ +#ifdef BOOST_CONTRACT_HEADER_ONLY + // NOTE: This header must be included in the middle of this file (because + // its impl depends on both from and assert_failure types). This is not + // ideal, but it is better than splitting this file into multiple + // independent ones because all content in this file is logically related + // from the user prospective. + #include <boost/contract/detail/inlined/core/exception.hpp> +#endif +/** @endcond */ + +namespace boost { namespace contract { + +// Following must be inline for static linkage (no DYN_LINK and no HEADER_ONLY). + +/** +Set failure handler for implementation checks. + +Set a new failure handler and returns it. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@param f New failure handler functor to set. + +@return Same failure handler functor @p f passed as parameter (e.g., for + concatenating function calls). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{advanced.implementation_checks, Implementation Checks} +*/ +inline failure_handler const& set_check_failure(failure_handler const& f) + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::set_check_failure_locked(f); + #else + return exception_::set_check_failure_unlocked(f); + #endif +} + +/** +Return failure handler currently set for implementation checks. + +This is often called only internally by this library. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@return A copy of the failure handler currently set. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{advanced.implementation_checks, Implementation Checks} +*/ +inline failure_handler get_check_failure() + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::get_check_failure_locked(); + #else + return exception_::get_check_failure_unlocked(); + #endif +} + +/** +Call failure handler for implementation checks. + +This is often called only internally by this library. + +@b Throws: This can throw in case programmers specify a failure handler that + throws exceptions on implementation check failures (not the + default). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{advanced.implementation_checks, Implementation Checks} +*/ +inline void check_failure() /* can throw */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + exception_::check_failure_locked(); + #else + exception_::check_failure_unlocked(); + #endif +} + +/** +Set failure handler for preconditions. + +Set a new failure handler and returns it. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@param f New failure handler functor to set. + +@return Same failure handler functor @p f passed as parameter (e.g., for + concatenating function calls). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.preconditions, Preconditions} +*/ +inline from_failure_handler const& set_precondition_failure(from_failure_handler + const& f) /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::set_pre_failure_locked(f); + #else + return exception_::set_pre_failure_unlocked(f); + #endif +} + +/** +Return failure handler currently set for preconditions. + +This is often called only internally by this library. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@return A copy of the failure handler currently set. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.preconditions, Preconditions} +*/ +inline from_failure_handler get_precondition_failure() + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::get_pre_failure_locked(); + #else + return exception_::get_pre_failure_unlocked(); + #endif +} + +/** +Call failure handler for preconditions. + +This is often called only internally by this library. + +@b Throws: This can throw in case programmers specify a failure handler that + throws exceptions on contract assertion failures (not the default). + +@param where Operation that failed the contract assertion (when this function + is called by this library, this parameter will never be + @c from_destructor because destructors do not have + preconditions). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.preconditions, Preconditions} +*/ +inline void precondition_failure(from where) /* can throw */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + exception_::pre_failure_locked(where); + #else + exception_::pre_failure_unlocked(where); + #endif +} + +/** +Set failure handler for postconditions. + +Set a new failure handler and returns it. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@param f New failure handler functor to set. + +@return Same failure handler functor @p f passed as parameter (e.g., fr + concatenating function calls). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.postconditions, Postconditions} +*/ +inline from_failure_handler const& set_postcondition_failure( + from_failure_handler const& f +) /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::set_post_failure_locked(f); + #else + return exception_::set_post_failure_unlocked(f); + #endif +} + +/** +Return failure handler currently set for postconditions. + +This is often called only internally by this library. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@return A copy of the failure handler currently set. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.postconditions, Postconditions} +*/ +inline from_failure_handler get_postcondition_failure() + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::get_post_failure_locked(); + #else + return exception_::get_post_failure_unlocked(); + #endif +} + +/** +Call failure handler for postconditions. + +This is often called only internally by this library. + +@b Throws: This can throw in case programmers specify a failure handler that + throws exceptions on contract assertion failures (not the default). + +@param where Operation that failed the contract assertion (e.g., this might + be useful to program failure handler functors that never throw + from destructors, not even when they are programmed by users to + throw exceptions instead of terminating the program). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.postconditions, Postconditions} +*/ +inline void postcondition_failure(from where) /* can throw */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + exception_::post_failure_locked(where); + #else + exception_::post_failure_unlocked(where); + #endif +} + +/** +Set failure handler for exception guarantees. + +Set a new failure handler and returns it. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@param f New failure handler functor to set. + +@return Same failure handler functor @p f passed as parameter (e.g., for + concatenating function calls). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.exception_guarantees, Exception Guarantees} +*/ +inline from_failure_handler const& set_except_failure(from_failure_handler + const& f) /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::set_except_failure_locked(f); + #else + return exception_::set_except_failure_unlocked(f); + #endif +} + +/** +Return failure handler currently set for exception guarantees. + +This is often called only internally by this library. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@return A copy of the failure handler currently set. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.exception_guarantees, Exception Guarantees} +*/ +inline from_failure_handler get_except_failure() + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::get_except_failure_locked(); + #else + return exception_::get_except_failure_unlocked(); + #endif +} + +/** +Call failure handler for exception guarantees. + +This is often called only internally by this library. + +@b Throws: This can throw in case programmers specify a failure handler that + throws exceptions on contract assertion failures (not the default), + however: + +@warning When this failure handler is called there is already an active + exception (the one that caused the exception guarantees to be + checked in the first place). + Therefore, programming this failure handler to throw yet another + exception will force C++ to automatically terminate the program. + +@param where Operation that failed the contract assertion. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.exception_guarantees, Exception Guarantees} +*/ +inline void except_failure(from where) /* can throw */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + exception_::except_failure_locked(where); + #else + exception_::except_failure_unlocked(where); + #endif +} + +/** +Set failure handler for old value copies at body. + +Set a new failure handler and returns it. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@param f New failure handler functor to set. + +@return Same failure handler functor @p f passed as parameter (e.g., for + concatenating function calls). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body} +*/ +inline from_failure_handler const& set_old_failure(from_failure_handler const& + f) /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::set_old_failure_locked(f); + #else + return exception_::set_old_failure_unlocked(f); + #endif +} + +/** +Return failure handler currently set for old value copies at body. + +This is often called only internally by this library. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@return A copy of the failure handler currently set. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body} +*/ +inline from_failure_handler get_old_failure() + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::get_old_failure_locked(); + #else + return exception_::get_old_failure_unlocked(); + #endif +} + +/** +Call failure handler for old value copies at body. + +This is often called only internally by this library. + +@b Throws: This can throw in case programmers specify a failure handler that + throws exceptions on contract assertion failures (not the default). + +@param where Operation that failed the old value copy (e.g., this might + be useful to program failure handler functors that never throw + from destructors, not even when they are programmed by users to + throw exceptions instead of terminating the program). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body} +*/ +inline void old_failure(from where) /* can throw */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + exception_::old_failure_locked(where); + #else + exception_::old_failure_unlocked(where); + #endif +} + +/** +Set failure handler for class invariants at entry. + +Set a new failure handler and returns it. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@param f New failure handler functor to set. + +@return Same failure handler functor @p f passed as parameter (e.g., for + concatenating function calls). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.volatile_public_functions, + Volatile Public Functions} +*/ +inline from_failure_handler const& set_entry_invariant_failure( + from_failure_handler const& f +)/** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::set_entry_inv_failure_locked(f); + #else + return exception_::set_entry_inv_failure_unlocked(f); + #endif +} + +/** +Return failure handler currently set for class invariants at entry. + +This is often called only internally by this library. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@return A copy of the failure handler currently set. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.volatile_public_functions, + Volatile Public Functions} +*/ +inline from_failure_handler get_entry_invariant_failure() + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::get_entry_inv_failure_locked(); + #else + return exception_::get_entry_inv_failure_unlocked(); + #endif +} + +/** +Call failure handler for class invariants at entry. + +This is often called only internally by this library. + +@b Throws: This can throw in case programmers specify a failure handler that + throws exceptions on contract assertion failures (not the default). + +@param where Operation that failed the contract assertion (e.g., this might + be useful to program failure handler functors that never throw + from destructors, not even when they are programmed by users to + throw exceptions instead of terminating the program). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.volatile_public_functions, + Volatile Public Functions} +*/ +inline void entry_invariant_failure(from where) /* can throw */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::entry_inv_failure_locked(where); + #else + return exception_::entry_inv_failure_unlocked(where); + #endif +} + +/** +Set failure handler for class invariants at exit. + +Set a new failure handler and returns it. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@param f New failure handler functor to set. + +@return Same failure handler functor @p f passed as parameter (e.g., for + concatenating function calls). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.volatile_public_functions, + Volatile Public Functions} +*/ +inline from_failure_handler const& set_exit_invariant_failure( + from_failure_handler const& f +) /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::set_exit_inv_failure_locked(f); + #else + return exception_::set_exit_inv_failure_unlocked(f); + #endif +} + +/** +Return failure handler currently set for class invariants at exit. + +This is often called only internally by this library. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@return A copy of the failure handler currently set. + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.volatile_public_functions, + Volatile Public Functions} +*/ +inline from_failure_handler get_exit_invariant_failure() + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + return exception_::get_exit_inv_failure_locked(); + #else + return exception_::get_exit_inv_failure_unlocked(); + #endif +} + +/** +Call failure handler for class invariants at exit. + +This is often called only internally by this library. + +@b Throws: This can throw in case programmers specify a failure handler that + throws exceptions on contract assertion failures (not the default). + +@param where Operation that failed the contract assertion (e.g., this might + be useful to program failure handler functors that never throw + from destructors, not even when they are programmed by users to + throw exceptions instead of terminating the program). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.volatile_public_functions, + Volatile Public Functions} +*/ +inline void exit_invariant_failure(from where) /* can throw */ { + #ifndef BOOST_CONTRACT_DISABLE_THREADS + exception_::exit_inv_failure_locked(where); + #else + exception_::exit_inv_failure_unlocked(where); + #endif +} + +/** +Set failure handler for class invariants (at both entry and exit). + +This is provided for convenience and it is equivalent to call both +@RefFunc{boost::contract::set_entry_invariant_failure} and +@RefFunc{boost::contract::set_exit_invariant_failure} with the same functor +parameter @p f. + +@b Throws: This is declared @c noexcept (or @c throw() before C++11). + +@param f New failure handler functor to set for both entry and exit invariants. + +@return Same failure handler functor @p f passed as parameter (e.g., for + concatenating function calls). + +@see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, + @RefSect{tutorial.class_invariants, Class Invariants}, + @RefSect{extras.volatile_public_functions, + Volatile Public Functions} +*/ +/** @cond */ BOOST_CONTRACT_DETAIL_DECLSPEC /** @endcond */ +from_failure_handler const& set_invariant_failure(from_failure_handler const& f) + /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */; + +} } // namespace + +#endif // #include guard + diff --git a/boost/contract/core/specify.hpp b/boost/contract/core/specify.hpp new file mode 100644 index 0000000000..ef0bea9b09 --- /dev/null +++ b/boost/contract/core/specify.hpp @@ -0,0 +1,650 @@ + +#ifndef BOOST_CONTRACT_SPECIFY_HPP_ +#define BOOST_CONTRACT_SPECIFY_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 + +/** @file +Specify preconditions, old value copies at body, postconditions, and exception +guarantees + +Preconditions, old value copies at body, postconditions, and exception +guarantees are all optionals but, when they are specified, they need to be +specified in that order. +*/ + +#include <boost/contract/core/config.hpp> +#include <boost/contract/detail/decl.hpp> +#if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \ + defined(BOOST_CONTRACT_STATIC_LINK) + #include <boost/contract/detail/condition/cond_base.hpp> + #include <boost/contract/detail/condition/cond_post.hpp> + #include <boost/contract/detail/auto_ptr.hpp> + #include <boost/contract/detail/none.hpp> +#endif +#if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + #include <boost/contract/detail/debug.hpp> +#endif +#include <boost/config.hpp> + +// NOTE: No inheritance for faster run-times (macros to avoid duplicated code). + +/* PRIVATE */ + +/* @cond */ + +// NOTE: Private copy ops below will force compile-time error is `auto c = ...` +// is used instead of `check c = ...` but only up to C++17. C++17 strong copy +// elision on function return values prevents this lib from generating a +// compile-time error in those cases, but the lib will still generate a run-time +// error according with ON_MISSING_CHECK_DECL. +#if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \ + defined(BOOST_CONTRACT_STATIC_LINK) + #define BOOST_CONTRACT_SPECIFY_CLASS_IMPL_(class_type, cond_type) \ + private: \ + boost::contract::detail::auto_ptr<cond_type > cond_; \ + explicit class_type(cond_type* cond) : cond_(cond) {} \ + class_type(class_type const& other) : cond_(other.cond_) {} \ + class_type& operator=(class_type const& other) { \ + cond_ = other.cond_; \ + return *this; \ + } + + #define BOOST_CONTRACT_SPECIFY_COND_RELEASE_ cond_.release() +#else + #define BOOST_CONTRACT_SPECIFY_CLASS_IMPL_(class_type, cond_type) \ + private: \ + class_type() {} \ + class_type(class_type const&) {} \ + class_type& operator=(class_type const&) { return *this; } + + #define BOOST_CONTRACT_SPECIFY_COND_RELEASE_ /* nothing */ +#endif + +#ifndef BOOST_CONTRACT_NO_PRECONDITIONS + #define BOOST_CONTRACT_SPECIFY_PRECONDITION_IMPL_ \ + BOOST_CONTRACT_DETAIL_DEBUG(cond_); \ + cond_->set_pre(f); \ + return specify_old_postcondition_except<VirtualResult>( \ + BOOST_CONTRACT_SPECIFY_COND_RELEASE_); +#else + #define BOOST_CONTRACT_SPECIFY_PRECONDITION_IMPL_ \ + return specify_old_postcondition_except<VirtualResult>( \ + BOOST_CONTRACT_SPECIFY_COND_RELEASE_); +#endif + +#ifndef BOOST_CONTRACT_NO_OLDS + #define BOOST_CONTRACT_SPECIFY_OLD_IMPL_ \ + BOOST_CONTRACT_DETAIL_DEBUG(cond_); \ + cond_->set_old(f); \ + return specify_postcondition_except<VirtualResult>( \ + BOOST_CONTRACT_SPECIFY_COND_RELEASE_); +#else + #define BOOST_CONTRACT_SPECIFY_OLD_IMPL_ \ + return specify_postcondition_except<VirtualResult>( \ + BOOST_CONTRACT_SPECIFY_COND_RELEASE_); +#endif + +#ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + #define BOOST_CONTRACT_SPECIFY_POSTCONDITION_IMPL_ \ + BOOST_CONTRACT_DETAIL_DEBUG(cond_); \ + cond_->set_post(f); \ + return specify_except(BOOST_CONTRACT_SPECIFY_COND_RELEASE_); +#else + #define BOOST_CONTRACT_SPECIFY_POSTCONDITION_IMPL_ \ + return specify_except(BOOST_CONTRACT_SPECIFY_COND_RELEASE_); +#endif + +#ifndef BOOST_CONTRACT_NO_EXCEPTS + #define BOOST_CONTRACT_SPECIFY_EXCEPT_IMPL_ \ + BOOST_CONTRACT_DETAIL_DEBUG(cond_); \ + cond_->set_except(f); \ + return specify_nothing(BOOST_CONTRACT_SPECIFY_COND_RELEASE_); +#else + #define BOOST_CONTRACT_SPECIFY_EXCEPT_IMPL_ \ + return specify_nothing(BOOST_CONTRACT_SPECIFY_COND_RELEASE_); +#endif + +/* @endcond */ + +/* CODE */ + +namespace boost { + namespace contract { + class virtual_; + + template<typename VR> + class specify_precondition_old_postcondition_except; + + template<typename VR> + class specify_old_postcondition_except; + + template<typename VR> + class specify_postcondition_except; + + class specify_except; + } +} + +namespace boost { namespace contract { + +/** +Used to prevent setting other contract conditions after exception guarantees. + +This class has no member function so it is used to prevent specifying additional +functors to check any other contract. +This object is internally constructed by this library when users specify +contracts calling @RefFunc{boost::contract::function} and similar functions +(that is why this class does not have a public constructor). + +@see @RefSect{tutorial, Tutorial} +*/ +class specify_nothing { // Privately copyable (as *). +public: + /** + Destruct this object. + + @b Throws: This can throw in case programmers specify failure handlers that + throw exceptions instead of terminating the program (see + @RefSect{advanced.throw_on_failures__and__noexcept__, + Throw on Failure}). + (This is declared @c noexcept(false) since C++11.) + */ + ~specify_nothing() BOOST_NOEXCEPT_IF(false) {} + + // No set member function here. + +/** @cond */ +private: + BOOST_CONTRACT_SPECIFY_CLASS_IMPL_(specify_nothing, + boost::contract::detail::cond_base) + + // Friends (used to limit library's public API). + + friend class check; + + template<typename VR> + friend class specify_precondition_old_postcondition_except; + + template<typename VR> + friend class specify_old_postcondition_except; + + template<typename VR> + friend class specify_postcondition_except; + + friend class specify_except; +/** @endcond */ +}; + +/** +Allow to specify exception guarantees. + +Allow to specify the functor this library will call to check exception +guarantees. +This object is internally constructed by this library when users specify +contracts calling @RefFunc{boost::contract::function} and similar functions +(that is why this class does not have a public constructor). + +@see @RefSect{tutorial.exception_guarantees, Exception Guarantees} +*/ +class specify_except { // Privately copyable (as *). +public: + /** + Destruct this object. + + @b Throws: This can throw in case programmers specify failure handlers that + throw exceptions instead of terminating the program (see + @RefSect{advanced.throw_on_failures__and__noexcept__, + Throw on Failure}). + (This is declared @c noexcept(false) since C++11.) + */ + ~specify_except() BOOST_NOEXCEPT_IF(false) {} + + /** + Allow to specify exception guarantees. + + @param f Nullary functor called by this library to check exception + guarantees @c f(). + Assertions within this functor are usually programmed using + @RefMacro{BOOST_CONTRACT_ASSERT}, but any exception thrown by a + call to this functor indicates a contract assertion failure (and + will result in this library calling + @RefFunc{boost::contract::except_failure}). + This functor should capture variables by (constant) references + (to access the values they will have at function exit). + + @return After exception guarantees have been specified, the object returned + by this function does not allow to specify any additional contract. + */ + template<typename F> + specify_nothing except(F const& f) { + BOOST_CONTRACT_SPECIFY_EXCEPT_IMPL_ + } + +/** @cond */ +private: + BOOST_CONTRACT_SPECIFY_CLASS_IMPL_(specify_except, + boost::contract::detail::cond_base) + + // Friends (used to limit library's public API). + + friend class check; + + template<typename VR> + friend class specify_precondition_old_postcondition_except; + + template<typename VR> + friend class specify_old_postcondition_except; + + template<typename VR> + friend class specify_postcondition_except; +/** @endcond */ +}; + +/** +Allow to specify postconditions or exception guarantees. + +Allow to specify functors this library will call to check postconditions or +exception guarantees. +This object is internally constructed by this library when users specify +contracts calling @RefFunc{boost::contract::function} and similar functions +(that is why this class does not have a public constructor). + +@see @RefSect{tutorial.postconditions, Postconditions}, + @RefSect{tutorial.exception_guarantees, Exception Guarantees} + +@tparam VirtualResult Return type of the enclosing function declaring the + contract if that function is either a virtual public + function or a public function override. + Otherwise, this type is always @c void. +*/ +template<typename VirtualResult = void> +class specify_postcondition_except { // Privately copyable (as *). +public: + /** + Destruct this object. + + @b Throws: This can throw in case programmers specify failure handlers that + throw exceptions instead of terminating the program (see + @RefSect{advanced.throw_on_failures__and__noexcept__, + Throw on Failure}). + (This is declared @c noexcept(false) since C++11.) + */ + ~specify_postcondition_except() BOOST_NOEXCEPT_IF(false) {} + + /** + Allow to specify postconditions. + + @param f Functor called by this library to check postconditions + @c f(...). + Assertions within this functor are usually programmed using + @RefMacro{BOOST_CONTRACT_ASSERT}, but any exception thrown by a + call to this functor indicates a contract assertion failure (and + will result in this library calling + @RefFunc{boost::contract::postcondition_failure}). + This functor should capture variables by (constant) references + (to access the values they will have at function exit). + This functor must be a nullary functor if @c VirtualResult is + @c void, otherwise it must be a unary functor accepting the + return value as a parameter of type <c>VirtualResult const&</c> + (to avoid extra copies of the return value, or of type + @c VirtualResult or <c>VirtualResult const</c> if extra copies + of the return value are irrelevant). + + @return After postconditions have been specified, the object returned by + this function allows to optionally specify exception guarantees. + */ + template<typename F> + specify_except postcondition(F const& f) { + BOOST_CONTRACT_SPECIFY_POSTCONDITION_IMPL_ + } + + /** + Allow to specify exception guarantees. + + @param f Nullary functor called by this library to check exception + guarantees @c f(). + Assertions within this functor are usually programmed using + @RefMacro{BOOST_CONTRACT_ASSERT}, but any exception thrown by a + call to this functor indicates a contract assertion failure (and + will result in this library calling + @RefFunc{boost::contract::except_failure}). + This functor should capture variables by (constant) references + (to access the values they will have at function exit). + + @return After exception guarantees have been specified, the object returned + by this function does not allow to specify any additional contract. + */ + template<typename F> + specify_nothing except(F const& f) { + BOOST_CONTRACT_SPECIFY_EXCEPT_IMPL_ + } + +/** @cond */ +private: + BOOST_CONTRACT_SPECIFY_CLASS_IMPL_( + specify_postcondition_except, + boost::contract::detail::cond_post<typename + boost::contract::detail::none_if_void<VirtualResult>::type> + ) + + // Friends (used to limit library's public API). + + friend class check; + friend class specify_precondition_old_postcondition_except<VirtualResult>; + friend class specify_old_postcondition_except<VirtualResult>; +/** @endcond */ +}; + +/** +Allow to specify old value copies at body, postconditions, and exception +guarantees. + +Allow to specify functors this library will call to copy old value at body, +check postconditions, and check exception guarantees. +This object is internally constructed by this library when users specify +contracts calling @RefFunc{boost::contract::function} and similar functions +(that is why this class does not have a public constructor). + +@see @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body}, + @RefSect{tutorial.postconditions, Postconditions}, + @RefSect{tutorial.exception_guarantees, Exception Guarantees} + +@tparam VirtualResult Return type of the enclosing function declaring the + contract if that function is either a virtual public + function or a public function override. + Otherwise, this type is always @c void. +*/ +template<typename VirtualResult = void> +class specify_old_postcondition_except { // Privately copyable (as *). +public: + /** + Destruct this object. + + @b Throws: This can throw in case programmers specify failure handlers that + throw exceptions instead of terminating the program (see + @RefSect{advanced.throw_on_failures__and__noexcept__, + Throw on Failure}). + (This is declared @c noexcept(false) since C++11.) + */ + ~specify_old_postcondition_except() BOOST_NOEXCEPT_IF(false) {} + + /** + Allow to specify old value copies at body. + + It should often be sufficient to initialize old value pointers as soon as + they are declared, without using this function (see + @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body}). + + @param f Nullary functor called by this library @c f() to assign old + value copies just before the body is executed but after entry + invariants (when they apply) and preconditions are checked. + Old value pointers within this functor call are usually assigned + using @RefMacro{BOOST_CONTRACT_OLDOF}. + Any exception thrown by a call to this functor will result in + this library calling @RefFunc{boost::contract::old_failure} + (because old values could not be copied to check postconditions + and exception guarantees). + This functor should capture old value pointers by references so + they can be assigned (all other variables needed to evaluate old + value expressions can be captured by (constant) value, or better + by (constant) reference to avoid extra copies). + + @return After old value copies at body have been specified, the object + returned by this function allows to optionally specify + postconditions and exception guarantees. + */ + template<typename F> + specify_postcondition_except<VirtualResult> old(F const& f) { + BOOST_CONTRACT_SPECIFY_OLD_IMPL_ + } + + /** + Allow to specify postconditions. + + @param f Functor called by this library to check postconditions + @c f(...). + Assertions within this functor are usually programmed using + @RefMacro{BOOST_CONTRACT_ASSERT}, but any exception thrown by a + call to this functor indicates a contract assertion failure (and + will result in this library calling + @RefFunc{boost::contract::postcondition_failure}). + This functor should capture variables by (constant) references + (to access the values they will have at function exit). + This functor must be a nullary functor if @c VirtualResult is + @c void, otherwise it must be a unary functor accepting the + return value as a parameter of type <c>VirtualResult const&</c> + (to avoid extra copies of the return value, or of type + @c VirtualResult or <c>VirtualResult const</c> if extra copies + of the return value are irrelevant). + + @return After postconditions have been specified, the object returned by + this function allows to optionally specify exception guarantees. + */ + template<typename F> + specify_except postcondition(F const& f) { + BOOST_CONTRACT_SPECIFY_POSTCONDITION_IMPL_ + } + + /** + Allow to specify exception guarantees. + + @param f Nullary functor called by this library to check exception + guarantees @c f(). + Assertions within this functor are usually programmed using + @RefMacro{BOOST_CONTRACT_ASSERT}, but any exception thrown by a + call to this functor indicates a contract assertion failure (and + will result in this library calling + @RefFunc{boost::contract::except_failure}). + This functor should capture variables by (constant) references + (to access the values they will have at function exit). + + @return After exception guarantees have been specified, the object returned + by this function does not allow to specify any additional contract. + */ + template<typename F> + specify_nothing except(F const& f) { + BOOST_CONTRACT_SPECIFY_EXCEPT_IMPL_ + } + +/** @cond */ +private: + BOOST_CONTRACT_SPECIFY_CLASS_IMPL_( + specify_old_postcondition_except, + boost::contract::detail::cond_post<typename + boost::contract::detail::none_if_void<VirtualResult>::type> + ) + + // Friends (used to limit library's public API). + + friend class check; + friend class specify_precondition_old_postcondition_except<VirtualResult>; + + template<class C> + friend specify_old_postcondition_except<> constructor(C*); + + template<class C> + friend specify_old_postcondition_except<> destructor(C*); +/** @endcond */ +}; + +/** +Allow to specify preconditions, old value copies at body, postconditions, and +exception guarantees. + +Allow to specify functors this library will call to check preconditions, copy +old values at body, check postconditions, and check exception guarantees. +This object is internally constructed by this library when users specify +contracts calling @RefFunc{boost::contract::function} and similar functions +(that is why this class does not have a public constructor). + +@see @RefSect{tutorial.preconditions, Preconditions}, + @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body}, + @RefSect{tutorial.postconditions, Postconditions}, + @RefSect{tutorial.exception_guarantees, Exception Guarantees} + +@tparam VirtualResult Return type of the enclosing function declaring the + contract if that function is either a virtual public + function or a public function override. + Otherwise, this type is always @c void. +*/ +template< + typename VirtualResult /* = void (already in fwd decl from decl.hpp) */ + #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN + = void + #endif +> +class specify_precondition_old_postcondition_except { // Priv. copyable (as *). +public: + /** + Destruct this object. + + @b Throws: This can throw in case programmers specify failure handlers that + throw exceptions instead of terminating the program (see + @RefSect{advanced.throw_on_failures__and__noexcept__, + Throw on Failure}). + (This is declared @c noexcept(false) since C++11.) + */ + ~specify_precondition_old_postcondition_except() BOOST_NOEXCEPT_IF(false) {} + + /** + Allow to specify preconditions. + + @param f Nullary functor called by this library to check preconditions + @c f(). + Assertions within this functor are usually programmed using + @RefMacro{BOOST_CONTRACT_ASSERT}, but any exception thrown by a + call to this functor indicates a contract assertion failure (and + will result in this library calling + @RefFunc{boost::contract::precondition_failure}). + This functor should capture variables by (constant) value, or + better by (constant) reference (to avoid extra copies). + + @return After preconditions have been specified, the object returned by this + function allows to optionally specify old value copies at body, + postconditions, and exception guarantees. + */ + template<typename F> + specify_old_postcondition_except<VirtualResult> precondition(F const& f) { + BOOST_CONTRACT_SPECIFY_PRECONDITION_IMPL_ + } + + /** + Allow to specify old value copies at body. + + It should often be sufficient to initialize old value pointers as soon as + they are declared, without using this function (see + @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body}). + + @param f Nullary functor called by this library @c f() to assign old + value copies just before the body is executed but after entry + invariants (when they apply) and preconditions are checked. + Old value pointers within this functor call are usually assigned + using @RefMacro{BOOST_CONTRACT_OLDOF}. + Any exception thrown by a call to this functor will result in + this library calling @RefFunc{boost::contract::old_failure} + (because old values could not be copied to check postconditions + and exception guarantees). + This functor should capture old value pointers by references so + they can be assigned (all other variables needed to evaluate old + value expressions can be captured by (constant) value, or better + by (constant) reference to avoid extra copies). + + @return After old value copies at body have been specified, the object + returned by this functions allows to optionally specify + postconditions and exception guarantees. + */ + template<typename F> + specify_postcondition_except<VirtualResult> old(F const& f) { + BOOST_CONTRACT_SPECIFY_OLD_IMPL_ + } + + /** + Allow to specify postconditions. + + @param f Functor called by this library to check postconditions + @c f(...). + Assertions within this functor are usually programmed using + @RefMacro{BOOST_CONTRACT_ASSERT}, but any exception thrown by a + call to this functor indicates a contract assertion failure (and + will result in this library calling + @RefFunc{boost::contract::postcondition_failure}). + This functor should capture variables by (constant) references + (to access the values they will have at function exit). + This functor must be a nullary functor if @c VirtualResult is + @c void, otherwise it must be a unary functor accepting the + return value as a parameter of type <c>VirtualResult const&</c> + (to avoid extra copies of the return value, or of type + @c VirtualResult or <c>VirtualResult const</c> if extra copies + of the return value are irrelevant). + + @return After postconditions have been specified, the object returned by + this function allows to optionally specify exception guarantees. + */ + template<typename F> + specify_except postcondition(F const& f) { + BOOST_CONTRACT_SPECIFY_POSTCONDITION_IMPL_ + } + + /** + Allow to specify exception guarantees. + + @param f Nullary functor called by this library to check exception + guarantees @c f(). + Assertions within this functor are usually programmed using + @RefMacro{BOOST_CONTRACT_ASSERT}, but any exception thrown by a + call to this functor indicates a contract assertion failure (and + will result in this library calling + @RefFunc{boost::contract::except_failure}). + This functor should capture variables by (constant) references + (to access the values they will have at function exit). + + @return After exception guarantees have been specified, the object returned + by this function does not allow to specify any additional contract. + */ + template<typename F> + specify_nothing except(F const& f) { + BOOST_CONTRACT_SPECIFY_EXCEPT_IMPL_ + } + +/** @cond */ +private: + BOOST_CONTRACT_SPECIFY_CLASS_IMPL_( + specify_precondition_old_postcondition_except, + boost::contract::detail::cond_post<typename + boost::contract::detail::none_if_void<VirtualResult>::type> + ) + + // Friends (used to limit library's public API). + + friend class check; + friend specify_precondition_old_postcondition_except<> function(); + + template<class C> + friend specify_precondition_old_postcondition_except<> public_function(); + + template<class C> + friend specify_precondition_old_postcondition_except<> public_function(C*); + + template<class C> + friend specify_precondition_old_postcondition_except<> public_function( + virtual_*, C*); + + template<typename VR, class C> + friend specify_precondition_old_postcondition_except<VR> public_function( + virtual_*, VR&, C*); + + BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTIONS_Z(1, + O, VR, F, C, Args, v, r, f, obj, args) +/** @endcond */ +}; + +} } // namespace + +#endif // #include guard + diff --git a/boost/contract/core/virtual.hpp b/boost/contract/core/virtual.hpp new file mode 100644 index 0000000000..fcdd60555d --- /dev/null +++ b/boost/contract/core/virtual.hpp @@ -0,0 +1,161 @@ + +#ifndef BOOST_CONTRACT_VIRTUAL_HPP_ +#define BOOST_CONTRACT_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 + +/** @file +Handle virtual public functions with contracts (for subcontracting). +*/ + +// IMPORTANT: Included by contract_macro.hpp so must #if-guard all its includes. +#include <boost/contract/core/config.hpp> +#ifndef BOOST_CONTRACT_NO_CONDITIONS + #include <boost/contract/detail/decl.hpp> +#endif +#ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + #include <boost/any.hpp> +#endif +#ifndef BOOST_CONTRACT_NO_OLDS + #include <boost/shared_ptr.hpp> + #include <queue> +#endif + +namespace boost { namespace contract { + +#ifndef BOOST_CONTRACT_NO_CONDITIONS + namespace detail { + BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1, + /* is_friend = */ 0, OO, RR, FF, CC, AArgs); + } +#endif + +/** +Type of extra function parameter to handle contracts for virtual public +functions (for subcontracting). + +Virtual public functions (and therefore also public function overrides) +declaring contracts using this library must specify an extra function parameter +at the very end of the parameter list. +This parameter must be a pointer to this class and it must have default value +@c 0 (i.e., @c nullptr). +(This extra parameter is often named @c v in this documentation, but any name +can be used.) + +In practice this extra parameter does not alter the calling interface of the +enclosing function declaring the contract because it is always the very last +parameter and it has a default value (so it can always be omitted when users +call the function). +This extra parameter must be passed to +@RefFunc{boost::contract::public_function}, @RefMacro{BOOST_CONTRACT_OLDOF}, and +all other operations of this library that accept a pointer to +@RefClass{boost::contract::virtual_}. +A part from that, this class is not intended to be directly used by programmers +(and that is why this class does not have any public member and it is not +copyable). + +@see @RefSect{tutorial.virtual_public_functions, Virtual Public Functions}, + @RefSect{tutorial.public_function_overrides__subcontracting_, + Public Function Overrides} +*/ +class virtual_ { // Non-copyable (see below) to avoid copy queue, stack, etc. +/** @cond */ +private: // No public API (so users cannot use it directly by mistake). + + // No boost::noncopyable to avoid its overhead when contracts disabled. + virtual_(virtual_&); + virtual_& operator=(virtual_&); + + #ifndef BOOST_CONTRACT_NO_CONDITIONS + enum action_enum { + // virtual_ always held/passed as ptr so nullptr used for user call. + no_action, + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + check_entry_inv, + #endif + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + check_pre, + #endif + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + check_exit_inv, + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + // For outside .old(...). + push_old_init_copy, + // pop_old_init_copy as static function below. + // For inside .old(...). + call_old_ftor, + push_old_ftor_copy, + pop_old_ftor_copy, + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + check_post, + #endif + #ifndef BOOST_CONTRACT_NO_EXCEPTS + check_except, + #endif + }; + #endif + + #ifndef BOOST_CONTRACT_NO_OLDS + // Not just an enum value because the logical combination of two values. + inline static bool pop_old_init_copy(action_enum a) { + return + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + a == check_post + #endif + #if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ + !defined(BOOST_CONTRACT_NO_EXCEPTS) + || + #endif + #ifndef BOOST_CONTRACT_NO_EXCEPTS + a == check_except + #endif + ; + } + #endif + + #ifndef BOOST_CONTRACT_NO_CONDITIONS + explicit virtual_(action_enum a) : + action_(a) + , failed_(false) + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + , result_type_name_() + , result_optional_() + #endif + {} + #endif + + #ifndef BOOST_CONTRACT_NO_CONDITIONS + action_enum action_; + bool failed_; + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + std::queue<boost::shared_ptr<void> > old_init_copies_; + std::queue<boost::shared_ptr<void> > old_ftor_copies_; + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + boost::any result_ptr_; // Result for virtual and overriding functions. + char const* result_type_name_; + bool result_optional_; + #endif + + // Friends (used to limit library's public API). + #ifndef BOOST_CONTRACT_NO_OLDS + friend bool copy_old(virtual_*); + friend class old_pointer; + #endif + #ifndef BOOST_CONTRACT_NO_CONDITIONS + BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1, + /* is_friend = */ 1, OO, RR, FF, CC, AArgs); + #endif +/** @endcond */ +}; + +} } // namespace + +#endif // #include guard + |