diff --git a/doc/acknowledgments.qbk b/doc/acknowledgments.qbk index 5ecc55b..56a4f3f 100644 --- a/doc/acknowledgments.qbk +++ b/doc/acknowledgments.qbk @@ -10,21 +10,21 @@ This section aims to recognize the contributions of /all/ the different people t Sincere thanks to my parents for their support with my education and my studies in computer science. +Many thanks to Andrzej Krzemienski for reviewing early versions of this library providing valuable insights and exchanging early ideas on assertion requirements. + +Many thanks to Vicente J. Botet Escriba for reviewing earlier versions of this library providing valuable insights and for suggesting to use a dedicated trait to copy old values. + +Thanks to Steven Watanabe for providing valuable insights on C++, SFINAE, and introspection. + +Thanks to Dave Abrahams for moderating the Boost review of this library. + +Thanks to David Maley for sharing source code form his inspiring work on emulating Contract Programming and subcontracting in C++ in __Maley99__. + +Many thanks to Thorsten Ottosen for his work on the __N1962__ proposal (and its previous revisions) and for clarifying the proposal requirements directly with the library authors when needed. + Many thanks to Bertrand Meyer for his pioneering and thorough work on Contract Programming in __Meyer97__. -Many thanks to Thorsten Ottosen for his work with __N1962__ (and previous revisions) and for clarifying the __N1962__ requirements directly with the library authors when needed. - -Many thanks to Andrzej Krzemienski for reviewing earlier versions of this library providing valuable insights, for exchanging ideas on implementing assertion requirements, and for suggesting to support named parameters. - -Many thanks to Vicente J. Botet Escriba for reviewing earlier versions of this library providing valuable insights and for suggesting to use `contract::copy`. - -Thanks to Steven Watanabe for providing valuable insights on C++ and for hinting to use template meta-programming introspection to detect if a base class has a given member function (technique which turned out to be essential to fully automate subcontracting). - -Thanks to Dave Abrahams for providing valuable comments on the library syntax and especially on the syntax to support named parameters. - -Thanks to David Maley for having shared source code form his inspiring work in __Maley99__ on emulating Contract Programming in C++. - -Finally, many thanks to the entire __Boost__ community and [@http://lists.boost.org mailing list] for providing valuable comments about this library and great insights on the C++ programming language. +Finally, many thanks to the entire Boost community and [@http://lists.boost.org mailing list] for providing valuable comments about this library and great insights on the C++ programming language. [endsect] diff --git a/doc/advanced_topics.qbk b/doc/advanced_topics.qbk index 6d1fe2e..1204dfe 100644 --- a/doc/advanced_topics.qbk +++ b/doc/advanced_topics.qbk @@ -120,6 +120,8 @@ For example (see also [@../../example/features/private_protected_virtual_multi.c [warning Unfortunately, the code above does not compile on MSVC (at least up to Visual Studio 2015) because MSVC incorrectly gives a compile-time error when SFINAE fails due to private or protected access levels. Instead, GCC and Clang correctly implement SFINAE failures due to private and protected member functions so the code above correctly complies on GCC and Clang. + +Therefore, currently it is not possible to override a member that is public in one base but private or protected in other base using this library on MSVC, that can be done instead on GCC or CLang. ] [endsect] @@ -411,7 +413,7 @@ This library passes a [classref boost::contract::from] parameter to the contract This [classref boost::contract::from] parameter indicates if the contract failure occurred in a destructor, constructor, or function call so programmers can use it code custom contract failure hander functions that never throw from destructors (in the example above, contract failures from destructors are simply ignored even if that is probably never a safe thing to do in real code). * Implementation checks can appear in any code, including destructor implementation code, so [funcref boost::contract::check_failure] should also never throw, or implementation checks should never be used in destructors. * The contract failure handler for exception guarantees [funcref boost::contract::except_failure] should also never throw (regardless of its [classref boost::contract::from] parameter). -That is because when [funcref boost::contract::except_failure] is called there is already an active exception on the stack, the exception that triggered the exception guarantees to be checked in the first place (throwing an exception while there is already an active exception leads to undefined behaviour in C++, most programs will segfault). +That is because when [funcref boost::contract::except_failure] is called there is already an active exception on the stack, the exception that triggered the exception guarantees to be checked in the first place (throwing an exception while there is already an active exception will force C++ to terminate the program). [note It is the responsibility of the programmers to decide how to handle contract failures from destructors when they program custom contract failure handlers that throw exceptions instead of terminating the program (given that C++ and STL exception safety rules requires destructors to never throw). diff --git a/doc/bibliography.qbk b/doc/bibliography.qbk index 4c07747..415fe88 100644 --- a/doc/bibliography.qbk +++ b/doc/bibliography.qbk @@ -60,8 +60,6 @@ This section lists all references consulted while designing and developing this [#N2906_anchor] [N2906] B. Stroustrup. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2906.pdf /Simplifying the sue of concepts/]. The C++ Standards Committee, N2906, 2009. -[#N3613_anchor] [N3613] B. Stroustrup, G. Dos Reis, A. Sutton. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3613.pdf /"Static If" Considered/]. The C++ Standards Committee, N3613, 2013. - [#Rosenblum95_anchor] [Rosenblum95] D. S. Rosenblum. [@http://www.cs.toronto.edu/~chechik/courses06/csc410/rosenblum_assert95.pdf /A practical Approach to Programming With Assertions/]. IEEE Transactions on Software Engineering, 1995. [#SPARKAda_anchor] [SPARKAda] Praxis. [@http://www.praxis-his.com/sparkada/language.asp /SPARKAda (Ada-like Language with Contract Programming)/]. diff --git a/doc/contract_programming_overview.qbk b/doc/contract_programming_overview.qbk index 2fe0f1b..3e10820 100644 --- a/doc/contract_programming_overview.qbk +++ b/doc/contract_programming_overview.qbk @@ -335,7 +335,7 @@ This customizable failure handling mechanism is similar to the one used by `std: [note In C++ there are a number of issues with programming contract failure handlers that throw exceptions instead of terminating the program. Specifically, destructors check class invariants so they will throw if programmers change class invariant failure handlers to throw instead of terminating the program, but in general destructors should not throw in C++ (to comply with STL exception safety, etc.). -Furthermore, programming an exception specification failure handler to throw will throw an exception (the one reporting the contract failure) while there is already an active exception (the one that caused the exception specification assertions to be checked in the first place), and this leads to undefined behavior in C++. +Furthermore, programming an exception specification failure handler to throw will throw an exception (the one reporting the contract failure) while there is already an active exception (the one that caused the exception specification assertions to be checked in the first place), and this will force C++ to terminate the program. ] Therefore, it is recommended to terminate the program at least for contract failures from destructors and because when checking exception guarantees (if not in all other cases of contract failures as it is done by default by this library). diff --git a/doc/examples.qbk b/doc/examples.qbk index 32b5fe7..4181482 100644 --- a/doc/examples.qbk +++ b/doc/examples.qbk @@ -6,12 +6,14 @@ [section Examples] -This section lists examples taken from different Contract Programming sources and re-implemented using this library. +This section lists examples taken from different sources discussing Contract Programming and re-implemented using this library. -Some of these examples might be from old sources, containing old or obsolete code practices, not optimized for execution speed, and they be more relevant in the context programming languages other than C++. -Nevertheless, programmers are encouraged to review these examples to see a few diverse usages of this library that might be relevant for the contracts they need to write in their code. +[note +Some of these examples might be from old sources, containing old or obsolete code practices, not optimized for execution speed, not complete, and they might be more relevant in the context of programming languages different from C++. +Nevertheless, programmers are encouraged to review these examples to see a few diverse usages of this library that might be relevant for contracts they need to write in their code. +] -Sources: +Sources of the listed examples: * __N1962__: Examples from the proposal to add Contract Programming to C++11 (unfortunately, this proposal was never accepted into the standard). * __Meyer97__: Examples using the Eiffel programming language and reprogrammed using this library for C++. @@ -27,41 +29,49 @@ A few notable examples: * [link Cline90_vector_anchor \[Cline90\] Vector]: Comparison with A++ syntax. [#N1962_vector_anchor] -[heading \[N1962\] Vector: STL Vector contracts and comparison with C++ contract proposal syntax] +[section \[N1962\] Vector: STL Vector contracts and comparison with C++ contract proposal syntax] [import ../example/n1962/vector.cpp] [import ../example/n1962/vector_n1962.hpp] [table - [ [This Library] [Contract \[N1962\] and Static-If \[N3613\] Proposals (neither part of C++)] ] + [ [This Library] [Contract Programming Proposal \[N1962\] (not part of C++) plus C++17 [^if constexpr]] ] [ [[n1962_vector]] [[n1962_vector_n1962]] ] ] -[heading \[N1962\] Circle: Subcontracting] +On compilers that support C++17 `if constexpr`, the above example using this library can be simplified removing [funcref boost::contract::condition_if] and related functor templates `all_of_equal_to`, etc. (making the code to the left more similar to the code to the right). +[endsect] + +[section \[N1962\] Circle: Subcontracting] [import ../example/n1962/circle.cpp] [n1962_circle] +[endsect] -[heading \[N1962\] Factorial: Recursion and assertion computational complexity] +[section \[N1962\] Factorial: Recursion and assertion computational complexity] [import ../example/n1962/factorial.cpp] [n1962_factorial] +[endsect] -[heading \[N1962\] Equal: Operators] +[section \[N1962\] Equal: Operators] [import ../example/n1962/equal.cpp] [n1962_equal] +[endsect] -[heading \[N1962\] Sum: Array parameter] +[section \[N1962\] Sum: Array parameter] [import ../example/n1962/sum.cpp] [n1962_sum] +[endsect] [#N1962_square_root_anchor] -[heading \[N1962\] Square Root: Default parameters and comparison with D syntax] +[section \[N1962\] Square Root: Default parameters and comparison with D syntax] [import ../example/n1962/sqrt.cpp] [import ../example/n1962/sqrt.d] [table [ [This Library] [The D Programming Language] ] [ [[n1962_sqrt]] [[n1962_sqrt_d]] ] ] +[endsect] [#Meyer97_stack4_anchor] -[heading \[Meyer97\] Stack4: Comparison with Eiffel syntax] +[section \[Meyer97\] Stack4: Comparison with Eiffel syntax] [import ../example/meyer97/stack4.hpp] [import ../example/meyer97/stack4_main.cpp] [import ../example/meyer97/stack4.e] @@ -70,45 +80,54 @@ A few notable examples: [ [[meyer97_stack4]] [[meyer97_stack4_e]] ] [ [[meyer97_stack4_main]] [] ] ] +[endsect] -[heading \[Meyer97\] Stack3: Error codes instead of preconditions] +[section \[Meyer97\] Stack3: Error codes instead of preconditions] [import ../example/meyer97/stack3.cpp] [meyer97_stack3] +[endsect] -[heading \[Mitchell02\] Name List: Relaxing subcontracts] +[section \[Mitchell02\] Name List: Relaxed subcontracts] [import ../example/mitchell02/name_list.cpp] [mitchell02_name_list] +[endsect] -[heading \[Mitchell02\] Dictionary: Key-value map] +[section \[Mitchell02\] Dictionary: Key-value map] [import ../example/mitchell02/dictionary.cpp] [mitchell02_dictionary] +[endsect] -[heading \[Mitchell02\] Courier: Subcontracting and static class invariants] +[section \[Mitchell02\] Courier: Subcontracting and static class invariants] [import ../example/mitchell02/courier.cpp] [mitchell02_courier] +[endsect] -[heading \[Mitchell02\] Stack: Stack-like container] +[section \[Mitchell02\] Stack: Stack-like container] [import ../example/mitchell02/stack.cpp] [mitchell02_stack] +[endsect] -[heading \[Mitchell02\] Simple Queue: Queue-like container] +[section \[Mitchell02\] Simple Queue: Queue-like container and assertion big-O complexity] [import ../example/mitchell02/simple_queue.cpp] [mitchell02_simple_queue] +[endsect] -[heading \[Mitchell02\] Customer Manager: Contracts instead of Defensive Programming] +[section \[Mitchell02\] Customer Manager: Contracts instead of Defensive Programming] [import ../example/mitchell02/customer_manager.cpp] [mitchell02_customer_manager] +[endsect] -[heading \[Mitchell02\] Observer: Pure virtual functions] +[section \[Mitchell02\] Observer: Pure virtual functions] [import ../example/mitchell02/observer/observer.hpp] [mitchell02_observer] [import ../example/mitchell02/observer/subject.hpp] [mitchell02_subject] [import ../example/mitchell02/observer_main.cpp] [mitchell02_observer_main] +[endsect] [#Mitchell02_counter_anchor] -[heading \[Mitchell02\] Counter: Subcontracting] +[section \[Mitchell02\] Counter: Subcontracting] [import ../example/mitchell02/counter/push_button.hpp] [mitchell02_push_button] [import ../example/mitchell02/counter/decrement_button.hpp] @@ -117,9 +136,10 @@ A few notable examples: [mitchell02_counter] [import ../example/mitchell02/counter_main.cpp] [mitchell02_counter_main] +[endsect] [#Cline90_vector_anchor] -[heading \[Cline90\] Vector: Comparison with A++ proposed syntax] +[section \[Cline90\] Vector: Comparison with A++ proposed syntax] [import ../example/cline90/vector.hpp] [import ../example/cline90/vector_main.cpp] [import ../example/cline90/vector_axx.hpp] @@ -128,18 +148,22 @@ A few notable examples: [ [[cline90_vector]] [[cline90_vector_axx]] ] [ [[cline90_vector_main]] [] ] ] +[endsect] -[heading \[Cline90\] Stack: Stack-like container] +[section \[Cline90\] Stack: Stack-like container] [import ../example/cline90/stack.cpp] [cline90_stack] +[endsect] -[heading \[Cline90\] Vector-Stack: Subcontracting] +[section \[Cline90\] Vector-Stack: Subcontracting] [import ../example/cline90/vstack.cpp] [cline90_vstack] +[endsect] -[heading \[Cline90\] Calendar: A very simple calendar] +[section \[Cline90\] Calendar: A very simple calendar] [import ../example/cline90/calendar.cpp] [cline90_calendar] +[endsect] [endsect] diff --git a/doc/extra_topics.qbk b/doc/extra_topics.qbk index cbc9319..b97e925 100644 --- a/doc/extra_topics.qbk +++ b/doc/extra_topics.qbk @@ -10,47 +10,54 @@ This section can be consulted selectively for specific topics of interest. [section Old Value Requirements (Templates)] -TODO: This now uses boost::contract::is_old_value_copyable instead of using boost::is_copyable directly, update this doc. -Actually, add an example that uses both is_old_value_copyable and also old_value_copy for example to copy a type that is declared boost::noncopyable. +Old values require to copy the expression passed to [macroref BOOST_CONTRACT_OLDOF] thus the type of that expression must be copyable. +More precisely, dereferencing an old value pointer of type [classref boost::contract::old_ptr]`` requires [classref boost::contract::is_old_value_copyable]`::value` to be `true` (otherwise this library will generate a compile-time error). -Old values require to copy the expression passed to [macroref BOOST_CONTRACT_OLDOF] thus the type of that expression must be copy constructible. -More precisely, dereferencing an old value pointer of type [classref boost::contract::old_ptr]`` requires `boost::is_copy_constructible::value` to be `true` (otherwise this library will generate a compile-time error). - -In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses old value types that are not copy constructible (because it is not possible to fully check the correctness of the program as stated by the contract assertions that use the old values). +In some cases it might be acceptable, or even desirable, to cause a compile-time error when a program uses old value types that are not copyable (because it is not possible to fully check the correctness of the program as stated by the contract assertions that use the old values). In these cases, programmers can declare old values using [classref boost::contract::old_ptr] as seen so far. -However, in other cases it might be desirable to simply not check assertions that use old values when the respective old value types are not copy constructible. +However, in other cases it might be desirable to simply not check assertions that use old values when the respective old value types are not copyable. Programmers can do this by using [classref boost::contract::old_ptr_if_copyable] 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 function template that could in general be instantiated for types `T` that are not copy constructible (that is for which `boost::is_copy_constructible::value` is `false`, see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): +For example, consider the following function template that could in general be instantiated for types `T` that are not copy constructible (that is for which `boost::contract::is_old_value_copyable::value` is `false`, see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): [footnote *Rationale:* __N1962__ and other proposals to add contracts to C++ do not provide a mechanism to selectively disable copies for only old value types that are not copy constructible. However, this library provides such a mechanism to allow to program contracts for template code without necessarily adding extra copy constructible type requirements that would not be present if it were not for copying the old values (so compiling the code with and without contracts will not necessarily alter the type requirements of the program). -As for extending the C++ language, something similar could be achieved by combing both __N1962__ (contracts) and __N3613__ (`static if`) so that old value expressions within template code could be guarded by `static if` statements checking if the old value types are copyable or not. +As for extending the C++ language, something similar could be achieved by combing both __N1962__ (contracts) and C++17 `if constexpr` so that old value expressions within template code could be guarded by `if constexpr` statements checking if the old value types are copyable or not. ] [import ../example/features/old_if_copyable.cpp] -[old_if_copyable] +[old_if_copyable_offset] -The old value pointer `old_total` is programmed using [classref boost::contract::old_ptr_if_copyable] 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 postconditions and exception guarantees). +The old value pointer `old_total` is programmed using [classref boost::contract::old_ptr_if_copyable] so if `T` is not copyable 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 postconditions and exception guarantees). If the above example used [classref boost::contract::old_ptr] instead then the library would have generated a compile-time error when `accumulate` is instantiated with types `T` that are not copy constructible (but only if `old_total` is actually dereferenced somewhere in the contract assertions using `*old_total ...`, `old_total->...`, etc.). -[note -The `..._if_copyable` postfix in the type name [classref boost::contract::old_ptr_if_copyable]`` refers to the pointed type `T` which might 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). -] - -When C++11 `auto` declarations are used with [macroref BOOST_CONTRACT_OLDOF], this library always defaults to using the [classref boost::contract::old_ptr] type (because this type requirements are more stringent than the requirements of [classref boost::contract::old_ptr_if_copyable]). +When C++11 `auto` declarations are used with [macroref BOOST_CONTRACT_OLDOF], this library always defaults to using the [classref boost::contract::old_ptr] type (because this type requirements are more stringent, if programmers want to relax the copyable type requirement they must do so explicitly by using [classref boost::contract::old_ptr_if_copyable] instead of using `auto`). For example, the following will use [classref boost::contract::old_ptr] and not [classref boost::contract::old_ptr_if_copyable] to declare `old_x`: auto old_x = BOOST_CONTRACT_OLDOF(x); // C++11 auto declarations. +This library internally uses [classref boost::contract::is_old_value_copyable] to determine if an old value type is copyable or not, and then [classref boost::contract::old_value_copy] to actually copy the old value. +By default, `boost::contract::is_old_value_copyable` is equivalent to `boost::is_copy_constructible` and `boost::contract::old_value_copy` is implemented using `T`'s copy constructor. +However, the type traits provided by this library can be specialized to avoid making old value copies of types even when they have a copy constructor (because these copy constructors might be expensive, etc.) or, on the flip side, to make old value copies for types that do not have a copy constructor. +For example, the following specialization of [classref boost::contract::is_old_value_copyable] will avoid making old value copies for all expressions of type `w` even if that type has a copy constructor (see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): + +[old_if_copyable_w_decl] +[old_if_copyable_w_spec] + +While the following specializations of [classref boost::contract::is_old_value_copyable] and [classref boost::contract::old_value_copy] make old value copies of expressions of type `p` even if that type does not have a copy constructor (see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): + +[old_if_copyable_p_decl] +[old_if_copyable_p_spec] + [heading No C++11] -In general, the `boost::is_copy_constructible` type trait requires C++11 for full support. -On non-C++11 compilers, it is possible to inherit the old value type from `boost::noncopyable`, or use `BOOST_MOVABLE_BUT_NOT_COPYABLE`, or explicitly specialize the `boost::is_copy_constructible` template (see [@http://www.boost.org/doc/libs/release/libs/type_traits/doc/html/boost_typetraits/reference/is_copy_constructible.html boost::is_copy_constrictible] for more information). -For example, for some non-copyable old value type `n` (see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): +In general, `boost::contract::is_copy_constructible` and therefore [classref boost::contract::is_old_value_copyable] require C++11 `decltype` and SFINAE to automatically detect if a given type is not copyable. +On non-C++11 compilers, it is possible to inherit the old value type from `boost::noncopyable`, or use `BOOST_MOVABLE_BUT_NOT_COPYABLE`, or specialize `boost::is_copy_constructible` (see [@http://www.boost.org/doc/libs/release/libs/type_traits/doc/html/boost_typetraits/reference/is_copy_constructible.html `boost::is_copy_constructible`] documentation for more information). +Alternatively, it is possible to just specialize [classref boost::contract::is_old_value_copyable], for example for a non-copyable type `n` (see also [@../../example/features/old_if_copyable.cpp =old_if_copyable.cpp=]): -[old_if_copyable_specialization] +[old_if_copyable_n_decl] +[old_if_copyable_n_spec] [endsect] @@ -113,15 +120,14 @@ The [funcref boost::contract::condition_if_c], [funcref boost::contract::call_if [heading Static-If Emulation (C++14)] The [funcref boost::contract::call_if] function template is a general facility and its use is not limited to programming contracts. -In fact, [funcref boost::contract::call_if] can be used together with C++14 generic lambdas to program statements similar to `static if` at least a function scope (`static if` was unsuccessfully proposed for addition to the C++ standard a number of different times, see __N3613__). -For example, consider the following implementation of `std::advance` that uses statements similar to `static if` but programmed via [funcref boost::contract::call_if] (see also [@../../example/features/call_if_cxx14.cpp =call_if_cxx14.cpp=]): +In fact, [funcref boost::contract::call_if] can be used together with C++14 generic lambdas to emulate statements similar to C++17 `if constexpr`, for example (see also [@../../example/features/call_if_cxx14.cpp =call_if_cxx14.cpp=]): [import ../example/features/call_if_cxx14.cpp] [call_if_cxx14] -This implementation is more concise, easier to read and maintain than the usual implementation of `std::advance` that uses tag dispatching. +This implementation is more concise, easier to read and maintain than the usual implementation of `std::advance` that uses tag dispatching (but of course a similar implementation using C++17 `if constexpr` would be even more readable and concise). [footnote -Boost.Hana (`boost::hana::if_`) can also be used to emulate function scope `static if` with C++14 generic lambdas. +Boost.Hana (`boost::hana::if_`) can also be used together with C++14 generic lambdas to emulate statements similar to C++17 `if constexpr`. ] [endsect] @@ -278,7 +284,9 @@ For constructors, destructors, and public functions instead (see also [@../../ex [ [[ifdef_macro_class]] [[ifdef_class]] ] ] -The authors of this library do not recommend to use these techniques unless strictly necessary because they both make the contract code more verbose, less readable, and can cause cryptic compiler error messages. +Macro code expands on a single line so using these macros will cause all assertions within a given set of preconditions, postconditions, exception guarantees, and class invariants to list the same line number in their error messages if they fail at run-time (but the assertion code will be listed as well and it should allow programmers to identify the specific assertion that failed). + +In general, the authors do not recommend to use these techniques unless strictly necessary because they both make the contract code more verbose, less readable, and can cause cryptic compiler error messages. In most cases, the compile-time overhead of contracts should not represent an issue and it should be sufficient to disable contract checking at run-time as indicated in __Disable_Contract_Checking__. [endsect] diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 7f6f06e..f2b4a34 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -6,9 +6,21 @@ [section Release Notes] -This section contains notes on the current and on all previous library releases (in chronological order). +This section contains notes on all releases of this library (from the latest to the oldest). -[heading Release 0.4.1] +[section Release 0.5.0] + +August 1, 2017 + +Notes: + +TODO + +Released TODO. + +[endsect] + +[section Release 0.4.1] August 20, 2012 @@ -18,9 +30,11 @@ Notes: # Added a couple of notes to the documentation. # Changed `CONTRACT_MEMBER_BODY(class_type, function_name)` to `class_type::CONTRACT_MEMBER_BODY(function_name)` so the macro can also be used to declare derived classes avoiding using the library syntax even when the base class has contracts. -Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1/doc/html/index.html documentation]. +Released [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1/doc/html/index.html documentation]. -[heading Release 0.4.0] +[endsect] + +[section Release 0.4.0] June 4, 2012 @@ -40,9 +54,11 @@ Removed the `copyable` tag. # Added concept checking. # Removed the interface to use the library without the macro (programmers were required to write too much boiler-plate code for the non-macro interface to be actually usable, plus supporting both the macro and non-macro interfaces limited what the macros could do). -Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_0 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_0/doc/html/index.html documentation]. +Released [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_0 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_0/doc/html/index.html documentation]. -[heading Release 0.3.490] +[endsect] + +[section Release 0.3.490] March 7, 2010 @@ -51,9 +67,11 @@ Notes: # Added support and examples for `volatile`, `auto`, `explicit`, `export`, `extern`, `friend`, `inline`, `struct`, and `throw` (for exception specifications). # Documented that `union` cannot be contracted. -Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_490 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_490/doc/html/index.html documentation]. +Released [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_490 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_490/doc/html/index.html documentation]. -[heading Release 0.3.469] +[endsect] + +[section Release 0.3.469] February 21, 2010 @@ -74,9 +92,11 @@ For non-void functions, users can name the result argument with `(postcondition) # Removed feature for automatic contract documentation using Doxygen (this is not compatible with added `(precondition)`, `(postcondition)`, and `(body)` because Doxygen preprocessor is not capable to handle Boost.Preprocessor sequences). # Rewritten entire documentation (now using Boost.QuickBook instead of Doxygen). -Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_469 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_469/doc/html/index.html documentation]. +Released [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_469 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_469/doc/html/index.html documentation]. -[heading Release 0.2.190] +[endsect] + +[section Release 0.2.190] November 21, 2009 @@ -86,9 +106,11 @@ Notes: # Required to use void to specify empty function argument list. This is to comply with C++03 standard that does not allow to pass empty macro parameters so it does not support empty preprocessor sequences `()`. -Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_2_190 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_2_190/doc/html/index.html documentation]. +Released [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_2_190 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_2_190/doc/html/index.html documentation]. -[heading Release 0.1.126] +[endsect] + +[section Release 0.1.126] June 17, 2009 @@ -96,9 +118,11 @@ Notes: # Completed first documentation draft. -Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_126 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_126/doc/html/index.html documentation]. +Released [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_126 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_126/doc/html/index.html documentation]. -[heading Release 0.1.55] +[endsect] + +[section Release 0.1.55] April 19, 2009 @@ -107,9 +131,11 @@ Notes: # Reorganized files to cleanup root directory. # Added installation program. -Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_55 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_55/doc/DBC_Documentation.txt documentation]. +Released [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_55 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_55/doc/DBC_Documentation.txt documentation]. -[heading Release 0.1.50] +[endsect] + +[section Release 0.1.50] April 19, 2009 @@ -117,7 +143,9 @@ Notes: # First public release. -Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_50 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_50/README.txt documentation]. +Released [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_50 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_50/README.txt documentation]. + +[endsect] [endsect] diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index 05bd842..c3f38f5 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -248,7 +248,7 @@ It is also recommended to use [macroref BOOST_CONTRACT_ASSERT] to program except This library will automatically call the failure handler [funcref boost::contract::except_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] conditions are `false` and also if calling the functor specified via `.except(...)` throws an exception (by default, this handler prints an error message to `std::cerr` and terminates the program calling `std::terminate`). [important -While it is technically possible for programmers to specify an exception-guarantee handler that throws an exception in case of an exception-guarantee failure, this will lead to undefined behaviour in C++. +While it is technically possible for programmers to specify an exception-guarantee handler that throws an exception in case of an exception-guarantee failure, this will force C++ to terminate the program anyway. That is because the handler will throw an exception while there is already an active exception on the stack (the exception thrown by the function body that caused this library to check the exception guarantees in the first place). Therefore, programmers are strongly advised to not change the exception-guarantee failure handler to throw exceptions instead of terminating the program. diff --git a/example/cline90/vector_axx.hpp b/example/cline90/vector_axx.hpp index 4fc8e8f..9d2acb2 100644 --- a/example/cline90/vector_axx.hpp +++ b/example/cline90/vector_axx.hpp @@ -61,6 +61,13 @@ public: + + + + + + + T& operator[](int index) { return data_[index]; } @@ -72,13 +79,6 @@ public: - - - - - - - T& operator[](int index) const { return data_[index]; } diff --git a/example/cline90/vstack.cpp b/example/cline90/vstack.cpp index dd85564..178f62e 100644 --- a/example/cline90/vstack.cpp +++ b/example/cline90/vstack.cpp @@ -10,7 +10,7 @@ #include #include -// NOTE: Incomplete contract assertions, addressing `empty` and `full` only. +// NOTE: Incomplete contract assertions, addressing only `empty` and `full`. template class abstract_stack { public: @@ -110,7 +110,7 @@ void abstract_stack::push(T const& value, boost::contract::virtual_* v) { template T const& abstract_stack::pop(boost::contract::virtual_* v) { boost::optional result; - boost::contract::old_ptr old_item = BOOST_CONTRACT_OLD(v, item()); + boost::contract::old_ptr old_item = BOOST_CONTRACT_OLDOF(v, item()); boost::contract::check c = boost::contract::public_function(v, result, this) .precondition([&] { BOOST_CONTRACT_ASSERT(!empty()); diff --git a/example/features/access.cpp b/example/features/access.cpp index 618f3ec..2f502f8 100644 --- a/example/features/access.cpp +++ b/example/features/access.cpp @@ -29,7 +29,7 @@ protected: template void pushable::push_back(T const& value, boost::contract::virtual_* v) { boost::contract::old_ptr old_capacity = - BOOST_CONTRACT_OLD(v, capacity()); + BOOST_CONTRACT_OLDOF(v, capacity()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(capacity() < max_size()); @@ -63,7 +63,7 @@ public: void push_back(T const& value, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(v, size()); + BOOST_CONTRACT_OLDOF(v, size()); boost::contract::check c = boost::contract::public_function< override_push_back>(v, &vector::push_back, this, value) .precondition([&] { diff --git a/example/features/base_types.cpp b/example/features/base_types.cpp index 7d4d873..9710079 100644 --- a/example/features/base_types.cpp +++ b/example/features/base_types.cpp @@ -26,7 +26,7 @@ protected: template void pushable::push_back(T x, boost::contract::virtual_* v) { boost::contract::old_ptr old_capacity = - BOOST_CONTRACT_OLD(v, capacity()); + BOOST_CONTRACT_OLDOF(v, capacity()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(capacity() < max_size()); @@ -85,9 +85,9 @@ public: virtual void push_back(char x, boost::contract::virtual_* v = 0) { boost::contract::old_ptr old_find = - BOOST_CONTRACT_OLD(v, find(x)); + BOOST_CONTRACT_OLDOF(v, find(x)); boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(v, size()); + BOOST_CONTRACT_OLDOF(v, size()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(!find(x)); @@ -149,9 +149,9 @@ public: void push_back(char x, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_find = - BOOST_CONTRACT_OLD(v, find(x)); + BOOST_CONTRACT_OLDOF(v, find(x)); boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(v, size()); + BOOST_CONTRACT_OLDOF(v, size()); boost::contract::check c = boost::contract::public_function< override_push_back>(v, &chars::push_back, this, x) .precondition([&] { diff --git a/example/features/base_types_no_macro.cpp b/example/features/base_types_no_macro.cpp index 1a79044..7312ce6 100644 --- a/example/features/base_types_no_macro.cpp +++ b/example/features/base_types_no_macro.cpp @@ -26,7 +26,7 @@ protected: template void pushable::push_back(T x, boost::contract::virtual_* v) { boost::contract::old_ptr old_capacity = - BOOST_CONTRACT_OLD(v, capacity()); + BOOST_CONTRACT_OLDOF(v, capacity()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(capacity() < max_size()); @@ -85,9 +85,9 @@ public: virtual void push_back(char x, boost::contract::virtual_* v = 0) { boost::contract::old_ptr old_find = - BOOST_CONTRACT_OLD(v, find(x)); + BOOST_CONTRACT_OLDOF(v, find(x)); boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(v, size()); + BOOST_CONTRACT_OLDOF(v, size()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(!find(x)); @@ -149,9 +149,9 @@ public: void push_back(char x, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_find = - BOOST_CONTRACT_OLD(v, find(x)); + BOOST_CONTRACT_OLDOF(v, find(x)); boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(v, size()); + BOOST_CONTRACT_OLDOF(v, size()); boost::contract::check c = boost::contract::public_function< override_push_back>(v, &chars::push_back, this, x) .precondition([&] { diff --git a/example/features/code_block.cpp b/example/features/code_block.cpp index 63f250a..222dc0a 100644 --- a/example/features/code_block.cpp +++ b/example/features/code_block.cpp @@ -14,7 +14,7 @@ int main() { //[code_block { // Contract for a code block. - boost::contract::old_ptr old_total = BOOST_CONTRACT_OLD(total); + boost::contract::old_ptr old_total = BOOST_CONTRACT_OLDOF(total); boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT(v.size() == 3); diff --git a/example/features/introduction.cpp b/example/features/introduction.cpp index 110e61a..455b387 100644 --- a/example/features/introduction.cpp +++ b/example/features/introduction.cpp @@ -11,7 +11,7 @@ #include void inc(int& x) { - boost::contract::old_ptr old_x = BOOST_CONTRACT_OLD(x); + boost::contract::old_ptr old_x = BOOST_CONTRACT_OLDOF(x); boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT(x < std::numeric_limits::max()); // Line 17. diff --git a/example/features/lambda.cpp b/example/features/lambda.cpp index a6b5137..a324b45 100644 --- a/example/features/lambda.cpp +++ b/example/features/lambda.cpp @@ -15,7 +15,8 @@ int main() { std::for_each(v.cbegin(), v.cend(), [&total] (int const x) { // Contract for a lambda function. - boost::contract::old_ptr old_total = BOOST_CONTRACT_OLD(total); + boost::contract::old_ptr old_total = + BOOST_CONTRACT_OLDOF(total); boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT( diff --git a/example/features/loop.cpp b/example/features/loop.cpp index 723f8e0..9eeba0d 100644 --- a/example/features/loop.cpp +++ b/example/features/loop.cpp @@ -14,7 +14,7 @@ int main() { int total = 0; for(std::vector::const_iterator i = v.begin(); i != v.end(); ++i) { // Contract for a for-loop (same for while- and all other loops). - boost::contract::old_ptr old_total = BOOST_CONTRACT_OLD(total); + boost::contract::old_ptr old_total = BOOST_CONTRACT_OLDOF(total); boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT( diff --git a/example/features/no_lambdas.hpp b/example/features/no_lambdas.hpp index dfdd5c3..bb381c1 100644 --- a/example/features/no_lambdas.hpp +++ b/example/features/no_lambdas.hpp @@ -28,7 +28,7 @@ public: } static void constructor_old(boost::contract::old_ptr& old_instances) { - old_instances = BOOST_CONTRACT_OLD(instances()); + old_instances = BOOST_CONTRACT_OLDOF(instances()); } void constructor_postcondition(unsigned const count, boost::contract::old_ptr const old_instances) const { @@ -39,7 +39,7 @@ public: virtual ~array(); void destructor_old(boost::contract::old_ptr& old_instances) const { - old_instances = BOOST_CONTRACT_OLD(instances()); + old_instances = BOOST_CONTRACT_OLDOF(instances()); } static void destructor_postcondition(boost::contract::old_ptr const old_instances) { @@ -52,7 +52,7 @@ public: } void push_back_old(boost::contract::virtual_* v, boost::contract::old_ptr& old_size) const { - old_size = BOOST_CONTRACT_OLD(v, size()); + old_size = BOOST_CONTRACT_OLDOF(v, size()); } void push_back_postcondition( boost::contract::old_ptr const old_size) const { diff --git a/example/features/no_lambdas_local_func.cpp b/example/features/no_lambdas_local_func.cpp index c9bdeee..5790486 100644 --- a/example/features/no_lambdas_local_func.cpp +++ b/example/features/no_lambdas_local_func.cpp @@ -33,7 +33,7 @@ public: { boost::contract::old_ptr old_instances; void BOOST_LOCAL_FUNCTION_TPL(bind& old_instances) { - old_instances = BOOST_CONTRACT_OLD(array::instances()); + old_instances = BOOST_CONTRACT_OLDOF(array::instances()); } BOOST_LOCAL_FUNCTION_NAME_TPL(old) void BOOST_LOCAL_FUNCTION_TPL(const bind this_, const bind& count, const bind& old_instances) { @@ -51,7 +51,7 @@ public: virtual ~array() { boost::contract::old_ptr old_instances; void BOOST_LOCAL_FUNCTION_TPL(const bind this_, bind& old_instances) { - old_instances = BOOST_CONTRACT_OLD(this_->instances()); + old_instances = BOOST_CONTRACT_OLDOF(this_->instances()); } BOOST_LOCAL_FUNCTION_NAME_TPL(old) void BOOST_LOCAL_FUNCTION_TPL(const bind& old_instances) { BOOST_CONTRACT_ASSERT(array::instances() == *old_instances - 1); @@ -70,7 +70,7 @@ public: } BOOST_LOCAL_FUNCTION_NAME_TPL(pre) void BOOST_LOCAL_FUNCTION_TPL(const bind v, const bind this_, bind& old_size) { - old_size = BOOST_CONTRACT_OLD(v, this_->size()); + old_size = BOOST_CONTRACT_OLDOF(v, this_->size()); } BOOST_LOCAL_FUNCTION_NAME_TPL(old) void BOOST_LOCAL_FUNCTION_TPL(const bind this_, const bind& old_size) { BOOST_CONTRACT_ASSERT(this_->size() == *old_size + 1); diff --git a/example/features/non_member.cpp b/example/features/non_member.cpp index 2444e07..6308c4d 100644 --- a/example/features/non_member.cpp +++ b/example/features/non_member.cpp @@ -13,7 +13,7 @@ // Contract for a non-member function. int inc(int& x) { int result; - boost::contract::old_ptr old_x = BOOST_CONTRACT_OLD(x); + boost::contract::old_ptr old_x = BOOST_CONTRACT_OLDOF(x); boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT(x < std::numeric_limits::max()); diff --git a/example/features/old.cpp b/example/features/old.cpp index bed555b..99b44b7 100644 --- a/example/features/old.cpp +++ b/example/features/old.cpp @@ -17,7 +17,7 @@ char replace(std::string& s, unsigned index, char x) { BOOST_CONTRACT_ASSERT(index < s.size()); }) .old([&] { // ...after preconditions (and invariants) checked. - old_y = BOOST_CONTRACT_OLD(s[index]); // Checked `index` in range. + old_y = BOOST_CONTRACT_OLDOF(s[index]); // Checked `index` in range. }) .postcondition([&] { BOOST_CONTRACT_ASSERT(s[index] == x); diff --git a/example/features/old_if_copyable.cpp b/example/features/old_if_copyable.cpp index f46043d..a5553a5 100644 --- a/example/features/old_if_copyable.cpp +++ b/example/features/old_if_copyable.cpp @@ -5,62 +5,129 @@ // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html #include +#include +#include #include -//[old_if_copyable +//[old_if_copyable_offset template -void accumulate(T& total, T const& x) { +void offset(T& x, int count) { // No compiler error if T has no copy constructor... - boost::contract::old_ptr_if_copyable old_total = - BOOST_CONTRACT_OLD(total); + boost::contract::old_ptr_if_copyable old_x = BOOST_CONTRACT_OLDOF(x); boost::contract::check c = boost::contract::function() .postcondition([&] { // ...but old value null if T has no copy constructor. - if(old_total) BOOST_CONTRACT_ASSERT(total == *old_total + x); + if(old_x) BOOST_CONTRACT_ASSERT(x == *old_x + count); }) ; - total += x; + x += count; } //] -struct n { - int value; +//[old_if_copyable_w_decl +// Copyable type but... +class w { +public: + w(w const&) { /* Some very expensive copy here operation... */ } - n() : value(0) {} - n operator+(n const& r) const { n x; x.value = value + r.value; return x; } - n& operator+=(n const& r) { value = value + r.value; return *this; } - bool operator==(n const& r) const { return value == r.value; } + /* ... */ +//] + w() : num_(0) {} + int operator+(int i) const { return num_ + i; } + w& operator+=(int i) { num_ += i; return *this; } + bool operator==(int i) const { return num_ == i; } private: - n(n const&) {} // Hide copy constructor (non copy-constructible). + unsigned long num_; }; -// Specialize `boost::is_copy_constructible` trait (not needed on C++11): -#include -#ifdef BOOST_NO_CXX11_DELETED_FUNCTIONS - -//[old_if_copyable_specialization -#include - -namespace boost { +//[old_if_copyable_w_spec +// ...never copy old values for type `w` (because its copy is too expensive). +namespace boost { namespace contract { template<> - struct is_copy_constructible : false_type {}; -} + struct is_old_value_copyable : boost::false_type {}; +} } // namespace //] -#endif +//[old_if_copyable_p_decl +// Non-copyable type but... +class p : private boost::noncopyable { + int* num_; + + friend struct boost::contract::old_value_copy

; + + /* ... */ +//] +public: + p() : num_(new int(0)) {} + ~p() { delete num_; } + int operator+(int i) const { return *num_ + i; } + p& operator+=(int i) { *num_ += i; return *this; } + bool operator==(int i) const { return *num_ == i; } +}; + +//[old_if_copyable_p_spec +// ...still copy old values for type `p` (using a deep copy). +namespace boost { namespace contract { + template<> + struct old_value_copy

{ + explicit old_value_copy(p const& old) { + *old_.num_ = *old.num_; // Deep copy pointed value. + } + + p const& old() const { return old_; } + + private: + p old_; + }; + + template<> + struct is_old_value_copyable

: boost::true_type {}; +} } // namespace +//] + +//[old_if_copyable_n_decl +// Non-copyable type so... +class n { + int num_; + + n(n const&); // Unimplemented private copy constructor (not copyable). + + /* ... */ +//] + +public: + n() : num_(0) {} + int operator+(int i) const { return num_ + i; } + n& operator+=(int i) { num_ += i; return *this; } + bool operator==(int i) const { return num_ == i; } +}; + +//[old_if_copyable_n_spec +// ...specialize `boost::is_copy_constructible` (no need for this on C++11). +namespace boost { namespace contract { + template<> + struct is_old_value_copyable : boost::false_type {}; +} } // namespace +//] int main() { - n j, k; // Non copyable (no compiler error but no old-value checks). - j.value = 1; - k.value = 2; - accumulate(j, k); - assert(j.value == 3); - - int i = 1; // Copyable (check old values). - accumulate(i, 2); + int i = 0; // Copy constructor, copy and check old values. + offset(i, 3); assert(i == 3); + + w j; // Expensive copy constructor, so never copy or check old values. + offset(j, 3); + assert(j == 3); + p k; // No copy constructor, but still copy and check old values. + offset(k, 3); + assert(k == 3); + + n h; // No copy constructor, no compiler error but no old value checks. + offset(h, 3); + assert(h == 3); + return 0; } diff --git a/example/features/overload.cpp b/example/features/overload.cpp index ae276e4..e8c4424 100644 --- a/example/features/overload.cpp +++ b/example/features/overload.cpp @@ -118,7 +118,7 @@ public: void put(std::string const& x, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_str = - BOOST_CONTRACT_OLD(v, str()); + BOOST_CONTRACT_OLDOF(v, str()); boost::contract::check c = boost::contract::public_function< override_put>( v, @@ -138,7 +138,7 @@ public: // Overload on argument type. void put(char x, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_str = - BOOST_CONTRACT_OLD(v, str()); + BOOST_CONTRACT_OLDOF(v, str()); boost::contract::check c = boost::contract::public_function< override_put>( v, @@ -159,7 +159,7 @@ public: void put(int x, bool tab = false, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_str = - BOOST_CONTRACT_OLD(v, str()); + BOOST_CONTRACT_OLDOF(v, str()); boost::contract::check c = boost::contract::public_function< override_put>( v, diff --git a/example/features/private_protected.cpp b/example/features/private_protected.cpp index 1f81800..60bd02d 100644 --- a/example/features/private_protected.cpp +++ b/example/features/private_protected.cpp @@ -27,7 +27,7 @@ protected: private: void dec() { - boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(get()); + boost::contract::old_ptr old_get = BOOST_CONTRACT_OLDOF(get()); boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT( diff --git a/example/features/private_protected_virtual.cpp b/example/features/private_protected_virtual.cpp index fad9694..dfc8775 100644 --- a/example/features/private_protected_virtual.cpp +++ b/example/features/private_protected_virtual.cpp @@ -28,7 +28,7 @@ protected: private: virtual void dec(boost::contract::virtual_* = 0) { - boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(get()); + boost::contract::old_ptr old_get = BOOST_CONTRACT_OLDOF(get()); boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT( @@ -95,7 +95,7 @@ public: } virtual void dec(boost::contract::virtual_* v = 0) /* override */ { - boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(v, get()); + boost::contract::old_ptr old_get = BOOST_CONTRACT_OLDOF(v, get()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT( diff --git a/example/features/private_protected_virtual_multi.cpp b/example/features/private_protected_virtual_multi.cpp index fa89272..ed76833 100644 --- a/example/features/private_protected_virtual_multi.cpp +++ b/example/features/private_protected_virtual_multi.cpp @@ -41,7 +41,7 @@ protected: private: virtual void dec(boost::contract::virtual_* = 0) { - boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(get()); + boost::contract::old_ptr old_get = BOOST_CONTRACT_OLDOF(get()); boost::contract::check c = boost::contract::function() .precondition([&] { BOOST_CONTRACT_ASSERT( @@ -96,7 +96,7 @@ public: //] void countable::dec(boost::contract::virtual_* v) { - boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(v, get()); + boost::contract::old_ptr old_get = BOOST_CONTRACT_OLDOF(v, get()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(get() > std::numeric_limits::min()); @@ -154,7 +154,7 @@ public: } virtual void dec(boost::contract::virtual_* v = 0) /* override */ { - boost::contract::old_ptr old_get = BOOST_CONTRACT_OLD(v, get()); + boost::contract::old_ptr old_get = BOOST_CONTRACT_OLDOF(v, get()); boost::contract::check c = boost::contract::public_function< override_dec>(v, &counter10::dec, this) .precondition([&] { diff --git a/example/features/public.cpp b/example/features/public.cpp index 3a94f11..b2c2339 100644 --- a/example/features/public.cpp +++ b/example/features/public.cpp @@ -78,9 +78,9 @@ public: virtual int push_back(int id, boost::contract::virtual_* v = 0) { int result; boost::contract::old_ptr old_find = - BOOST_CONTRACT_OLD(v, find(id)); // Pass `v`. + BOOST_CONTRACT_OLDOF(v, find(id)); // Pass `v`. boost::contract::old_ptr old_sizs = - BOOST_CONTRACT_OLD(v, size()); // Pass `v`. + BOOST_CONTRACT_OLDOF(v, size()); // Pass `v`. boost::contract::check c = boost::contract::public_function( v, result, this) // Pass `v` and `result`. .precondition([&] { @@ -129,8 +129,9 @@ public: int push_back(int id, boost::contract::virtual_* v = 0) /* override */ { int result; boost::contract::old_ptr old_find = - BOOST_CONTRACT_OLD(v, find(id)); - boost::contract::old_ptr old_size = BOOST_CONTRACT_OLD(v, size()); + BOOST_CONTRACT_OLDOF(v, find(id)); + boost::contract::old_ptr old_size = + BOOST_CONTRACT_OLDOF(v, size()); boost::contract::check c = boost::contract::public_function< override_push_back // Pass override plus below function pointer... >(v, result, &identifiers::push_back, this, id) // ...and arguments. diff --git a/example/features/separate_body.hpp b/example/features/separate_body.hpp index 5e21179..e260965 100644 --- a/example/features/separate_body.hpp +++ b/example/features/separate_body.hpp @@ -39,7 +39,7 @@ public: virtual void push_back(T const& value, boost::contract::virtual_* v = 0) { boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(v, size()); + BOOST_CONTRACT_OLDOF(v, size()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(size() < MaxSize); diff --git a/example/features/static_public.cpp b/example/features/static_public.cpp index 55d06d5..5984bee 100644 --- a/example/features/static_public.cpp +++ b/example/features/static_public.cpp @@ -28,7 +28,7 @@ public: make() : object() { boost::contract::old_ptr old_instances = - BOOST_CONTRACT_OLD(instances()); + BOOST_CONTRACT_OLDOF(instances()); boost::contract::check c = boost::contract::constructor(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(instances() == *old_instances + 1); @@ -40,7 +40,7 @@ public: ~make() { boost::contract::old_ptr old_instances = - BOOST_CONTRACT_OLD(instances()); + BOOST_CONTRACT_OLDOF(instances()); boost::contract::check c = boost::contract::destructor(this) .postcondition([&] { // (An example of destructor postconditions.) BOOST_CONTRACT_ASSERT(instances() == *old_instances - 1); diff --git a/example/features/union.cpp b/example/features/union.cpp index 983a5a2..2f690fa 100644 --- a/example/features/union.cpp +++ b/example/features/union.cpp @@ -30,7 +30,7 @@ public: BOOST_CONTRACT_ASSERT(x > 0); }); boost::contract::old_ptr old_instances = - BOOST_CONTRACT_OLD(instances()); + BOOST_CONTRACT_OLDOF(instances()); boost::contract::check c = boost::contract::constructor(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(instances() == *old_instances + 1); @@ -43,7 +43,7 @@ public: ~positive() { // Contracts for the destructor. boost::contract::old_ptr old_instances = - BOOST_CONTRACT_OLD(instances()); + BOOST_CONTRACT_OLDOF(instances()); boost::contract::check c = boost::contract::destructor(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(instances() == *old_instances - 1); @@ -82,7 +82,7 @@ public: BOOST_CONTRACT_ASSERT(x > 0); }); boost::contract::old_ptr old_instances = - BOOST_CONTRACT_OLD(instances()); + BOOST_CONTRACT_OLDOF(instances()); boost::contract::check c = boost::contract::constructor(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(instances() == *old_instances + 1); diff --git a/example/meyer97/stack3.cpp b/example/meyer97/stack3.cpp index 56dc112..ae36bff 100644 --- a/example/meyer97/stack3.cpp +++ b/example/meyer97/stack3.cpp @@ -20,7 +20,7 @@ class stack3 { if(!error()) { BOOST_CONTRACT_ASSERT(count() >= 0); // Count non-negative. BOOST_CONTRACT_ASSERT(count() <= capacity()); // Count bounded. - // Empty if no item. + // Empty if no element. BOOST_CONTRACT_ASSERT(empty() == (count() == 0)); } } @@ -35,7 +35,7 @@ public: /* Initialization */ - // Create stack for max of n items, if n < 0 set error (no preconditions). + // Create stack for max of n elems, if n < 0 set error (no preconditions). explicit stack3(int n, T const& default_value = T()) : stack_(0), error_(no_error) { boost::contract::check c = boost::contract::constructor(this) @@ -55,21 +55,21 @@ public: /* Access */ - // Max number of stack items. + // Max number of stack elements. int capacity() const { // Check invariants. boost::contract::check c = boost::contract::public_function(this); return stack_.capacity(); } - // Number of stack items. + // Number of stack elements. int count() const { // Check invariants. boost::contract::check c = boost::contract::public_function(this); return stack_.count(); } - // Top item if present, otherwise none and set error (no preconditions). + // Top element if present, otherwise none and set error (no preconditions). boost::optional item() const { boost::contract::check c = boost::contract::public_function(this) .postcondition([&] { @@ -110,12 +110,12 @@ public: return stack_.full(); } - /* Item Change */ + /* Element Change */ // Add x to top if capacity allows, otherwise set error (no preconditions). void put(T const& x) { - boost::contract::old_ptr old_full = BOOST_CONTRACT_OLD(full()); - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + boost::contract::old_ptr old_full = BOOST_CONTRACT_OLDOF(full()); + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .postcondition([&] { // Error if impossible. @@ -138,10 +138,11 @@ public: } } - // Remove top item if possible, otherwise set error (no preconditions). + // Remove top element if possible, otherwise set error (no preconditions). void remove() { - boost::contract::old_ptr old_empty = BOOST_CONTRACT_OLD(empty()); - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + boost::contract::old_ptr old_empty = + BOOST_CONTRACT_OLDOF(empty()); + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .postcondition([&] { // Error if impossible. diff --git a/example/meyer97/stack4.e b/example/meyer97/stack4.e index 0f9b0b8..02deda5 100644 --- a/example/meyer97/stack4.e +++ b/example/meyer97/stack4.e @@ -23,7 +23,7 @@ invariant -feature -- Initialization. +feature -- Initialization -- Allocate stack for a maximum of n elements. make(n: INTEGER) is @@ -83,7 +83,7 @@ feature -- Initialization. -feature -- Access. +feature -- Access -- Max number of stack elements. capacity: INTEGER @@ -99,7 +99,7 @@ feature -- Access. - -- Top element + -- Top element. item: G is require not_empty: not empty -- i.e., count > 0 @@ -110,7 +110,7 @@ feature -- Access. -feature -- Status report. +feature -- Status report -- Is stack empty? empty: BOOLEAN is @@ -138,7 +138,7 @@ feature -- Status report. -feature -- Element change. +feature -- Element change -- Add x on top. put(x: G) is diff --git a/example/meyer97/stack4.hpp b/example/meyer97/stack4.hpp index 947e70f..25aba47 100644 --- a/example/meyer97/stack4.hpp +++ b/example/meyer97/stack4.hpp @@ -24,13 +24,13 @@ class stack4 void invariant() const { BOOST_CONTRACT_ASSERT(count() >= 0); // Count non-negative. BOOST_CONTRACT_ASSERT(count() <= capacity()); // Count bounded. - BOOST_CONTRACT_ASSERT(empty() == (count() == 0)); // Empty if no item. + BOOST_CONTRACT_ASSERT(empty() == (count() == 0)); // Empty if no elem. } public: /* Initialization */ - // Allocate static from a maximum of n items. + // Allocate static from a maximum of n elements. explicit stack4(int n) : boost::contract::constructor_precondition([&] { BOOST_CONTRACT_ASSERT(n >= 0); // Non-negative capacity. @@ -53,7 +53,7 @@ public: .postcondition([&] { BOOST_CONTRACT_ASSERT(capacity() == other.capacity()); BOOST_CONTRACT_ASSERT(count() == other.count()); - // All items equal to other's items one by one. + // All elements equal to other's elements one by one. }) ; @@ -69,7 +69,7 @@ public: .postcondition([&] { BOOST_CONTRACT_ASSERT(capacity() == other.capacity()); BOOST_CONTRACT_ASSERT(count() == other.count()); - // All items euqal to other's items one by one. + // All elements equal to other's elements one by one. }) ; @@ -90,25 +90,25 @@ public: /* Access */ - // Max number of stack items. + // Max number of stack elements. int capacity() const { // Check invariants. boost::contract::check c = boost::contract::public_function(this); return capacity_; } - // Number of stack items. + // Number of stack elements. int count() const { // Check invariants. boost::contract::check c = boost::contract::public_function(this); return count_; } - // Top item. + // Top element. T const& item() const { boost::contract::check c = boost::contract::public_function(this) .precondition([&] { - BOOST_CONTRACT_ASSERT(!empty()); // Not empty (count > 0). + BOOST_CONTRACT_ASSERT(!empty()); // Not empty (i.e., count > 0). }) ; @@ -143,11 +143,11 @@ public: return result = (count_ == capacity_); } - /* Item Change */ + /* Element Change */ // Add x on top. void put(T const& x) { - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!full()); // Not full. @@ -162,12 +162,12 @@ public: array_[count_++] = x; } - // Remove top item. + // Remove top element. void remove() { - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { - BOOST_CONTRACT_ASSERT(!empty()); // Not empty (count > 0). + BOOST_CONTRACT_ASSERT(!empty()); // Not empty (i.e., count > 0). }) .postcondition([&] { BOOST_CONTRACT_ASSERT(!full()); // Not full. @@ -181,7 +181,7 @@ public: private: int capacity_; int count_; - T* array_; // Internally using C-style array. + T* array_; // Internally use C-style array. }; #endif // #include guard diff --git a/example/mitchell02/counter/counter.hpp b/example/mitchell02/counter/counter.hpp index 0cae53d..4ac671d 100644 --- a/example/mitchell02/counter/counter.hpp +++ b/example/mitchell02/counter/counter.hpp @@ -48,7 +48,7 @@ public: // Decrement counter value. void decrement() { - boost::contract::old_ptr old_value = BOOST_CONTRACT_OLD(value()); + boost::contract::old_ptr old_value = BOOST_CONTRACT_OLDOF(value()); boost::contract::check c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(value() == *old_value - 1); // Decrement. diff --git a/example/mitchell02/counter/decrement_button.hpp b/example/mitchell02/counter/decrement_button.hpp index 0eea5e5..1ca16a4 100644 --- a/example/mitchell02/counter/decrement_button.hpp +++ b/example/mitchell02/counter/decrement_button.hpp @@ -47,7 +47,7 @@ public: virtual void on_bn_clicked(boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_value = - BOOST_CONTRACT_OLD(v, counter_.value()); + BOOST_CONTRACT_OLDOF(v, counter_.value()); boost::contract::check c = boost::contract::public_function< override_on_bn_clicked >(v, &decrement_button::on_bn_clicked, this) diff --git a/example/mitchell02/customer_manager.cpp b/example/mitchell02/customer_manager.cpp index c3cf5e5..a3cb4ac 100644 --- a/example/mitchell02/customer_manager.cpp +++ b/example/mitchell02/customer_manager.cpp @@ -79,7 +79,7 @@ public: /* Commands */ void add(customer_info const& info) { - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { // Not already active. diff --git a/example/mitchell02/dictionary.cpp b/example/mitchell02/dictionary.cpp index 98ce9fc..6eac901 100644 --- a/example/mitchell02/dictionary.cpp +++ b/example/mitchell02/dictionary.cpp @@ -74,7 +74,7 @@ public: // Add value of a given key. void put(K const& key, T const& value) { - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!has(key)); // Has not key already. @@ -92,7 +92,7 @@ public: // Remove value for given key. void remove(K const& key) { - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(has(key)); // Has key. diff --git a/example/mitchell02/name_list.cpp b/example/mitchell02/name_list.cpp index b67ebde..92baecc 100644 --- a/example/mitchell02/name_list.cpp +++ b/example/mitchell02/name_list.cpp @@ -66,9 +66,9 @@ public: virtual void put(std::string const& name, boost::contract::virtual_* v = 0) { boost::contract::old_ptr old_has_name = - BOOST_CONTRACT_OLD(v, has(name)); + BOOST_CONTRACT_OLDOF(v, has(name)); boost::contract::old_ptr old_count = - BOOST_CONTRACT_OLD(v, count()); + BOOST_CONTRACT_OLDOF(v, count()); boost::contract::check c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(!has(name)); // Not already in list. @@ -104,9 +104,9 @@ public: void put(std::string const& name, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr old_has_name = - BOOST_CONTRACT_OLD(v, has(name)); + BOOST_CONTRACT_OLDOF(v, has(name)); boost::contract::old_ptr old_count = - BOOST_CONTRACT_OLD(v, count()); + BOOST_CONTRACT_OLDOF(v, count()); boost::contract::check c = boost::contract::public_function< override_put>(v, &relaxed_name_list::put, this, name) .precondition([&] { // Relax inherited preconditions. diff --git a/example/mitchell02/observer/subject.hpp b/example/mitchell02/observer/subject.hpp index d68a791..9eda058 100644 --- a/example/mitchell02/observer/subject.hpp +++ b/example/mitchell02/observer/subject.hpp @@ -24,9 +24,9 @@ class subject { friend class boost::contract::access; void invariant() const { - if(O_N <= COMPLEXITY_MAX) { + #if O_N <= COMPLEXITY_MAX BOOST_CONTRACT_ASSERT(all_observers_valid(observers())); // Valid. - } + #endif } public: @@ -63,7 +63,7 @@ public: // Attach given object as an observer. void attach(observer* ob) { boost::contract::old_ptr > old_observers = - BOOST_CONTRACT_OLD(observers()); + BOOST_CONTRACT_OLDOF(observers()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(ob); // Not null. @@ -71,11 +71,11 @@ public: }) .postcondition([&] { BOOST_CONTRACT_ASSERT(attached(ob)); // Attached. - if(O_N <= COMPLEXITY_MAX) { + #if O_N <= COMPLEXITY_MAX // Others not changed (frame rule). BOOST_CONTRACT_ASSERT(other_observers_unchanged( *old_observers, observers(), ob)); - } + #endif }) ; @@ -104,10 +104,10 @@ protected: // Protected members use `function` (no inv and no subcontracting). boost::contract::check c = boost::contract::function() .postcondition([&] { - if(O_N <= COMPLEXITY_MAX) { + #if O_N <= COMPLEXITY_MAX // All updated. BOOST_CONTRACT_ASSERT(all_observers_updated(observers())); - } + #endif }) ; diff --git a/example/mitchell02/simple_queue.cpp b/example/mitchell02/simple_queue.cpp index 082cd51..6dca4ff 100644 --- a/example/mitchell02/simple_queue.cpp +++ b/example/mitchell02/simple_queue.cpp @@ -136,8 +136,10 @@ public: void remove() { // Expensive all_equal postcond. and old_items copy might be skipped. boost::contract::old_ptr > old_items; - if(O_N <= COMPLEXITY_MAX) old_items = BOOST_CONTRACT_OLD(items()); - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + #if O_N <= COMPLEXITY_MAX + old_items = BOOST_CONTRACT_OLDOF(items()); + #endif + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!is_empty()); // Not empty. @@ -155,8 +157,10 @@ public: void put(T const& item) { // Expensive all_equal postcond. and old_items copy might be skipped. boost::contract::old_ptr > old_items; - if(O_N <= COMPLEXITY_MAX) old_items = BOOST_CONTRACT_OLD(items()); - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + #if O_N <= COMPLEXITY_MAX + old_items = BOOST_CONTRACT_OLDOF(items()); + #endif + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(count() < capacity()); // Room for add. diff --git a/example/mitchell02/stack.cpp b/example/mitchell02/stack.cpp index 2eed3e2..331a6ac 100644 --- a/example/mitchell02/stack.cpp +++ b/example/mitchell02/stack.cpp @@ -92,7 +92,7 @@ public: // Push item to the top. void put(T const& new_item) { - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(count() == *old_count + 1); // Count inc. @@ -105,7 +105,7 @@ public: // Pop top item. void remove() { - boost::contract::old_ptr old_count = BOOST_CONTRACT_OLD(count()); + boost::contract::old_ptr old_count = BOOST_CONTRACT_OLDOF(count()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(count() > 0); // Not empty. diff --git a/example/n1962/circle.cpp b/example/n1962/circle.cpp index 2bd4633..864c385 100644 --- a/example/n1962/circle.cpp +++ b/example/n1962/circle.cpp @@ -23,7 +23,7 @@ unsigned shape::compute_area(boost::contract::virtual_* v) const { }) ; assert(false); - return result = 0; + return result; } class circle diff --git a/example/n1962/factorial.cpp b/example/n1962/factorial.cpp index 17a1d83..817d6b7 100644 --- a/example/n1962/factorial.cpp +++ b/example/n1962/factorial.cpp @@ -29,12 +29,12 @@ int factorial(int n ) { // Following assertion introduce significant run-time overhead // (same as the function body) so assertion can be selectively // disabled by setting COMPLEXITY_MAX. - if(O_SAME_AS_BODY <= COMPLEXITY_MAX) { + #if O_SAME_AS_BODY <= COMPLEXITY_MAX // Assertions automatically disabled in other assertions. // Therefore, this postcondition can recursively call the // function without causing infinite recursion. BOOST_CONTRACT_ASSERT(n * factorial(n - 1)); - } + #endif } }) ; diff --git a/example/n1962/vector.cpp b/example/n1962/vector.cpp index fddf027..5c06866 100644 --- a/example/n1962/vector.cpp +++ b/example/n1962/vector.cpp @@ -100,7 +100,7 @@ public: ; } - vector(size_type count, const T& value, Allocator const& alloc) : + vector(size_type count, T const& value, Allocator const& alloc) : vect_(count, value, alloc) { boost::contract::check c = boost::contract::constructor(this) .postcondition([&] { @@ -111,7 +111,7 @@ public: boost::cref(value)) ) ); - BOOST_CONTRACT_ASSERT(alloc == get_allocator()); + BOOST_CONTRACT_ASSERT(get_allocator() == alloc); }) ; } @@ -268,7 +268,7 @@ public: void resize(size_type count, T const& value = T()) { boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(size()); + BOOST_CONTRACT_OLDOF(size()); boost::contract::check c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == count); @@ -398,9 +398,9 @@ public: void push_back(T const& value) { boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(size()); + BOOST_CONTRACT_OLDOF(size()); boost::contract::old_ptr old_capacity = - BOOST_CONTRACT_OLD(capacity()); + BOOST_CONTRACT_OLDOF(capacity()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(size() < max_size()); @@ -422,7 +422,7 @@ public: void pop_back() { boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(size()); + BOOST_CONTRACT_OLDOF(size()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!empty()); @@ -469,7 +469,7 @@ public: iterator insert(iterator where, T const& value) { iterator result; boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(size()); + BOOST_CONTRACT_OLDOF(size()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(size() < max_size()); @@ -494,11 +494,11 @@ public: void insert(iterator where, size_type count, T const& value) { boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(size()); + BOOST_CONTRACT_OLDOF(size()); boost::contract::old_ptr old_capacity = - BOOST_CONTRACT_OLD(capacity()); + BOOST_CONTRACT_OLDOF(capacity()); boost::contract::old_ptr old_where = - BOOST_CONTRACT_OLD(where); + BOOST_CONTRACT_OLDOF(where); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(size() + count < max_size()); @@ -528,9 +528,9 @@ public: template void insert(iterator where, InputIter first, InputIter last) { boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(size()); + BOOST_CONTRACT_OLDOF(size()); boost::contract::old_ptr old_capacity = - BOOST_CONTRACT_OLD(capacity()); + BOOST_CONTRACT_OLDOF(capacity()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(size() + std::distance(first, last) < @@ -550,7 +550,7 @@ public: iterator erase(iterator where) { iterator result; boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(size()); + BOOST_CONTRACT_OLDOF(size()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!empty()); @@ -569,7 +569,7 @@ public: iterator erase(iterator first, iterator last) { iterator result; boost::contract::old_ptr old_size = - BOOST_CONTRACT_OLD(size()); + BOOST_CONTRACT_OLDOF(size()); boost::contract::check c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(size() >= std::distance(first, last)); @@ -596,8 +596,9 @@ public: } void swap(vector& other) { - boost::contract::old_ptr old_me = BOOST_CONTRACT_OLD(*this); - boost::contract::old_ptr old_other = BOOST_CONTRACT_OLD(other); + boost::contract::old_ptr old_me = BOOST_CONTRACT_OLDOF(*this); + boost::contract::old_ptr old_other = + BOOST_CONTRACT_OLDOF(other); boost::contract::check c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT( diff --git a/example/n1962/vector_n1962.hpp b/example/n1962/vector_n1962.hpp index 6705eca..4a04944 100644 --- a/example/n1962/vector_n1962.hpp +++ b/example/n1962/vector_n1962.hpp @@ -27,6 +27,7 @@ + template< class T, class Allocator = std::allocator > class vector { @@ -75,7 +76,7 @@ public: explicit vector(size_type count) postcondition { size() == count; - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { boost::algorithm::all_of_equal(begin(), end(), T()); } } @@ -88,21 +89,20 @@ public: vector(size_type count, T const& value) postcondition { size() == count; - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { boost::algorithm::all_of_equal(begin(), end(), value); } } : vect_(count, value) {} - vector(size_type count, T const& value, Allocator const& alloc) postcondition { size() == count; - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { boost::algorithm::all_of_equal(begin(), end(), value); } get_allocator() == alloc; @@ -139,7 +139,7 @@ public: /* implicit */ vector(vector const& other) postcondition { - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { *this == other; } } @@ -152,7 +152,7 @@ public: vector& operator=(vector const& other) postcondition(result) { - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { *this == other; result == *this; } @@ -165,8 +165,9 @@ public: - - + + + @@ -268,7 +269,7 @@ public: void resize(size_type count, T const& value = T()) postcondition { size() == count; - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { if(count > oldof size()) { boost::algorithm::all_of_equal(begin() + oldof size(), end(), value); @@ -377,7 +378,7 @@ public: reference back() precondition { - empty(); + !empty(); } { return vect_.back(); @@ -387,7 +388,7 @@ public: const_reference back() const precondition { - empty(); + !empty(); } { return vect_.back(); @@ -402,7 +403,7 @@ public: postcondition { size() == oldof size() + 1; capacity() >= oldof capacity() - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { back() == value; } } @@ -452,7 +453,7 @@ public: count <= max_size(); } postcondition { - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { boost::algorithm::all_of_equal(begin(), end(), value); } } @@ -471,7 +472,7 @@ public: } postcondition(result) { size() == oldof size() + 1; - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { *result == value; } // if(capacity() > oldof capacity()) @@ -498,7 +499,7 @@ public: postcondition { size() == oldof size() + count; capacity() >= oldof capacity(); - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { if(capacity() == oldof capacity()) { boost::algorithm::all_of_equal(boost::prior(oldof where), boost::prior(oldof where) + count, value); @@ -596,7 +597,7 @@ public: void swap(vector& other) postcondition { - static if(boost::has_equal_to::value) { + if constexpr(boost::has_equal_to::value) { *this == oldof other; other == oldof *this; } @@ -666,6 +667,8 @@ private: + + diff --git a/include/boost/contract.hpp b/include/boost/contract.hpp index 2e26865..08897b2 100644 --- a/include/boost/contract.hpp +++ b/include/boost/contract.hpp @@ -25,20 +25,8 @@ never be used directly by programmers. @see @RefSect{getting_started, Getting Started} */ -// TODO: Document that this lib will not work in general if link!=shared (link=static and link=header only provided for convenience because they might work OK in simple cases of a single program, but won't work in general with multiple programs/libs so only link=shared should be used in real code). - -// TODO: Document that boost::contract::function() can be used to program contracts for lambda functions. And also "abused" a bit to program pre/postconditions for any arbitrary scope of code in function body. - -// TODO: Document that friends do not in general check invariants so their contracts are usually programmed using function(). But if a function friend of an object takes an instance of that object as a parameter and therefore is essentially part of the object's public API, then programmers can make that explicit by using public_function(obj) after function() to program the friend function contract (but note that in general friends functions can take instances of multiple different objects because the same function can be friend of different classes). Also add a test (under test/public_function/...) and an example for friend. - // TODO: Document that noexcept (and exception throw(...)) specifications of the enclosing function apply to contracts. So if a contract handler is set so contract failures throw, noexcept function will still not throw, they will always terminate (because that's what users of such functions except, even if the function fails in any way, including the function contract fails). -// TODO: Document that if installing contract failure handlers that throw, it might be a good idea to check invariants at exit. That way the destructor entry invariant should *in theory* never fail (unless not all public functions, ctors are contracted, or because of non-contracted friends, or because of public data members... all those can still break the invariant before the dtor is called and before this lib will detect the invariants have failed so the dtor entry inv will fail... and what will dtor do in that case? terminate?). - -// TODO: Document (in Getting Started) that some example source code has `//[...` and `//]` tags used to import example code in Quickbook docs (so doc's examples always up to date with code). - -// TODO: Document that result is NOT accessible in .except's functor because function threw. Old values are accessible in both post and except so OLDOF copies disabled on if both except and post checking disabled (NO_EXCEPTS && NO_POSTCONDITIONS). except will have its own failure handler except_failure, check disabling macro NO_EXCEPTS, etc. - // TODO: Document that contract for constexpr functions cannot be supported at the moment because constexpr functions cannot: (1) declare local variables of (literal) types with non-trivial constexpr destructors (needed by this lib to check inv, post, and except at exit), (2) call other (constexpr) functions with try-catch statements (used by this lib to report assertion failure and catch any other exception that might be thrown by the evaluation of the asserted conditions), (3) use lambda functions (use by this for convenience to program functors that check per and post). Also note that even if supported, contracts for constexpr probably will not use old values (because constexpr prevent the function from having any side effect visible to the caller, variables around such side-effects are usually the candidates for old value copies) and subcontracting (because constexpr functions cannot be virtual). // TODO: Documentation updates based on all emails to Boost (review all emails). diff --git a/include/boost/contract/assert.hpp b/include/boost/contract/assert.hpp index c583734..35185be 100644 --- a/include/boost/contract/assert.hpp +++ b/include/boost/contract/assert.hpp @@ -38,10 +38,10 @@ Assert contract conditions. @RefSect{extra_topics.no_macros__no_c__11_, No Macros} @param condition The contract condition being checked. - This is not a variadic macro parameter so any comma it - might contain must be protected by round parenthesis - (i.e., @c BOOST_CONTRACT_ASSERT((condition)) will always - work). + (This is not a variadic macro parameter so any comma it + might contain must be protected by round parenthesis, + but @c BOOST_CONTRACT_ASSERT((condition)) will always + work.) */ #define BOOST_CONTRACT_ASSERT(condition) {} #endif diff --git a/include/boost/contract/call_if.hpp b/include/boost/contract/call_if.hpp index c9a30cd..1f03ca1 100644 --- a/include/boost/contract/call_if.hpp +++ b/include/boost/contract/call_if.hpp @@ -10,9 +10,9 @@ /** @file Statically disable compilation and execution of functor template calls. -@note This facility also allows to emulate static if statements but - only when used together with functor templates (or C++14 generic - lambdas). +@note This facility also allows to emulate C++17 if constexpr + statements but only when used together with functor templates (or C++14 + generic lambdas). */ #include diff --git a/include/boost/contract/check.hpp b/include/boost/contract/check.hpp index 15b2fbb..64e1db4 100644 --- a/include/boost/contract/check.hpp +++ b/include/boost/contract/check.hpp @@ -7,10 +7,6 @@ // 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 -// TODO: Document that using an auto declaration instead of check will cause a compile-time error (instead missing check and using no declaration at all will cause a run-time error--as already documented). - -// TODO: Document check (class) and CHECK (macro) to program implementation assertions (for loops, code blocks, etc.) similar to C-style assert() but can be disabled, calls check_failure hander, etc. - /** @file RAII object to check contracts. */ diff --git a/include/boost/contract/core/check_macro.hpp b/include/boost/contract/core/check_macro.hpp index fab329a..14c2656 100644 --- a/include/boost/contract/core/check_macro.hpp +++ b/include/boost/contract/core/check_macro.hpp @@ -32,10 +32,10 @@ Macro for implementation checks. @param condition The condition to be asserted within implementation code (function body, etc.). - This is not a variadic macro parameter so any comma it - might contain must be protected by round parenthesis - (i.e., @c BOOST_CONTRACT_CHECK((condition)) will always - work). + (This is not a variadic macro parameter so any comma it + might contain must be protected by round parenthesis, + but @c BOOST_CONTRACT_CHECK((condition)) will always + work.) */ #define BOOST_CONTRACT_CHECK(condition) /* nothing */ #endif diff --git a/include/boost/contract/core/config.hpp b/include/boost/contract/core/config.hpp index 7815a0f..3281dcd 100644 --- a/include/boost/contract/core/config.hpp +++ b/include/boost/contract/core/config.hpp @@ -239,7 +239,6 @@ Configure this library compile-time and run-time behaviours. #define BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION #endif -// TODO: Add NO_CHECK to boost_contract_no build for tests, etc. #ifdef DOXYGEN /** If defined, this library does not perform implementation checks (undefined diff --git a/include/boost/contract/core/exception.hpp b/include/boost/contract/core/exception.hpp index beb8226..218d28c 100644 --- a/include/boost/contract/core/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -251,149 +251,164 @@ typedef boost::function failure_handler; namespace exception_ { // Check failure. - failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + failure_handler const& set_check_failure_unlocked(failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + failure_handler const& set_check_failure_locked(failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC get_check_failure_unlocked() + BOOST_CONTRACT_DETAIL_DECLSPEC failure_handler get_check_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; - failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC get_check_failure_locked() + BOOST_CONTRACT_DETAIL_DECLSPEC failure_handler get_check_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; - void BOOST_CONTRACT_DETAIL_DECLSPEC check_failure_unlocked() + BOOST_CONTRACT_DETAIL_DECLSPEC void check_failure_unlocked() /* can throw */; - void BOOST_CONTRACT_DETAIL_DECLSPEC check_failure_locked() + BOOST_CONTRACT_DETAIL_DECLSPEC void check_failure_locked() /* can throw */; // Precondition failure. - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_pre_failure_unlocked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_pre_failure_locked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_pre_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_pre_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; - void BOOST_CONTRACT_DETAIL_DECLSPEC pre_failure_unlocked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void pre_failure_unlocked(from where) /* can throw */; - void BOOST_CONTRACT_DETAIL_DECLSPEC pre_failure_locked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void pre_failure_locked(from where) /* can throw */; // Postcondition failure. - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_post_failure_unlocked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_post_failure_locked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_post_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_post_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; - void BOOST_CONTRACT_DETAIL_DECLSPEC post_failure_unlocked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void + post_failure_unlocked(from where) /* can throw */; void BOOST_CONTRACT_DETAIL_DECLSPEC post_failure_locked(from where) /* can throw */; // Except failure. - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_except_failure_unlocked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_except_failure_locked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_except_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_except_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; - void BOOST_CONTRACT_DETAIL_DECLSPEC except_failure_unlocked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void except_failure_unlocked(from where) /* can throw */; - void BOOST_CONTRACT_DETAIL_DECLSPEC except_failure_locked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void except_failure_locked(from where) /* can throw */; // Old-copy failure. - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_old_failure_unlocked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_old_failure_locked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_old_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_old_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; - void BOOST_CONTRACT_DETAIL_DECLSPEC old_failure_unlocked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void old_failure_unlocked(from where) /* can throw */; - void BOOST_CONTRACT_DETAIL_DECLSPEC old_failure_locked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void old_failure_locked(from where) /* can throw */; // Entry invariant failure. - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_entry_inv_failure_unlocked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_entry_inv_failure_locked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_entry_inv_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_entry_inv_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; - void BOOST_CONTRACT_DETAIL_DECLSPEC entry_inv_failure_unlocked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void entry_inv_failure_unlocked(from where) /* can throw */; - void BOOST_CONTRACT_DETAIL_DECLSPEC entry_inv_failure_locked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void entry_inv_failure_locked(from where) /* can throw */; // Exit invariant failure. - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_exit_inv_failure_unlocked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler const& BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC + from_failure_handler const& set_exit_inv_failure_locked(from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW ; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_exit_inv_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW; - from_failure_handler BOOST_CONTRACT_DETAIL_DECLSPEC + BOOST_CONTRACT_DETAIL_DECLSPEC from_failure_handler get_exit_inv_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW; - void BOOST_CONTRACT_DETAIL_DECLSPEC exit_inv_failure_unlocked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void exit_inv_failure_unlocked(from where) /* can throw */; - void BOOST_CONTRACT_DETAIL_DECLSPEC exit_inv_failure_locked(from where) + BOOST_CONTRACT_DETAIL_DECLSPEC void exit_inv_failure_locked(from where) /* can throw */; } @@ -673,8 +688,7 @@ This is often called only internally by this library. @warning However, note that when this failure handler is called there is already an active exception (the one that caused the exception guarantees to be checked in the first place) so throwing yet another - exception will result in undefined behaviour in C++ (most likely in - a segfault). + exception will force C++ to terminate the program. @param where Operation that failed the contract assertion. diff --git a/include/boost/contract/core/specify.hpp b/include/boost/contract/core/specify.hpp index e48ab52..39da3ae 100644 --- a/include/boost/contract/core/specify.hpp +++ b/include/boost/contract/core/specify.hpp @@ -7,8 +7,6 @@ // 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 -// TODO: Document that set_except_failure shall never be set to throw because that will cause the contract failure handler to throw an exception while there's already an active exception (the reason .except() functor is being executed) so C++ will always call std::terminate in this case (again, not a good idea to throw on contract failures, especially from destructors but also for all .except() failures). - /** @file Specify preconditions, old value copies at body, postconditions, and exception guarantees @@ -65,7 +63,7 @@ specified in that order. #define BOOST_CONTRACT_SPECIFY_CLASS_IMPL_(class_type, cond_type) \ /* (default) constructor */ \ class_type() {} \ - /* copy operations (private to force `auto c = ...` error) */ \ + /* copy operations (decl. private to force `auto c = ...` error) */ \ class_type(class_type const&) {} \ class_type& operator=(class_type const&) {} diff --git a/include/boost/contract/detail/inlined/core/exception.hpp b/include/boost/contract/detail/inlined/core/exception.hpp index 02f2486..66ba9be 100644 --- a/include/boost/contract/detail/inlined/core/exception.hpp +++ b/include/boost/contract/detail/inlined/core/exception.hpp @@ -55,11 +55,11 @@ char const* assertion_failure::what() const BOOST_NOEXCEPT_OR_NOTHROW { return what_.c_str(); } -char const* const assertion_failure::file() const { return file_; } +char const* assertion_failure::file() const { return file_; } unsigned long assertion_failure::line() const { return line_; } -char const* const assertion_failure::code() const { return code_; } +char const* assertion_failure::code() const { return code_; } void assertion_failure::init() { std::ostringstream text; diff --git a/include/boost/contract/old.hpp b/include/boost/contract/old.hpp index fd58d57..edd3e91 100644 --- a/include/boost/contract/old.hpp +++ b/include/boost/contract/old.hpp @@ -76,25 +76,41 @@ value pointer. The expression expanded by this macro should be assigned to an old value pointer of type @RefClass{boost::contract::old_ptr} or @RefClass{boost::contract::old_ptr_if_copyable}. +This is an overloaded variadic macro and it can be used in the following +different ways. + +1\. From within virtual public functions and public functions overrides: + +@code +BOOST_CONTRACT_OLDOF(v, expr) +@endcode + +2\. From all other operations: + +@code +BOOST_CONTRACT_OLDOF(expr) +@endcode + +Where: + +@arg v is the extra parameter of type + @RefClass{boost::contract::virtual_}* and default value @c 0 + from the enclosing virtual public function or public function + overrides declaring the contract. + (This is not a variadic macro parameter so any comma it might contain + must be protected by round parenthesis, but + BOOST_CONTRACT_OLDOF((v), expr) will always work.) +@arg expr is the expression to be evaluated and copied in + the old value pointer. + (This is not a variadic macro parameter so any comma it might contain + must be protected by round parenthesis, but + BOOST_CONTRACT_OLDOF(v, (expr)) will always work.) -This is a variadic macro. On compilers that do not support variadic macros, programmers can manually copy old value expressions without using this macro (see @RefSect{extra_topics.no_macros__no_c__11_, No Macros}). @see @RefSect{tutorial.old_values, Old Values} - -@param ... This macro usually takes a single parameter as the old value - expression to be copied (e.g., @c BOOST_CONTRACT_OLDOF(expr)). - However, for virtual public functions and public functions overrides - the extra parameter of type - @RefClass{boost::contract::virtual_}* must be passed to - this macro as well and before the old value expression to be copied - (e.g., @c BOOST_CONTRACT_OLDOF(v, expr)). - In either case, any comma the old value expression might contain - must be protected by round parenthesis (i.e., - @c BOOST_CONTRACT_OLDOF((expr)) and - BOOST_CONTRACT_OLDOF(v, ((expr))) will always work). */ #define BOOST_CONTRACT_OLDOF(...) \ BOOST_PP_CAT( /* CAT(..., EMTPY()) required on MSVC */ \ @@ -175,22 +191,23 @@ that are copyable (i.e., for which Old Value Requirements} */ template // Used only if is_old_value_copyable. -class old_value_copy { -public: +struct old_value_copy { /** Construct this object by making a copy of the specified old value. This is the operation within this library that makes the one single copy of old values. - */ - explicit old_value_copy(T const& value) : - value_(value) {} // This makes the one single copy of T. - /** Return a (constant) reference to the old value copy. */ - T const& value() const { return value_; } + @param old The old value to copy. + */ + explicit old_value_copy(T const& old) : + old_(old) {} // This makes the one single copy of T. + + /** Return a (constant) reference to the old value that was copied. */ + T const& old() const { return old_; } private: - T const value_; + T const old_; }; template @@ -322,8 +339,6 @@ public: /** Construct this old value pointer as null. */ old_ptr_if_copyable() {} - // TODO: Document that auto old_x = BOOST_CONTRACT_OLDOF(...) will use old_ptr and not old_ptr_if_copyable (auto will by default not use old_ptr_if_conpyable because old_ptr is more stringent from a type requirement prospective, if users want to relax the copyable type requirements they need to explicitly use old_ptr_if_copyable instead of using auto). - /** Construct this old value pointer from from an old value pointer of copyable-only type. @@ -353,7 +368,7 @@ public: */ T const& operator*() const { BOOST_CONTRACT_DETAIL_DEBUG(typed_copy_); - return typed_copy_->value(); + return typed_copy_->old(); } /** diff --git a/include/boost/contract/override.hpp b/include/boost/contract/override.hpp index 1d8c419..79ed655 100644 --- a/include/boost/contract/override.hpp +++ b/include/boost/contract/override.hpp @@ -94,6 +94,9 @@ Handle public function overrides (for subcontracting). @see @RefSect{advanced_topics.named_overrides, Named Overrides} @param override_name Name of the override type being declared. + (This is not a variadic macro parameter but it will + never contain any comma because it is an + identifier.) @param function_name Function name of the public function override. This macro is called just once even if the function name is overloaded and the same override type is @@ -101,6 +104,9 @@ Handle public function overrides (for subcontracting). name (see @RefSect{advanced_topics.function_overloads, Function Overloads}). + (This is not a variadic macro parameter but it will + never contain any comma because it is an + identifier.) */ #define BOOST_CONTRACT_NAMED_OVERRIDE(override_name, function_name) \ struct override_name {}; /* empty (not used), just to compile */ @@ -124,6 +130,8 @@ Declare the override type to be passed as an explicit template parameter to name (see @RefSect{advanced_topics.function_overloads, Function Overloads}). + (This is not a variadic macro parameter but it will + never contain any comma because it is an identifier.) */ #define BOOST_CONTRACT_OVERRIDE(function_name) \ BOOST_CONTRACT_NAMED_OVERRIDE(BOOST_PP_CAT(override_, function_name), \ @@ -156,6 +164,8 @@ Declare the override type to be passed as an explicit template parameter to @param ... A comma separated list of one or more function names of public function overrides. + (Each function name will never contain any commas because it is + an identifier.) */ #define BOOST_CONTRACT_OVERRIDES(...) \ BOOST_PP_SEQ_FOR_EACH(BOOST_CONTRACT_OVERRIDES_SEQ_, ~, \ diff --git a/include/boost/contract_macro.hpp b/include/boost/contract_macro.hpp index b25fdd0..8436b12 100644 --- a/include/boost/contract_macro.hpp +++ b/include/boost/contract_macro.hpp @@ -10,6 +10,10 @@ /** @file Completely disable run-time and compile-time overheads of contract code. +This header also includes all headers file boost/contract/\*.hpp are +necessary to use this macro (including the ones that define ASSERT, virtual_, +access, OVERRIDE, BASE_TYPES, CHECK, constructor_precondition, etc.) + Almost all the macros defined in this header file are variadic macros. On compilers that do not support variadic macros, programmers can manually code #ifndef BOOST_CONTRACT_NO_... statements instead (see @@ -39,12 +43,6 @@ Disable Contract Compilation}). #include #endif -// TODO: Document these macros will cause all pre, post, inv assertions to have the same line number (but different code text) in the error message. And that is bad for compiler errors while programming contracts as well (all on same line... and more cryptic). - -// TODO: Add tests for all variadic macros defined here (with unwrapped commas in code, types, etc.). - -// TODO: Make sure there are test for /all/ these macros (OLD_PTR_IF_COPYABLE, EXPECT, INVARIANT_VOLATILE, etc.). - #ifndef BOOST_CONTRACT_NO_PRECONDITIONS #define BOOST_CONTRACT_PRECONDITION(...) .precondition(__VA_ARGS__) #else @@ -70,8 +68,8 @@ Disable Contract Compilation}). @RefFunc{boost::contract::precondition_failure}). This functor should capture variables by (constant) value, or better by (constant) reference (to avoid extra copies). - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @see @RefSect{tutorial.preconditions, Preconditions}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -108,8 +106,8 @@ Disable Contract Compilation}). This functor takes the return value as its one single parameter but only for virtual public functions and public functions overrides, otherwise it takes no parameter. - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @see @RefSect{tutorial.postconditions, Postconditions}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -144,8 +142,8 @@ Disable Contract Compilation}). @RefFunc{boost::contract::except_failure}). This functor should capture variables by (constant) references (to access the values they will have at function exit). - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @see @RefSect{tutorial.exception_guarantees, Exception Guarantees}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -214,8 +212,8 @@ Disable Contract Compilation}). can be assigned (all other variables needed to evaluate old value expressions can be captured by (constant) value, or better by (constant) reference to avoid extra copies). - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @see @RefSect{advanced_topics.old_values_at_body, Old Values at Body}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -267,19 +265,23 @@ Disable Contract Compilation}). otherwise this pointer will always be null and this library will generate a compile-time error when the pointer is dereferenced (but see also @c BOOST_CONTRACT_OLD_PTR_IF_COPYABLE). - This is a variadic macro - parameter so it can contain commas not protected by round - parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @arg v is the extra parameter of type @RefClass{boost::contract::virtual_}* and default value @c 0 from the enclosing virtual public function or public function overrides declaring the contract. + (This is not a variadic macro parameter so any comma it might + contain must be protected by round parenthesis, but + BOOST_CONTRACT_OLD_PTR(T)((v), ptr, expr) will always work.) @arg ptr is the name of the old value pointer variable. + (This is not a variadic macro parameter but it will never contain + any comma because it is an identifier.) @arg expr is the expression to be evaluated and copied in the old value pointer. - This is not a variadic macro parameter so any comma it might - contain must be protected by round parenthesis (i.e., - BOOST_CONTRACT_OLD_PTR(T)(v, ptr, (expr)) will always work). + (This is not a variadic macro parameter so any comma it might + contain must be protected by round parenthesis, but + BOOST_CONTRACT_OLD_PTR(T)(v, ptr, (expr)) will always work.) @see @RefSect{tutorial.old_values, Old Values}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -333,19 +335,25 @@ Disable Contract Compilation}). @c false), this pointer will always be null, but this library will not generate a compile-time error when this pointer is dereferenced (see also @c BOOST_CONTRACT_OLD_PTR). - This is a variadic macro - parameter so it can contain commas not protected by round - parenthesis. - @arg v is the extra parameter of type + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) + @arg v is the extra parameter of type @RefClass{boost::contract::virtual_}* and default value @c 0 from the enclosing virtual public function or public function overrides declaring the contract. + (This is not a variadic macro parameter so any comma it might + contain must be protected by round parenthesis, but + BOOST_CONTRACT_OLD_PTR_IF_COPYABLE(T)((v), ptr, expr) will + always work.) @arg ptr is the name of the old value pointer variable. + (This is not a variadic macro parameter but it will never contain + any commas because it is an identifier.) @arg expr is the expression to be evaluated and copied in the old value pointer. - This is not a variadic macro parameter so any comma it might - contain must be protected by round parenthesis (i.e., - BOOST_CONTRACT_OLD_PTR(T)(v, ptr, (expr)) will always work). + (This is not a variadic macro parameter so any comma it might + contain must be protected by round parenthesis, but + BOOST_CONTRACT_OLD_PTR_IF_COPYABLE(T)(v, ptr, (expr)) will + always work.) @see @RefSect{extra_topics.old_value_requirements__templates_, Old Value Requirements}, @@ -393,8 +401,8 @@ Disable Contract Compilation}). result in this library calling either @RefFunc{boost::contract::entry_invariant_failure} or @RefFunc{boost::contract::exit_invariant_failure}). - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @see @RefSect{tutorial.class_invariants, Class Invariants}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -428,8 +436,8 @@ Disable Contract Compilation}). result in this library calling either @RefFunc{boost::contract::entry_invariant_failure} or @RefFunc{boost::contract::exit_invariant_failure}). - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @see @RefSect{extra_topics.volatile_public_functions, Volatile Public Functions}, @@ -464,8 +472,8 @@ Disable Contract Compilation}). result in this library calling either @RefFunc{boost::contract::entry_invariant_failure} or @RefFunc{boost::contract::exit_invariant_failure}). - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @see @RefSect{tutorial.class_invariants, Class Invariants}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -491,8 +499,8 @@ Disable Contract Compilation}). @code #ifndef BOOST_CONTRACT_NO_CONSTRUCTORS - boost::contract::check internal_identifier = - boost::contract::constructor(obj) + boost::contract::check internal_var = boost::contract:: + constructor(obj) #endif @endcode @@ -500,15 +508,17 @@ Disable Contract Compilation}). @arg obj is the object @c this from the scope of the enclosing constructor declaring the contract. - (Constructors check all class invariants, including static and - volatile invariants, see also @RefSect{tutorial.class_invariants, + Constructors check all class invariants, including static and + volatile invariants (see also @RefSect{tutorial.class_invariants, Class Invariants} and @RefSect{advanced_topics.volatile_public_functions, Volatile Public Functions}). - @arg internal_identifier is a variable name internally - generated by this library (this is unique but only on different - lines so this macro cannot be expanded multiple times on the same - line number). + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) + @arg internal_var is a variable name internally generated + by this library (this name is unique but only on different lines so + this macro cannot be expanded multiple times on the same line + number). @see @RefSect{tutorial.constructors, Constructors}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -549,8 +559,8 @@ Disable Contract Compilation}). @arg Class is the class type of the constructor for which preconditions are being programmed. - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @arg f is the nullary functor called by this library to check constructor preconditions @c f(). Assertions within this functor call are usually programmed using @@ -560,8 +570,8 @@ Disable Contract Compilation}). @RefFunc{boost::contract::precondition_failure}). This functor should capture variables by (constant) value, or better by (constant) reference to avoid extra copies. - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) @see @RefSect{tutorial.constructors, Constructors}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -591,8 +601,8 @@ Disable Contract Compilation}). @code #ifndef BOOST_CONTRACT_NO_DESTRUCTORS - boost::contract::check internal_identifier = - boost::contract::destructor(obj) + boost::contract::check internal_var = boost::contract:: + destructor(obj) #endif @endcode @@ -600,15 +610,17 @@ Disable Contract Compilation}). @arg obj is the object @c this from the scope of the enclosing destructor declaring the contract. - (Destructors check all class invariants, including static and - volatile invariants, see also @RefSect{tutorial.class_invariants, + Destructors check all class invariants, including static and + volatile invariants (see also @RefSect{tutorial.class_invariants, Class Invariants} and @RefSect{advanced_topics.volatile_public_functions, Volatile Public Functions}). - @arg internal_identifier is a variable name internally - generated by this library (this is unique but only on different - lines so this macro cannot be expanded multiple times on the same - line number). + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) + @arg internal_var is a variable name internally generated + by this library (this name is unique but only on different lines so + this macro cannot be expanded multiple times on the same line + number). @see @RefSect{tutorial.destructors, Destructors}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -649,8 +661,8 @@ Disable Contract Compilation}). @code #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS - boost::contract::check internal_identifier = - boost::contract::public_function(obj) + boost::contract::check internal_var = boost::contract:: + public_function(obj) #endif @endcode @@ -660,8 +672,8 @@ Disable Contract Compilation}). @code #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS - boost::contract::check internal_identifier = - boost::contract::public_function(v, obj) + boost::contract::check internal_var = boost::contract:: + public_function(v, obj) #endif @endcode @@ -671,13 +683,13 @@ Disable Contract Compilation}). @code #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS - boost::contract::check internal_identifier = - boost::contract::public_function(v, r, obj) + boost::contract::check internal_var = boost::contract:: + public_function(v, r, obj) #endif @endcode - Where: - + Where (these are all variadic macro parameters so they can contain commas + not protected by round parenthesis): @arg v is the extra parameter of type @RefClass{boost::contract::virtual_}* and default value @c 0 @@ -695,10 +707,10 @@ Disable Contract Compilation}). function (volatile public functions will check volatile class invariants, see @RefSect{extra_topics.volatile_public_functions, Volatile Public Functions}). - @arg internal_identifier is a variable name internally - generated by this library (this is unique but only on different - lines so this macro cannot be expanded multiple times on the same - line number). + @arg internal_var is a variable name internally generated + by this library (this name is unique but only on different lines so + this macro cannot be expanded multiple times on the same line + number). @see @RefSect{tutorial.public_functions, Public Functions}, @RefSect{tutorial.virtual_public_functions, @@ -721,7 +733,7 @@ Disable Contract Compilation}). @code #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS - boost::contract::check internal_identifier = boost::contract:: + boost::contract::check internal_var = boost::contract:: public_function(v, f, obj, ...) #endif @endcode @@ -732,19 +744,18 @@ Disable Contract Compilation}). @code #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS - boost::contract::check internal_identifier = boost::contract:: + boost::contract::check internal_var = boost::contract:: public_function(v, r, f, obj, ...) #endif @endcode - Where: + Where (these are all variadic macro parameters so they can contain commas + not protected by round parenthesis): @arg Override is the type override_function-name declared using the @RefMacro{BOOST_CONTRACT_OVERRIDE} (or equivalent) macro from the enclosing function name. - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. @arg v is the extra parameter of type @RefClass{boost::contract::virtual_}* and default value @c 0 from the enclosing virtual public function declaring the contract. @@ -767,10 +778,10 @@ Disable Contract Compilation}). arguments passed to the enclosing public function override declaring the contract (by reference and in order they appear in the enclosing function declaration), but excluding the trailing argument @c v. - @arg internal_identifier is a variable name internally - generated by this library (this is unique but only on different - lines so this macro cannot be expanded multiple times on the same - line number). + @arg internal_var is a variable name internally generated + by this library (this name is unique but only on different lines so + this macro cannot be expanded multiple times on the same line + number). @see @RefSect{tutorial.public_function_overrides, Public Function Overrides}, @@ -789,8 +800,8 @@ Disable Contract Compilation}). @code #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS - boost::contract::check internal_identifier = - boost::contract::public_function() + boost::contract::check internal_var = boost::contract:: + public_function() #endif @endcode @@ -798,12 +809,12 @@ Disable Contract Compilation}). @arg Class is the class type of the enclosing static public function declaring the contract. - This is a variadic macro parameter so it can contain commas not - protected by round parenthesis. - @arg internal_identifier is a variable name internally - generated by this library (this is unique but only on different - lines so this macro cannot be expanded multiple times on the same - line number). + (This is a variadic macro parameter so it can contain commas not + protected by round parenthesis.) + @arg internal_var is a variable name internally generated + by this library (this name is unique but only on different lines so + this macro cannot be expanded multiple times on the same line + number). @see @RefSect{tutorial.static_public_functions, Static Public Functions}, @RefSect{extra_topics.disable_contract_compilation__macro_interface_, @@ -835,17 +846,17 @@ Disable Contract Compilation}). @code #ifndef BOOST_CONTRACT_NO_FUNCTIONS - boost::contract::check internal_identifier = - boost::contract::function() + boost::contract::check internal_var = boost::contract:: + function() #endif @endcode Where: - @arg internal_identifier is a variable name internally - generated by this library (this is unique but only on different - lines so this macro cannot be expanded multiple times on the same - line number). + @arg internal_far is a variable name internally generated + by this library (this name is unique but only on different lines so + this macro cannot be expanded multiple times on the same line + number). @see @RefSect{tutorial.non_member_functions, Non-Member Functions}, @RefSect{advanced_topics.private_and_protected_functions, diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 74597fc..56944b2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -139,6 +139,7 @@ test-suite public_function : [ subdir-run public_function : protected ] [ subdir-compile-fail public_function : protected_error ] + [ subdir-run public_function : friend ] [ subdir-run public_function : throwing_pre ] [ subdir-run public_function : throwing_old ] @@ -186,6 +187,9 @@ test-suite invariant : [ subdir-run invariant : decl_cv ] [ subdir-run invariant : decl_const ] [ subdir-run invariant : decl_nothing ] + + [ subdir-run invariant : ifdef ] + [ subdir-run invariant : ifdef_macro ] [ subdir-compile-fail invariant : static_mutable_error ] [ subdir-run invariant : static_mutable_permissive ] @@ -249,6 +253,9 @@ test-suite old : [ subdir-run old : if_copyable ] [ subdir-compile-fail old : if_copyable_error ] + [ subdir-run old : if_copyable_macro ] + + [ subdir-run old : copyable_traits ] ; test-suite disable : diff --git a/test/check/ifdef_macro.cpp b/test/check/ifdef_macro.cpp index 3e77e40..0793a0f 100644 --- a/test/check/ifdef_macro.cpp +++ b/test/check/ifdef_macro.cpp @@ -7,6 +7,7 @@ // Test contract compilation on/off (using macro interface only). #include "../detail/oteststream.hpp" +#include "../detail/unprotected_commas.hpp" #include #include #include @@ -14,10 +15,14 @@ boost::contract::test::detail::oteststream out; void f(bool check) { - BOOST_CONTRACT_CHECK([&] () -> bool { - out << "f::check" << std::endl; - return check; - }()); + BOOST_CONTRACT_CHECK(( + [&] () -> bool { + typedef boost::contract::test::detail::unprotected_commas t1; + out << "f::check" << std::endl; + return check; + }() + )); out << "f::body" << std::endl; } diff --git a/test/constructor/ifdef_macro.cpp b/test/constructor/ifdef_macro.cpp index b57c55b..9163ef1 100644 --- a/test/constructor/ifdef_macro.cpp +++ b/test/constructor/ifdef_macro.cpp @@ -7,6 +7,7 @@ // Test contract compilation on/off (using macro interface). #include "../detail/oteststream.hpp" +#include "../detail/unprotected_commas.hpp" #include #include // Outside #if below for ctor pre. #include @@ -18,18 +19,42 @@ boost::contract::test::detail::oteststream out; struct b : private boost::contract::constructor_precondition // OK, always in code. { - BOOST_CONTRACT_STATIC_INVARIANT({ out << "b::static_inv" << std::endl; }) - BOOST_CONTRACT_INVARIANT({ out << "b::inv" << std::endl; }) + BOOST_CONTRACT_STATIC_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::static_inv" << std::endl; + }) + + BOOST_CONTRACT_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::inv" << std::endl; + }) explicit b(int x) : BOOST_CONTRACT_CONSTRUCTOR_PRECONDITION(b)([] { + typedef boost::contract::test::detail::unprotected_commas< + void, void, void> t; out << "b::ctor::pre" << std::endl; }) { - BOOST_CONTRACT_OLD_PTR(int)(old_x, x); + BOOST_CONTRACT_OLD_PTR( + boost::contract::test::detail::unprotected_commas::type1 + )( + old_x, + (boost::contract::test::detail::unprotected_commasvoid::same(x)) + ); BOOST_CONTRACT_CONSTRUCTOR(this) - BOOST_CONTRACT_OLD([] { out << "b::f::old" << std::endl; }) + BOOST_CONTRACT_OLD([] { + typedef boost::contract::test::detail::unprotected_commas< + void, void, void> t; + out << "b::f::old" << std::endl; + }) BOOST_CONTRACT_POSTCONDITION([] { + typedef boost::contract::test::detail::unprotected_commas< + void, void, void> t; out << "b::ctor::post" << std::endl; }) ; @@ -41,19 +66,44 @@ struct a: private boost::contract::constructor_precondition, // OK, always in code. public b { - BOOST_CONTRACT_STATIC_INVARIANT({ out << "a::static_inv" << std::endl; }) - BOOST_CONTRACT_INVARIANT({ out << "a::inv" << std::endl; }) + BOOST_CONTRACT_STATIC_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::static_inv" << std::endl; + }) + + BOOST_CONTRACT_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::inv" << std::endl; + }) explicit a(int x) : BOOST_CONTRACT_CONSTRUCTOR_PRECONDITION(a)([] { + typedef boost::contract::test::detail::unprotected_commas t; out << "a::ctor::pre" << std::endl; } ), b(x) { - BOOST_CONTRACT_OLD_PTR(int)(old_x, x); - BOOST_CONTRACT_CONSTRUCTOR(this) - BOOST_CONTRACT_OLD([] { out << "a::f::old" << std::endl; }) + BOOST_CONTRACT_OLD_PTR( + boost::contract::test::detail::unprotected_commas::type1 + )( + old_x, + (boost::contract::test::detail::unprotected_commas::same(x)) + ); + BOOST_CONTRACT_CONSTRUCTOR(boost::contract::test::detail:: + unprotected_commas::same(this)) + BOOST_CONTRACT_OLD([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::f::old" << std::endl; + }) BOOST_CONTRACT_POSTCONDITION([] { + typedef boost::contract::test::detail::unprotected_commas t; out << "a::ctor::post" << std::endl; }) ; diff --git a/test/destructor/ifdef_macro.cpp b/test/destructor/ifdef_macro.cpp index 343ef8c..270f0e9 100644 --- a/test/destructor/ifdef_macro.cpp +++ b/test/destructor/ifdef_macro.cpp @@ -7,6 +7,7 @@ // Test contract compilation on/off (using macro interface). #include "../detail/oteststream.hpp" +#include "../detail/unprotected_commas.hpp" #include #include #include @@ -15,14 +16,37 @@ boost::contract::test::detail::oteststream out; struct b { - BOOST_CONTRACT_STATIC_INVARIANT({ out << "b::static_inv" << std::endl; }) - BOOST_CONTRACT_INVARIANT({ out << "b::inv" << std::endl; }) + BOOST_CONTRACT_STATIC_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::static_inv" << std::endl; + }) + + BOOST_CONTRACT_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::inv" << std::endl; + }) virtual ~b() { - BOOST_CONTRACT_OLD_PTR(int)(old_y, y); - BOOST_CONTRACT_DESTRUCTOR(this) - BOOST_CONTRACT_OLD([] { out << "b::dtor::old" << std::endl; }) + BOOST_CONTRACT_OLD_PTR( + boost::contract::test::detail::unprotected_commas::type1 + )( + old_y, + (boost::contract::test::detail::unprotected_commas::same(y)) + ); + BOOST_CONTRACT_DESTRUCTOR(boost::contract::test::detail:: + unprotected_commas::same(this)) + BOOST_CONTRACT_OLD([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::dtor::old" << std::endl; + }) BOOST_CONTRACT_POSTCONDITION([] { + typedef boost::contract::test::detail::unprotected_commas t; out << "b::dtor::post" << std::endl; }) ; @@ -34,14 +58,37 @@ struct b { int b::y = 0; struct a : public b { - BOOST_CONTRACT_STATIC_INVARIANT({ out << "a::static_inv" << std::endl; }) - BOOST_CONTRACT_INVARIANT({ out << "a::inv" << std::endl; }) + BOOST_CONTRACT_STATIC_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::static_inv" << std::endl; + }) + + BOOST_CONTRACT_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::inv" << std::endl; + }) virtual ~a() { - BOOST_CONTRACT_OLD_PTR(int)(old_x, x); - BOOST_CONTRACT_DESTRUCTOR(this) - BOOST_CONTRACT_OLD([] { out << "a::dtor::old" << std::endl; }) + BOOST_CONTRACT_OLD_PTR( + boost::contract::test::detail:uunprotected_commas::type1 + )( + old_x, + (boost::contract::test::detail:uunprotected_commas::same(x)) + ); + BOOST_CONTRACT_DESTRUCTOR(boost::contract::test::detail:: + unprotected_commas::same(this)) + BOOST_CONTRACT_OLD([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::dtor::old" << std::endl; + }) BOOST_CONTRACT_POSTCONDITION([] { + typedef boost::contract::test::detail::unprotected_commas t; out << "a::dtor::post" << std::endl; }) ; diff --git a/test/detail/unprotected_commas.hpp b/test/detail/unprotected_commas.hpp new file mode 100644 index 0000000..ff86d3c --- /dev/null +++ b/test/detail/unprotected_commas.hpp @@ -0,0 +1,24 @@ + +#ifndef BOOST_CONTRACT_TEST_DETAIL_UNPROTECTED_COMMAS_HPP_ +#define BOOST_CONTRACT_TEST_DETAIL_UNPROTECTED_COMMAS_HPP_ + +// Copyright (C) 2008-2016 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +namespace boost { namespace contract { namespace test { namespace detail { + +// Used to test passing unprotected commas into macro parameters. +template +struct unprotected_commas { + typedef T1 type1; // For type and code block macro parameters. + + template + static U& same(U& x) { return x; } // For value macro parameters. +}; + +} } } } // namespace + +#endif // #include guard + diff --git a/test/function/ifdef_macro.cpp b/test/function/ifdef_macro.cpp index 0f26f31..f66d4f2 100644 --- a/test/function/ifdef_macro.cpp +++ b/test/function/ifdef_macro.cpp @@ -4,27 +4,56 @@ // 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 -// Test contract compilation on/off (using macro interface). +// Test contract compilation on/off (including EXCEPT, using macro interface). #include "../detail/oteststream.hpp" +#include "../detail/unprotected_commas.hpp" #include #include #include boost::contract::test::detail::oteststream out; +struct except_error {}; + void f(int x) { - BOOST_CONTRACT_OLD_PTR(int)(old_x, x); + BOOST_CONTRACT_OLD_PTR( + boost::contract::test::detail::unprotected_commas:: + type1 + )( + old_x, + (boost::contract::test::detail::unprotected_commas:: + same(x)) + ); BOOST_CONTRACT_FUNCTION() - BOOST_CONTRACT_PRECONDITION([] { out << "f::pre" << std::endl; }) - BOOST_CONTRACT_OLD([] { out << "f::old" << std::endl; }) - BOOST_CONTRACT_POSTCONDITION([] { out << "f::post" << std::endl; }) + BOOST_CONTRACT_PRECONDITION([] { + typedef boost::contract::test::detail::unprotected_commas< + void, void, void> t; + out << "f::pre" << std::endl; + }) + BOOST_CONTRACT_OLD([] { + typedef boost::contract::test::detail::unprotected_commas< + void, void, void> t; + out << "f::old" << std::endl; + }) + BOOST_CONTRACT_POSTCONDITION([] { + typedef boost::contract::test::detail::unprotected_commas< + void, void, void> t; + out << "f::post" << std::endl; + }) + BOOST_CONTRACT_EXCEPT([] { // Test EXCEPT macro (at least 1 time here). + typedef boost::contract::test::detail::unprotected_commas< + void, void, void> t; + out << "f::except" << std::endl; + }) ; out << "f::body" << std::endl; + if(x == -1) throw except_error(); } int main() { std::ostringstream ok; + out.str(""); f(123); ok.str(""); ok @@ -40,6 +69,27 @@ int main() { #endif ; BOOST_TEST(out.eq(ok.str())); + + boost::contract::set_except_failure([] (boost::contract::from) {}); + out.str(""); + try { + f(-1); // Test throw and EXCEPT macro (test only here... that's fine). + BOOST_TEST(false); + } catch(except_error const&) {} // OK. + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + << "f::pre" << std::endl + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + << "f::old" << std::endl + #endif + << "f::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXCEPTS + << "f::except" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + return boost::report_errors(); } diff --git a/test/invariant/decl.hpp b/test/invariant/decl.hpp index e11a4dc..15d3705 100644 --- a/test/invariant/decl.hpp +++ b/test/invariant/decl.hpp @@ -18,6 +18,7 @@ #include #include #include +#include boost::contract::test::detail::oteststream out; diff --git a/test/invariant/ifdef.cpp b/test/invariant/ifdef.cpp new file mode 100644 index 0000000..3f4e0a5 --- /dev/null +++ b/test/invariant/ifdef.cpp @@ -0,0 +1,174 @@ + +// Copyright (C) 2008-2016 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +// Test invariant compilation on/off. + +#include "../detail/oteststream.hpp" +#include +#include +#include +#include +#include +#include + +boost::contract::test::detail::oteststream out; + +class a { +public: + #ifndef BOOST_CONTRACT_NO_INVARIANTS + static void static_invariant() { + out << "a::static_inv" << std::endl; + } + + void invariant() const volatile { + out << "a::cv_inv" << std::endl; + } + + void invariant() const { + out << "a::const_inv" << std::endl; + } + #endif + + a() { // Test check both cv and const invariant (at exit if no throw). + #ifndef BOOST_CONTRACT_NO_CONSTRUCTORS + boost::contract::check c= boost::contract::constructor(this); + #endif + out << "a::ctor::body" << std::endl; + } + + ~a() { // Test check both cv and const invariant (at entry). + #ifndef BOOSTT_CONTRACT_NO_DESTRUCTORS + boost::contract::check c = boost::contract::destructor(this); + #endif + out << "a::dtor::body" << std::endl; + } + + void m() { // Test check const invariant (at entry and exit). + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + boost::contract::check c = boost::contract::public_function(this); + #endif + out << "a::m::body" << std::endl; + } + + void c() const { // Test check const invariant (at entry and exit). + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + boost::contract::check c = boost::contract::public_function(this); + #endif + out << "a::c::body" << std::endl; + } + + void v() volatile { // Test check cv invariant (at entry and exit). + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + boost::contract::check c = boost::contract::public_function(this); + #endif + out << "a::v::body" << std::endl; + } + + void cv() const volatile { // Test check cv invariant (at entry and exit). + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + boost::contract::check c = boost::contract::public_function(this); + #endif + out << "a::cv::body" << std::endl; + } +}; + +int main() { + std::ostringstream ok; + + { + out.str(""); + a aa; + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + #endif + << "a::ctor::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + << "a::const_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + aa.m(); + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::const_inv" << std::endl + #endif + << "a::m::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::const_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + aa.c(); + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::const_inv" << std::endl + #endif + << "a::c::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::const_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + aa.v(); + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + #endif + << "a::v::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + aa.cv(); + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + #endif + << "a::cv::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + } // Call dtor. + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + << "a::const_inv" << std::endl + #endif + << "a::dtor::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/invariant/ifdef_macro.cpp b/test/invariant/ifdef_macro.cpp new file mode 100644 index 0000000..82eee3c --- /dev/null +++ b/test/invariant/ifdef_macro.cpp @@ -0,0 +1,170 @@ + +// Copyright (C) 2008-2016 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +// Test invariant compilation on/off (using macro interface). + +#include "../detail/oteststream.hpp" +#include "../detail/unprotected_commas.hpp" +#include +#include +#include + +boost::contract::test::detail::oteststream out; + +class a { +public: + BOOST_CONTRACT_STATIC_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas::type1 t; + out << "a::static_inv" << std::endl; + }) + + BOOST_CONTRACT_INVARIANT_VOLATILE({ + typedef boost::contract::test::detail::unprotected_commas::type1 t; + out << "a::cv_inv" << std::endl; + }) + + BOOST_CONTRACT_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas::type1 t; + out << "a::const_inv" << std::endl; + }) + + a() { // Test check both cv and const invariant (at exit if no throw). + BOOST_CONTRACT_CONSTRUCTOR(boost::contract::test::detail:: + unprotected_commas::same(this)); + out << "a::ctor::body" << std::endl; + } + + ~a() { // Test check both cv and const invariant (at entry). + BOOST_CONTRACT_DESTRUCTOR(boost::contract::test::detail:: + unprotected_commas::same(this)); + out << "a::dtor::body" << std::endl; + } + + void m() { // Test check const invariant (at entry and exit). + BOOST_CONTRACT_PUBLIC_FUNCTION(boost::contract::test::detail:: + unprotected_commas::same(this)); + out << "a::m::body" << std::endl; + } + + void c() const { // Test check const invariant (at entry and exit). + BOOST_CONTRACT_PUBLIC_FUNCTION(boost::contract::test::detail:: + unprotected_commas::same(this)); + out << "a::c::body" << std::endl; + } + + void v() volatile { // Test check cv invariant (at entry and exit). + BOOST_CONTRACT_PUBLIC_FUNCTION(boost::contract::test::detail:: + unprotected_commas::same(this)); + out << "a::v::body" << std::endl; + } + + void cv() const volatile { // Test check cv invariant (at entry and exit). + BOOST_CONTRACT_PUBLIC_FUNCTION(boost::contract::test::detail:: + unprotected_commas::same(this)); + out << "a::cv::body" << std::endl; + } +}; + +int main() { + std::ostringstream ok; + + { + out.str(""); + a aa; + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + #endif + << "a::ctor::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + << "a::const_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + aa.m(); + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::const_inv" << std::endl + #endif + << "a::m::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::const_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + aa.c(); + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::const_inv" << std::endl + #endif + << "a::c::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::const_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + aa.v(); + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + #endif + << "a::v::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + aa.cv(); + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + #endif + << "a::cv::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + } // Call dtor. + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + << "a::static_inv" << std::endl + << "a::cv_inv" << std::endl + << "a::const_inv" << std::endl + #endif + << "a::dtor::body" << std::endl + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + << "a::static_inv" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/old/copyable_traits.cpp b/test/old/copyable_traits.cpp new file mode 100644 index 0000000..83c8150 --- /dev/null +++ b/test/old/copyable_traits.cpp @@ -0,0 +1,106 @@ + +// Copyright (C) 2008-2016 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +// Test specializations of old value copy type traits. + +#include +#include +#include +#include +#include + +template +void f(T& x) { + boost::contract::old_ptr_if_copyable old_x = BOOST_CONTRACT_OLDOF(x); +} + +// Test copyable type but... +struct w { + w() {} + w(w const&) { BOOST_TEST(false); } // Test this doesn't get copied. +}; + +// ...never copy old values for type `w` (because its copy is too expensive). +namespace boost { namespace contract { + template<> + struct is_old_value_copyable : boost::false_type {}; +} } // namespace + +// Test non-copyable type but... +struct p : private boost::noncopyable { // Non-copyable via Boost. + static bool copied; + p() : num_(new int(0)) {} + ~p() { delete num_; } +private: + int* num_; + friend struct boost::contract::old_value_copy

; +}; +bool p::copied = false; + +// ...still copy old values for type `p` (using a deep copy). +namespace boost { namespace contract { + template<> + struct old_value_copy

{ + explicit old_value_copy(p const& old) { + *old_.num_ = *old.num_; // Deep copy pointed value. + p::copied = true; + } + + p const& old() const { return old_; } + + private: + p old_; + }; + + template<> + struct is_old_value_copyable

: boost::true_type {}; +} } // namespace + +// Non-copyable type so... +struct n { + n() {} +private: + n(n const&); // Non-copyable (but not via Boost). +}; + +// ...specialize `boost::is_copy_constructible` (no need for this on C++11). +namespace boost { namespace contract { + template<> + struct is_old_value_copyable : boost::false_type {}; +} } // namespace + +int main() { + // NOTE: No test::detail::counter below because that is for copyable types. + + { + int x; // Test has copy ctor so copy olds. + f(x); + } + + { + w x; // Test has copy ctor but never copy olds (see TEST(...) above). + f(x); + } + + p::copied = false; + { + p x; // Test no copy ctor but still old copies. + f(x); + } + #ifndef BOOST_CONTRACT_NO_OLDS + BOOST_TEST(p::copied); + #else + BOOST_TEST(!p::copied); + #endif + + { + n x; // Test no copy ctor so no old copies. + f(x); + } + + return boost::report_errors(); +} + diff --git a/test/old/if_copyable.cpp b/test/old/if_copyable.cpp index 85a18ce..a19ac21 100644 --- a/test/old/if_copyable.cpp +++ b/test/old/if_copyable.cpp @@ -23,7 +23,7 @@ template struct b { virtual void next(T& x, boost::contract::virtual_* v = 0) { boost::contract::old_ptr_if_copyable old_x = - BOOST_CONTRACT_OLD(v, x); + BOOST_CONTRACT_OLDOF(v, x); boost::contract::check c = boost::contract::public_function(v, this) .postcondition([&] { if(old_x) { @@ -47,7 +47,7 @@ struct a virtual void next(T& x, boost::contract::virtual_* v = 0) /* override */ { boost::contract::old_ptr_if_copyable old_x = - BOOST_CONTRACT_OLD(v, x); + BOOST_CONTRACT_OLDOF(v, x); boost::contract::check c = boost::contract::public_function< override_next>(v, &a::next, this, x) .postcondition([&] { @@ -64,7 +64,7 @@ struct a template void next(T& x) { - boost::contract::old_ptr_if_copyable old_x = BOOST_CONTRACT_OLD(x); + boost::contract::old_ptr_if_copyable old_x = BOOST_CONTRACT_OLDOF(x); boost::contract::check c = boost::contract::function() .postcondition([&] { if(old_x) { diff --git a/test/old/if_copyable_macro.cpp b/test/old/if_copyable_macro.cpp new file mode 100644 index 0000000..18b1083 --- /dev/null +++ b/test/old/if_copyable_macro.cpp @@ -0,0 +1,172 @@ + +// Copyright (C) 2008-2016 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +// Test old values of non-copyable types (using macro interface). + +#include "if_copyable.hpp" +#include "../detail/unprotected_commas.hpp" +#include +#include +#include + +unsigned old_checks; + +template +struct b { + virtual void next(T& x, boost::contract::virtual_* v = 0) { + BOOST_CONTRACT_OLD_PTR_IF_COPYABLE( + typename boost::contract::test::detail::unprotected_commas::type1 + )( + (boost::contract::test::detail::unprotected_commas::same(v)), + old_x, + (boost::contract::test::detail::unprotected_commas::same(x)) + ); + BOOST_CONTRACT_PUBLIC_FUNCTION( + boost::contract::test::detail::unprotected_commas::same(v), + boost::contract::test::detail::unprotected_commas::same(this) + ) + BOOST_CONTRACT_POSTCONDITION([&] { + typedef boost::contract::test::detail::unprotected_commas t; + if(old_x) { + BOOST_CONTRACT_ASSERT(x == *old_x + T(1)); + ++old_checks; + } + }) + ; + ++x; + } + BOOST_CONTRACT_OVERRIDE(next) +}; + +template +struct a + #define BASES public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + virtual void next(T& x, boost::contract::virtual_* v = 0) /* override */ { + BOOST_CONTRACT_OLD_PTR_IF_COPYABLE( + typename boost::contract::test::detail::unprotected_commas::type1 + )( + (boost::contract::test::detail::unprotected_commas::same(v)), + old_x, + (boost::contract::test::detail::unprotected_commas::same(x)) + ); + BOOST_CONTRACT_PUBLIC_FUNCTION_OVERRIDE( + typename boost::contract::test::detail::unprotected_commas< + override_next, void, void>::type1 + )( + boost::contract::test::detail::unprotected_commas::same(v), + &a::next, + boost::contract::test::detail::unprotected_commas::same(this), + boost::contract::test::detail::unprotected_commas::same(x) + ) + BOOST_CONTRACT_POSTCONDITION([&] { + typedef boost::contract::test::detail::unprotected_commas t; + if(old_x) { + BOOST_CONTRACT_ASSERT(x == *old_x + T(1)); + ++old_checks; + } + }) + ; + ++x; + } + BOOST_CONTRACT_OVERRIDE(next) +}; + +template +void next(T& x) { + BOOST_CONTRACT_OLD_PTR_IF_COPYABLE( + typename boost::contract::test::detail::unprotected_commas::type1 + )( + old_x, + (boost::contract::test::detail::unprotected_commas::same(x)) + ); + BOOST_CONTRACT_FUNCTION() + BOOST_CONTRACT_POSTCONDITION([&] { + typedef boost::contract::test::detail::unprotected_commas t; + if(old_x) { + BOOST_CONTRACT_ASSERT(x == *old_x + T(1)); + ++old_checks; + } + }) + ; + ++x; +} + +int main() { + int i = 1; // Test built-in copyable type. + cp c(1); // Test custom copyable type. + ncp n(1); // Test non-copyable type. + + // Test free functions (old values without `v`). + + unsigned cnt = + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + 1 + #else + 0 + #endif + ; + + old_checks = 0; + next(i); + BOOST_TEST_EQ(old_checks, cnt); + + old_checks = 0; + next(c); + BOOST_TEST_EQ(old_checks, cnt); + + old_checks = 0; + next(n); + BOOST_TEST_EQ(old_checks, 0u); + + // Test virtual functions (old values with `v`). + + cnt = + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + 2 + #else + 0 + #endif + ; + + a ai; + old_checks = 0; + ai.next(i); + BOOST_TEST_EQ(old_checks, cnt); + + a ac; + old_checks = 0; + ac.next(c); + BOOST_TEST_EQ(old_checks, cnt); + + a an; + old_checks = 0; + an.next(n); + BOOST_TEST_EQ(old_checks, 0u); + + return boost::report_errors(); +} + diff --git a/test/public_function/friend.cpp b/test/public_function/friend.cpp index b25b5ce..84d7e6a 100644 --- a/test/public_function/friend.cpp +++ b/test/public_function/friend.cpp @@ -1,7 +1,15 @@ -#include -#include -#include +// Test friend functions (also forcing them to check invariants). + +#include "../detail/oteststream.hpp" +#include +#include +#include +#include +#include +#include + +boost::contract::test::detail::oteststream out; class y; class z; @@ -9,13 +17,14 @@ class z; class x { public: void invariant() const { - std::cout << "x::inv" << std::endl; + out << "x::inv" << std::endl; BOOST_CONTRACT_ASSERT(get() >= 0); } x() : value_(0) {} int get() const { return value_; } - friend void set_all(x&, y&, int value); + + friend void f(x&, y&, int value); private: int value_; @@ -24,22 +33,23 @@ private: class y { public: void invariant() const { - std::cout << "y::inv" << std::endl; + out << "y::inv" << std::endl; BOOST_CONTRACT_ASSERT(get() >= 0); } y() : value_(0) {} int get() const { return value_; } - friend void set_all(x&, y&, int value); + + friend void f(x&, y&, int value); private: int value_; }; -void set_all(x& a, y& b, int value) { +void f(x& a, y& b, int value) { boost::contract::check post = boost::contract::function() .postcondition([&] { - std::cout << "f::post" << std::endl; + out << "f::post" << std::endl; BOOST_CONTRACT_ASSERT(a.get() == value); BOOST_CONTRACT_ASSERT(b.get() == value); }) @@ -48,21 +58,45 @@ void set_all(x& a, y& b, int value) { boost::contract::check inv_a = boost::contract::public_function(&a); boost::contract::check pre = boost::contract::function() .precondition([&] { - std::cout << "f::pre" << std::endl; + out << "f::pre" << std::endl; BOOST_CONTRACT_ASSERT(value > 0); }) ; - std::cout << "f::body" << std::endl; + out << "f::body" << std::endl; a.value_ = b.value_ = value; } int main() { + std::ostringstream ok; + x a; y b; - set_all(a, b, 123); - assert(a.get() == 123); - assert(b.get() == 123); - return 1; + + out.str(""); + f(a, b, 123); + ok.str(""); ok + #ifndef BOOST_CONTRACT_NO_INVARIANTS + << "y::inv" << std::endl + << "x::inv" << std::endl + #endif + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + << "f::pre" << std::endl + #endif + << "f::body" << std::endl + #ifndef BOOST_CONTRACT_NO_INVARIANTS + << "x::inv" << std::endl + << "y::inv" << std::endl + #endif + #ifndef BOOST_CONTRACT_NO_POSTONDITIONS + << "f::post" << std::endl + #endif + ; + BOOST_TEST(out.eq(ok.str())); + + BOOST_TEST_EQ(a.get(), 123); + BOOST_TEST_EQ(b.get(), 123); + + return boost::report_errors(); } diff --git a/test/public_function/ifdef_macro.cpp b/test/public_function/ifdef_macro.cpp index 84ed123..b90c12c 100644 --- a/test/public_function/ifdef_macro.cpp +++ b/test/public_function/ifdef_macro.cpp @@ -7,6 +7,7 @@ // Test contract compilation on/off (using macro interface). #include "../detail/oteststream.hpp" +#include "../detail/unprotected_commas.hpp" #include #include #include @@ -16,38 +17,113 @@ boost::contract::test::detail::oteststream out; struct b { - BOOST_CONTRACT_STATIC_INVARIANT({ out << "b::static_inv" << std::endl; }) - BOOST_CONTRACT_INVARIANT({ out << "b::inv" << std::endl; }) + BOOST_CONTRACT_STATIC_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::static_inv" << std::endl; + }) + + BOOST_CONTRACT_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::inv" << std::endl; + }) virtual void f(int x, boost::contract::virtual_* v = 0) = 0; }; void b::f(int x, boost::contract::virtual_* v) { - BOOST_CONTRACT_OLD_PTR(int)(v, old_x, x); - BOOST_CONTRACT_PUBLIC_FUNCTION(v, this) - BOOST_CONTRACT_PRECONDITION([] { out << "b::f::pre" << std::endl; }) - BOOST_CONTRACT_OLD([] { out << "b::f::old" << std::endl; }) - BOOST_CONTRACT_POSTCONDITION([] { out << "b::f::post" << std::endl; }) + BOOST_CONTRACT_OLD_PTR( + boost::contract::test::detail::unprotected_commas:: + type1 + )( + (boost::contract::test::detail::unprotected_commas:: + same(v)), + old_x, + (boost::contract::test::detail::unprotected_commas:: + same(x)) + ); + BOOST_CONTRACT_PUBLIC_FUNCTION( + boost::contract::test::detail::unprotected_commas:: + same(v), + boost::contract::test::detail::unprotected_commas:: + same(this) + ) + BOOST_CONTRACT_PRECONDITION([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::f::pre" << std::endl; + }) + BOOST_CONTRACT_OLD([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::f::old" << std::endl; + }) + BOOST_CONTRACT_POSTCONDITION([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "b::f::post" << std::endl; + }) ; out << "b::f::body" << std::endl; } struct a - #define BASES public b + #define BASES public boost::contract::test::detail::unprotected_commas< \ + b, void, void>::type1 : BASES { - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // OK, always in code. - BOOST_CONTRACT_OVERRIDE(f) // OK if always in code. + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + BOOST_CONTRACT_OVERRIDE(f) - BOOST_CONTRACT_STATIC_INVARIANT({ out << "a::static_inv" << std::endl; }) - BOOST_CONTRACT_INVARIANT({ out << "a::inv" << std::endl; }) + BOOST_CONTRACT_STATIC_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::static_inv" << std::endl; + }) + + BOOST_CONTRACT_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::inv" << std::endl; + }) virtual void f(int x, boost::contract::virtual_* v = 0) { - BOOST_CONTRACT_OLD_PTR(int)(v, old_x, x); - BOOST_CONTRACT_PUBLIC_FUNCTION_OVERRIDE(override_f)(v, &a::f, this, x) - BOOST_CONTRACT_PRECONDITION([] { out << "a::f::pre" << std::endl; }) - BOOST_CONTRACT_OLD([] { out << "a::f::old" << std::endl; }) + BOOST_CONTRACT_OLD_PTR( + boost::contract::test::detail::unprotected_commas:: + type1 + )( + (boost::contract::test::detail::unprotected_commas::same(v)), + old_x, + (boost::contract::test::detail::unprotected_commas::same(x)) + ); + BOOST_CONTRACT_PUBLIC_FUNCTION_OVERRIDE( + boost::contract::test::detail::unprotected_commas::type1 + )( + boost::contract::test::detail::unprotected_commas + ::same(v), + &a::f, + boost::contract::test::detail::unprotected_commas + ::same(this), + boost::contract::test::detail::unprotected_commas + ::same(x) + ) + BOOST_CONTRACT_PRECONDITION([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::f::pre" << std::endl; + }) + BOOST_CONTRACT_OLD([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::f::old" << std::endl; + }) BOOST_CONTRACT_POSTCONDITION([] { + typedef boost::contract::test::detail::unprotected_commas t; out << "a::f::post" << std::endl; }) ; diff --git a/test/public_function/static_ifdef_macro.cpp b/test/public_function/static_ifdef_macro.cpp index ca83df1..55ba67f 100644 --- a/test/public_function/static_ifdef_macro.cpp +++ b/test/public_function/static_ifdef_macro.cpp @@ -7,6 +7,7 @@ // Test public static member function contract compilation on/off (w/ macros). #include "../detail/oteststream.hpp" +#include "../detail/unprotected_commas.hpp" #include #include #include @@ -15,15 +16,42 @@ boost::contract::test::detail::oteststream out; struct a { - BOOST_CONTRACT_STATIC_INVARIANT({ out << "a::static_inv" << std::endl; }) - BOOST_CONTRACT_INVARIANT({ out << "a::inv" << std::endl; }) + BOOST_CONTRACT_STATIC_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::static_inv" << std::endl; + }) + + BOOST_CONTRACT_INVARIANT({ + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::inv" << std::endl; + }) static void f(int x) { - BOOST_CONTRACT_OLD_PTR(int)(old_x, x); - BOOST_CONTRACT_STATIC_PUBLIC_FUNCTION(a) - BOOST_CONTRACT_PRECONDITION([] { out << "a::f::pre" << std::endl; }) - BOOST_CONTRACT_OLD([] { out << "a::f::old" << std::endl; }) + BOOST_CONTRACT_OLD_PTR( + boost::contract::test::detail::unprotected_commas:: + type1 + )( + old_x, + (boost::contract::test::detail::unprotected_commas::same(x)) + ); + BOOST_CONTRACT_STATIC_PUBLIC_FUNCTION(boost::contract::test::detail:: + unprotected_commas::type1) + BOOST_CONTRACT_PRECONDITION([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::f::pre" << std::endl; + }) + BOOST_CONTRACT_OLD([] { + typedef boost::contract::test::detail::unprotected_commas t; + out << "a::f::old" << std::endl; + }) BOOST_CONTRACT_POSTCONDITION([] { + typedef boost::contract::test::detail::unprotected_commas t; out << "a::f::post" << std::endl; }) ; diff --git a/test/public_function/virtual_access_multi.cpp b/test/public_function/virtual_access_multi.cpp index 5189f1b..c012daf 100644 --- a/test/public_function/virtual_access_multi.cpp +++ b/test/public_function/virtual_access_multi.cpp @@ -9,7 +9,6 @@ #include #ifdef BOOST_MSVC -// TODO: Document following warning about MSVC in lib docs. // WARNING: MSVC (at least up to VS 2015) gives a compile-time error if SFINAE // cannot introspect a member because of its private or protected access level. // That is incorrect, SFINAE should fail in these cases without generating