diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 9bbf19a..777b0df 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -2,38 +2,48 @@ import quickbook ; using boostbook ; -#doxygen reference -# : -# ../include/contract/function.hpp -# ../include/contract/constructor.hpp -# ../include/contract/destructor.hpp -# ../include/contract/class.hpp -# ../include/contract/class_invariant.hpp -# ../include/contract/body.hpp -# ../include/contract/block_invariant.hpp -# ../include/contract/loop_variant.hpp -# ../include/contract/parameter.hpp -# ../include/contract/oldof.hpp -# ../include/contract/copy.hpp -# ../include/contract/broken.hpp -# ../include/contract/config.hpp -# ../include/contract/limits.hpp -# : -# "Reference" -# contract # Strip path prefix. -# PREDEFINED="DOXYGEN" -# QUIET=YES -# WARN_IF_UNDOCUMENTED=NO -# HIDE_UNDOC_MEMBERS=YES -# HIDE_UNDOC_CLASSES=YES -# SHORT_NAMES=NO -# ALIASES=" Params=\"Parameters: \" Param{2}=\"\" EndParams=\"
\\1\\2
\" Returns=\"Returns:\" Note=\"Note:\" Warning=\"Warning:\" SeeAlso=\"See also:\" RefSect{2}=\"\\xmlonly\\2\\endxmlonly\" RefClass{1}=\"\\xmlonly\\1\\endxmlonly\" RefFunc{1}=\"\\xmlonly\\1\\endxmlonly\" RefMacro{1}=\"\\xmlonly\\1\\endxmlonly\" RefEnum{1}=\"\\xmlonly\\1\\endxmlonly\" " -# ; +doxygen reference +: + ../include/boost/contract/constructor.hpp + ../include/boost/contract/destructor.hpp + ../include/boost/contract/public_function.hpp + ../include/boost/contract/function.hpp + ../include/boost/contract/base_types.hpp + ../include/boost/contract/override.hpp + ../include/boost/contract/guard.hpp + ../include/boost/contract/assert.hpp + ../include/boost/contract/old.hpp + ../include/boost/contract/call_if.hpp -xml contract : contract.qbk -# : reference + ../include/boost/contract/core/access.hpp + ../include/boost/contract/core/virtual.hpp + ../include/boost/contract/core/set_precondition_old_postcondition.hpp + ../include/boost/contract/core/set_old_postcondition.hpp + ../include/boost/contract/core/set_postcondition_only.hpp + ../include/boost/contract/core/set_nothing.hpp + ../include/boost/contract/core/exception.hpp + ../include/boost/contract/core/config.hpp + + ../include/boost/contract.hpp +: + "Reference" + # But Quickbook's Doxygen does not show destructor exception specs. + PREDEFINED="DOXYGEN BOOST_NOEXCEPT_OR_NOTHROW:=noexcept BOOST_NOEXCEPT_IF:=noexcept BOOST_PP_VARIADICS" + MACRO_EXPANSION=YES + INCLUDE_PATH="../include" + QUIET=YES + JAVADOC_AUTOBRIEF=YES + WARN_IF_UNDOCUMENTED=NO + # Does not work for XML output (use @cond/#ifdef DOXYGEN in code instead). + EXTRACT_PRIVATE=NO + HIDE_UNDOC_MEMBERS=YES + HIDE_UNDOC_CLASSES=YES + SHORT_NAMES=NO + ALIASES=" Params=\"Parameters: \" Param{2}=\"\" EndParams=\"
\\1\\2
\" Returns=\"Returns:\" Note=\"Note:\" Warning=\"Warning:\" SeeAlso=\"See also:\" RefSect{2}=\"\\xmlonly\\2\\endxmlonly\" RefClass{1}=\"\\xmlonly\\1\\endxmlonly\" RefFunc{1}=\"\\xmlonly\\1\\endxmlonly\" RefMacro{1}=\"\\xmlonly\\1\\endxmlonly\" RefEnum{1}=\"\\xmlonly\\1\\endxmlonly\" " ; +xml contract : contract.qbk : reference ; + boostbook doc : contract : html diff --git a/doc/advanced_topics.qbk b/doc/advanced_topics.qbk index 71c6d27..c9114e9 100644 --- a/doc/advanced_topics.qbk +++ b/doc/advanced_topics.qbk @@ -258,20 +258,20 @@ More precisely, dereferencing an old value pointer of type [classref boost::cont In these cases, programmers can declare old values using [classref boost::contract::old_ptr] as seen so far (or equivalently using C++11 `auto` declarations `auto ... = BOOST_CONTRACT_OLDOF(...)`). [footnote *Rationale*. -When C++11 `auto` declarations are used, this library defaults the type of [macroref BOOST_CONTRACT_OLDOF] to [classref boost::contract::old_ptr] because it generates a compile-time error for non-copyable types so it is in general more conservative than [classref boost::contract::noncopyable_old_ptr]. +When C++11 `auto` declarations are used, this library defaults the type of [macroref BOOST_CONTRACT_OLDOF] to [classref boost::contract::old_ptr] because it generates a compile-time error for non-copyable types so it is in general more conservative than [classref boost::contract::old_ptr_noncopyable]. ] * However, in other cases it might be desirable to simply not check assertions that use some old values when the related old value types are not copy constructible. -Programmers can do this by using [classref boost::contract::noncopyable_old_ptr] instead of [classref boost::contract::old_ptr] to program these old values (and by checking if the old value pointer is not null before dereferencing it in postconditions). +Programmers can do this by using [classref boost::contract::old_ptr_noncopyable] instead of [classref boost::contract::old_ptr] to program these old values (and by checking if the old value pointer is not null before dereferencing it in postconditions). -For example, consider the following `accumulate` function template that could in general be instantiated for types `T` that are not copy constructible (i.e., `boost::is_copy_constructible::value` is `false`): +For example, consider the following `accumulate` function template that could in general be instantiated for types `T` that are not copy constructible, that is when `boost::is_copy_constructible::value` is `false` (see also [@../../example/features/old_noncopyable.cpp =noncopyable.cpp=]): -[import ../example/features/noncopyable_old.cpp] -[noncopyable_old] +[import ../example/features/old_noncopyable.cpp] +[old_noncopyable] -The old value pointer `old_total` is programmed using [classref boost::contract::noncopyable_old_ptr] so if `T` is not copy constructible then `total` will simply not be copied and `old_total` will be left as a null pointer (in these cases `old_total` must be checked to be not null `if(old_total) ...` before it can be dereferenced in the postconditions). +The old value pointer `old_total` is programmed using [classref boost::contract::old_ptr_noncopyable] so if `T` is not copy constructible then `total` will simply not be copied and `old_total` will be left as a null pointer (in these cases `old_total` must be checked to be not null `if(old_total) ...` before it can be dereferenced in the postconditions). If the above example used [classref boost::contract::old_ptr] instead then the library would have generated a compile-time error if `accumulate` is instantiated for types `T` that are not copy constructible (but only if `old_total` is actually dereferenced in the contract assertions somewhere `*old_total ...`). -Note that the `noncopyable_...` prefix of the name [classref boost::contract::noncopyable_old_ptr]`` refers to the pointed type `T` that may or not be copy constructible without causing a compile-time error in this case (the old value pointer itself is always copyable, or at least copy assignable). +The `..._noncopyable` postfix in the type name [classref boost::contract::old_ptr_noncopyable]`` refers to the pointed type `T` that may or not be copy constructible without causing a compile-time error in this case (the old value pointer itself is always copyable, or at least copy assignable). [heading No C++11] diff --git a/doc/contract.qbk b/doc/contract.qbk index 988ff0c..770a9e4 100644 --- a/doc/contract.qbk +++ b/doc/contract.qbk @@ -106,8 +106,8 @@ All Contract Programming features are supported by this library: subcontracting, [include contract_programming_overview.qbk] [include tutorial.qbk] [include advanced_topics.qbk] +[xinclude reference.xml] [include examples.qbk] -[/ xinclude reference.xml] [include release_notes.qbk] [include bibliography.qbk] [include acknowledgments.qbk] diff --git a/include/boost/contract.hpp b/include/boost/contract.hpp index ce625af..ad0fc0b 100644 --- a/include/boost/contract.hpp +++ b/include/boost/contract.hpp @@ -7,9 +7,11 @@ // 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 */ +/** @file +Include all header files required by this library at once. +*/ -// Include all and only public headers as users would (not core headers, etc.). +#include #include #include #include diff --git a/include/boost/contract/assert.hpp b/include/boost/contract/assert.hpp index f4244c6..a8c66a5 100644 --- a/include/boost/contract/assert.hpp +++ b/include/boost/contract/assert.hpp @@ -7,22 +7,39 @@ // 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 */ +/** @file +Facilities to assert contract conditions. +*/ #include /* PUBLIC */ -// Must use ternary operator expr here (instead of if-statement) so this macro -// can always be used with if-statements and all other C++ constructs. #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ !defined(BOOST_CONTRACT_NO_INVARIANTS) #include + // Ternary operator used so this macro expand to an expression and it can + // be used with `if` and all other statements. #define BOOST_CONTRACT_ASSERT(condition) \ ((condition) ? (void*)0 : throw boost::contract::assertion_failure( \ __FILE__, __LINE__, BOOST_PP_STRINGIZE(condition))) #else + /** + Preferred way to assert contract conditions. + Any exception thrown from within a preconditions, postcondition, and + class invariant functor is interpreted by this library as a contract + failure. Therefore, users can program contract assertions manually throwing + exceptions in case the asserted condition is checked to be @c false (this + library will then call the appropriate contract failure handler). + However, using this macro is preferred because in case @condition is + checked to be @c false, this macro expands to code that throws + @RefClass{boost::contract::assertion_failure} with the correct assertion + file name (@c __FILE__), line number (@c __LINE__), and condition source + code text that will produce an informative error message. + @see @RefSect{advanced_topics, Advanced Topics}. + @param condition The contract condition being checked. + */ #define BOOST_CONTRACT_ASSERT(condition) /* nothing */ #endif diff --git a/include/boost/contract/base_types.hpp b/include/boost/contract/base_types.hpp index d1aecc4..a2cd3b7 100644 --- a/include/boost/contract/base_types.hpp +++ b/include/boost/contract/base_types.hpp @@ -9,7 +9,9 @@ // TODO: Document the max number of bases is 20 because of Boost.MPL vector limit. If Boost.MPL vector and related alg impl was to change to use variadic templates in the future there will be not limit to max bases (but for now this high limit is better than the extra complexity of reimpl all Boost.MPL vector, etc. within this lib with variadic templates). -/** @file */ +/** @file +Facilities to specify base classes so to support subcontracting. +*/ #include #include @@ -21,6 +23,18 @@ BOOST_CONTRACT_ERROR_macro_BASE_TYPES_requires_variadic_macros_otherwise_manuall #elif defined(BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS) +/** +Variadic macro to program base classes @c typedef. +A class that has contracts for one or more overriding public functions must +declare a @c typedef named @RefMacro{BOOST_CONTRACT_BASE_TYPEDEF} using this +macro. +This @c typedef can be programmed manually without this macro on compilers that +do not support variadic macros (see @RefSect{advanced_topics, Advanced Topics}). +@see @RefSect{tutorial, Tutorial}. +@param ... Comma separated list of base classes with must explicitly list their + access (@c public, @c protected, or @c private) and @c virtual (if + present) specifiers. +*/ #define BOOST_CONTRACT_BASE_TYPES(...) void /* dummy type for typedef */ #else // contracts on diff --git a/include/boost/contract/call_if.hpp b/include/boost/contract/call_if.hpp index 2108c00..dabc012 100644 --- a/include/boost/contract/call_if.hpp +++ b/include/boost/contract/call_if.hpp @@ -7,6 +7,10 @@ // 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 +Statically disable execution but also compilation of functor calls. +*/ + // Do not include all_core_headers here (call_if is essentially standalone). #include #include @@ -16,6 +20,8 @@ /* PRIVATE */ +/** @cond */ + // Boost.ResultOf not always able to deduce lambda result type (on MSVC). #ifndef BOOST_NO_CXX11_DECL_TYPE #include @@ -27,43 +33,152 @@ typename boost::result_of::type #endif +/** @endcond */ + /* CODE */ namespace boost { namespace contract { -template +/** +Unspecialized class template to control execution and compilation of functor +calls via a static boolean condition. +This class template has no member because it should never be used directly, it +should only be used via its specializations. +@see @RefSect{advanced_topics, Advanced Topics} +@tparam Cond Static boolean condition controlling functor calls. +@tparam Then Type of functor to call when the static condition if true. +@tparam R Return type of then-branch functor. +*/ +template struct call_if_statement {}; // Empty so cannot be used (but copyable). -// Dispatch true condition (then) between non-void and void calls. -// IMPORTANT: result_of can be evaluated only when condition is already -// checked to be true (as Then() is required to be valid only in that case) so -// this extra level of dispatching is necessary to avoid compiler errors. +/** +Template specialization to dispatch between then-branch functor calls that +return void and the ones that return non-void. +@note result_of should be evaluated only when the static + condition is already checked to be true (because @c Then() is + required to compile only in that case). Thus, this template + specialization introduces an extra level of indirectly necessary to the + proper lazy evaluation of that result-of. +The base class is a call-if statement so the else statement and other else-if +can be specified if needed. Ultimately this will return the return value of the +functor being compiled and called. +@see @RefSect{advanced_topics, Advanced Topics} +@tparam Then Type of functor to call when the static condition if true. +*/ template -struct call_if_statement : - call_if_statement -{ +struct call_if_statement : + call_if_statement::type + #endif + > +{ // Copyable (as its base). + /** + Construct this object with the then-branch functor. + @param f Then-branch nullary functor, called or compiled in this case. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + */ explicit call_if_statement(Then f) : call_if_statement(f) {} }; -// True condition (then) for non-void call. +/** +Template specialization to handle true static conditions for then-branch functor +calls returning non-void. +@see @RefSect{advanced_topics, Advanced Topics} +@tparam Then Type of functor to call when the static condition if true. +@tparam R Non-void return type of the then-branch functor call. +*/ template struct call_if_statement { // Copyable (as *). + /** + Construct this object with the then-branch functor. + @param f Then-branch nullary functor, called and compiled in this case. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + */ explicit call_if_statement(Then f) : r_(boost::make_shared(f())) {} - operator R() const { return *r_; } + /** Return value returned by the call to the then-branch functor. */ + operator R const&() const { return *r_; } + /** Return value returned by the call to the then-branch functor. */ + operator R&() { return *r_; } + + /** + Specify the else-branch functor. + @param f Else-branch nullary functor, never called or compiled in this + case. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + @return Return value returned by the call to the then-branch functor. + */ template - R else_(Else const&) const { return *r_; } + R const& else_(Else const& f) const { return *r_; } + + /** + Specify the else-branch functor. + @param f Else-branch nullary functor, never called or compiled in this + case. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + @return Return value returned by the call to the then-branch functor. + */ + template + R& else_(Else const& f) { return *r_; } + /** + Specify an else-if-branch functor. + @param f Else-if-branch nullary functor, never called or compiled in this + case. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + @tparam ElseIfCond Static boolean condition controlling functor calls. + @return The call-if statement so the else statement and other else-if can be + specified if needed. Ultimately will return the return value of the + then-branch functor in this case. + */ template - call_if_statement else_if_c(ElseIfThen const&) const { + call_if_statement else_if_c(ElseIfThen const& f) const { return *this; } + /** + Specify an else-if-branch functor. + @param f Else-if-branch nullary functor, never called or compiled in this + case. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + @tparam ElseIfCond Static boolean nullary meta-function controlling functor + calls. + @return The call-if statement so the else statement and other else-if can be + specified if needed. Ultimately will return the return value of the + then-branch functor in this case. + */ template - call_if_statement else_if(ElseIfThen const&) const { + call_if_statement else_if(ElseIfThen const& f) const { return *this; } @@ -71,45 +186,149 @@ private: boost::shared_ptr r_; }; -// True condition (then) for void call. +/** +Template specialization to handle true static conditions for then-branch functor +calls returning void. +@see @RefSect{advanced_topics, Advanced Topics} +@tparam Then Type of functor to call when the static condition if true. +*/ template struct call_if_statement { // Copyable (no data). + /** + Construct this object with the then-branch functor. + @param f Then-branch nullary functor, called and compiled in this case. + The return type of this functor as well as of all other + specified functors for the call-if object must be @c void in + this case. + */ explicit call_if_statement(Then f) { f(); } // Cannot provide `operator R()` here, because R is void. + /** + Specify the else-branch functor. + @param f Else-branch nullary functor, never called or compiled in this + case. + The return type of this functor as well as of all other + specified functors for the call-if object must be @c void in + this case. + */ template - void else_(Else const&) const {} + void else_(Else const& f) const {} + /** + Specify an else-if-branch functor. + @param f Else-if-branch nullary functor, never called or compiled in this + case. + The return type of this functor as well as of all other + specified functors for the call-if object must be @c void in + this case. + @tparam ElseIfCond Static boolean condition controlling functor calls. + @return The call-if statement so the else statement and other else-if can be + specified if needed. Ultimately @c void will be returned in this + case. + */ template - call_if_statement else_if_c(ElseIfThen const&) const { + call_if_statement else_if_c(ElseIfThen const& f) const { return *this; } + /** + Specify an else-if-branch functor. + @param f Else-if-branch nullary functor, never called or compiled in this + case. + The return type of this functor as well as of all other + specified functors for the call-if object must be @c void in + this case. + @tparam ElseIfCond Static boolean nullary meta-function controlling functor + calls. + @return The call-if statement so the else statement and other else-if can be + specified if needed. Ultimately @c void will be returned in this + case. + */ template - call_if_statement else_if(ElseIfThen const&) const { + call_if_statement else_if(ElseIfThen const& f) const { return *this; } }; -// False condition (else) for both non-void and void calls. +/** +Template specialization to handle false static conditions. +This single specialization can handle both else-branch functor calls that +return void and that return non-void. +@see @RefSect{advanced_topics, Advanced Topics} +@tparam Then Type of functor to call when the static condition if true. +*/ template // Copyable (no data). -struct call_if_statement { - explicit call_if_statement(Then const&) {} +struct call_if_statement { + /** + Construct this object with the then-branch functor. + @param f Then-branch nullary functor, never called or compiled in this + case. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + */ + explicit call_if_statement(Then const& f) {} // Do not provide `operator result_type()` here, require else_ instead. - // IMPORTANT: result_of can be evaluated only when condition is - // already checked to be false (as Else() is required to be valid only in - // that case) so this is done lazily only in this template instantiation. + /** + Specify the else-branch functor. + @note result_of should be evaluated only when the static + condition is already checked to be false (because @c Else() is + required to compile only in that case). Thus, that result-of is + evaluate lazily only in this template instantiation. + @param f Else-branch nullary functor, called and compiled in this case. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + @return The return value of the call to the else-branch functor. + */ template - BOOST_CONTRACT_CALL_IF_RESULT_OF_(Else) else_(Else f) const { return f(); } + #ifndef DOXYGEN + BOOST_CONTRACT_CALL_IF_RESULT_OF_(Else) + #else + typename result_of::type + #endif + else_(Else f) const { return f(); } + /** + Specify an else-if-branch functor. + @param f Else-if-branch nullary functor, called and compiled if and only + if @c ElseIfCond is @c true. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + @tparam ElseIfCond Static boolean condition controlling functor calls. + @return The call-if statement so the else statement and other else-if can be + specified if needed. Ultimately will return the return value of the + functor call being compiled and executed. + */ template call_if_statement else_if_c(ElseIfThen f) const { return call_if_statement(f); } + /** + Specify an else-if-branch functor. + @param f Else-if-branch nullary functor, called and compiled if and only + if @c ElseIfCond::value is @c true. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. + @tparam ElseIfCond Static boolean nullary meta-function controlling functor + calls. + @return The call-if statement so the else statement and other else-if can be + specified if needed. Ultimately will return the return value of the + functor call being compiled and executed. + */ template call_if_statement else_if(ElseIfThen f) const { @@ -117,22 +336,64 @@ struct call_if_statement { } }; +/** +Make a call-if object with the specified then-branch functor +@param f Then-branch nullary functor, called and compiled if and only if + @c Cond if @c true. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. +@tparam Cond Static boolean condition controlling functor compilation and calls. +@return The call-if statement so the else statement and other else-if can be + specified if needed. Ultimately will return the return value of the + functor call being compiled and executed. +*/ template call_if_statement call_if_c(Then f) { return call_if_statement(f); } +/** +Make a call-if object with the specified then-branch functor +@param f Then-branch nullary functor, called and compiled if and only if + @c Cond::value if @c true. + The return type of this functor must be the same or implicitly + convertible into the return type of all other functors specified + for the call-if object. +@tparam Cond Static boolean nullary meta-function controlling functor calls. +@return The call-if statement so the else statement and other else-if can be + specified if needed. Ultimately will return the return value of the + functor call being compiled and executed. +*/ template call_if_statement call_if(Then f) { return call_if_statement(f); } +/** +Return value of specified functor call if and only if specified static condition +is true, otherwise return true. +@param f Nullary boolean functor to call and compile if and only if @c Cond + is @c true. +@tparam Cond Static boolean condition controlling functor compilation and call. +@return Boolean value returned by @c f() if static condition if true, otherwise + simply return @c true (i.e., check trivially passed). +*/ template bool check_if_c(F f) { return call_if_c(f).else_( boost::contract::detail::always_true()); } +/** +Return value of specified functor call if and only if specified static condition +is true, otherwise return true. +@param f Nullary boolean functor to call and compile if and only if + @c Cond::value is @c true. +@tparam Cond Static boolean nullary meta-function controlling functor calls. +@return Boolean value returned by @c f() if static condition if true, otherwise + simply return @c true (i.e., check trivially passed). +*/ template bool check_if(F f) { return call_if_c(f).else_( diff --git a/include/boost/contract/constructor.hpp b/include/boost/contract/constructor.hpp index 5362a30..f727879 100644 --- a/include/boost/contract/constructor.hpp +++ b/include/boost/contract/constructor.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Program contracts for constructors. +*/ #include #if !defined(BOOST_CONTRACT_NO_CONSTRUCTORS) || \ @@ -20,6 +22,17 @@ namespace boost { namespace contract { +/** +Program contracts for constructors. +This is used to specify postconditions and check class invariants for +constructors (see @RefClass{boost::contract::constructor_precondition} to +specify preconditions for constructors instead). +@see @RefSect{tutorial, Tutorial}. +@param obj The object @c this in scope of the constructor being contracted. +@return The result of this function must be assigned to variable of type + @RefClass{boost::contract::guard} declared locally within the + constructor being contracted. +*/ template set_old_postcondition<> constructor(C* obj) { // Must #if also on ..._PRECONDITIONS here because set_... is generic. @@ -33,17 +46,42 @@ set_old_postcondition<> constructor(C* obj) { } // TODO: Document that constructor_precondition for unions must be called at the very beginning of ctor body before `boost::contract::guard c = ...` (because unions cannot have base classes, not even in C++11). -template // tparam avoids multiple instance of same base in user code. +/** +Program constructor preconditions. +This class must be the very first base class of the class being contracted. Also +the contracted class must privately inherit from this base class. + +Unions cannot have base classes so this class can be used to declare a local +object within the constructor function just before +@RefClass{boost::contract::constructor} is used (see +@RefSect{advanced_topics, Advanced Topics}). + +@see @RefSect{tutorial, Tutorial}. +@tparam C Class of constructor being contracted (CRTP used here to avoid + multiple instances of same base class error). +*/ +template class constructor_precondition { // Copyable (no data). public: - constructor_precondition() {} // For user ctor overloads with no pre. + /** Construct this object for constructor that do not have preconditions. */ + constructor_precondition() {} + /** + Constructor this object specifying constructor preconditions. + @param f Functor called by this library to check preconditions. Any + exception thrown by a call to this functor indicates a + precondition failure. Assertions within this functor are usually + programmed using @RefMacro{BOOST_CONTRACT_ASSERT}. This functor + must be a nullary functor. This functor could capture variables + by value, or better by (constant) reference to void extra + copies. + */ template explicit constructor_precondition(F const& f) { #ifndef BOOST_CONTRACT_NO_PRECONDITIONS if(boost::contract::detail::check_guard::checking()) return; try { - #ifndef BOOST_CONTRACT_PRECONDITIONS_DISABLE_NOTHING + #ifndef BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION boost::contract::detail::check_guard checking; #endif f(); diff --git a/include/boost/contract/core/access.hpp b/include/boost/contract/core/access.hpp index 87a81d5..a158b65 100644 --- a/include/boost/contract/core/access.hpp +++ b/include/boost/contract/core/access.hpp @@ -7,6 +7,10 @@ // 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 +Used to declare invariants, base types, etc private members. +*/ + #include #include #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ @@ -40,14 +44,20 @@ namespace boost { namespace boost { namespace contract { -// NOTE: Not making this class friend will cause compiler errors on some -// compilers (e.g., MSVC) because the private members needed for contracts -// will not be accessible. On other compilers (e.g., GCC and CLang), the -// private access will instead simply fail SFINAE and no compiler error will be -// reported but invariants and subcontracting checking will be silently skipped -// at run-time. Therefore programmers must make sure to either declare contract -// members public or to make this class a friend. +/** +Friend class to declare invariants, base types, etc private members. +Declare this class as friend of the class being contracted in order to declare +the class invariants member functions and the base types as non-public members. +@note Not making this class friend will cause compiler errors on some compilers +(e.g., MSVC) because the private members needed for 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 but invariants and +subcontracting will be silently be skipped at run-time. Therefore programmers +must make sure to either declare contract members public or to make this class +a friend. +*/ class access { // Copyable (as shell with no data member). +/** @cond */ // No public APIs (so users cannot use it directly by mistake). #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ @@ -124,6 +134,7 @@ class access { // Copyable (as shell with no data member). BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTIONS_Z(1, OO, RR, FF, CC, AArgs, vv, rr, ff, oobj, aargs) +/** @endcond */ }; } } // namespace diff --git a/include/boost/contract/core/config.hpp b/include/boost/contract/core/config.hpp index a7b3198..9302f9e 100644 --- a/include/boost/contract/core/config.hpp +++ b/include/boost/contract/core/config.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Configuration macros. +*/ // 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 @@ -16,78 +18,229 @@ // TODO: Document that when contracts are programmed in .cpp and all these lib headers are #include only from within .cpp, then a given lib can be compiled for example without inv/post, only with pre. The code that will link to that lib will not be able to enable inv/post, or disable the pre. However, if contracts are programmed in .hpp and this lib headers are #included in .hpp that are shipped to users with a given lib, users of that lib can turn on/off all contracts for the shipped lib as well. -// BOOST_CONTRACT_DYN_LINK -// BOOST_CONTRACT_HEADER_ONLY - -// Rationale: Named after BOOST_DISABLE_THREADS, BOOST_ASIO_DISABLE_THREADS, etc. -// BOOST_CONTRACT_DISABLE_THREADS - -// Rationale: Named after BOOST_FUNCTION_MAX_ARGS, etc. -#ifndef BOOST_CONTRACT_MAX_ARGS -# define BOOST_CONTRACT_MAX_ARGS 10 +#ifdef DOXYGEN + /** + Define this macro to compile this library as a shared library or DLL + (undefined by default). + In general, this library must be compiled as a shared library defining this + macro when used by multiple programs otherwise the contracts will not + necessarily be checked correctly at run-time. + Rationale: Named after @c BOOST_ALL_DYN_LINK. + @see @RefSect{getting_started, Getting Started}. + */ + #define BOOST_CONTRACT_DYN_LINK +#endif + +#ifdef DOXYGEN + /** + Define this macro to compile user code with this library composed of headers + only (undefined by default). + If this macro is defined, this library does not have to be compiled + separately. This library headers can simply be included in the user program + and this library code will be compiled directly as part of the user program. + However, in general this library must be compiled as a shared library + defining @RefMacro{BOOST_CONTRACT_DYN_LINK} when used by multiple programs + otherwise the contracts will not necessarily be checked correctly at + run-time. + Rationale: Named after @c BOOST_CHRONO_HEADER_ONLY. + @see @RefSect{getting_started, Getting Started}. + */ + #define BOOST_CONTRACT_HEADER_ONLY +#endif + +#ifdef 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 + strictly under single-threaded applications. However, when this macro is + left undefined this library needs to use "global" locks to ensure contract + checking is globally disabled when other contracts are being checked and + also to safely access the failure handler functors (this could introduce a + significant amount of synchronization in multi-threaded applications). + Rationale: Named after @c BOOST_DISABLE_THREADS, + @c BOOST_ASIO_DISABLE_THREADS, etc. + @see @RefSect{contract_programming_overview, Contract Programming Overview}. + */ + #define BOOST_CONTRACT_DISABLE_THREADS +#endif + +#ifndef BOOST_CONTRACT_MAX_ARGS + /** + Maximum number of function arguments when no variadic macros are supported + (default to @c 10). + This defines the maximum number of arguments of the overriding public + function pointer passed to @RefFunc{boost::contract::public_function} on + compilers that do not support variadic macros. This macro has no effect on + compilers that support variadic macros. + @note Regardless of the value of this macro and of compiler support for + variadic macros, there is an intrinsic limit around 19 arguments + for overriding public functions (because of a similar limit of some + Boost libraries like Boost.MPL and Boost.FunctionTypes internally + used by this library). + + Rationale: Named after @c BOOST_FUNCTION_MAX_ARGS, etc. + */ + #define BOOST_CONTRACT_MAX_ARGS 10 #endif -// Rationale: This cannot be called BASE_TYPES because BASE_TYPES(...) is already used as the macro to extract the public bases... so BASE_TYPEDEF seemed a reasonable naming alternative, but don't change base_types default #define because `typedef BASE_TYPES(...) base_types` is usually the best syntax in user's code. #ifndef BOOST_CONTRACT_BASE_TYPEDEF + /** + Define the name of the base type @c typedef (@c base_types by default). + Rationale: This cannot be called @c BOOST_CONTRACT_BASE_TYPES + because that is already used as the name of macro to + extract the public bases. Then + @c BOOST_CONTRACT_BASE_TYPEDEF is a reasonable naming + alternative (but without changing this macro default to + @c base_typedef because + typedef BOOST_CONTRACT_BASE_TYPES(...) base_types + is the preferred syntax in user code). + */ #define BOOST_CONTRACT_BASE_TYPEDEF base_types #endif #ifndef BOOST_CONTRACT_INVARIANT + /** + Define the name of the @c const and const volatile member functions + that checks mutable and volatile class invariants respectively (@c invariant + by default). + */ #define BOOST_CONTRACT_INVARIANT invariant #endif -// C++ does not allow to overload member functions based on static classifier, -// so a name different from the non-static class invariant member must be used. #ifndef BOOST_CONTRACT_STATIC_INVARIANT + /** + Define the name of the @c static member function that checks static class + invariants (@c static_invariant by default). + @note C++ does not allow to overload member functions based on static + classifier, so a name different from the non-static class invariant + name expanded by @RefMacro{BOOST_CONTRACT_INVARIANT} must be used + here. + */ #define BOOST_CONTRACT_STATIC_INVARIANT static_invariant #endif -// BOOST_CONTRACT_PERMISSIVE +#ifdef DOXYGEN + /** + Disable a number of static checks and compiler warnings generated by this + library (undefined by default). + Among other things, this macro checks: + @li Static invariant member function is @c static. + @li Non-static invariant member function is either @c const, + const volatile, or volatile const. + @li A class that has contracts for one or more overriding public functions + must also define the @RefMacro{BOOST_CONTRACT_BASE_TYPES} @c typedef. + */ + #define BOOST_CONTRACT_PERMISSIVE +#endif -// Type of exception to throw is `guard c = ...` is missing. This is a -// programming error so by default this library calls abort. If this macro is -// #defined however, this library will throw the exception specified by the -// macro value instead of calling abort. When #defined, this macro must be a -// default constructible type. -// Code instruction(s) to execute when contracts are missing `guard c = ...`. -// In general, this is #undefined and this library calls `assert(false)` when -// contract guards are missing. Missing a contract guard is a logic error in -// the program (similar to dereferencing a null pointer) so terminating the -// program via `abort` or `assert` as this library does by default is the only -// safe thing to do. Therefore, it is recommended to never #define this macro. -// However, this macro can be defined to throw an exception, call a function, -// a no-op, or any other user code in case users truly need to handle missing -// contract guard logic errors without terminating the program, for example: -// #define BOOST_CONTRACT_ON_MISSING_GUARD { throw my_logic_error(); } -// (It can even be defined to expand to nothing.) -// BOOST_CONTRACT_ON_MISSING_GUARD +#ifdef DOXYGEN + /** + Code block to execute if boost::contract::guard c = ... assignment is + missing (undefined by default). + In general, if programmer omit this assignment, it is a logic error in the + program. Therefore, when this macro is not defined, by default this library + calls calls @c assert with a @c false condition. If this macro is defined, + this library will execute the code expanded by this macro instead of calling + @c assert. + */ + #define OOST_CONTRACT_ON_MISSING_GUARD +#endif -// Contract checking is not disable while checking preconditions. -// This is what N1962 does by default. N1962 authors indicated it can be shown -// that unchecked arguments are passed to function bodies if contract checking -// is disable within precondition checking). -// However, not disabling contract checking while checking preconditions can -// lead to infinite recursive call in user code so by default this macro is -// not defined. -// TODO: Rename this BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTIONS -// BOOST_CONTRACT_PRECONDITIONS_DISABLE_NOTHING +#ifdef DOXYGEN + /** + If defined, checking preconditions does not disable checking of other + assertions (undefined by default). + This is what [N1962] does by default because unchecked arguments are passed + to function bodies if contract checking is disable within precondition + checking (function bodies need to be executed directly or indirectly while + checking the preconditions in question). However, not disabling assertion + checking while checking preconditions can lead to infinite recursive calls + in user code so by default this macro is not defined. + */ + #define OOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION +#endif -// BOOST_CONTRACT_NO_PRECONDITIONS -// BOOST_CONTRACT_NO_POSTCONDITIONS +#ifdef DOXYGEN + /** + If defined, this library does not check preconditions at run-time (undefined + by default). + This library implementation code is also optimized to avoid overhead in + associated with precondition checking when possible also at compile-time. + Users can manually program @c #ifdef statements using this macro to disable + precondition compilation (not just run-time checking). + @see @RefSect{advanced_topics, Advanced Topics}. + */ + #define BOOST_CONTRACT_NO_PRECONDITIONS +#endif -#if !defined(BOOST_CONTRACT_NO_ENTRY_INVARIANTS) && \ - defined(BOOST_CONTRACT_NO_INVARIANTS) +#ifdef DOXYGEN + /** + If defined, this library does not check postconditions at run-time + (undefined by default). + This library implementation code is also optimized to avoid overhead in + associated with postcondition checking when possible also at compile-time. + Users can manually program @c #ifdef statements using this macro to disable + postcondition compilation (not just run-time checking). + @see @RefSect{advanced_topics, Advanced Topics}. + */ + #define BOOST_CONTRACT_NO_POSTCONDITIONS +#endif + +#if defined(DOXYGEN) || (!defined(BOOST_CONTRACT_NO_ENTRY_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_INVARIANTS)) + /** + If defined, this library does not check entry invariants at run-time + (undefined by default). + This library implementation code is also optimized to avoid overhead in + associated with entry invariant checking when possible also at compile-time. + Users can manually program @c #ifdef statements using this macro to disable + class invariant compilation (not just run-time checking). + + This macro can always be defined by itself but it is also automatically + defined when @RefMacro{BOOST_CONTRACT_NO_INVARIANTS} is defined. + + @see @RefSect{advanced_topics, Advanced Topics}. + */ #define BOOST_CONTRACT_NO_ENTRY_INVARIANTS #endif -#if !defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) && \ - defined(BOOST_CONTRACT_NO_INVARIANTS) +#if defined(DOXYGEN) || (!defined(BOOST_CONTRACT_NO_EXIT_INVARIANTS) && \ + defined(BOOST_CONTRACT_NO_INVARIANTS)) + /** + If defined, this library does not check exit invariant at run-time + (undefined by default). + This library implementation code is also optimized to avoid overhead in + associated with exit invariant checking when possible also at compile-time. + Users can manually program @c #ifdef statements using this macro to disable + class invariant compilation (not just run-time checking). + + This macro can always be defined by itself but it is also automatically + defined when @RefMacro{BOOST_CONTRACT_NO_INVARIANTS} is defined. + + @see @RefSect{advanced_topics, Advanced Topics}. + */ #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 at run-time + (undefined by default). + This library implementation code is also optimized to avoid overhead in + associated with class invariant checking when possible also at compile-time. + Users can manually program @c #ifdef statements using this macro to disable + class invariant compilation (not just run-time checking). + + This macro can always be defined by itself but it is also automatically + defined when @RefMacro{BOOST_CONTRACT_NO_ENTRY_INVARIANTS} and + @RefMacro{BOOST_CONTRACT_NO_EXIT_INVARIANTS} are both defined. + + @see @RefSect{advanced_topics, Advanced Topics}. + */ #define BOOST_CONTRACT_NO_INVARIANTS #endif @@ -98,6 +251,21 @@ #error "define NO_ENTRY_INVARIANTS, NO_EXIT_INVARIANTS, and NO_POSTCONDITIONS instead" #elif defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ defined(BOOST_CONTRACT_NO_INVARIANTS) + /** + This library defines this macro if constructor contracts are not being + checked by @RefFunc{boost::contract::constructor}. + This macro is automatically defined or not by this library, and it is not a + configuration macro. This library will generate a compile-time error if + users manually define this macro. + Users can manually define @RefMacro{BOOST_CONTRACT_NO_ENTRY_INVARIANTS}, + @RefMacro{BOOST_CONTRACT_NO_EXIT_INVARIANTS}, and + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS} instead. + + Note that constructor preconditions are checked separately by + @RefClass{boost::contract::constructor_precondition} so their run-time check + ing is disabled by @RefMacro{BOOST_CONTRACT_NO_PRECONDITIONS} directly. + @see @RefSect{advanced_topics, Advanced Topics}. + */ #define BOOST_CONTRACT_NO_CONSTRUCTORS #endif @@ -105,6 +273,18 @@ #error "define NO_ENTRY_INVARIANTS, NO_EXIT_INVARIANTS, and NO_POSTCONDITIONS instead" #elif defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ defined(BOOST_CONTRACT_NO_INVARIANTS) + /** + This library defines this macro if destructor contracts are not being + checked by @RefFunc{boost::contract::destructor}. + This macro is automatically defined or not by this library, and it is not a + configuration macro. This library will generate a compile-time error if + users manually define this macro. + Users can manually define @RefMacro{BOOST_CONTRACT_NO_ENTRY_INVARIANTS}, + @RefMacro{BOOST_CONTRACT_NO_EXIT_INVARIANTS}, and + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS} instead. + (Note that destructors have no preconditions.) + @see @RefSect{advanced_topics, Advanced Topics}. + */ #define BOOST_CONTRACT_NO_DESTRUCTORS #endif @@ -113,6 +293,18 @@ #elif defined(BOOST_CONTRACT_NO_PRECONDITIONS) && \ defined(BOOST_CONTRACT_NO_POSTCONDITIONS) && \ defined(BOOST_CONTRACT_NO_INVARIANTS) + /** + This library defines this macro if public function contracts are not being + checked by @RefFunc{boost::contract::public_function}. + This macro is automatically defined or not by this library, and it is not a + configuration macro. This library will generate a compile-time error if + users manually define this macro. + Users can manually define @RefMacro{BOOST_CONTRACT_NO_ENTRY_INVARIANTS}, + @RefMacro{BOOST_CONTRACT_NO_PRECONDITIONS}, + @RefMacro{BOOST_CONTRACT_NO_EXIT_INVARIANTS}, and + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS} instead. + @see @RefSect{advanced_topics, Advanced Topics}. + */ #define BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS #endif @@ -120,6 +312,17 @@ #error "define NO_PRECONDITIONS and NO_POSTCONDITIONS instead" #elif defined(BOOST_CONTRACT_NO_PRECONDITIONS) && \ defined(BOOST_CONTRACT_NO_POSTCONDITIONS) + /** + This library defines this macro if non-member, private, or protected + function contracts are not being checked by + @RefFunc{boost::contract::function}. + This macro is automatically defined or not by this library, and it is not a + configuration macro. This library will generate a compile-time error if + users manually define this macro. + Users can manually define @RefMacro{BOOST_CONTRACT_NO_PRECONDITIONS} and + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS} instead. + @see @RefSect{advanced_topics, Advanced Topics}. + */ #define BOOST_CONTRACT_NO_FUNCTIONS #endif @@ -129,6 +332,18 @@ defined(BOOST_CONTRACT_NO_DESTRUCTORS) && \ defined(BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS) && \ defined(BOOST_CONTRACT_NO_FUNCTIONS) + /** + This library defines this macro if no contracts (for any operation) are + being checked. + This macro is automatically defined or not by this library, and it is not a + configuration macro. This library will generate a compile-time error if + users manually define this macro. + Users can manually define @RefMacro{BOOST_CONTRACT_NO_ENTRY_INVARIANTS}, + @RefMacro{BOOST_CONTRACT_NO_PRECONDITIONS}, + @RefMacro{BOOST_CONTRACT_NO_EXIT_INVARIANTS}, and + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS} instead. + @see @RefSect{advanced_topics, Advanced Topics}. + */ #define BOOST_CONTRACT_NO_ALL #endif diff --git a/include/boost/contract/core/exception.hpp b/include/boost/contract/core/exception.hpp index cb7a558..4f98f71 100644 --- a/include/boost/contract/core/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Exception and utilities to report contract assertion failures. +*/ #include #include @@ -23,43 +25,121 @@ namespace boost { namespace contract { -// Placeholder base class to group all this lib exceptions. -// IMPORTANT: Must not inherit from std::exception as derived exceptions will. +/** +Public base class for all this library exceptions. +This class does not inherit from @c std::exception because derived exceptions +will (inheriting from @c std::exception, or @c std::bad_cast, etc.). +@see @RefSect{advanced_topics, Advanced Topics}. +*/ class BOOST_CONTRACT_DETAIL_DECLSPEC exception { public: - virtual ~exception(); + /** Destruct this object. */ + virtual ~exception() BOOST_NOEXCEPT_OR_NOTHROW; }; -// Rationale: boost::bad_any_cast exception does not print from/to type names, -// so throw custom exception. +/** +Exception internally thrown by for inconsistent return values passed to +overridden virtual public functions. +This exception is internally thrown by this library when users specify a return +value for an overriding public function in a derived class that is inconsistent +with the return type of the virtual public function being overridden in the base +class. + +Rationale: The @c boost::bad_any_cast exception could not be used + because it does not print the from and to type names (so it + is not descriptive enough). + +@see @RefSect{tutorial, Tutorial}. +*/ 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 types. + @param from_type_name Name of the source type. + @param to_type_name Name of the type destination type. + */ explicit bad_virtual_result_cast(char const* from_type_name, char const* to_type_name); - virtual ~bad_virtual_result_cast(); - virtual char const* what() const BOOST_NOEXCEPT; + /** Destruct this object. */ + virtual ~bad_virtual_result_cast() BOOST_NOEXCEPT_OR_NOTHROW; + /** Return an error description (containing both from and to type names). */ + virtual char const* what() const BOOST_NOEXCEPT_OR_NOTHROW; + +/** @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). +@see @RefSect{advanced_topics, Advanced Topics}. +*/ class BOOST_CONTRACT_DETAIL_DECLSPEC assertion_failure : // Copy (as str, etc.). public std::exception, public boost::contract::exception { public: + /** + Construct this object optionally with assertion file, line, and code + information. + This constructor can also be used to specify no information, or to specify + only file and line but not code information (because of its parameter + default values). + @param file Name of the file containing the assertion (usually set using + __FILE__). + @param line Number of the line containing the assertion (usually set using + __LINE__). + @param code String text of the condition code being asserted. + */ explicit assertion_failure(char const* const file = "", unsigned long const line = 0, char const* const code = ""); + + /** + Construct this object with code information. + This constructor can be used to specify only code but no file and line + information. + @param code String text of the condition code being asserted. + */ explicit assertion_failure(char const* const code); - virtual ~assertion_failure(); + + /** Destruct this object. */ + virtual ~assertion_failure() BOOST_NOEXCEPT_OR_NOTHROW; - // Return something like `assertion "..." failed: file "...", line ...`. - virtual char const* what() const BOOST_NOEXCEPT; + /** + Return string describing the failed assertion. + @return Return a string similar to + assertion "`code()`" failed: file "`file()`", line \`line()\` + (parts of this information will be omitted if they were not + specified at construction). + */ + virtual char const* what() const BOOST_NOEXCEPT_OR_NOTHROW; + /** + Return assertion file. + @return Return file as specified at construction (or @c "" if no file was + specified). + */ char const* const file() const; + + /** + Return assertion line number. + @return Return line number as specified at construction (or @c 0 if no line + number was specified). + */ unsigned long line() const; + + /** + Return assertion condition code. + @return Return assertion condition code as specified at construction (or + @c "" if no code was specified at construction). + */ char const* const code() const; +/** @cond */ private: void init(); @@ -67,63 +147,157 @@ private: unsigned long const line_; char const* const code_; std::string what_; +/** @endcond */ }; -enum from { from_constructor, from_destructor, from_function }; +/** +Context of assertion failure. +This is passed as a parameter of the assertion failure handler functions. +For example, it might be necessary to know the kind of operation that threw an +assertion failure to make sure exception are never thrown by destructors even +when contract failures are handled by throwing exceptions instead of terminating +the program (default). +@see @RefSect{advanced_topics, Advanced Topics}. +*/ +enum from { + /** Assertion failed in constructor contract. */ + from_constructor, + /** Assertion failed in destructor contract. */ + from_destructor, + /** Assertion failed in function (member or not) contract. */ + from_function +}; -// Use Boost.Function to handle also lambdas, binds, etc, +/** +Typef all assertion failure handler functions. +Rationale: Using Boost.Function to handle also lambdas, binds, etc. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ typedef boost::function assertion_failure_handler; -assertion_failure_handler -BOOST_CONTRACT_DETAIL_DECLSPEC set_precondition_failure( - assertion_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; - -assertion_failure_handler -BOOST_CONTRACT_DETAIL_DECLSPEC get_precondition_failure() +/** +Set the precondition failure handler. +@param f New precondition failure handler functor. +@return Old precondition failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ +assertion_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC +set_precondition_failure(assertion_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; -void BOOST_CONTRACT_DETAIL_DECLSPEC precondition_failure(from where) - /* can throw */; +/** +Return the precondition failure handler. +@return Current precondition failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ +assertion_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC +get_precondition_failure() BOOST_NOEXCEPT_OR_NOTHROW; -assertion_failure_handler -BOOST_CONTRACT_DETAIL_DECLSPEC set_postcondition_failure( - assertion_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; +/** +Call the precondition hander functor. +This is typically only called internally by this library. +@param where Context of precondition failure. +*/ +void BOOST_CONTRACT_DETAIL_DECLSPEC +precondition_failure(from where) /* can throw */; -assertion_failure_handler -BOOST_CONTRACT_DETAIL_DECLSPEC get_postcondition_failure() +/** +Set the postcondition failure handler. +@param f New postcondition failure handler functor. +@return Old postcondition failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ +assertion_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC +set_postcondition_failure(assertion_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; -void BOOST_CONTRACT_DETAIL_DECLSPEC postcondition_failure(from where) - /* can throw */; +/** +Return the postcondition failure handler. +@return Current postcondition failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ +assertion_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC +get_postcondition_failure() BOOST_NOEXCEPT_OR_NOTHROW; +/** +Call the postcondition hander functor. +This is typically only called internally by this library. +@param where Context of postcondition failure. +*/ +void BOOST_CONTRACT_DETAIL_DECLSPEC +postcondition_failure(from where) /* can throw */; + +/** +Set the entry invariant failure handler. +@param f New entry invariant failure handler functor. +@return Old entry invariant failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ assertion_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC set_entry_invariant_failure(assertion_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; +/** +Return the entry invariant failure handler. +@return Current entry invariant failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ assertion_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC get_entry_invariant_failure() BOOST_NOEXCEPT_OR_NOTHROW; -void BOOST_CONTRACT_DETAIL_DECLSPEC entry_invariant_failure(from where) - /* can throw */; +/** +Call the entry invariant hander functor. +This is typically only called internally by this library. +@param where Context of entry invariant failure. +*/ +void BOOST_CONTRACT_DETAIL_DECLSPEC +entry_invariant_failure(from where) /* can throw */; +/** +Set the exit invariant failure handler. +@param f New exit invariant failure handler functor. +@return Old exit invariant failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ assertion_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC set_exit_invariant_failure(assertion_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; +/** +Return the exit invariant failure handler. +@return Current exit invariant failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ assertion_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC get_exit_invariant_failure() BOOST_NOEXCEPT_OR_NOTHROW; -void BOOST_CONTRACT_DETAIL_DECLSPEC exit_invariant_failure(from where) - /* can throw */; +/** +Call the exit invariant hander functor. +This is typically only called internally by this library. +@param where Context of exit invariant failure. +*/ +void BOOST_CONTRACT_DETAIL_DECLSPEC +exit_invariant_failure(from where) /* can throw */; -// Set all inv failures (entry inv and exit inv) at once. -void BOOST_CONTRACT_DETAIL_DECLSPEC set_invariant_failure( - assertion_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; +/** +Set the both entry and exit invariant failure handlers at once (for +convenience). +@param f New invariant failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ +void BOOST_CONTRACT_DETAIL_DECLSPEC +set_invariant_failure(assertion_failure_handler const& f) + BOOST_NOEXCEPT_OR_NOTHROW; -// Set all failures (pre, post, entry inv, and exit int) at once. -void BOOST_CONTRACT_DETAIL_DECLSPEC set_failure( - assertion_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; +/** +Set the all (precondition, postcondition, entry and exit invariant) failure +handlers at once (for convenience). +@param f New failure handler functor. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ +void BOOST_CONTRACT_DETAIL_DECLSPEC +set_failure(assertion_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW; } } // namespace diff --git a/include/boost/contract/core/set_nothing.hpp b/include/boost/contract/core/set_nothing.hpp index 850b044..adaf947 100644 --- a/include/boost/contract/core/set_nothing.hpp +++ b/include/boost/contract/core/set_nothing.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Used to prevent setting other contract conditions after postconditions. +*/ #include #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ @@ -33,12 +35,19 @@ namespace boost { namespace boost { namespace contract { +/** +Used to prevent setting other contract conditions after postconditions. +This class has no member function so it cannot be used to set any contract +functor. +*/ class set_nothing { // Copyable (as *). public: + /** Destruct this object. */ ~set_nothing() BOOST_NOEXCEPT_IF(false) {} // No set member functions here. +/** @cond */ private: #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ @@ -62,6 +71,7 @@ private: template friend class set_postcondition_only; +/** @endcond */ }; } } // namespace diff --git a/include/boost/contract/core/set_old_postcondition.hpp b/include/boost/contract/core/set_old_postcondition.hpp index b63a134..2fa1631 100644 --- a/include/boost/contract/core/set_old_postcondition.hpp +++ b/include/boost/contract/core/set_old_postcondition.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Allow to specify old value assignments and postconditions. +*/ #include #include @@ -32,12 +34,34 @@ namespace boost { } namespace boost { namespace contract { - + +/** +Allow to specify old value assignments and postconditions. +Allow to program functors this library will call to assign old values before +body execution and to check postconditions. +@tparam R Return type of the function being contracted if that function is a + non-void virtual or overriding public function, otherwise this is + always @c void. +@see @RefSect{tutorial, Tutorial}, @RefSect{advanced_topics, Advances Topics}. +*/ template class set_old_postcondition { // Copyable (as *). public: + /** Destruct this object. */ ~set_old_postcondition() BOOST_NOEXCEPT_IF(false) {} + /** + Allow to specify old value assignments to execute just before function body. + @param f Functor called by this library to assign old values. This + functor is called just before the function body is executed, but + after preconditions and class invariants are checked. Old values + are usually assigned using @RefMacro{BOOST_CONTRACT_OLDOF}. This + functor must be a nullary functor. This functor should capture + old value pointers (and in general all other variables) by + (constant) reference. + @return After old value assignments have been specified, return object that + allows to optionally specify postconditions. + */ template set_postcondition_only old(F const& f) { #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS @@ -53,6 +77,21 @@ public: #endif } + /** + Allow to specify postconditions. + @param f Functor called by this library to check postconditions. Any + exception thrown by a call to this functor indicates a + postcondition failure. Assertions within this functor are + usually programmed using @RefMacro{BOOST_CONTRACT_ASSERT}. This + functor must be a nullary functor if @c R is @c void, otherwise + it must be unary functor taking the return value as a parameter + of type R const& (to avoid extra copies, or @c R and also + R const if extra copies of the return value are + irrelevant). This functor should capture variables by + (constant) reference. + @return After postconditions have been specified, return object that does + not allow to specify any additional contract (i.e., set nothing). + */ template set_nothing postcondition(F const& f) { #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS @@ -68,6 +107,7 @@ public: #endif } +/** @cond */ private: #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ @@ -91,6 +131,7 @@ private: template friend set_old_postcondition<> destructor(CC* oobj); +/** @endcond */ }; } } // namespace diff --git a/include/boost/contract/core/set_postcondition_only.hpp b/include/boost/contract/core/set_postcondition_only.hpp index ee18858..b444bc3 100644 --- a/include/boost/contract/core/set_postcondition_only.hpp +++ b/include/boost/contract/core/set_postcondition_only.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Allow to specify postconditions. +*/ #include #include @@ -34,12 +36,36 @@ namespace boost { } namespace boost { namespace contract { - + +/** +Allow to specify postconditions. +Allow to program functors this library will call to check postconditions. +@tparam R Return type of the function being contracted if that function is a + non-void virtual or overriding public function, otherwise this is + always @c void. +@see @RefSect{tutorial, Tutorial}, @RefSect{advanced_topics, Advances Topics}. +*/ template class set_postcondition_only { // Copyable (as *). public: + /** Destruct this object. */ ~set_postcondition_only() BOOST_NOEXCEPT_IF(false) {} + /** + Allow to specify postconditions. + @param f Functor called by this library to check postconditions. Any + exception thrown by a call to this functor indicates a + postcondition failure. Assertions within this functor are + usually programmed using @RefMacro{BOOST_CONTRACT_ASSERT}. This + functor must be a nullary functor if @c R is @c void, otherwise + it must be unary functor taking the return value as a parameter + of type R const& (to avoid extra copies, or @c R and also + R const if extra copies of the return value are + irrelevant). This functor should capture variables by + (constant) reference. + @return After postconditions have been specified, return object that does + not allow to specify any additional contract (i.e., set nothing). + */ template set_nothing postcondition(F const& f) { #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS @@ -55,6 +81,7 @@ public: #endif } +/** @cond */ private: #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ @@ -74,6 +101,7 @@ private: friend class set_precondition_old_postcondition; friend class set_old_postcondition; +/** @endcond */ }; } } // namespace diff --git a/include/boost/contract/core/set_precondition_old_postcondition.hpp b/include/boost/contract/core/set_precondition_old_postcondition.hpp index 075188e..79bffeb 100644 --- a/include/boost/contract/core/set_precondition_old_postcondition.hpp +++ b/include/boost/contract/core/set_precondition_old_postcondition.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Allow to specify preconditions, old value assignments, and postconditions. +*/ #include #include @@ -34,12 +36,39 @@ namespace boost { } namespace boost { namespace contract { - -template + +/** +Allow to specify preconditions, old value assignments, and postconditions. +Allow to program functors this library will call to check preconditions, assign +old values before body execution, and check postconditions. +@tparam R Return type of the function being contracted if that function is a + non-void virtual or overriding public function, otherwise this is + always @c void. +@see @RefSect{tutorial, Tutorial}, @RefSect{advanced_topics, Advances Topics}. +*/ +template< + typename R /* = void (already in fwd decl from decl.hpp) */ + #ifdef DOXYGEN + = void + #endif +> class set_precondition_old_postcondition { // Copyable (as *). public: + /** Destruct this object. */ ~set_precondition_old_postcondition() BOOST_NOEXCEPT_IF(false) {} + /** + Allow to specify preconditions. + @param f Functor called by this library to check preconditions. Any + exception thrown by a call to this functor indicates a + precondition failure. Assertions within this functor are usually + programmed using @RefMacro{BOOST_CONTRACT_ASSERT}. This functor + must be a nullary functor. This functor could capture variables + by value, or better by (constant) reference to avoid extra + copies. + @return After preconditions have been specified, return object that allows + to optionally specify old value assignments and postconditions. + */ template set_old_postcondition precondition(F const& f) { #ifndef BOOST_CONTRACT_NO_PRECONDITIONS @@ -55,6 +84,18 @@ public: #endif } + /** + Allow to specify old value assignments to execute just before function body. + @param f Functor called by this library to assign old values. This + functor is called just before the function body is executed, but + after preconditions and class invariants are checked. Old values + are usually assigned using @RefMacro{BOOST_CONTRACT_OLDOF}. This + functor must be a nullary functor. This functor should capture + old value pointers (and in general all other variables) by + (constant) reference. + @return After old value assignments have been specified, return object that + allows to optionally specify postconditions. + */ template set_postcondition_only old(F const& f) { #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS @@ -70,6 +111,21 @@ public: #endif } + /** + Allow to specify postconditions. + @param f Functor called by this library to check postconditions. Any + exception thrown by a call to this functor indicates a + postcondition failure. Assertions within this functor are + usually programmed using @RefMacro{BOOST_CONTRACT_ASSERT}. This + functor must be a nullary functor if @c R is @c void, otherwise + it must be unary functor taking the return value as a parameter + of type R const& (to avoid extra copies, or @c R and also + R const if extra copies of the return value are + irrelevant). This functor should capture variables by + (constant) reference. + @return After postconditions have been specified, return object that does + not allow to specify any additional contract (i.e., set nothing). + */ template set_nothing postcondition(F const& f) { #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS @@ -85,6 +141,7 @@ public: #endif } +/** @cond */ private: #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ @@ -120,6 +177,7 @@ private: BOOST_CONTRACT_DETAIL_DECL_FRIEND_OVERRIDING_PUBLIC_FUNCTIONS_Z(1, OO, RR, FF, CC, AArgs, vv, rr, ff, oobj, aargs) +/** @endcond */ }; } } // namespace diff --git a/include/boost/contract/core/virtual.hpp b/include/boost/contract/core/virtual.hpp index cbb5c45..b41dd8c 100644 --- a/include/boost/contract/core/virtual.hpp +++ b/include/boost/contract/core/virtual.hpp @@ -7,6 +7,10 @@ // 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 +Used to contract virtual public functions. +*/ + #include #include #include @@ -28,7 +32,20 @@ namespace boost { namespace boost { namespace contract { +/** +Class to mark virtual public functions. +Virtual and overriding public functions contracted using this library must have +an extra parameter at the very end of their parameter list. This parameter must +be a pointer to this class and it must be assigned to @c 0 by default. (This +extra parameter is often named @c v in this documentation, but any name can be +used.) + +Rationale: This extra parameter is internally used by this library to +recognize virtual public functions and implement subcontracting. +@see @RefSect{tutorial, Tutorial}. +*/ class virtual_ : private boost::noncopyable { // Avoid copy queue, stack, etc. +/** @cond */ // No public API (so users cannot use it directly by mistake). enum action_enum { @@ -97,6 +114,7 @@ class virtual_ : private boost::noncopyable { // Avoid copy queue, stack, etc. BOOST_CONTRACT_DETAIL_DECL_DETAIL_CHECK_SUBCONTRACTED_PRE_POST_INV_Z(1, /* is_friend = */ 1, OO, RR, FF, CC, AArgs); +/** @endcond */ }; } } // namespace diff --git a/include/boost/contract/destructor.hpp b/include/boost/contract/destructor.hpp index f8e6ddf..2264fb3 100644 --- a/include/boost/contract/destructor.hpp +++ b/include/boost/contract/destructor.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Program contracts for destructors. +*/ #include #if !defined(BOOST_CONTRACT_NO_DESTRUCTORS) || \ @@ -17,6 +19,17 @@ namespace boost { namespace contract { +/** +Program contracts for destructors. +Used to specify postconditions and check class invariants for destructors +(destructors do not have preconditions). +@see @RefSect{tutorial, Tutorial}. +@param obj The destructor's object @c this. +@return The result of this function must be assigned to a local variable of type + @RefClass{boost::contract::guard} declared at the beginning of the + destructor definition (after specifying old value assignments and + postconditions if they are present). +*/ template set_old_postcondition<> destructor(C* obj) { // Must #if also on ..._PRECONDITIONS here because set_... is generic. diff --git a/include/boost/contract/detail/operation/function.hpp b/include/boost/contract/detail/operation/function.hpp index 6413db5..5a62efa 100644 --- a/include/boost/contract/detail/operation/function.hpp +++ b/include/boost/contract/detail/operation/function.hpp @@ -35,7 +35,7 @@ private: if(check_guard::checking()) return; #ifndef BOOST_CONTRACT_NO_PRECONDITIONS { - #ifndef BOOST_CONTRACT_PRECONDITIONS_DISABLE_NOTHING + #ifndef BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION check_guard checking; #endif this->check_pre(); diff --git a/include/boost/contract/detail/operation/public_function.hpp b/include/boost/contract/detail/operation/public_function.hpp index 0c49113..77cec76 100644 --- a/include/boost/contract/detail/operation/public_function.hpp +++ b/include/boost/contract/detail/operation/public_function.hpp @@ -76,7 +76,7 @@ private: this->check_subcontracted_entry_inv(); #endif #ifndef BOOST_CONTRACT_NO_PRECONDITIONS - #ifndef BOOST_CONTRACT_PRECONDITIONS_DISABLE_NOTHING + #ifndef BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION this->check_subcontracted_pre(); } // Release check guard. #else diff --git a/include/boost/contract/detail/operation/public_static_function.hpp b/include/boost/contract/detail/operation/public_static_function.hpp index 1e809b7..9f0a926 100644 --- a/include/boost/contract/detail/operation/public_static_function.hpp +++ b/include/boost/contract/detail/operation/public_static_function.hpp @@ -50,7 +50,7 @@ private: this->check_entry_static_inv(); #endif #ifndef BOOST_CONTRACT_NO_PRECONDITIONS - #ifndef BOOST_CONTRACT_PRECONDITIONS_DISABLE_NOTHING + #ifndef BOOST_CONTRACT_PRECONDITIONS_DISABLE_NO_ASSERTION this->check_pre(); } // Release check guard. #else diff --git a/include/boost/contract/function.hpp b/include/boost/contract/function.hpp index 642c1da..e8b5810 100644 --- a/include/boost/contract/function.hpp +++ b/include/boost/contract/function.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Program contracts for non-member, private, and protected functions. +*/ #include #if !defined(BOOST_CONTRACT_NO_FUNCTIONS) || \ @@ -17,6 +19,35 @@ namespace boost { namespace contract { +/** +Program contracts for non-member, private and protected functions. + +Allow to program preconditions and postconditions (both optional) for +non-member, private and protected functions (these functions never check +invariants or participate in subcontracting). +The result of this function must be assigned to a local variable of type +@RefClass{boost::contract::guard} at the scope of the function being contracted. + +@code + // Enclosing function scope. + boost::contract::guard c = boost::contract::function() + .precondition(...) // Optional. + .old(...) // Optional. + .postcondition(...) // Optional. + ; + ... // Enclosing function body. +@endcode + +For optimization purposes this can be avoided for functions that do not have +preconditions and postconditions. + +Where .precondition(...), .old(...), and +.postcondition(...) take nullary functors that assert preconditions, +assign old value pointers just before body execution (most of the times it +should be sufficient to assign these pointers where they are first declared +instead), and assert postconditions respectively. +@SeeAlso @RefSect{tutorial, Tutorial} +*/ set_precondition_old_postcondition<> function() { // Must #if also on ..._INVARIANTS here because set_... is generic. #if !defined(BOOST_CONTRACT_NO_FUNCTIONS) || \ diff --git a/include/boost/contract/guard.hpp b/include/boost/contract/guard.hpp index d5776c1..88b32d0 100644 --- a/include/boost/contract/guard.hpp +++ b/include/boost/contract/guard.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +RAII object that checks the contracts. +*/ #include #include @@ -17,6 +19,8 @@ /* PRIVATE */ +/** @cond */ + #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ !defined(BOOST_CONTRACT_NO_INVARIANTS) @@ -30,19 +34,30 @@ #define BOOST_CONTRACT_GUARD_CTOR_DEF_(contract_type) {} #endif -// Following implicit to allow syntax `guard c = ...`. -#define BOOST_CONTRACT_GUARD_CTOR_(contract_type) \ - /* implicit */ guard(contract_type const& contract) \ - BOOST_CONTRACT_GUARD_CTOR_DEF_(contract_type) +/** @endcond */ /* CODE */ namespace boost { namespace contract { +/** +RAII object that checks the contracts. +In general, this object checks entry invariants, preconditions, and assigns old +values when it is constructed. It then checks exit invariants and postconditions +when it is destructed. However, special attention in placed in marking sure +postconditions are checked only if the body did not throw an exception, +constructors never check entry invariants, destructor check exit invariants only +if their body throws, etc. (see also +@RefSect{contract_programming_overview, Contract Programming Overview}). +@see @RefSect{tutorial, Tutorial}. +*/ class guard { // Non-copyable (but copy ctor ~= move via ptr release). public: - // Following copy and implicit type conversion ctors allow `guard c = ...`. - + /** + Construct this object copying it from specified one. + This object will check the contract, the copied-from object will not (i.e., + contract checking ownership is transfered to the this object). + */ guard(guard const& other) // Copy ctor moves check_ pointer to dest. #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \ !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \ @@ -51,19 +66,106 @@ public: #endif {} - template - BOOST_CONTRACT_GUARD_CTOR_(set_precondition_old_postcondition) - - template - BOOST_CONTRACT_GUARD_CTOR_(set_old_postcondition) - - template - BOOST_CONTRACT_GUARD_CTOR_(set_postcondition_only) - - BOOST_CONTRACT_GUARD_CTOR_(set_nothing) + /** + Construct this object from specified contract. + Check entry invariants (as they apply for specified contract). + Implicit so initialization operator @c = can be used. + Throws: This can throw any exception (exception specification + noexcept(false)) to allow to configure this library + to throw on contract failure. + @param contract Contract to be guarded by this object. + @tparam R Return type of operation being contracted if that operation is a + non-void virtual or overriding public function, otherwise this + is always void. + */ + template + /* implicit */ guard(set_precondition_old_postcondition const& contract) + #ifndef DOXYGEN + BOOST_CONTRACT_GUARD_CTOR_DEF_(set_precondition_old_postcondition) + #else + ; + #endif + + /** + Construct this object from specified contract. + Check entry invariants (as they apply for specified contract) and check + preconditions. + Implicit so initialization operator @c = can be used. + + Throws: This can throw any exception (exception specification + noexcept(false)) to allow to configure this library + to throw on contract failure. + @param contract Contract to be guarded by this object. + @tparam R Return type of operation being contracted if that operation is a + non-void virtual or overriding public function, otherwise this + is always void. + */ + template + /* implicit */ guard(set_old_postcondition const& contract) + #ifndef DOXYGEN + BOOST_CONTRACT_GUARD_CTOR_DEF_(set_old_postcondition) + #else + ; + #endif + + /** + Construct this object from specified contract. + Check entry invariants (as they apply for specified contract), check + preconditions, and assign old values. + Implicit so initialization operator @c = can be used. + + Throws: This can throw any exception (exception specification + noexcept(false)) to allow to configure this library + to throw on contract failure. + @param contract Contract to be guarded by this object. + @tparam R Return type of operation being contracted if that operation is a + non-void virtual or overriding public function, otherwise this + is always void. + */ + template + /* implicit */ guard(set_postcondition_only const& contract) + #ifndef DOXYGEN + BOOST_CONTRACT_GUARD_CTOR_DEF_(set_postcondition_only) + #else + ; + #endif + + /** + Construct this object from specified contract. + Check entry invariants (as they apply for specified contract), check + preconditions, and assign old values. (In this case, the destructor of this + object will also check postconditions.) + Implicit so initialization operator @c = can be used. + + Throws: This can throw any exception (exception specification + noexcept(false)) to allow to configure this library + to throw on contract failure. + @param contract Contract to be guarded by this object. + @tparam R Return type of operation being contracted if that operation is a + non-void virtual or overriding public function, otherwise this + is always void. + */ + /* implicit */ guard(set_nothing const& contract) + #ifndef DOXYGEN + BOOST_CONTRACT_GUARD_CTOR_DEF_(set_nothing) + #else + ; + #endif + + /** + Destroy this object. + Check exit invariants (as they apply for specified contract). Check + postconditions (if the body did not throw and postconditions where + specified for the contract specified when constructing this object). + + Throws: This can throw any exception (exception specification + noexcept(false)) to allow to configure this library + to throw on contract failure. + */ ~guard() BOOST_NOEXCEPT_IF(false) {} // Allow auto_ptr dtor to throw. +/** @cond */ private: guard& operator=(guard const&); // Cannot copy outside of `guard c = ...`. @@ -73,6 +175,7 @@ private: boost::contract::detail::auto_ptr check_; #endif +/** @endcond */ }; } } // namespace diff --git a/include/boost/contract/old.hpp b/include/boost/contract/old.hpp index 0e07d34..baccf4b 100644 --- a/include/boost/contract/old.hpp +++ b/include/boost/contract/old.hpp @@ -7,7 +7,9 @@ // 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 */ +/** @file +Facilities for old values. +*/ #include #include @@ -35,6 +37,8 @@ BOOST_CONTRACT_ERROR_macro_OLDOF_requires_variadic_macros_otherwise_manually_pro /* PRIVATE */ +/** @cond */ + #ifdef BOOST_NO_CXX11_AUTO_DECLARATIONS #define BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value) /* nothing */ #else @@ -55,10 +59,29 @@ BOOST_CONTRACT_ERROR_macro_OLDOF_requires_variadic_macros_otherwise_manually_pro BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value)(boost::contract::make_old( \ boost::contract::copy_old() ? (value) : boost::contract::null_old() \ )) - + +/** @endcond */ + /* PUBLIC */ // NOTE: Leave this #defined the same regardless of ..._POSTCONDITIONS. +/** +Macro typically used to copy old value expressions. +This is a variadic macro, program the old value expression copy manually on +compilers that do not support variadic macros (see +also @RefSect{advanced_topics, Advanced Topics}). +@see @RefSect{tutorial, Tutorial}. +@param ... This macro usually takes a single parameter as the expressions to + be assigned to the old value. However, in virtual or overriding + public functions where the extra + @RefClass{boost::contract::virtual_}* function parameter must + be used, this macro takes two parameters: The first parameter is + the pointer to @RefClass{boost::contract::virtual_} and then the + old value expression to be copied. +@return The expression expanded by this macro should be assigned to an old + value pointer, either @RefClass{boost::contract::old_ptr} or + @RefClass{boost::contract::old_ptr_noncopyable}. +*/ #define BOOST_CONTRACT_OLDOF(...) \ BOOST_PP_CAT( /* CAT(..., EMTPY()) required on MSVC */ \ BOOST_PP_OVERLOAD( \ @@ -72,30 +95,47 @@ BOOST_CONTRACT_ERROR_macro_OLDOF_requires_variadic_macros_otherwise_manually_pro /* CODE */ -// Specialization because `unconvertible_old` incomplete type when trait used. +/** @cond */ namespace boost { namespace contract { class unconvertible_old; } + // Needed because `unconvertible_old` incomplete type when trait used. template<> struct is_copy_constructible : true_type {}; } +/** @endcond */ namespace boost { namespace contract { template class old_ptr_noncopyable; +/** +Old value pointer (requires pointed old value type to be copyable). +@see @RefSect{tutorial, Tutorial}. +@tparam T Type of pointed old value. If this type is not copyable, this + pointer will always be left null and this library will generate a + compile-time error when this pointer is dereferenced of accessed. +*/ template class old_ptr { /* copyable (as *) */ public: + /** Pointed old value type. */ typedef T element_type; + /** Construct this object as a null old value pointer. */ old_ptr() {} - /* only const access (contracts should not change old values) */ - + /** + Dereference this old value pointer. + This will generate a run-time error if this pointer is null and a + compile-time error if the pointed type is not copyable. + @return The old value (contract assertions should not change the state of + the program so the old value is always returned as a constant + reference and this member function is @c const). + */ T const& operator*() const { BOOST_STATIC_ASSERT_MSG( boost::is_copy_constructible::value, @@ -105,6 +145,13 @@ public: return *ptr_; } + /** + Access the pointed old value. + This will generate a compile-time error if the pointed type is not copyable. + @return The old value (contract assertions should not change the state of + the program so the old value is always returned as a pointer to + constant object and this member function is @c const). + */ T const* operator->() const { BOOST_STATIC_ASSERT_MSG( boost::is_copy_constructible::value, @@ -113,8 +160,17 @@ public: return ptr_.operator->(); } - BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(old_ptr, !!ptr_) + #ifndef DOXYGEN + BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(old_ptr, !!ptr_) + #else + /** + Safe-bool operator. + @return True if this pointer is not null, false otherwise. + */ + explicit operator bool() const; + #endif +/** @cond */ private: #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS explicit old_ptr(boost::shared_ptr ptr) : @@ -125,33 +181,72 @@ private: friend class convertible_old; friend class old_ptr_noncopyable; +/** @endcond */ }; -// Similar to above, but does not statically assert copy constructible. +/** +Old value pointer (does not require pointed old value type to be copyable). +@see @RefSect{advanced_topics, Advanced Topics}. +@tparam T Type of pointed old value. If this type is not copyable, this + pointer will always be left null (but this library will not generate + compile-time errors when this pointer is dereferenced of accessed). +*/ template class old_ptr_noncopyable { /* copyable (as *) */ public: + /** Pointed old value type. */ typedef T element_type; + /** Construct this object as a null old value pointer. */ old_ptr_noncopyable() {} - // Required to assign to OLDOF (as OLDOF returns old_ptr for auto decl). + /** + Construct this object from a old value pointer for copyable-only types. + Implicitly called when assign an object of this type to + @RefMacro{BOOST_CONTRACT_OLDOF}. + @param other Copyable-only old value pointer. + */ /* implicit */ old_ptr_noncopyable(old_ptr const& other) : ptr_(other.ptr_) {} - /* only const access (contracts should not change old values) */ + // Only const access (contracts should not change old values). + /** + Dereference this old value pointer. + This will generate a run-time error if this pointer is null (but no + compile-time error if the pointed type is not copyable). + @return The old value (contract assertions should not change the state of + the program so the old value is always returned as a constant + reference and this member function is @c const). + */ T const& operator*() const { BOOST_CONTRACT_DETAIL_DEBUG(ptr_); return *ptr_; } + /** + Access the pointed old value. + (This will not generate a compile-time error if the pointed type is not + copyable.) + @return The old value (contract assertions should not change the state of + the program so the old value is always returned as a pointer to + constant object and this member function is @c const). + */ T const* operator->() const { return ptr_.operator->(); } - BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(old_ptr_noncopyable, !!ptr_) + #ifndef DOXYGEN + BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(old_ptr_noncopyable, !!ptr_) + #else + /** + Safe-bool operator. + @return True if this pointer is not null, false otherwise. + */ + explicit operator bool() const; + #endif +/** @cond */ private: #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS explicit old_ptr_noncopyable(boost::shared_ptr ptr) : @@ -161,12 +256,26 @@ private: boost::shared_ptr ptr_; friend class convertible_old; +/** @endcond */ }; +/** +Internally hold old value copies. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ class unconvertible_old { // Copyable (as *). public: // Following implicitly called by ternary operator `... ? ... : null_old()`. + /** + Construct this object from the specified old value (for copyable old value + types). + The specified old value is copied one time and the related old value pointer + will not be null (as long as postconditions are being checked, see + @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS}). + @tparam T Old value type. + @param old_value Old value to be copied. + */ template /* implicit */ unconvertible_old( T const& old_value, @@ -174,15 +283,24 @@ public: ) #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS : ptr_(boost::make_shared(old_value)) // The one single T's copy. - #endif // Else, null ptr_ (so not copy of T). + #endif // Else, leave ptr_ null (and no copy of T). {} + /** + Construct this object from the specified old value (for non-copyable old + value types). + The specified old value cannot and so it is not copied in this case, thus + the related old value pointer will always be null. + @tparam T Old value type. + @param old_value Old value (that will not be copied in this case). + */ template /* implicit */ unconvertible_old( - T const&, + T const& old_value, typename boost::disable_if >::type* = 0 - ) {} // Null ptr_ (so no copy of T). + ) {} // Leave ptr_ null (and no copy of T). +/** @cond */ private: explicit unconvertible_old() {} @@ -193,22 +311,38 @@ private: friend class convertible_old; friend unconvertible_old null_old(); +/** @endcond */ }; +/** +Internally convert old value copies to old value pointers. +@see @RefSect{advanced_topics, Advanced Topics}. +*/ class convertible_old { // Copyable (as *). public: - // Implicitly called by ctor init `old_ptr_noncopyable old_x = ...`. + /** + Convert this object to an old value pointer. + For example, implicitly called when assigning or initializing an old value + pointer. + @tparam T Type of pointed old value (might or might be copyable). + */ template /* implicit */ operator old_ptr_noncopyable() { return ptr >(); } - // Implicitly called by ctor init `old_ptr old_x = ...`. + /** + Convert this object to an old value pointer. + For example, implicitly called when assigning or initializing an old value + pointer. + @tparam T Type of pointed old value (must be copyable). + */ template /* implicit */ operator old_ptr() { return ptr >(); } +/** @cond */ private: explicit convertible_old(virtual_* v, unconvertible_old const& old) #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS @@ -277,18 +411,43 @@ private: friend convertible_old make_old(unconvertible_old const&); friend convertible_old make_old(virtual_*, unconvertible_old const&); +/** @endcond */ }; - + +/** +Make a null old value copy (i.e., the related old value pointer will be null). +@see @RefSect{advanced_topics, Advanced Topics}. +*/ unconvertible_old null_old() { return unconvertible_old(); } +/** +Make an old value copy (for non virtual and not overriding public functions). +@see @RefSect{advanced_topics, Advanced Topics}. +@param old Old value (implicitly and automatically wrapped in + @RefClass{boost::contract::uncovertible_old}). +*/ convertible_old make_old(unconvertible_old const& old) { return convertible_old(0, old); } +/** +Make an old value copy (for virtual and overriding public functions). +@see @RefSect{advanced_topics, Advanced Topics}. +@param v Contracted virtual and overriding public function extra parameter. +@param old Old value (implicitly and automatically wrapped in + @RefClass{boost::contract::uncovertible_old}). +*/ convertible_old make_old(virtual_* v, unconvertible_old const& old) { return convertible_old(v, old); } +/** +Return true if and only if old values need to be copied (for non virtual and +not overriding public functions). +For example, this function always returns false when postconditions are not +being checked (see @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS}). +@see @RefSect{advanced_topics, Advanced Topics}. +*/ bool copy_old() { #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS return !boost::contract::detail::check_guard::checking(); @@ -297,6 +456,14 @@ bool copy_old() { #endif } +/** +Return true if and only if old values need to be copied (for virtual and +overriding public functions). +For example, this function always returns false when postconditions are not +being checked (see @RefMacro{BOOST_CONTRACT_NO_POSTCONDITIONS}). +@see @RefSect{advanced_topics, Advanced Topics}. +@param v Contracted virtual and overriding public function extra parameter. +*/ bool copy_old(virtual_* v) { #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS if(!v) return !boost::contract::detail::check_guard::checking(); diff --git a/include/boost/contract/override.hpp b/include/boost/contract/override.hpp index 62abd1a..badc128 100644 --- a/include/boost/contract/override.hpp +++ b/include/boost/contract/override.hpp @@ -7,18 +7,24 @@ // 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 +Support contracts for overriding public functions. +*/ + #include #include #include -/* PRIVATE */ #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS #include #include #include - #define BOOST_CONTRACT_OVERRIDE_CALL_BASE_(z, arity, arity_compl, f) \ + /* PRIVATE */ + + #define BOOST_CONTRACT_OVERRIDE_CALL_BASE_(z, \ + arity, arity_compl, function_name) \ template< \ class BOOST_CONTRACT_DETAIL_NAME1(B), \ class BOOST_CONTRACT_DETAIL_NAME1(C) \ @@ -40,7 +46,7 @@ boost::contract::detail::none&) \ ) { \ BOOST_CONTRACT_DETAIL_NAME1(obj)-> \ - BOOST_CONTRACT_DETAIL_NAME1(B)::f( \ + BOOST_CONTRACT_DETAIL_NAME1(B)::function_name( \ BOOST_CONTRACT_DETAIL_TVARIADIC_ARGS_Z(z, arity, \ BOOST_CONTRACT_DETAIL_NAME1(args)) \ BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(arity) \ @@ -49,38 +55,66 @@ } #if BOOST_CONTRACT_DETAIL_TVARIADIC - #define BOOST_CONTRACT_OVERRIDE_CALL_BASE_DECL_(f) \ - BOOST_CONTRACT_OVERRIDE_CALL_BASE_(1, ~, ~, f) + #define BOOST_CONTRACT_OVERRIDE_CALL_BASE_DECL_(function_name) \ + BOOST_CONTRACT_OVERRIDE_CALL_BASE_(1, ~, ~, function_name) #else #include #include #include - #define BOOST_CONTRACT_OVERRIDE_CALL_BASE_DECL_(f) \ + #define BOOST_CONTRACT_OVERRIDE_CALL_BASE_DECL_(function_name) \ BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_CONTRACT_MAX_ARGS), \ - BOOST_CONTRACT_OVERRIDE_CALL_BASE_ARITY_, f) \ + BOOST_CONTRACT_OVERRIDE_CALL_BASE_ARITY_, function_name) \ - #define BOOST_CONTRACT_OVERRIDE_CALL_BASE_ARITY_(z, arity, f) \ + #define BOOST_CONTRACT_OVERRIDE_CALL_BASE_ARITY_(z, arity, \ + function_name) \ BOOST_CONTRACT_OVERRIDE_CALL_BASE_(z, arity, \ - BOOST_PP_SUB(BOOST_CONTRACT_MAX_ARGS, arity), f) + BOOST_PP_SUB(BOOST_CONTRACT_MAX_ARGS, arity), function_name) #endif -/* PUBLIC */ + /* PUBLIC */ - #define BOOST_CONTRACT_NAMED_OVERRIDE(name, f) \ + #define BOOST_CONTRACT_NAMED_OVERRIDE(override_name, function_name) \ struct name { \ BOOST_CONTRACT_DETAIL_INTROSPECTION_HAS_MEMBER_FUNCTION( \ - BOOST_CONTRACT_DETAIL_NAME1(has_member_function), f) \ - \ - BOOST_CONTRACT_OVERRIDE_CALL_BASE_DECL_(f) \ + BOOST_CONTRACT_DETAIL_NAME1(has_member_function), \ + function_name \ + ) \ + BOOST_CONTRACT_OVERRIDE_CALL_BASE_DECL_(function_name) \ }; #else - // Empty type (not actually used) just needed to compile user contract code. - #define BOOST_CONTRACT_NAMED_OVERRIDE(name, f) struct name {}; + /** + Declare override type allowing to explicitly specify its name. + Declare override type to be passed as an explicit template parameter to + @RefFunc{boost::contract::public_function} for overriding public functions. + @see @RefSect{tutorial, Tutorial}. + @param override_name Name of override type to be declared. + @param function_name Name of the overriding public function. This macro + is called just once even if the function name is + overloaded and the same override type can be used + for all overloaded functions (see + @RefSect{advanced_topics, Advanced Topics}). + */ + #define BOOST_CONTRACT_NAMED_OVERRIDE(override_name, function_name) \ + struct name {}; /* empty type (not used) just to compile code */ #endif + +/* PUBLIC */ -#define BOOST_CONTRACT_OVERRIDE(f) \ - BOOST_CONTRACT_NAMED_OVERRIDE(BOOST_PP_CAT(override_, f), f) +/** +Declare override type naming it override_function_name. +Declare override type to be passed as an explicit template parameter to +@RefFunc{boost::contract::public_function} for overriding public functions. +@see @RefSect{tutorial, Tutorial}. +@param function_name Name of the overriding public function. This macro + is called just once even if the function name is + overloaded and the same override type can be used + for all overloaded functions (see + @RefSect{advanced_topics, Advanced Topics}). +*/ +#define BOOST_CONTRACT_OVERRIDE(function_name) \ + BOOST_CONTRACT_NAMED_OVERRIDE(BOOST_PP_CAT(override_, function_name), \ + function_name) #if BOOST_CONTRACT_DETAIL_TVARIADIC #include @@ -88,11 +122,23 @@ /* PRIVATE */ - #define BOOST_CONTRACT_OVERRIDES_SEQ_(r, unused, f) \ - BOOST_CONTRACT_OVERRIDE(f) + /** @cond */ + #define BOOST_CONTRACT_OVERRIDES_SEQ_(r, unused, function_name) \ + BOOST_CONTRACT_OVERRIDE(function_name) + /** @endcond */ /* PUBLIC */ + /** + Declare multiple override types at once naming them override_.... + This is a variadic macro, call @RefMacro{BOOST_CONTRACT_OVERRIDE} multiple + times on compilers that do not support variadic macros instead. + @see @RefSect{tutorial, Tutorial}. + @param ... A comma separated list of one or more names of overriding + public functions. This macro is provided for convenience, it is + equivalent to calling @RefMacro{BOOST_CONTRACT_OVERRIDE} for + each specified function name. + */ #define BOOST_CONTRACT_OVERRIDES(...) \ BOOST_PP_SEQ_FOR_EACH(BOOST_CONTRACT_OVERRIDES_SEQ_, ~, \ BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) diff --git a/include/boost/contract/public_function.hpp b/include/boost/contract/public_function.hpp index 21a505e..6bc5cce 100644 --- a/include/boost/contract/public_function.hpp +++ b/include/boost/contract/public_function.hpp @@ -7,6 +7,12 @@ // 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 contracts for public member functions. +Different overloads are provided to handle static, virtual void/non-void, and +overriding void/non-void public functions. +*/ + // TODO: Document that even with variadic templates there's a hard limit to function max args (18 works, but MAX_ARGS=19 does not). This limit comes from Boost.MPL (vector, push_back, etc.), Boost.FunctionTypes, and other Boost algorithm that do not currently have a variadic template implementation. However, re-impl all these Boost alg would be too much work for this lib, plus the 19 max args limit seems high enough, and it would eventually be removed if Boost.MPL, Boost.FunctionTypes are ever ported to impl that use variadic templates. // TODO: Document that not using variadic templates (i.e., using pp meta-programming impl instead) does not increase compilation times (I measured this with the max_arg test program). @@ -51,7 +57,20 @@ namespace boost { namespace contract { // However, R is never specified, not even for virtual functions, when the // return type is void (i.e., R always optional). -// For static public functions. +/** +Program contracts for static public functions. +Used to specify preconditions, postconditions, old value assignments, and check +static class invariants for static public functions. +@see @RefSect{tutorial, Tutorial}. +@tparam C Class of contracted member function. This template parameter must + be explicitly specified for static public functions (because they + have no object so this template parameter cannot be automatically + deduced). +@return The result of this function must be assigned to a local variable of type + @RefClass{boost::contract::guard} declared at the beginning of the + static public function definition (after declaring old value pointers + if they are present). +*/ template set_precondition_old_postcondition<> public_function() { #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS @@ -62,7 +81,22 @@ set_precondition_old_postcondition<> public_function() { #endif } -// For non-static, non-virtual, and non-overriding public functions. +/** +Program contracts for non-static, non-virtual, and not overriding public +functions. +Used to specify preconditions, postconditions, old value assignments, and to +check class invariants for public functions that are not static, not virtual, +and do not override. +@see @RefSect{tutorial, Tutorial}. +@param obj The public function's object @c this. It will be @c const and/or + @c volatile depending on the cv-qualifier for the contracted public + function (volatile public functions will check volatile class + invariants, see also @RefSect{advanced_topics, Advanced Topics}). +@return The result of this function must be assigned to a local variable of type + @RefClass{boost::contract::guard} declared at the beginning of the + static public function definition (after declaring old value pointers + if they are present). +*/ template set_precondition_old_postcondition<> public_function(C* obj) { #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS @@ -95,6 +129,8 @@ set_precondition_old_postcondition<> public_function(C* obj) { #endif } +/** @cond */ + // To use within macro expansions instead of defined(...) (PRIVATE macro). #ifdef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS #define BOOST_CONTRACT_PUBLIC_FUNCTIONS_ 0 @@ -158,8 +194,65 @@ set_precondition_old_postcondition<> public_function(C* obj) { ) \ } -BOOST_CONTRACT_PUBLIC_FUNCTION_VIRTUAL_NO_OVERRIDE_(/* has_result = */ 0) -BOOST_CONTRACT_PUBLIC_FUNCTION_VIRTUAL_NO_OVERRIDE_(/* has_result = */ 1) +/** @endcond */ + +#ifdef DOXYGEN + /** + Program contracts for virtual but not overriding public functions returning + void. + Used to specify preconditions, postconditions, old value assignments, and + to check class invariants for public functions that are virtual, do not + override, and return @c void. + @see @RefSect{tutorial, Tutorial}. + @param v The contracted virtual function extra trailing parameter of type + @RefClass{boost::contract::virtual_}* and with default + value @c 0. + @param obj The public function's object @c this. It will be @c const and/or + @c volatile depending on the cv-qualifier for the contracted + public function (volatile public functions will check volatile + class invariants, see also + @RefSect{advanced_topics, Advanced Topics}). + @return The result of this function must be assigned to a local variable of + type @RefClass{boost::contract::guard} declared at the beginning of + the static public function definition (after declaring old value + pointers if they are present). + */ + template + set_precondition_old_postcondition<> public_function(virtual_* v, C* obj); + + /** + Program contracts for virtual but not overriding public functions returning + non-void. + Used to specify preconditions, postconditions, old value assignments, and + to check class invariants for public functions that are virtual, do not + override, and do not return @c void. + @see @RefSect{tutorial, Tutorial}. + @param v The contracted virtual function extra trailing parameter of type + @RefClass{boost::contract::virtual_}* and with default + value @c 0. + @param r A reference to the contracted virtual function return value. + (This could be a variable local to the contracted function + scope, but it must be set by programmers at each function + @c return statement.) + @param obj The public function's object @c this. It will be @c const and/or + @c volatile depending on the cv-qualifier for the contracted + public function (volatile public functions will check volatile + class invariants, see also + @RefSect{advanced_topics, Advanced Topics}). + @return The result of this function must be assigned to a local variable of + type @RefClass{boost::contract::guard} declared at the beginning of + the static public function definition (after declaring old value + pointers if they are present). + */ + template + set_precondition_old_postcondition public_function( + virtual_* v, R& r, C* obj); +#else + BOOST_CONTRACT_PUBLIC_FUNCTION_VIRTUAL_NO_OVERRIDE_(/* has_result = */ 0) + BOOST_CONTRACT_PUBLIC_FUNCTION_VIRTUAL_NO_OVERRIDE_(/* has_result = */ 1) +#endif + +/** @cond */ // For non-static, virtual, and overriding public functions (PRIVATE macro). #define BOOST_CONTRACT_PUBLIC_FUNCTION_VIRTUAL_OVERRIDE_Z_( \ @@ -234,7 +327,87 @@ BOOST_CONTRACT_PUBLIC_FUNCTION_VIRTUAL_NO_OVERRIDE_(/* has_result = */ 1) ) \ } -#if BOOST_CONTRACT_DETAIL_TVARIADIC +/** @endcond */ + +#ifdef DOXYGEN + /** + Program contracts for overriding (virtual or not) public functions returning + void. + Used to specify preconditions, postconditions, old value assignments, and + to check class invariants for public functions that are virtual, do not + override, and return @c void. + @see @RefSect{tutorial, Tutorial}. + @param v The contracted virtual function extra trailing parameter of type + @RefClass{boost::contract::virtual_}* and with default + value @c 0. + @param f A pointer to the contracted function. + @param obj The public function's object @c this. It will be @c const and/or + @c volatile depending on the cv-qualifier for the contracted + public function (volatile public functions will check volatile + class invariants, see also + @RefSect{advanced_topics, Advanced Topics}). + @param args The contracted function formal parameters (by reference and in + the oder they appear in the contracted function declaration). + On compilers that do not support variadic templates, this + library internally implements this function using preprocessor + meta-programming (in this case, the maximum number of supported + arguments @p args is defined by + @RefMacro{BOOST_CONTRACT_MAX_ARGS}). + @tparam O The overriding type @c override_... declared invoking the + @RefMacro{BOOST_CONTRACT_OVERRIDE} (or similar) macro with the + contracted function name. This template parameter must be + explicitly specified (because it is not used in this function + formal parameter so it cannot be automatically deduced). + @return The result of this function must be assigned to a local variable of + type @RefClass{boost::contract::guard} declared at the beginning of + the static public function definition (after declaring old value + pointers if they are present). + */ + template + set_precondition_old_postcondition<> public_function( + virtual_* v, F f, C* obj, Args&... args); + + /** + Program contracts for overriding (virtual or not) public functions returning + non-void. + Used to specify preconditions, postconditions, old value assignments, and + to check class invariants for public functions that are virtual, do not + override, and do not return @c void. + @see @RefSect{tutorial, Tutorial}. + @param v The contracted virtual function extra trailing parameter of type + @RefClass{boost::contract::virtual_}* and with default + value @c 0. + @param r A reference to the contracted virtual function return value. + (This could be a variable local to the contracted function + scope, but it must be set by programmers at each function + @c return statement.) + @param f A pointer to the contracted function. + @param obj The public function's object @c this. It will be @c const and/or + @c volatile depending on the cv-qualifier for the contracted + public function (volatile public functions will check volatile + class invariants, see also + @RefSect{advanced_topics, Advanced Topics}). + @param args The contracted function formal parameters (by reference and in + the oder they appear in the contracted function declaration). + On compilers that do not support variadic templates, this + library internally implements this function using preprocessor + meta-programming (in this case, the maximum number of supported + arguments @p args is defined by + @RefMacro{BOOST_CONTRACT_MAX_ARGS}). + @tparam O The overriding type @c override_... declared invoking the + @RefMacro{BOOST_CONTRACT_OVERRIDE} (or similar) macro with the + contracted function name. This template parameter must be + explicitly specified (because it is not used in this function + formal parameter so it cannot be automatically deduced). + @return The result of this function must be assigned to a local variable of + type @RefClass{boost::contract::guard} declared at the beginning of + the static public function definition (after declaring old value + pointers if they are present). + */ + template + set_precondition_old_postcondition public_function( + virtual_* v, R& r, F f, C* obj, Args&... args); +#elif BOOST_CONTRACT_DETAIL_TVARIADIC BOOST_CONTRACT_PUBLIC_FUNCTION_VIRTUAL_OVERRIDE_Z_(1, /* arity = */ ~, /* arity_compl = */ ~, /* has_result = */ 0) BOOST_CONTRACT_PUBLIC_FUNCTION_VIRTUAL_OVERRIDE_Z_(1, diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 46f260e..7d5383a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -187,6 +187,9 @@ test-suite function [ subdir-run-with-no function : body_throw ] [ subdir-run-with-no function : old_throw ] + + [ subdir-run-with-no function : check_if ] + [ subdir-compile-fail function : no_check_if_error ] ; test-suite result @@ -202,13 +205,13 @@ test-suite old [ subdir-run-with-no old : auto ] [ subdir-run-with-no old : no_macros ] + [ subdir-run-with-no old : no_macros_noncopyable ] + [ subdir-compile-fail old : no_make_old_error ] + [ subdir-compile-fail old : no_make_old_noncopyable_error ] [ subdir-run-with-no old : noncopyable ] [ subdir-compile-fail old : noncopyable_error ] - - [ subdir-run-with-no old : no_equal ] - [ subdir-compile-fail old : no_equal_error ] ; test-suite disable diff --git a/test/function/check_if.cpp b/test/function/check_if.cpp new file mode 100644 index 0000000..27f4736 --- /dev/null +++ b/test/function/check_if.cpp @@ -0,0 +1,59 @@ + +// Test assertions skipped when operations to check them missing (e.g., `==`). + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned equal_skips; + +template +void push_back(std::vector& vect, T const& val) { + boost::contract::guard c = boost::contract::function() + .postcondition([&] { + BOOST_CONTRACT_ASSERT( + boost::contract::call_if >( + boost::bind(std::equal_to(), boost::cref(vect.back()), + boost::cref(val)) + ).else_([] { ++equal_skips; return true; }) + ); + }) + ; + vect.push_back(val); +} + +struct j { // Type without operator==. + explicit j(int i) : j_(i) {} +private: + int j_; +}; + +int main() { + std::vector vi; + equal_skips = 0; + push_back(vi, 123); + BOOST_TEST_EQ(equal_skips, 0); + + unsigned const cnt = + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + 1 + #else + 0 + #endif + ; + + j jj(456); + std::vector vj; + equal_skips = 0; + push_back(vj, jj); + BOOST_TEST_EQ(equal_skips, cnt); + + return boost::report_errors(); +} + diff --git a/test/function/no_check_if_error.cpp b/test/function/no_check_if_error.cpp new file mode 100644 index 0000000..b3431e3 --- /dev/null +++ b/test/function/no_check_if_error.cpp @@ -0,0 +1,35 @@ + +// Test assertion error when operations to check them missing (e.g., `==`). + +#include +#include +#include +#include + +template +void push_back(std::vector& vect, T const& val) { + boost::contract::guard c = boost::contract::function() + .postcondition([&] { + BOOST_CONTRACT_ASSERT(vect.back() == val); // Error (j has no ==). + }) + ; + vect.push_back(val); +} + +struct j { // Type without operator==. + explicit j(int i) : j_(i) {} +private: + int j_; +}; + +int main() { + std::vector vi; + push_back(vi, 123); + + j jj(456); + std::vector vj; + push_back(vj, jj); + + return 0; +} + diff --git a/test/old/no_equal.cpp b/test/old/no_equal.cpp index 5ff4ee9..27f4736 100644 --- a/test/old/no_equal.cpp +++ b/test/old/no_equal.cpp @@ -1,9 +1,8 @@ -// Test old value skipped when operations to check them missing (e.g., `==`). +// Test assertions skipped when operations to check them missing (e.g., `==`). #include #include -#include #include #include #include diff --git a/test/old/no_equal_error.cpp b/test/old/no_equal_error.cpp index b69226c..b3431e3 100644 --- a/test/old/no_equal_error.cpp +++ b/test/old/no_equal_error.cpp @@ -1,9 +1,8 @@ -// Test old value error when operations to check them missing (e.g., `==`). +// Test assertion error when operations to check them missing (e.g., `==`). #include #include -#include #include #include diff --git a/test/old/no_macros.cpp b/test/old/no_macros.cpp index d29b4d8..9d05636 100644 --- a/test/old/no_macros.cpp +++ b/test/old/no_macros.cpp @@ -1,182 +1,4 @@ -// Test old values without BOOST_CONTRACT_OLDOF macro. - -#include "../detail/oteststream.hpp" -#include "../detail/counter.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -boost::contract::test::detail::oteststream out; - -struct i_tag; typedef boost::contract::test::detail::counter i_type; -struct j_tag; typedef boost::contract::test::detail::counter j_type; - -struct b { - virtual void swap(i_type& i, j_type& j, boost::contract::virtual_* v = 0); -}; - -void b::swap(i_type& i, j_type& j, boost::contract::virtual_* v) { - boost::contract::old_ptr old_i = boost::contract::make_old(v, - boost::contract::copy_old(v) ? - i_type::eval(i) - : - boost::contract::null_old() - ); - boost::contract::old_ptr old_j; - boost::contract::guard c = boost::contract::public_function(v, this) - .precondition([&] { - out << "b::swap::pre" << std::endl; - BOOST_CONTRACT_ASSERT(i.value != j.value); - }) - .old([&] { - out << "b::swap::old" << std::endl; - old_j = boost::contract::make_old(v, boost::contract::copy_old(v) ? - j_type::eval(j) : boost::contract::null_old()); - }) - .postcondition([&] { - out << "b::swap::post" << std::endl; - BOOST_CONTRACT_ASSERT(i.value == old_j->value); - BOOST_CONTRACT_ASSERT(j.value == old_i->value); - }) - ; - assert(false); -}; - -struct a - #define BASES public b - : BASES -{ - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void swap(i_type& i, j_type& j, boost::contract::virtual_* v = 0) - /* override */ { - boost::contract::guard c = boost::contract::public_function< - override_swap>(v, &a::swap, this, i, j); - - out << "a::swap::body" << std::endl; - int t = i.value; - i.value = j.value; - j.value = t; - } - BOOST_CONTRACT_OVERRIDE(swap) -}; - -struct x_tag; -typedef boost::contract::test::detail::counter x_type; - -struct y_tag; -typedef boost::contract::test::detail::counter y_type; - -void swap(x_type& x, y_type& y) { - boost::contract::old_ptr old_x = boost::contract::make_old( - boost::contract::copy_old() ? - x_type::eval(x) - : - boost::contract::null_old() - ); - boost::contract::old_ptr old_y; - boost::contract::guard c = boost::contract::function() - .precondition([&] { - out << "swap::pre" << std::endl; - BOOST_CONTRACT_ASSERT(x.value != y.value); - }) - .old([&] { - out << "swap::old" << std::endl; - old_y = boost::contract::make_old(boost::contract::copy_old() ? - y_type::eval(y) : boost::contract::null_old()); - }) - .postcondition([&] { - out << "swap::post" << std::endl; - BOOST_CONTRACT_ASSERT(x.value == old_y->value); - BOOST_CONTRACT_ASSERT(y.value == old_x->value); - }) - ; - - out << "swap::body" << std::endl; - char t = x.value; - x.value = y.value; - y.value = t; -} - -int main() { - std::ostringstream ok; - - out.str(""); - x_type x; x.value = 'a'; - y_type y; y.value = 'b'; - swap(x, y); - - ok.str(""); ok - #ifndef BOOST_CONTRACT_NO_PRECONDITIONS - << "swap::pre" << std::endl - #endif - #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS - << "swap::old" << std::endl - #endif - << "swap::body" << std::endl - #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS - << "swap::post" << std::endl - #endif - ; - BOOST_TEST(out.eq(ok.str())); - - unsigned const cnt = - #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS - 1 - #else - 0 - #endif - ; - - BOOST_TEST_EQ(x.value, 'b'); - BOOST_TEST_EQ(x.copies(), cnt); - BOOST_TEST_EQ(x.evals(), cnt); - BOOST_TEST_EQ(x.ctors(), x.dtors() + 1); // 1 for local var. - - BOOST_TEST_EQ(y.value, 'a'); - BOOST_TEST_EQ(y.copies(), cnt); - BOOST_TEST_EQ(y.evals(), cnt); - BOOST_TEST_EQ(y.ctors(), y.dtors() + 1); // 1 for local var. - - a aa; - i_type i; i.value = 1; - j_type j; j.value = 2; - out.str(""); - aa.swap(i, j); - - ok.str(""); ok - #ifndef BOOST_CONTRACT_NO_PRECONDITIONS - << "b::swap::pre" << std::endl - #endif - #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS - << "b::swap::old" << std::endl - #endif - << "a::swap::body" << std::endl - #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS - << "b::swap::old" << std::endl - << "b::swap::post" << std::endl - #endif - ; - BOOST_TEST(out.eq(ok.str())); - - BOOST_TEST_EQ(i.value, 2); - BOOST_TEST_EQ(i.copies(), cnt); - BOOST_TEST_EQ(i.evals(), cnt); - BOOST_TEST_EQ(i.ctors(), i.dtors() + 1); // 1 for local var. - - BOOST_TEST_EQ(j.value, 1); - BOOST_TEST_EQ(j.copies(), cnt); - BOOST_TEST_EQ(j.evals(), cnt); - BOOST_TEST_EQ(j.ctors(), j.dtors() + 1); // 1 for local var. - - return boost::report_errors(); -} +#define BOOST_CONTRACT_TEST_OLD_PTR_TYPE boost::contract::old_ptr +#include "no_macros.hpp" diff --git a/test/old/no_macros.hpp b/test/old/no_macros.hpp new file mode 100644 index 0000000..a7fdc6c --- /dev/null +++ b/test/old/no_macros.hpp @@ -0,0 +1,186 @@ + +// Test old values without BOOST_CONTRACT_OLDOF macro. + +#ifndef BOOST_CONTRACT_TEST_OLD_PTR_TYPE + #error "must define BOOST_CONTRACT_TEST_OLD_PTR_TYPE" +#endif + +#include "../detail/oteststream.hpp" +#include "../detail/counter.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +boost::contract::test::detail::oteststream out; + +struct i_tag; typedef boost::contract::test::detail::counter i_type; +struct j_tag; typedef boost::contract::test::detail::counter j_type; + +struct b { + virtual void swap(i_type& i, j_type& j, boost::contract::virtual_* v = 0); +}; + +void b::swap(i_type& i, j_type& j, boost::contract::virtual_* v) { + BOOST_CONTRACT_TEST_OLD_PTR_TYPE old_i = boost::contract::make_old( + v, boost::contract::copy_old(v) ? + i_type::eval(i) + : + boost::contract::null_old() + ); + BOOST_CONTRACT_TEST_OLD_PTR_TYPE old_j; + boost::contract::guard c = boost::contract::public_function(v, this) + .precondition([&] { + out << "b::swap::pre" << std::endl; + BOOST_CONTRACT_ASSERT(i.value != j.value); + }) + .old([&] { + out << "b::swap::old" << std::endl; + old_j = boost::contract::make_old(v, boost::contract::copy_old(v) ? + j_type::eval(j) : boost::contract::null_old()); + }) + .postcondition([&] { + out << "b::swap::post" << std::endl; + BOOST_CONTRACT_ASSERT(i.value == old_j->value); + BOOST_CONTRACT_ASSERT(j.value == old_i->value); + }) + ; + assert(false); +}; + +struct a + #define BASES public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void swap(i_type& i, j_type& j, boost::contract::virtual_* v = 0) + /* override */ { + boost::contract::guard c = boost::contract::public_function< + override_swap>(v, &a::swap, this, i, j); + + out << "a::swap::body" << std::endl; + int t = i.value; + i.value = j.value; + j.value = t; + } + BOOST_CONTRACT_OVERRIDE(swap) +}; + +struct x_tag; +typedef boost::contract::test::detail::counter x_type; + +struct y_tag; +typedef boost::contract::test::detail::counter y_type; + +void swap(x_type& x, y_type& y) { + BOOST_CONTRACT_TEST_OLD_PTR_TYPE old_x = boost::contract::make_old( + boost::contract::copy_old() ? + x_type::eval(x) + : + boost::contract::null_old() + ); + BOOST_CONTRACT_TEST_OLD_PTR_TYPE old_y; + boost::contract::guard c = boost::contract::function() + .precondition([&] { + out << "swap::pre" << std::endl; + BOOST_CONTRACT_ASSERT(x.value != y.value); + }) + .old([&] { + out << "swap::old" << std::endl; + old_y = boost::contract::make_old(boost::contract::copy_old() ? + y_type::eval(y) : boost::contract::null_old()); + }) + .postcondition([&] { + out << "swap::post" << std::endl; + BOOST_CONTRACT_ASSERT(x.value == old_y->value); + BOOST_CONTRACT_ASSERT(y.value == old_x->value); + }) + ; + + out << "swap::body" << std::endl; + char t = x.value; + x.value = y.value; + y.value = t; +} + +int main() { + std::ostringstream ok; + + out.str(""); + x_type x; x.value = 'a'; + y_type y; y.value = 'b'; + swap(x, y); + + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + << "swap::pre" << std::endl + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + << "swap::old" << std::endl + #endif + << "swap::body" << std::endl + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + << "swap::post" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + unsigned const cnt = + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + 1 + #else + 0 + #endif + ; + + BOOST_TEST_EQ(x.value, 'b'); + BOOST_TEST_EQ(x.copies(), cnt); + BOOST_TEST_EQ(x.evals(), cnt); + BOOST_TEST_EQ(x.ctors(), x.dtors() + 1); // 1 for local var. + + BOOST_TEST_EQ(y.value, 'a'); + BOOST_TEST_EQ(y.copies(), cnt); + BOOST_TEST_EQ(y.evals(), cnt); + BOOST_TEST_EQ(y.ctors(), y.dtors() + 1); // 1 for local var. + + a aa; + i_type i; i.value = 1; + j_type j; j.value = 2; + out.str(""); + aa.swap(i, j); + + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + << "b::swap::pre" << std::endl + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + << "b::swap::old" << std::endl + #endif + << "a::swap::body" << std::endl + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + << "b::swap::old" << std::endl + << "b::swap::post" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + BOOST_TEST_EQ(i.value, 2); + BOOST_TEST_EQ(i.copies(), cnt); + BOOST_TEST_EQ(i.evals(), cnt); + BOOST_TEST_EQ(i.ctors(), i.dtors() + 1); // 1 for local var. + + BOOST_TEST_EQ(j.value, 1); + BOOST_TEST_EQ(j.copies(), cnt); + BOOST_TEST_EQ(j.evals(), cnt); + BOOST_TEST_EQ(j.ctors(), j.dtors() + 1); // 1 for local var. + + return boost::report_errors(); +} + diff --git a/test/old/no_macros_noncopyable.cpp b/test/old/no_macros_noncopyable.cpp new file mode 100644 index 0000000..1840435 --- /dev/null +++ b/test/old/no_macros_noncopyable.cpp @@ -0,0 +1,4 @@ + +#define BOOST_CONTRACT_TEST_OLD_PTR_TYPE boost::contract::old_ptr_noncopyable +#include "no_macros.hpp" + diff --git a/test/old/no_make_old_error.cpp b/test/old/no_make_old_error.cpp index 1daba50..a862ff4 100644 --- a/test/old/no_make_old_error.cpp +++ b/test/old/no_make_old_error.cpp @@ -1,12 +1,4 @@ -// Test error when make_old(...) not used by mistake. - -#include - -int main() { - int x = 1; - boost::contract::old_ptr old_x = boost::contract::copy_old() ? x : - boost::contract::null_old(); // Error (missing outer make_old(...)). - return 0; -} +#define BOOST_CONTRACT_TEST_OLD_PTR_TYPE boost::contract::old_ptr +#include "no_make_old_error.hpp" diff --git a/test/old/no_make_old_error.hpp b/test/old/no_make_old_error.hpp new file mode 100644 index 0000000..f38ec30 --- /dev/null +++ b/test/old/no_make_old_error.hpp @@ -0,0 +1,17 @@ + +// Test error when make_old(...) not used by mistake. + +#ifndef BOOST_CONTRACT_TEST_OLD_PTR_TYPE + #error "must define BOOST_CONTRACT_TEST_OLD_PTR_TYPE" +#endif + +#include + +int main() { + int x = 1; + // Error (missing outer make_old(...)). + BOOST_CONTRACT_TEST_OLD_PTR_TYPE old_x = boost::contract::copy_old() ? + x : boost::contract::null_old(); + return 0; +} + diff --git a/test/old/no_make_old_noncopyable_error.cpp b/test/old/no_make_old_noncopyable_error.cpp new file mode 100644 index 0000000..4852619 --- /dev/null +++ b/test/old/no_make_old_noncopyable_error.cpp @@ -0,0 +1,4 @@ + +#define BOOST_CONTRACT_TEST_OLD_PTR_TYPE boost::contract::old_ptr_noncopyable +#include "no_make_old_error.hpp" +