diff --git a/boost.css b/boost.css new file mode 100644 index 0000000..986c405 --- /dev/null +++ b/boost.css @@ -0,0 +1,66 @@ +/*============================================================================= + Copyright 2002 William E. Kempf + Distributed under the Boost Software License, Version 1.0. (See accompany- + ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +H1 +{ + FONT-SIZE: 200%; + COLOR: #00008B; +} +H2 +{ + FONT-SIZE: 150%; +} +H3 +{ + FONT-SIZE: 125%; +} +H4 +{ + FONT-SIZE: 108%; +} +BODY +{ + FONT-SIZE: 100%; + BACKGROUND-COLOR: #ffffff; + COLOR: #000000; +} +PRE +{ + MARGIN-LEFT: 2em; + FONT-FAMILY: Courier, + monospace; +} +CODE +{ + FONT-FAMILY: Courier, + monospace; +} +CODE.as_pre +{ + white-space: pre; +} +.index +{ + TEXT-ALIGN: left; +} +.page-index +{ + TEXT-ALIGN: left; +} +.definition +{ + TEXT-ALIGN: left; +} +.footnote +{ + FONT-SIZE: 66%; + VERTICAL-ALIGN: super; + TEXT-DECORATION: none; +} +.function-semantics +{ + CLEAR: left; +} \ No newline at end of file diff --git a/boost.png b/boost.png new file mode 100644 index 0000000..b4d51fc Binary files /dev/null and b/boost.png differ diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index cde2181..98f900e 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -1,7 +1,6 @@ import quickbook ; using boostbook ; -using doxygen ; #doxygen reference # : @@ -31,20 +30,18 @@ using doxygen ; # ALIASES=" Params=\"Parameters: \" Param{2}=\"\" EndParams=\"
\\1\\2
\" Returns=\"Returns:\" Note=\"Note:\" Warning=\"Warning:\" SeeAlso=\"See also:\" RefSect{2}=\"\\xmlonly\\2\\endxmlonly\" RefClass{1}=\"\\xmlonly\\1\\endxmlonly\" RefFunc{1}=\"\\xmlonly\\1\\endxmlonly\" RefMacro{1}=\"\\xmlonly\\1\\endxmlonly\" RefEnum{1}=\"\\xmlonly\\1\\endxmlonly\" " # ; -xml contractpp : qbk/contract.qbk ; -#: reference ; - -boostbook doc : contractpp : - html - toc.max.depth=1 - boost.defaults=Boost - boost.root=../../ - admon.graphics.path=../../doc/src/images/ - html.stylesheet=../../doc/src/boostbook.css - pdf:admon.graphics.extension=".svg" - pdf:img.src.path=html/ - pdf:draft.more="no" - pdf:page.orientation="landscape" - pdf:paper.type="A3" +xml contract + : qbk/contract.qbk +# : reference +; + +boostbook doc + : contract + : + html + boost.defaults=Boost + boost.root=../../ + admon.graphics.path=../../doc/src/images/ + html.stylesheet=../../doc/src/boostbook.css ; diff --git a/doc/qbk/advanced_topics.qbk b/doc/qbk/advanced_topics.qbk index 6c08b22..70b49a0 100644 --- a/doc/qbk/advanced_topics.qbk +++ b/doc/qbk/advanced_topics.qbk @@ -1,14 +1,204 @@ -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - [section Advanced Topics] -This section explains advanced usages of this library in programming contracts. -See the __Grammar__ section for a complete guide on this library syntax. +This section explains advanced usages of this library. + +[section Optional Return Value] + +It is possible to use `boost::optional` to handle the return value when programmers cannot construct the result variable at its point of declaration before the contract (e.g., because an appropriate constructor for the return type is not available at that point, or just because it is too expensive to execute an extra initialization of the result value at run-time). +[footnote +*Rationale.* +`boost::optional` was used instead of `std::optional` because this library is designed to work well with Boost and because `std::optional` is not part of the C++ standard yet. +] +For example (see also [@../../example/features/optional_result.cpp =optional_result.cpp=]): + +[import ../../example/features/optional_result.cpp] +[optional_result] + +In this example the return type `surface` does not have a default constructor that can be used to initialize `result` when it is first declared. +`surface` non-default constructor cannot be used to initialize `result` by passing it `edge * edge` because such an operation is the responsibility of the body (in fact, it makes logical sense to do such multiplication only after `edge` has been checked to be positive by the preconditions). +Therefore, instead of initializing `result` with some useless `area` value, `boost::optional` was used in this example to not initialize `result` with a return value when it is declared before the contract. +`result` is instead initialized only later in the body when the function body is about to return and directly using the correct return value `surface(edge * edge)`. + +When this technique is used, programmers have to make sure that each return statement in the function is of the following form: + + boost::optional<...> result; + ... + return *(result = ...); + +This ensures that `result` is always set to the return value before the postconditions are checked. +Therefore, programmers can always dereference `result` in postconditions to access the return value (using `operator*` and `operator->` as usual with `boost::optional`, and without having to explicitly check if `result` is an empty `boost::optional` object). + +Similarly, `boost::optional` can be used for return values passed to virtual and overriding functions (see also __Pure_Virtual_Functions__). + +[endsect] + +[section Old Values at Body] + +[import ../../example/features/old.cpp] +[old] + +[endsect] + +[section Pure Virtual Public Functions] + +In C++, pure virtual functions are allowed to have a /default implementation/ as long as such implementation is programmed out-of-line and defined outside the class declaring the pure virtual function as `virtual ... = 0;`. +Contracts for pure virtual public functions are programmed using the [funcref boost::contract::public_function] function very much like contracts for virtual public functions, so all consideration made in __Virtual_Public_Functions__ apply. +However, in this case contracts are always programmed out-of-line, in the default implementation of the pure virtual function. + +For example, note how the following `shape::area` default implementation (which is used to program the contract) must be defined out-of-line and therefore outside the `shape` class declaration (see also [@../../example/features/pure_virtual.cpp =pure_virtual.cpp=]): + +[import ../../example/features/pure_virtual.cpp] +[pure_virtual] + +This library will never actually execute the pure virtual function body while it is calling the pure virtual function default implementation to check its contract for subcontracting. +Therefore, programmers can safely `assert(false)` at the beginning of the body if they intend for that body to never be executed (or they can program a working body in case they want to take full advantage of C++ pure virtual function default implementation outside of what strictly needed by this library). +Finally, in this example, the pure virtual function does not have enough information to meaningfully initialize the return value `result` (it is missing the actual shape dimensions like edges, radius, etc.) so `boost::optional` is used to declare the return value (see also __Optional_Return_Value__). + +As already discussed in __Private_and_Protected_Functions__, private and protected member functions do not check class invariants and do not subcontract (not even when they are virtual or pure virtual). +Therefore, no contract is ever programmed for a private or protected pure virtual function (because that contract would never be checked during subcontracting anyway). + +[endsect] + +[section Static Public Functions] + +Contracts for static public member functions are programmed using the [funcref boost::contract::public_function] function. +However, in this case [funcref boost::contract::public_function] takes the enclosing class type as an explicit template parameter instead of taking the object `this` as a function parameter (because there is no object `this` in static member functions): + + auto c = boost::contract::public_function<``[^['class-type]]``>() + ... // Preconditions and postconditions. + ; + +For example (see also [@../../example/features/static.cpp =static.cpp=]): + +[import ../../example/features/static.cpp] +[static] + +Even if they are not present in this example, it is possible to specify both preconditions and postconditions for static public member functions (see also __Preconditions__ and __Postconditions__). +[funcref boost::contract::public_function] takes the class type as a template parameter because static public member functions check static class invariants (but it does not take the object `this` and obviously static public member functions do not check non-static class invariants, see also __Class_Invariants__). + +[funcref boost::contract::public_function] returns an RAII object (that can be assigned to a local variable of explicit type [classref boost::contract::guard] when programmers are not using C++11 auto declarations). +The static public member function body is programmed right after the declaration of this RAII object. +At construction, this RAII object does the following: + +# Check static class invariants, by calling [^['class-type]]`::static_invariant()` (but never non-static class invariants). +# Check preconditions, by calling the functor [^['f]]`()` passed to `.precondition(`[^['f]]`)`. + +At destruction instead: + +# Check static class invariants, by calling [^['class-type]]`::static_invariant()` (even if the function body threw and exception, but never non-static class invariants). +# If the function body did not throw an exception: + # Check postconditions, by calling the functor [^['g]]`()` passed to `.postcondition(`[^['g]]`)`. + +This ensures that static public member function contracts are correctly checked at run-time (note that static public member functions do not subcontract, see also __Public_Function_Calls__). + +[note +A static public member function can avoid calling [funcref boost::contract::public_function] for efficiency but only when it has no precondition and no postconditions, and its class has not static invariant (its class can still have non-static invariants or base classes instead). +] + +As already discussed in __Private_and_Protected_Functions__, private and protected member functions never check static or non-static class invariants (not even when they are static member functions). +Therefore, [funcref boost::contract::function] is always used for private and protected member functions, also whey they are static member functions. + +[heading Static Class Invariants] + +As shown by the example above, when static class invariants are specified, the re programmed in a public `static` member function named `static_invariant` taking no argument and returning `void` (this library will generate a compile-time error if the `static` classifier is missing, unless [macroref BOOST_CONTRACT_CONFIG_PERMISSIVE] is set). +Classes that do not static class invariants, simply do not declare a `static_invariant` member function. +[footnote +This library uses template meta-programming (SFINAE-based introspection techniques) to check static invariants only for classes that declare a member function named `static_invariant`. +] + +Any code can be programmed in the `static_invariant` function, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex static invariants that might be buggy and slow to execute at run-time). +It is also recommended to use the [macroref BOOST_CONTRACT_ASSERT] macro to program the assertions because it enables this library to print very informative error messages when the asserted conditions are evaluated to be false at run-time (this is not a variadic macro, but see also __No_Macros__): + + BOOST_CONTRACT_ASSERT(``/boolean-condition/``) + // Or, if condition has commas `,` not already within parenthesis `(...)`. + BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) + +This library will automatically call [funcref boost::contract::entry_invariant_failed] or [funcref boost::contract::exit_invariant_failed] if any of the [macroref BOOST_CONTRACT_ASSERT] macro conditions are `false` and also if the `static_invariant` function throws an exception (by default, this terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.). + +See __Access__ to avoid making `static_invariant` a public member function (e.g., in cases when all public members of a class must be controlled exactly). +Set the [macroref BOOST_CONTRACT_CONFIG_STATIC_INVARIANT] configuration macro to use a name different from `static_invariant` (e.g., because `static_invariant` clashes with other names in the user-defined class). +[footnote +*Rationale.* +It is not possible to overload a member function in C++ based on the `static` classifier. +Therefore, different function names have to be used for member functions checking static and non-static class invariants (e.g., `invariant` and `static_invariant`). +] + +Furthermore, see __Class_Invariants__ and __Volatile_Public_Functions__ for programming non-static and volatile class invariants respectively. + +[endsect] + +[section Volatile Public Functions] +[endsect] + +[section Throw on Failure] +[endsect] + +[section Separate Body Implementation] +[endsect] + +[section Access] + +* base_types +* invariant() and static_invariant() + +[classref BOOST_CONTRACT_OVERRIDE] must not necessarily be used in a `public` section of the class (e.g., it can be used in a `private` section in cases when all `public` members of a class must be controlled exactly). + +For example: + + class a + #define BASES public b + : BASES + { // In private section. + friend class boost::contract::access; + + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { /* ... */ } + static void static_invariant() { /* ... */ } + + BOOST_CONTRACT_OVERRIDE(f) + + public: // Public section not altered by contracts. + void f(boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function( + v, &a::f, this); + /* ... */ + } + }; + +[endsect] + +[section Override Trait] + +Calls to [funcref boost::contract::public_function] from different overloaded functions reuse the same `override_`[^['function-name]] template argument so [macroref BOOST_CONTRACT_OVERRIDE][^(['function-name])] is used only once in a given class even if [^['function-name]] is overloaded. +For example (see also [@../../example/features/override_overload.cpp =override_overload.cpp=]): + +[import ../../example/features/override_overload.cpp] +[override_overload] + +Note that the function name passed to [macroref BOOST_CONTRACT_OVERRIDE] should not start with an underscore to avoid generating named with double underscores `override__...` that are reserved by the C++ standard. +There is a separate macro [macroref BOOST_CONTRACT_OVERRIDE_TRAIT] that can be used to explicitly specify the name of the trait that will be passed as [funcref boost::contract::public_function] template argument separately from the function name. +This macro can be used for function names that start with an underscore, when the name `override_`[^['function-name]] clashes with other names the user-define class, or in any other case when programmers want to use a name different than `override_...`. +For example (see also [@../../example/features/override_trait.cpp =override_trait.cpp=]): + +[import ../../example/features/override_trait.cpp] +[override_trait] + +[endsect] + +[section Assertion Requirements (Call-If)] +[endsect] + +[section No Lambda Functions (No C++11)] +[endsect] + +[section No Macros (No C++11)] +[endsect] + +[section ---------------------------------------------------------------------] +[endsect] [section Commas and Leading Symbols in Macros] diff --git a/doc/qbk/contract.qbk b/doc/qbk/contract.qbk index fc5fc47..89154a9 100644 --- a/doc/qbk/contract.qbk +++ b/doc/qbk/contract.qbk @@ -1,15 +1,9 @@ -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - -[library Contract++ +[library Boost.Contract [quickbook 1.5] - [version 0.4.1] + [version 1.0] [authors [Caminiti lorcaminiti@gmail.com, Lorenzo]] - [copyright 2008-2012 Lorenzo Caminiti] + [copyright 2008-2015 Lorenzo Caminiti] [license 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])] [/ purpose Contract Programming for C++] [/ category Correctness and Testing] @@ -101,8 +95,8 @@ [def __Release_Notes__ [link contract__.release_notes Release Notes]] [def __Acknowledgments__ [link contract__.acknowledgments Acknowledgments]] -[def __logic_and__ [link logic_and_anchor logic-and]] -[def __logic_or__ [link logic_or_anchor logic-or]] +[def __AND__ [link logic_and_anchor [^AND]]] +[def __OR__ [link logic_or_anchor [^OR]]] [def __Assignable__ [@http://www.boost.org/doc/libs/release/libs/utility/Assignable.html [^Assignable]]] [def __ConstantCopyConstructible__ [link contract__.advanced_topics.old_and_result_value_copies [^ConstantCopyConstructible]]] [def __CopyConstructible__ [@http://www.boost.org/doc/libs/release/libs/utility/CopyConstructible.html [^CopyConstructible]]] @@ -113,25 +107,30 @@ [:['["Our field needs more formality, but the profession has not realized it yet.]]] [:['-- Bertrand Meyer (see __Meyer97__ page 400)]] -This library implements Contract Programming for the C++ programming language. -In addition, the library implements virtual specifiers (`final`, `override`, and `new`, see __CXX11__), concept checking, and named parameters. +This library implements +[@http://en.wikipedia.org/wiki/Design_by_contract Contract Programming] (a.k.a., Design by Contract, DbC) +[footnote +Design by Contract (DbC) is a registered trademark of [@http://en.wikipedia.org/wiki/Eiffel_Software Eiffel Software]. +Its methodology was first introduced by the __Eiffel__ programming language (see __Meyer97__). +] +for the C++ programming language. +All Contract Programming features are supported: subcontracting, class invariants, postconditions (with old and result values), preconditions, customizable actions on assertion failure, optional assertion compilation, disable assertion checking within other assertion checking, etc. -Consult this documentation in [@index.html HTML] or [@contractpp.pdf PDF] format. +Consult this documentation in [@index.html HTML] or [@contract.pdf PDF] format. -[/ include introduction.qbk] -[/ include full_table_of_contents.qbk] -[/ include getting_started.qbk] -[/ include contract_programming_overview.qbk] -[/ include tutorial.qbk] -[/ include advanced_topics.qbk] -[/ include virtual_specifiers.qbk] -[/ include concepts.qbk] -[/ include named_parameters.qbk] -[include examples.qbk] +[include introduction.qbk] +[include getting_started.qbk] +[include contract_programming_overview.qbk] +[include tutorial.qbk] +[include advanced_topics.qbk] +[include virtual_specifiers.qbk] +[include concepts.qbk] +[include named_parameters.qbk] +[/ include examples.qbk] [include grammar.qbk] -[/ include no_variadic_macros.qbk] +[include no_variadic_macros.qbk] [/ xinclude reference.xml] -[/ include release_notes.qbk] -[/ include bibliography.qbk] -[/ include acknowledgments.qbk] +[include release_notes.qbk] +[include bibliography.qbk] +[include acknowledgments.qbk] diff --git a/doc/qbk/contract_programming_overview.qbk b/doc/qbk/contract_programming_overview.qbk index 6c5ed4a..9b3c288 100644 --- a/doc/qbk/contract_programming_overview.qbk +++ b/doc/qbk/contract_programming_overview.qbk @@ -1,477 +1,454 @@ -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - [section Contract Programming Overview] [:['["It is absurd to make elaborate security checks on debugging runs, when no trust is put in the results, and then remove them in production runs, when an erroneous result could be expensive or disastrous. What would we think of a sailing enthusiast who wears his life-jacket when training on dry land but takes it off as soon as he goes to sea?]]] [:['-- Charles Antony Richard Hoare (see __Hoare73__)]] This section gives an overview of Contract Programming (see __Meyer97__, __Mitchell02__, and __N1613__ for a detailed introduction to Contract Programming). +Readers that already have a basic understanding of Contract Programming can skip this section and come back to it after reading the __Tutorial__ section. [note The objective of this library is /not/ to convince programmers to use Contract Programming. -It is assumed that programmes understand the benefits and trade-offs associated with Contract Programming and they have already decided to use this methodology to formally program specifications. +It is assumed that programmes understand the benefits and trade-offs associated with Contract Programming and they have already decided to use this methodology to code program specifications. Then, this library aims to be the best Contract Programming library for C++. ] [section Assertions] -Contract Programming is characterized by the following type of assertion mechanisms. +Contract Programming is characterized by the following assertion mechanisms: -[table -[ [Assertion] [Purpose] ] -[ [Preconditions] [ -These are logical conditions that programmers expect to be true when the function is called (e.g., to check constraints on the function arguments). -] ] -[ [Postconditions] [ -These are logical conditions that programmers expect to be true when the function has ended normally (e.g., to check the result and any side effect that a function might have). -Postconditions can usually access the function result value (for non-void functions) and /old values/ that expressions had before the body execution. -] ] -[ [Class Invariants] [ -These are logical conditions that programmers expect to be true after the constructor has been executed successfully, before and after the execution of every non-static public member function, and before the destructor is executed (e.g, class invariants can define valid states of all objects of a class). -It is possible to describe a different set of class invariants for volatile member functions but /volatile class invariants/ are assumed to be same as class invariants unless differently specified. -It is also possible to describe /static class invariants/ which are excepted to be true before and after the execution of any public member function (even if static), including constructor entry and destructor exit. +# Preconditions: These are logical conditions that programmers expect to be true when the function is called (e.g., to check constraints on the function arguments). +# Postconditions: These are logical conditions that programmers expect to be true when the function exits without throwing an exception (e.g., to check the result and any side effect that a function might have). +Postconditions can usually access the function return value (for non-void functions) and /old values/ that expressions had before the function body was executed. +# Class invariants: These are logical conditions that programmers expect to be true after the constructor exits without throwing an exception, before and after the execution of every public non-static member function (even if they throw exceptions), before the destructor is executed and if the destructor throws an exception (e.g, class invariants can define valid states for all objects of a class). +It is possible to specify a different set of class invariants for volatile member functions, but these /volatile class invariants/ are assumed to be the same as class invariants unless differently specified. +It is also possible to specify /static class invariants/ which are excepted to be true before and after the execution of any public member function (even if static), of constructors, and of the destructor (even when the destructor does not throw an exception). [footnote *Rationale.* -Static and volatile class invariants were first introduced by this library to reflect the fact that C++ support both static and volatile member functions. +Static and volatile class invariants were first introduced by this library to reflect the fact that C++ supports both static and volatile member functions. Static and volatile class invariants are not part of __N1962__. ] -] ] -[ [Subcontracting] [ -Subcontracting is defined using the __substitution_principle__ and it predicates that: Preconditions cannot be strengthen, postconditions and class invariants cannot be weaken. -] ] -[ [Block Invariants] [ -These are logical conditions that programmers except to be true every time the execution reaches the point where the condition is asserted. -When used within a loop (i.e., a block of code that can be executed in iteration), block invariants are also called /loop invariants/ and they assert conditions that are expected to be true for every loop iteration. -] ] -[ [Loop Variants] [ -For a given loop, a [@http://en.wikipedia.org/wiki/Loop_variant loop variant] is a non-negative integer expression (`>= 0`) with a value that is expected to decrease at every subsequent loop iteration. -Loop variants are used to ensure that loops terminate avoiding infinite iterations. -] ] +# Subcontracting: Subcontracting is defined according to the __substitution_principle__ and it indicates that preconditions cannot be strengthen, while postconditions and class invariants cannot be weaken. + +Furthermore, it is a common requirement for Contract Programming to automatically disable other contracts while a contract assertions is being checked (in order to avoid infinite recursion while checking contract assertions). + +[note +This library implements this requirement but it should be noted that, in order to globally disable assertions while checking another assertion, some type of global variable needs to be used. +In multi-threaded programs, the [macroref BOOST_CONTRACT_CONFIG_THREAD_SAFE] configuration macro can be defined to protect such a global variable from race conditions, but this will effectively introduce a global lock in the program. ] -It is a common Contract Programming requirement to disable other contracts while a contract assertions is being evaluated (in order to avoid infinite recursive calls). -This library implement this feature however it should be noted that in order to globally disable assertions while checking another assertion, some type of global variable needs to be used. -In multi-threaded environments, programmers can define the [macroref CONTRACT_CONFIG_THREAD_SAFE] configuration macro to protect such a global variable from racing conditions (but that will effectively introduce a global lock in the program). +In general, it is recommended to specify different contract conditions using separate assertion statements and not to group them together into a single condition using logical operators (`&&`, `||`, etc.). +This is because if contract conditions are programmed together using a single assertion then it will not be clear which condition actually failed in case the assertion is evaluated to be false at run-time. -A limited form of Contract Programming is the use of the C++ `assert` macro. -Using `assert` is common practice for many programmers but unfortunately it suffers from the following problems (that are instead resolved by using Contract Programming): +A limited form of Contract Programming is the use of the C-style `assert` macro. +Using `assert` is common practice for many programmers but it suffers of the following limitations (that are instead overcome by Contract Programming): -# `assert` is used within the implementation therefore the asserted conditions are not easily visible to the caller which is only familiar with the class and function declarations. -# `assert` does not distinguish between preconditions and postconditions. -In well-tested production code, postconditions can be disabled trusting the correctness of the implementation while preconditions might still need to remain enabled because of the evolution of the calling code. +* `assert` does not distinguish between preconditions and postconditions. +In well-tested production code, postconditions can usually be disabled trusting the correctness of the implementation while preconditions might still need to remain enabled because of possible changes in the calling code. Using `assert` it is not possible to selectively disable only postconditions and all assertions must be disabled at once. -# `assert` requires to manually program extra code to check class invariants (e.g., extra member functions and try blocks). -# `assert` does not support subcontracting. +* `assert` requires to manually program extra code to check class invariants (e.g., extra member functions and try blocks). +* `assert` does not support subcontracting. +* `assert` calls are usually scattered throughout the implementation thus the asserted conditions are not immediately visible in their entirety to programmers. [endsect] -[section Benefits] +[section Benefits and Costs] + +[heading Benefits] The main use of Contract Programming is to improve software quality. __Meyer97__ discusses how Contract Programming can be used as the basic tool to write ["correct] software. -Furhtermore, __Stroustrup97__ discusses the key importance of class invariants plus advantages and disadvantages of preconditions and postconditions. -The following is a short summary of the benefits associated with Contract Programming mainly taken from __N1613__. +__Stroustrup97__ discusses the key importance of class invariants plus advantages and disadvantages of preconditions and postconditions. +The following is a short summary of the benefits associated with Contract Programming mainly taken from __N1613__: -[table -[ [#] [Topic] [Benefit] ] -[ [1.] [Preconditions and Postconditions] [ -Using function preconditions and postconditions, programmers can give a precise semantic description of what a function requires at its entry and what it ensures under its (normal) exit. +# Preconditions and postconditions: +Using function preconditions and postconditions, programmers can give a precise semantic description of what a function requires at its entry and what it ensures under its exit (if it does not throw an exception). In particular, using postcondition old values, Contract Programming provides a mechanism that allows programmers to compare values of an expression before and after the function body execution. -This mechanism is powerful enough to enable programmers to express many constraints within the code, constraints that would otherwise have to be captured at best only informally by the code documentation. -] ] -[ [2.] [Class Invariants] [ +This mechanism is powerful enough to enable programmers to express many constraints within the code, constraints that would otherwise have to be captured at best only informally in the documentation. +# Class invariants: Using class invariants, programmers can describe what to expect from a class and the logic dependencies between the class members. It is the job of the constructor to ensure that the class invariants are satisfied when the object is first created. -Then the implementation of the member functions can be largely simplified as they can be written knowing that the class invariants are satisfied because Contract Programing checks them before and after the execution of every member function. +Then the implementation of the member functions can be largely simplified as they can be written knowing that the class invariants are satisfied because Contract Programing checks them before and after the execution of every public member function. Finally, the destructor makes sure that the class invariants hold for the entire life of the object, checking the class invariants one last time before the object is destructed. -] ] -[ [3.] [Self-Documenting Code] [ -Contracts are part of the source code, they are executed and verified at run-time so they are always up to date with the code itself. -Therefore the specifications, as documented by the contracts, can be trusted to always be up to date with the implementation code. -] ] -[ [4.] [Easier Debugging] [ +# Self-documenting code: +Contracts are part of the source code, they are checked at run-time so they are always up-to-date with the code itself. +Therefore the specifications, as documented by the contracts, can be trusted to always be up-to-date with the implementation. +# Easier debugging: Contract Programming can provide a powerful debugging facility because, if contracts are well written, bugs will cause contract assertions to fail exactly where the problem first occurs instead than at some later stage of the program execution in an apparently unrelated manner. Note that a precondition failure points to a bug in the function caller, a postcondition failure points instead to a bug in the function implementation. -Furthermore, in case of contract failure, this library provides detailed error messages that greatly helps debugging. -[footnote Of course, if the contract is ill written then Contract Programming is of little use. +[footnote +Of course, if the contract is ill-written then Contract Programming is of little use. However, it is less likely to have a bug in both the function body and the contract than in the function body only. For example, consider the validation of a result in postconditions. Validating the return value might seem redundant, but in this case we actually want that redundancy. When programmers write a function, there is a certain probability that they make a mistake in implementing the function body. When programmers specify the result of the function in the postconditions, there is also a certain probability that they make a mistake in writing the contract. -However, the probability that programmers make a mistake twice (in both the body /and/ the contract) is lower than the probability that the mistake is made just once (in either the body or the contract).] -] ] -[ [5.] [Easier Testing] [ +However, the probability that programmers make a mistake twice (in both the body /and/ the contract) is lower than the probability that the mistake is made just once (in either the body or the contract). +] +# Easier testing: Contract Programming facilitates testing because a contract naturally specifies what a test should check. -For example, preconditions of a function state which inputs cause the function to fail and postconditions state which outputs are produced by the function on normal exit. -] ] -[ [6.] [Formal Design] [ +For example, preconditions of a function state which inputs cause the function to fail and postconditions state which outputs are produced by the function on successful exit. +Obviously, Contract Programming should be seen as a tool to complement (and not to replace) testing. +# Formal design: Contract Programming can serve to reduce the gap between designers and programmers by providing a precise and unambiguous specification language. Moreover, contracts can make code reviews easier. -] ] -[ [7.] [Formal Inheritance] [ +# Formalized inheritance: Contract Programming formalizes the virtual function overriding mechanism using subcontracting as justified by the __substitution_principle__. -This keeps the base class programmers in control as overriding functions still have to fully satisfy the base class contracts. -] ] -[ [8.] [Replace Defensive Programming] [ +This keeps the base class programmers in control as overriding functions always have to fully satisfy the base class contracts. +# Replace Defensive Programming: Contract Programming assertions can replace [@http://en.wikipedia.org/wiki/Defensive_programming Defensive Programming] checks localizing these checks within the contract and making the code more readable. -] ] -] -[endsect] +[heading Costs] -[section Costs] +In general, Contract Programming benefits come to the cost of performance as discussed in detail by both __Stroustrup97__ and __Meyer97__. +However, while performance trade-offs should be carefully considered depending on the specific application domain, software quality cannot be sacrificed: It is difficult to see value in software that quickly and efficiently provides the incorrect result. -Contract Programming benefits come to the cost of performance as discussed in detail by both __Stroustrup97__ and __Meyer97__. -However, while performance trade-offs should be carefully considered depending on the specific application domain, software quality cannot be sacrificed (it is difficult to see the value of software that quickly and efficiently provides an incorrect result). +The run-time performances are negatively impacted by Contract Programming mainly because of extra time require to: -The run-time performances are negatively impacted by Contract Programming mainly because of the following: +# Check the asserted conditions. +# Call additional functions that specify preconditions, postconditions, class invariants, etc. +# Copy old values and return values when these are used in postconditions. -# The extra processing required to check the assertions. -# The extra processing required by the additional function calls (additional functions are invoked to check preconditions, postconditions, class invariants, etc). -# The extra processing required to copy expression results when old values that are used in postconditions. +To mitigate the run-time performance impact, programmers can selectively disable run-time checking of some of the contract assertions. +Programmers will have to decide based on the performance trade-offs required by their applications, but a reasonable approach often is to: -To mitigate the run-time performance impact, programmers can selectively turn off some of the contract compilation and the related run-time checking. -Programmers will have to decide based on the performance trade-offs required by their applications but a reasonable approach usually is to: - -* Always write contracts to clarify the semantics of the design embedding the specifications directly into the code and making the code self-documenting. -* Enable preconditions, postconditions, and class invariants compilation and checking during initial testing. -* Enable only preconditions (and possibly class invariants) during release testing and for the final release (see also [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS], and [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS]). +* Always write contracts to clarify the semantics of the design embedding the specifications directly in the code and making the code self-documenting. +* Enable precondition, postcondition, and class invariant checking during initial testing. +* Enable only precondition (and possibly class invariant) checking during release testing and for the final release (see also [macroref BOOST_CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS], and [macroref BOOST_CONTRACT_CONFIG_NO_INVARIANTS]). This approach is usually reasonable because in well-tested production code, validating the function body implementation using postconditions and class invariants is rarely needed since the function has shown itself to be ["correct] during testing. -On the other hand, checking function arguments using postconditions is always needed because of the evolution of the calling code. -Furthermore, postconditions are usually computationally more expensive to check (see the __Assertion_Requirements__ section for a mechanism to selectively enable assertions also based on their computational complexity). - -Compile-time performances are also impacted by this library mainly because: - -# The contracts appear in class and function declarations (usually header files) so they have to be re-compiled for each translation unit. -# The library implementation extensively uses preprocessor and template meta-programming which significantly stress compiler performances. - -[#compilation_time_warning_anchor] -[warning -Unfortunately, the current implementation of this library significantly slows down compilation. -For example, for a project with 122 files and 15,471 lines of code, adding contracts to a total of 50 classes and 302 functions increased compilation time from 1 minute to 26 minutes when compilation was enabled for all contracts, and from 1 minute to 2 minutes when contracts were left in the code but contract compilation was disabled using this library configuration macros `CONTRACT_CONFIG_NO_...`. -[footnote -This library macros always need to expand to generate the class and function declarations even when contract compilation is disabled. -That is why there is a compile-time overhead, even if significantly smaller, also when contracts are all disabled (in this case however there is zero run-time overhead). -The compilation time overhead when all contracts are turned off could be further reduced by optimizing the library implementation to not include internal headers that are not required when contracts are off (this type of optimizations will be a major focus on future releases). -] - -On compilers that support [@http://en.wikipedia.org/wiki/Precompiled_header pre-compiled headers] (GCC, MSVC, etc), these can be used to reduce re-compilation time. -For example, re-compilation time of [link contract__.examples.__n1962___vector__comparison_with_c___proposed_syntax =vector.cpp=] from the __Examples__ section is reduced from 44 seconds to 24 seconds (55% faster) when its header [link contract__.examples.__n1962___vector__comparison_with_c___proposed_syntax =vector.hpp=] is pre-compiled (with all contracts enabled). -[footnote -There is essentially no gain in pre-compiling this library headers because most of the compilation time is taken by expanding and compiling this library macros as they appear in the user code (and not by the library implementation code itself). -Furthermore, pre-compiled headers should be used with the usual care because they can complicate the build system and they introduce extra dependencies that might limit the amount of targets that can be built simultaneously in a parallel build. -However, if properly used, pre-compiled headers can significantly reduce re-compilation time when using this library. -] - -The authors have not done a detailed preprocessing-time and compile-time analysis of the performances of this library. -Therefore, the authors have not yet tried to optimize this library compilation-time. -Reducing compilation-time will be a major focus of future releases (see also [@https://sourceforge.net/apps/trac/contractpp/ticket/48 Ticket 48]). -] - -Finally, Contract Programming should be seen as a tool to complement (and not to substitute) testing. +On the other hand, checking function arguments using preconditions is always needed because of changes that can be made to the calling code (without having to necessarily re-test and re-released to called code). +Furthermore, postconditions are usually computationally more expensive to check (see the __Assertion_Complexity__ section for a mechanism to selectively tag and disable assertions based on their computational complexity). [endsect] -[section Free Function Calls] +[section Function Calls] -A /free function/ -[footnote -In C++, a free function is any function that is not a member function. -] -call executes the following steps: +[heading Free Functions] -# Check the function preconditions. +A call to a /free function/ (i.e., a function that is not a member function) with contracts executes the following steps (see also [funcref boost::contract::function]): + +# Check function preconditions. # Execute the function body. -# Check the function postconditions. +# If the body did not throw an exception, check function postconditions. + +[heading Private and Protected Member Functions] + +In Contract Programming, Private and protected member functions do not have to satisfy the class invariants (because these functions are considered part of the implementation of the class). +Furthermore, the __substitution_principle__ does not apply to private and protected member functions (because these functions are not accessible to the user at calling site where the __substitution_principle__ applies). + +Therefore, calls to private and protected member functions with contracts execute the same steps the ones indicated for free functions above (checking only preconditions and postconditions, but without checking class invariants and without subcontracting). [endsect] -[section Member Function Calls] +[section Public Function Calls] -A member function call executes the following steps: +[heading Overriding Public Member Functions] -# Check the static class invariants. -# Check the non-static class invariants (in __logic_and__ with the base class invariants when subcontracting). -These are checked only for non-static member functions. -[footnote -Static member functions cannot be virtual so they cannot be overridden and they do not subcontract. -] -Volatile member functions check volatile class invariants instead. -# Check the function preconditions (in __logic_or__ with the overridden function preconditions when subcontracting). -# Execute the function body. -# Check the static class invariants (even if the body throws an exception). -# Check the non-static class invariants (in __logic_and__ with the base class invariants when subcontracting). -These are checked only for non-static member functions and even if the body throws an exception. -Volatile member functions check volatile class invariants instead. -# Check the function postconditions (in __logic_and__ with the overridden function postconditions when subcontracting). -These are checked only if the body does not throw an exception. +Let's consider a public member function in a derived class that is overriding public virtual functions declared in a number of its base classes (because of multiple inheritance, the function could override from more than one base class). +We refer to the function in the derived class as the /overriding/ function, and to the functions being overridden in the different base classes as the /overridden/ functions. +Then a call to the overriding public member function with contracts executes the following steps (see also [funcref boost::contract::public_function]): + +# Check static class invariants __AND__ non-static class invariants for all overridden bases, __AND__ then check the derived class static __AND__ non-static invariants. +# Check preconditions of overridden public member functions from all overridden bases in __OR__ with each other, __OR__ else check the overriding function preconditions in the derived class. +# Executed the function body. +# Check static class invariants __AND__ non-static class invariants for all overridden bases, __AND__ then check the derived class static __AND__ non-static invariants (even if the body threw an exception). +# If the body did not throw an exception, check postconditions of overridden public member functions from all overridden bases in __AND__ with each other, __AND__ then check the overriding function postconditions in the derived class. + +Volatile member functions check static class invariants __AND__ non-static /volatile/ class invariants instead. +Preconditions and postconditions of volatile member functions and volatile class invariants access the object as `volatile`. + +[note [#logic_and_anchor] [#logic_or_anchor] -In this documentation __logic_and__ and __logic_or__ are the logic /and/ and /or/ operations evaluated in short-circuit: +In this documentation __AND__ and __OR__ indicate the logic /and/ and /or/ operations evaluated in /short-circuit/. +For example: `p` __AND__ `q` is true if and only if both `p` and `q` are true, but `q` is never evaluated when `p` is false; `p` __OR__ `q` is true if and only if either `p` or `q` are true, but `q` is never evaluated when `p` is true. +] -* `p` __logic_and__ `q` is true if and only if both `p` and `q` are true but `q` is evaluated only when `p` is true. -* `p` __logic_or__ `q` is true if and only if either `p` or `q` is true but `q` is evaluated only when `p` is false. +When subcontracting, overridden functions are searched deeply in the public branches of the inheritance tree (i.e., not just the derived class's direct public parents are inspected, but also all its public grandparents, etc.). +In case of multiple inheritance this search extends widely to all multiple public base classes following their order of declaration in the derived class inheritance list (as usual in C++, this search could result in overriding multiple base functions and therefore in subcontracting from multiple public base classes). +Note that only public base classes are considered for subcontracting (because private and protected base classes are not accessible to the user at the calling site where the __substitution_principle__ applies). -Class invariants are checked before preconditions and postconditions so that preconditions and postconditions assertions can be simplified by being programmed under the assumption that class invariants are satisfied (e.g., if class invariants assert that a pointer cannot be null then preconditions and postconditions can safety dereference the pointer without additional checking). -Similarly, subcontracting checks contracts of base classes before checking the derived class contracts so that the base class contract can be programmed under the assumption that the base class contracts are satisfied. -When a member function overrides more than one virtual base function because of multiple inheritance: +Class invariants are checked before preconditions and postconditions so that programming of precondition and postcondition assertions can be simplified by assuming that class invariants are satisfied (e.g., if class invariants assert that a pointer cannot be null then preconditions and postconditions can safety dereference that pointer without additional checking). +Similarly, subcontracting checks contracts of public base classes before checking the derived class contracts so that programming of derived class contract assertions can be simplified by assuming that public base class contracts are satisfied. -* Class invariants are checked in __logic_and__ with the class invariants of all base classes following the inheritance order. -* Preconditions are checked in __logic_or__ with the preconditions of all overridden functions following the inheritance order. -* Postconditions are checked in __logic_and__ with the postconditions of all overridden functions following the inheritance order. +[heading Non-Overriding Public Member Functions] -Note that: +A call to a public non-static member function with contracts but that is not overriding functions from any of the public base classes executes the following steps (see also [funcref boost::contract::public_function]): -* Preconditions and postconditions of static member functions cannot access the object. -* Preconditions, postconditions, and volatile class invariants of volatile member functions access the object as (constant) volatile. +# Check class static __AND__ non-static invariants (but none of the invariants from base classes). +# Check function preconditions (but none of the preconditions from functions in base classes). +# Executed the function body. +# Check the class static __AND__ non-static invariants (even if the body threw an exception, but none of the invariants from base classes). +# If the body did not throw an exception, check function postconditions (but none of the postconditions from functions in base classes). + +Volatile member functions check static class invariants __AND__ non-static /volatile/ class invariants instead. +Preconditions and postconditions of volatile member functions and volatile class invariants access the object as `volatile`. + +Class invariants are checked because this function is part of the class public API. +However, none of the contracts of the base classes are checked because this function is not overriding functions from any of the public base classes (so the __substitution_principle__ does not require this function to subcontract). + +[heading Static Public Member Functions] + +A call to a public static member function with contracts executes the following steps (see also [funcref boost::contract::public_function]): + +# Check static class invariants (but not the non-static invariants and none of the invariants base classes). +# Check function preconditions (but none of the preconditions from function in base classes). +# Executed the function body. +# Check static class invariants (even if the body threw an exception, but not the non-static invariants and none of the invariants from base classes). +# If the body did not throw an exception, check function postconditions (but none of the postconditions from functions in base classes). + +Class invariants are checked because this function is part of the class public API, but only static class invariants can be checked (because this is a static function so it cannot access the object that would instead be required to check non-static class invariants). +Furthermore, static functions cannot override any function so the __substitution_principle__ does not apply to them and they do not subcontract. + +Preconditions and postconditions of static member functions and static class invariants cannot access the object (because static member functions cannot access the object). [endsect] [section Constructor Calls] -A constructor call executes the following steps: +A call to a constructor with contracts executes the following steps (see also [funcref boost::contract::constructor] and [classref boost::contract::constructor_precondition]): -# Check the constructor preconditions. -# Initialize base classes and members executing the constructor member initialization list if present. -# Check the static class invariants (but not the non-static class invariants). +# Check the constructor preconditions (but these cannot access the object because the object is not constructed yet). +# Execute the constructor member initialization list (if present). + # Construct any base class (public or not) according with C++ construction mechanism and also check the contracts of these base constructors (according with steps similar to the ones listed here). +# Check the static class invariants (but not the non-static class invariants, because the object is not constructed yet). # Execute the constructor body. -# Check the static class invariants (even if the body throws an exception). -# Check the non-static class invariants, but only if the body did not throw an exception. -# Check the constructor postconditions, but only if the body did not throw an exception. +# Check the static class invariants (even if the body threw an exception). +# If the body did not throw an exception: + # Check the non-static class invariants (because the object is now successfully constructed). + # Check the constructor postconditions (but these cannot access the object old value because there was no object before the execution of the constructor body). -Preconditions are checked before initializing base classes and members so that these initializations can relay on preconditions to be true (for example to validate constructor arguments before they are used to initialize member variables). -C++ object construction mechanism will automatically check base class contracts when subcontracting. +The object is never volatile within constructors so constructors do not check volatile class invariants. -Note that: +Constructor preconditions are checked before executing the member initialization list so that programming of these initializations can be simplified by assuming the constructor preconditions are satisfied (e.g., constructor arguments can be validated by the constructor preconditions before they are used to initialize bases and data members). -* Non-static class invariants are not checked at constructor entry (because there is no object before the constructor body is executed). -* Preconditions cannot access the object (because there is no object before the constructor body is executed). -* Postconditions cannot access the object old value (because there was no object before the constructor body was executed). -* The object is never volatile within constructors so constructors do not check volatile class invariants. +As indicated in the steps above, C++ object construction mechanism will automatically check base class contracts when these bases are initialized. [endsect] [section Destructor Calls] -A destructor call executes the following steps: +A call to a destructor with contracts executes the following steps (see also [funcref boost::contract::destructor]): -# Check the static class invariants. -# Check the non-static class invariants. -# Execute the destructor body. -# Check the static class invariants (even if the body throws an exception). +# Check static class invariants __AND__ non-static class invariants. +# Execute the destructor body (destructors have no parameters and they can be called at any time after object construction so they have no preconditions). +# Check the static class invariants (even if the body threw an exception). +# If the body threw an exception, check the non-static class invariants (because the object was not successfully destructed so it still exists and should satisfy its invariants). +# If the body did not throw an exception: + # Check the destructor postconditions (but these can only access the class' static members because there is no object after successful execution of the destructor body). [footnote -For generality, this library does not require the destructor body to not throw exceptions. -However, in order to comply with the STL exception safety requirements, destructors should never throw. +None of the Contract Programming references that the authors have studied propose postconditions for destructor (neither __N1962__ nor __Meyer97__, but __Eiffel__ has no static data member). +However, in principle there could be uses cases for destructor postconditions (e.g., a class that counts object instances could use destructor postconditions to assert that an instance counter stored in a static data member is decreased of `1` because the object has been destructed) so this library support postconditions for destructors. +Of course, after destructor body execution there is no object anymore so destructor postconditions should only be allowed to access the class' static members. ] -# Check the non-static class invariants, but only if the body threw an exception. + # Destroy any base class (public or not) according with C++ destruction mechanism and also check the contracts of these base destructors (according with steps similar to the ones listed here). -C++ object destruction mechanism will automatically check base class contracts when subcontracting. +The object is never volatile within destructors so destructors do not check volatile class invariants. -Note that: +As indicated in the steps above, C++ object destruction mechanism will automatically check base class contracts when the destructor exits without throwing an exception. -* Destructors have no parameter and they can be called at any time after object construction so they have no preconditions. -* After the destructor body is executed, the object no longer exists so non-static class invariants do not have to be true and they are not checked at destructor exit. -* Destructors have no postconditions because they have no parameter and after the body execution there is no object. -[footnote -In theory, destructors could have static postconditions (i.e., postconditions that are not allowed to access the object which no longer exists after destruction). -Still destructors shall never have preconditions because a destructor can be called at any point after the object is constructed as long the class invariants hold. -None of the Contract Programming references that the authors have studied propose static postconditions for destructor (neither __N1962__ nor __Meyer97__, but __Eiffel__ has no static data member). -Future revisions of this library might implement destructor static postconditions (e.g., a destructor postconditions of a class that counts object instances could assert that the instance counter stored in a static data member should be decreased of one because the object has been destructed, see also [@https://sourceforge.net/apps/trac/contractpp/ticket/41 Ticket 41]). +[note +Given that C++ allows destructors to throw, this library handles the cases when destructor bodies throw exceptions. +However, in order to comply with STL exception safety guarantees and good C++ programming practices, users should program destructor bodies to never throw. ] -* The object is never volatile within destructors so destructors do not check volatile class invariants. [endsect] [section Constant-Correctness] Contracts are only responsible to check the program state in oder to ensure its compliance with the specifications. -Therefore, contracts should not be able to modify the program state and exclusively "read-only" operations (or /queries/) should be used to program contracts. +Therefore, contracts should only have access to the object, function arguments, function return value, old values, and all other program variables in `const` context (via `const&`, `const* const`, etc.). -This library enforces this constraint at compile-time using C++ `const` qualifier. -[footnote -As usual in C++, constant-correctness can be enforced at compile-time only as long as programmers do not use `const_cast` and `mutable`. -] -Contracts only have access to the object, function arguments, and function return value via constant references `const&` or pointers `const*`. -Other variables (static data members, global variables, etc) can be explicitly made constant using /constant assertions/ (see the __Advanced_Topics__ section). +Whenever possible (e.g., class invariants and postcondition old values), this library enforces this constant-correctness constraint at compile-time. +However, this library cannot automatically enforce this constraint at compile-time for all contract assertions. +It is the responsibility of the users to program assertions that do /not/ change program variables (the same limitation exists with the C-style `assert` mechanism). + +See the __Constant_Correct_Functors__ section for information on how to use this library to always enforce the constant-correctness constraint at compile-time (but these methods require a significant amount of boiler-plate code, so they are not recommended). [endsect] -[section Specification vs. Implementation] +[section Specification and Implementation] Contracts are part of the program specification and not of its implementation. -Therefore, contracts should appear within C++ declarations and not within definitions. -[footnote -This is a major conceptual difference with respect to [@http://en.wikipedia.org/wiki/Defensive_programming Defensive Programming] and using `assert` because they program assertions within the function body instead that with the function declaration. -] +Therefore, contracts should ideally be programmed within C++ declarations, and not within definitions. -Contracts are most useful when they assert conditions only using public members. -For example, the caller of a member function cannot in general make sure that the member function preconditions are satisfied if these preconditions use private members that are not accessible by the caller. -Therefore, a failure in the preconditions will not necessarily indicate a bug in the caller given that the caller was not able to fully check the preconditions before calling the member function. -In most cases, the need of using non-public members to check contracts indicates an error in the design of the class. -However, given that C++ provides programmers ways around access level restrictions (e.g., `friend` and function pointers), this library leaves it up to the programmers to make sure that only public members are used in contract assertions (__N1962__ follows the same approach not forcing contracts to only use public members, __Eiffel__ instead generates a compiler error if preconditions use non-public members). +In general, this library cannot satisfy this requirement but even when the contracts are programmed together with the body in the function definition, it is still very easy for users to identify and read just the contract portion of the function definition (because that must always appear at the very top of the function code). +See the __Separating_Body_Implementation__ section for information on how to separate contract specification from body implementation at the cost of programming one extra function (for applications were this is truly important). + +Furthermore, contracts are most useful when they assert conditions only using public members. In most cases, the need of using non-public members to check contracts indicates an error in the design of the class. + +For example, the caller of a public member function cannot in general make sure that the function preconditions are satisfied if these preconditions use private members that are not accessible by the caller (therefore, a failure in the preconditions will not necessarily indicate a bug in the caller given that the caller was not able to fully check the preconditions before calling the member function). +However, given that C++ provides programmers ways around access level restrictions (`friend`, function pointers, etc.), this library leaves it up to the programmers to make sure that only public members are used in contract assertions (__N1962__ follows the same approach not forcing contracts to only use public members, __Eiffel__ instead generates a compiler error if preconditions use non-public members). [footnote *Rationale.* -In theory, if C++ [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45 defect 45] were not fixed, this library could have generated a compile-time error for preconditions that use non-public members. +In theory, if C++ [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45 defect 45] did not get fixed, this library could have been used in a way that generated a compile-time error for preconditions that use non-public members (but even in that case at the expense of programmers writing extra boiler-plate code). ] -Finally, only public member functions shall check class invariants. -Private and protected member functions are allowed to brake class invariants because private and protected member are part of the class implementation and not of its specification. - [endsect] -[section Broken Contracts] +[section On Contract Failure] -After programmers specify contracts, this library automatically checks preconditions, postconditions, class invariants, block invariants, and loop variants at run-time. -If a precondition, postcondition, class invariant, block invariants, or loop variant is checked to be false or throws an exception then the library invokes the [funcref contract::precondition_broken], [funcref contract::postcondition_broken], [funcref contract::class_invariant_broken_on_entry] or [funcref contract::class_invariant_broken_on_exit] or [funcref contract::class_invariant_broken_on_throw], [funcref contract::block_invariant_broken], and [funcref contract::loop_variant_broken] function respectively. +If preconditions, postconditions, or class invariants throw an exception or their assertions are checked to be false at run-time then special failure handler functions are automatically called by this library. -These function invoke `std::terminate()` by default but programmers can redefine them to take a different action (throw an exception, exit the program, etc) using [funcref contract::set_precondition_broken], [funcref contract::set_postcondition_broken], [funcref contract::set_class_invariant_broken], [funcref contract::set_block_invariant_broken], and [funcref contract::set_loop_variant_broken] (this mechanism is similar to the one of C++'s `std::terminate()`). -See the __Contract_Broken_Handlers__ section for an example. +By default, these failure handler functions print a text message to the standard error `std::cerr` (with detailed information about the failure) and they terminate the program calling `std::terminate`. +However, user-defined failure handlers can be programmed to take any other action (throw an exception, exit the program with an error code, etc.) using [funcref boost::contract::set_precondition_failed], [funcref boost::contract::set_postcondition_failed], [funcref boost::contract::set_invariant_failed], etc. (see the __Contract_Failure_Handlers__ section for an example). +[footnote +*Rationale.* +This customizable failure handling mechanism is similar to the one used by `std::terminate` and also proposed by __N1962__. +] [endsect] [section Features] -The design of this library was largely based on __N1962__ and on the __Eiffel__ programming language as specified by __Meyer97__. -The following table compares features between this library, the proposal for adding Contract Programming to the C++ standard __N1962__, the __Eiffel__ programming language __Meyer97__, and the __D__ programming language __Bright04__. +The Contract Programming features supported by this library are largely based on __N1962__ and on the __Eiffel__ programming language (see __Meyer97__). +The following table compares this library features with the __N1962__ proposal for adding Contract Programming to the C++ standard, +[footnote +The __N1962__ was unfortunately rejected because the standard committee did not considered important to add Contract Programming to the core language (the __N1962__ proposal itself is sound). +In any case, this library will allow C++ programmers to still use Contract Programming even if the standard committee never decides to add it as a language feature. +] +the __Eiffel__ programming language (see __Meyer97__), and the __D__ programming language (see __Bright04__). [table [ [Feature] - [This Library (C++03)] + [This Library] [\[N1962\] Proposal (not part of C++)] [ISE Eiffel 5.4] [D] ][ - [['Keywords and Specifiers]] - [`precondition`, `postcondition`, `extends`, `initialize`, `requires`, `in`, `out`, `deduce`, `comma` (these are specifiers and not keywords, they have special meaning only in specific positions within the declarations passed to this library macros)] - [`invariant`, `precondition`, `postcondition`, `oldof`] - [=invariant=, =require=, =ensure=, =do=, =require else=, =ensure then=, =old=, =result=, =variant=] - [=invariant=, =in=, =out=, =assert=, =static=] + [['Keywords and specifiers]] + [ +Specifiers: `precondition`, `postcondition`, `invariant`, `static_invariant`, and `base_types`. + +(These last 3 specifiers appear in user-defined classes so their names can be changed using [macroref BOOST_CONTRACT_CONFIG_INVARIANT], [macroref BOOST_CONTRACT_CONFIG_STATIC_INVARIANT], and [macroref BOOST_CONTRACT_CONFIG_BASE_TYPES] respectively to avoid name clashes in user code.) + ] + [Keywords: `precondition`, `postcondition`, `oldof`, and `invariant`.] + [Keywords: =require=, =require else=, =ensure=, =ensure then=, =old=, =result=, =do=, and =invariant=.] + [Keywords: =in=, =out=, =assert=, and =invariant=.] ][ [['On contract failure]] - [Default to `std::terminate()` (but can be customized to exit, abort, throw exceptions, etc).] - [Default to `std::terminate()` (but can be customized to exit, abort, throw exceptions, etc).] - [Throw exceptions] - [Throw exceptions] + [Call `std::terminate` (but can be customized to throw exceptions, exit with an error code, etc.).] + [Call `std::terminate` (but can be customized to throw exceptions, exit with an error code, etc.).] + [Throw exceptions.] + [Throw exceptions.] ][ [['Result value in postconditions]] - [Yes, `auto `[^['result-variable-name]]` = return`.] + [Yes, captured by or passed as a parameter to (for virtual functions) the postcondition functor.] [Yes, `postcondition (`[^['result-variable-name]]`)`.] [Yes, =result= keyword.] [No.] ][ [['Old values in postconditions]] - [Yes, `auto `[^['old-variable-name]]` = CONTRACT_OLDOF `[^['oldof-expression]].] - [Yes, `oldof `[^['oldof-expression]].] - [Yes, [^old ['old-expression]].] + [Yes, [macroref BOOST_CONTRACT_OLDOF] macro.] + [Yes, `oldof` keyword.] + [Yes, =old= keyword.] [No.] +][ + [['Class invariants]] + [ +Checked at constructor exit, at destructor entry, and at public member function entry, exit, and throw. +Same for volatile class invariants. +Static class invariants checked at entry and exit of constructor, destructor, and any (also `static`) public member function. + ] + [ +Checked at constructor exit, at destructor entry, and at public member function entry, exit, and throw. +Volatile and static class invariants not supported. +] + [ +Checked at constructor exit, and around public member functions. +Volatile and static class invariants do not apply to __Eiffel__. + ] + [ +Checked at constructor exit, at destructor entry, and around public member functions. +Volatile and static class invariants not supported (`volatile` was deprecated all together from __D__). + ] ][ [['Subcontracting]] - [Yes, also support multiple base contracts for multiple inheritance (can force preconditions to be specified only by base classes using [macroref CONTRACT_CONFIG_DO_NOT_SUBCONTRACT_PRECONDITIONS]).] - [Yes, also support multiple base contracts but only base classes can specify preconditions.] + [ +Yes, also support subcontracting for multiple inheritance ([macroref BOOST_CONTRACT_BASE_TYPES], [macroref BOOST_CONTRACT_OVERRIDE], and [classref boost::contract::virtual_] are used when declaring base classes, overriding and virtual public member functions respectively). +] + [ +Yes, also support subcontracting for multiple inheritance. Only base classes can specify preconditions. +[footnote +*Rationale.* +The authors of __N1962__ decided to forbid derived classes from subcontracting preconditions because they found such a feature rarely if ever used (see [@http://lists.boost.org/Archives/boost/2010/04/164862.php Re: \[boost\] \[contract\] diff n1962]). +Still, it should be noted that even in __N1962__ if a derived class overrides two functions with preconditions coming from two different base classes via multiple inheritance, the overriding function contract will check preconditions from its two base function in __OR__ (so even in __N1962__ preconditions can actually be subcontracted by the derived class when multiple inheritance is used). +The authors of this library found that confusing about __N1962__. +Furthermore, subcontracting preconditions is soundly defined by the __substitution_principle__ and it is supported by __Eiffel__ so this library allows to subcontract preconditions (users can alway avoid using such a feature if they have no need for it). +(This is essentially the only feature on which this library deliberately differ from __N1962__.) +] + ] [Yes.] [Yes.] ][ [['Contracts for pure virtual functions]] - [Yes.] + [Yes (but they must be programmed in out-of-line functions as always in C++ with pure virtual function definitions).] [Yes.] [Yes (contracts for abstract functions).] [No (but planned).] ][ [['Arbitrary code in contracts]] + [Yes (but users are generally recommended to only program assertions using [macroref BOOST_CONTRACT_ASSERT] and if-guard statements within contracts, so to avoid introducing bugs and expensive code in contracts, and also to only use public functions to program preconditions).] [No, assertions only.] - [No, assertions only.] - [No, assertions only plus preconditions can only access public members.] + [No, assertions only. In addition only public members can be used in preconditions.] [Yes.] ][ - [['Constant-correct]] - [Yes.] + [['Constant-correctness]] + [Enforced only for class invariants and old values (making also preconditions and postconditions constant-correct is possible but requires users to program a fare amount of boiler-plate code, see also the __Constant_Correct_Functors__ section).] [Yes.] [Yes.] [No.] ][ [['Function code ordering]] - [Preconditions, postconditions, body.] + [Preconditions and postconditions in any order, but always before body.] [Preconditions, postconditions, body.] [Preconditions, body, postconditions.] [Preconditions, postconditions, body.] ][ - [['Static assertions]] - [Yes, can use `static_assert` (internally implemented using `BOOST_MPL_ASSERT_MSG`, no __CXX11__ required).] - [Yes, can use __CXX11__ `static_assert`.] - [No.] - [Yes.] -][ - [['Block invariants]] - [Yes, [macroref CONTRACT_BLOCK_INVARIANT].] - [Yes, `invariant`.] - [Yes (`check` instruction and loop invariants).] - [No (just `assert`).] -][ - [['Loop variants]] - [Yes, [macroref CONTRACT_LOOP_VARIANT].] - [No.] - [Yes.] - [No.] -][ - [['Disable assertion checking within assertions checking]] + [['Disable assertion checking within assertions checking (to avoid infinite recursion when checking contracts)]] [ - Yes (use [macroref CONTRACT_CONFIG_PRECONDITIONS_DISABLE_NO_ASSERTION] for preconditions to disable no assertion). - Use [macroref CONTRACT_CONFIG_THREAD_SAFE] to make the implementation of this feature thread-safe in multi-threaded programs (but it will introduce a global lock). +Yes (but use [macroref BOOST_CONTRACT_CONFIG_PRECONDITIONS_DISABLE_NO_ASSERTION] to disable no assertion while checking preconditions). +[footnote +*Rationale.* +Theoretically, it can be shown that an incorrect argument might be passed to the function body when assertion checking is disabled while checking preconditions (see [@http://lists.boost.org/Archives/boost/2010/04/164862.php Re: \[boost\] \[contract\] diff n1962]). +Therefore, __N1962__ does not disable any assertion while checking preconditions. +However, that makes it possible to have infinite recursion while checking preconditions, plus __Eiffel__ disables assertion checking also while checking preconditions. +Therefore, this library by default disables assertion checking also while checking preconditions, but it also provides the [macroref BOOST_CONTRACT_CONFIG_PRECONDITIONS_DISABLE_NO_ASSERTION] configuration macro so users can change that behaviour if they need to. ] - [Yes for class invariants and postconditions but preconditions disable no assertion.] + Use [macroref BOOST_CONTRACT_CONFIG_THREAD_SAFE] to make the implementation of this feature thread-safe in multi-threaded programs (but this will introduce a global lock).] + [Yes for class invariants and postconditions, but preconditions disable no assertion.] [Yes.] [No.] -][ - [['Assertion requirements]] - [Yes (compilation and run-time checking of single assertions can be disabled when specific assertion requirements are not met).] - [No.] - [No (but all types are __CopyConstructible__, __Assignable__, and __EqualityComparable__ in __Eiffel__ so there is not a real need for this).] - [No.] ][ [['Nested member function calls]] [ - Disable nothing. - [footnote - *Rationale.* - Older versions of this library automatically defined a data member used to disable checking of class invariants within member function calls. - However, this feature, which was required by older revisions of __N1962__, is no longer required by __N1962__, it complicates the implementation, and in multi-thread programs would introduce a lock that synchronizes all member functions calls for a given object so it was removed in the current revision of the library. - ] +Disable nothing. +[footnote +*Rationale.* +Older versions of this library defined a data member in the user class that was automatically used to disable checking of class invariants within nested member function calls (similarly to __Eiffel__). +However, this feature was required by older revisions of __N1962__ but it is no longer required by __N1962__. +Furthermore, in multi-threaded programs this feature would introduce a lock that synchronizes all member functions calls for a given object. +Therefore, this feature was removed in the current revision of this library. +] ] [Disable nothing.] - [Disable all checks.] + [Disable all contract assertions.] [Disable nothing.] ][ - [['Non-static class invariants checking]] + [['Disable contract checking]] [ - At constructor exit, at destructor entry, and at public member function entry, exit, and on throw (but only if programmers declare these functions using this library macros). - Same for volatile class invariants.] - [At constructor exit, at destructor entry, and at public member function entry, exit, and on throw (volatile class invariants not supported).] - [At constructor exit, and around public member functions.] - [At constructor exit, at destructor entry, an around public member functions.] -][ - [['Static class invariants checking]] - [At entry and exit of any (also static) member function, constructor, and destructor.] - [No.] - [No (but __Eiffel__ does not have static members).] - [No.] -][ - [['Removable from object code]] - [Yes, using any combination of [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS], [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS], [macroref CONTRACT_CONFIG_NO_BLOCK_INVARIANTS], and [macroref CONTRACT_CONFIG_NO_LOOP_VARIANTS].] - [Yes.] - [Yes (but predefined combinations only).] +Yes, contract checking can be skipped at run-time by defining any combination of the macros [macroref BOOST_CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS], and [macroref BOOST_CONTRACT_CONFIG_NO_INVARIANTS]. +(Also removing contract code from compiled object code is possible but requires users to program a fare amount of boiler-plate code, see also the __Smaller_Object_Code__ section.) +] + [Yes (contract code also removed from compiled object code).] + [Yes, but only predefined combinations of preconditions, postconditions, and class invariants can be disabled (contract code also removed from compiled object code).] [Yes.] ] ] -Contract Programming is also provided by the following references. +The authors of this library also consulted the following references that implement Contract Programming for C++ (but usually for a somewhat limited subset of the features above) or for other languages (see the __Bibliography__ section for a complete list of all the references consulted in the design and development of this library): [table [ [Reference] [Language] [Notes] ] @@ -479,23 +456,23 @@ Contract Programming is also provided by the following references. The Digital Mars C++ compiler extends C++ adding Contract Programming language support (among many other features). ] ] [ [__Lindrud04__] [C++] [ -This supports class invariants and old values but it does not support subcontracting, contracts are specified within definitions instead of declarations, assertions are not constant-correct (unfortunately, these missing features are all essential to Contract Programming). +This supports class invariants and old values but it does not support subcontracting (plus contracts are specified within definitions instead of declarations and assertions are not constant-correct). ] ] [ [__Tandin04__] [C++] [ Interestingly, these contract macros automatically generate __Doxygen__ documentation [footnote *Rationale.* -Older versions of this library used to automatically generate __Doxygen__ documentation from the contract macros. -This functionality was abandoned for a number of reasons: this library macros became too complex and the __Doxygen__ preprocessor is no longer able to expand them; the __Doxygen__ documentation was just a repeat of the contract code (so programmers can directly look at contracts in the header files), __Doxygen__ might not necessarily be the documentation tool chosen by all programmers. +Older versions of this library used to automatically generate __Doxygen__ documentation from contract definition macros. +This functionality was abandoned for a number of reasons: This library no longer uses macros to program contracts; The used macros became too complex and the __Doxygen__ preprocessor was no longer able to expand them; The __Doxygen__ documentation was just a repeat of the contract code (so programmers could directly look at contracts in the source code); __Doxygen__ might not necessarily be the C++ documentation tool used by all programmers. ] -but old values, class invariants, and subcontracting are not supported plus contracts are specified within definitions instead of declarations (unfortunately, these missing features are all essential to Contract Programming). +but old values, class invariants, and subcontracting are not supported (plus contracts are specified within definitions instead of declarations and assertions are not constant-correct). ] ] [ [__Maley99__] [C++] [ -This supports Contract Programming including subcontracting but with some limitations (e.g., programmers need to manually build an inheritance tree using artificial template parameters), it does not use macros so programmers are required to write by hand a significant amount of boiler-plate code. -(The authors have found this work very inspiring when they started to develop this library.) +This supports Contract Programming including subcontracting but with some limitations (e.g., programmers need to manually build an inheritance tree using artificial template parameters), it does not use macros but programmers are required to write by hand a significant amount of boiler-plate code. +(The authors have found this work very inspiring when developing the first revisions of this library especially for the attempt to support subcontracting.) ] ] [ [__C2__] [C++] [ -This uses an external preprocessing tool (the authors could no longer find this project code-base to evaluate it). +This uses an external preprocessing tool (the authors could no longer find this project's code to evaluate it). ] ] [ [__iContract__] [Java] [ This uses an external preprocessing tool. @@ -513,14 +490,21 @@ This is a C# extension with Contract Programming language support. This is the .NET version of Object Pascal and it has language support for Contract Programming. ] ] [ [__SPARKAda__] [Ada] [ -This is an Ada-like programming language with Contract Programming support. +This is an Ada-like programming language with support for Contract Programming. ] ] ] Typically, preprocessing tools external to the language work by transforming specially formatted code comments into contract code that is then checked at run-time. -One of this library primary goals was to support Contract Programming entirely within C++ and without using any tool external to the standard language (C++ macros were used instead of external preprocessing tools). +One of this library primary goals was to support Contract Programming entirely /within C++/ and without using any tool external to the standard language. -To the authors' knowledge, this the only library that fully support Contract Programming for C++ (see the __Bibliography__ section for the complete list of Contract Programming references studied by the authors). +To the authors' knowledge, this the only library that fully supports all Contract Programming features for C++. +[footnote +Generally speaking, implementing preconditions and postconditions in C++ is not difficult (e.g., using some type of __RAII__ object). +Implementing postcondition old values is also not too difficult (usually requiring users to copy old values into local variables, but it is somewhat more difficult to ensure such copies are not performed when postconditions are disable). +Most libraries stop here because implementing class invariants already becomes complex. +Then implementing subcontracting requires a significant amount of complexity and it seems to not be properly supported by any other library (especially with multiple inheritance, continuing to correctly copying postcondition old values across all overridden contracts, and reporting correct the result value to the postconditions overridden virtual functions). +This library supports all of these features instead. +] [endsect] diff --git a/doc/qbk/examples.qbk b/doc/qbk/examples.qbk index 18e03fb..ac55374 100644 --- a/doc/qbk/examples.qbk +++ b/doc/qbk/examples.qbk @@ -8,7 +8,7 @@ [section Examples] This section lists non-trivial examples programmed using this library. -The listed examples are taken from the following sources (which are referenced in the title of each example). +The listed examples are taken from the foloowing sources (which are referenced in the title of each example). [table [ [Sources] [Notes] ] @@ -55,9 +55,9 @@ A comparison between this library and A++ syntax. ] [section \[N1962\] Vector: Comparison with C++ proposed syntax] -[/ import ../example/n1962/vector.hpp] -[/ import ../example/n1962/vector.cpp] -[/ import ../example/n1962/vector_npaper.hpp] +[import ../example/n1962/vector.hpp] +[import ../example/n1962/vector.cpp] +[import ../example/n1962/vector_npaper.hpp] [table [ [This Library (C++03)] [\[N1962\] and \[N2081\] Proposals (not part of C++)] ] [ [[n1962_vector]] [[n1962_vector_npaper]] ] @@ -66,36 +66,36 @@ A comparison between this library and A++ syntax. [endsect] [section \[N1962\] Circle: Subcontracting] -[/ import ../example/n1962/circle.cpp] +[import ../example/n1962/circle.cpp] [n1962_circle] [endsect] [section \[N1962\] Factorial: Recursion and assertion computational complexity] -[/ import ../example/n1962/factorial.cpp] +[import ../example/n1962/factorial.cpp] [n1962_factorial] [endsect] [section \[N1962\] Equal: Operators] -[/ import ../example/n1962/equal.hpp] +[import ../example/n1962/equal.hpp] [n1962_equal_header] -[/ import ../example/n1962/equal_not.hpp] +[import ../example/n1962/equal_not.hpp] [n1962_equal_not_header] -[/ import ../example/n1962/equal_main.cpp] +[import ../example/n1962/equal_main.cpp] [n1962_equal_main] [endsect] [section \[N1962\] Sum: Separated body definitions] -[/ import ../example/n1962/sum.hpp] +[import ../example/n1962/sum.hpp] [n1962_sum_header] -[/ import ../example/n1962/sum.cpp] +[import ../example/n1962/sum.cpp] [n1962_sum] -[/ import ../example/n1962/sum_main.cpp] +[import ../example/n1962/sum_main.cpp] [n1962_sum_main] [endsect] [section \[N1962\] Square Root: Default parameters and comparison with D syntax] -[/ import ../example/n1962/sqrt.cpp] -[/ import ../example/n1962/sqrt.d] +[import ../example/n1962/sqrt.cpp] +[import ../example/n1962/sqrt.d] [table [ [This Library (C++03)] [The D Programming Language] ] [ [[n1962_sqrt]] [[n1962_sqrt_d]] ] @@ -103,87 +103,87 @@ A comparison between this library and A++ syntax. [endsect] [section \[N1962\] Block: Block invariants] -[/ import ../example/n1962/block_invariant.cpp] +[import ../example/n1962/block_invariant.cpp] [n1962_block_invariant] [endsect] [section \[N2081\] Add: Generic addition algorithm] -[/ import ../example/n2081/add.hpp] +[import ../example/n2081/add.hpp] [n2081_add_header] -[/ import ../example/n2081/add.cpp] +[import ../example/n2081/add.cpp] [n2081_add] -[/ import ../example/n2081/add_error.cpp] +[import ../example/n2081/add_error.cpp] [n2081_add_error] [endsect] [section \[N2081\] Advance: Concept-based iterator overloading (emulated using tags)] -[/ import ../example/n2081/advance.cpp] +[import ../example/n2081/advance.cpp] [n2081_advance] [endsect] [section \[N2081\] Find: Generic find algorithm] -[/ import ../example/n2081/find.hpp] +[import ../example/n2081/find.hpp] [n2081_find_header] -[/ import ../example/n2081/find.cpp] +[import ../example/n2081/find.cpp] [n2081_find] -[/ import ../example/n2081/find_error.cpp] +[import ../example/n2081/find_error.cpp] [n2081_find_error] [endsect] [section \[N2081\] Apply: Overloaded invocation of functors] -[/ import ../example/n2081/apply.cpp] +[import ../example/n2081/apply.cpp] [n2081_apply] [endsect] [section \[N2081\] For Each: Generic for-each algorithm] -[/ import ../example/n2081/for_each.cpp] +[import ../example/n2081/for_each.cpp] [n2081_for_each] [endsect] [section \[N2081\] Transform: Generic binary transformation algorithm] -[/ import ../example/n2081/transform.cpp] +[import ../example/n2081/transform.cpp] [n2081_transform] [endsect] [section \[N2081\] Count: Generic counting algorithm] -[/ import ../example/n2081/count.cpp] +[import ../example/n2081/count.cpp] [n2081_count] [endsect] [section \[N2081\] Convert: Conversion between two types] -[/ import ../example/n2081/convert.hpp] +[import ../example/n2081/convert.hpp] [n2081_convert_header] -[/ import ../example/n2081/convert.cpp] +[import ../example/n2081/convert.cpp] [n2081_convert] -[/ import ../example/n2081/convert_error.cpp] +[import ../example/n2081/convert_error.cpp] [n2081_convert_error] [endsect] [section \[N2081\] Equal: Generic equality comparison] -[/ import ../example/n2081/equal.hpp] +[import ../example/n2081/equal.hpp] [n2081_equal_header] -[/ import ../example/n2081/equal.cpp] +[import ../example/n2081/equal.cpp] [n2081_equal] -[/ import ../example/n2081/equal_error.cpp] +[import ../example/n2081/equal_error.cpp] [n2081_equal_error] [endsect] [section \[N2081\] Less Equal: Generic less-than or equal-to comparison] -[/ import ../example/n2081/less_eq.cpp] +[import ../example/n2081/less_eq.cpp] [n2081_less_eq] [endsect] [section \[N2081\] De-Ref: Generic iterator dereferencing] -[/ import ../example/n2081/deref.cpp] +[import ../example/n2081/deref.cpp] [n2081_deref] [endsect] [section \[N2081\] Min: Generic minimum algorithm] -[/ import ../example/n2081/min.hpp] +[import ../example/n2081/min.hpp] [n2081_min_header] -[/ import ../example/n2081/min.cpp] +[import ../example/n2081/min.cpp] [n2081_min] -[/ import ../example/n2081/min_error.cpp] +[import ../example/n2081/min_error.cpp] [n2081_min_error] [endsect] @@ -204,8 +204,8 @@ A comparison between this library and A++ syntax. [endsect] [section \[Meyer97\] GCD: Loop variants and invariants plus comparison with Eiffel syntax] -[/ import ../example/meyer97/gcd.cpp] -[/ import ../example/meyer97/gcd.e] +[import ../example/meyer97/gcd.cpp] +[import ../example/meyer97/gcd.e] [table [ [This Library (C++03)] [The Eiffel Programming Language] ] [ [[meyer97_gcd]] [[teletype] [meyer97_gcd_e] [c++]] ] @@ -213,85 +213,85 @@ A comparison between this library and A++ syntax. [endsect] [section \[Meyer97\] Max-Array: Nested loop variants and invariants] -[/ import ../example/meyer97/maxarray.cpp] +[import ../example/meyer97/maxarray.cpp] [meyer97_maxarray] [endsect] [section \[Mitchell02\] Name List: Relaxed subcontracts] -[/ import ../example/mitchell02/name_list.hpp] +[import ../example/mitchell02/name_list.hpp] [mitchell02_name_list_header] -[/ import ../example/mitchell02/name_list.cpp] +[import ../example/mitchell02/name_list.cpp] [mitchell02_name_list] -[/ import ../example/mitchell02/name_list_main.cpp] +[import ../example/mitchell02/name_list_main.cpp] [mitchell02_name_list_main] [endsect] [section \[Mitchell02\] Dictionary: Simple key-value map] -[/ import ../example/mitchell02/dictionary.cpp] +[import ../example/mitchell02/dictionary.cpp] [mitchell02_dictionary] [endsect] [section \[Mitchell02\] Courier: Subcontracting and static class invariants] -[/ import ../example/mitchell02/courier.hpp] +[import ../example/mitchell02/courier.hpp] [mitchell02_courier_header] -[/ import ../example/mitchell02/courier.cpp] +[import ../example/mitchell02/courier.cpp] [mitchell02_courier] -[/ import ../example/mitchell02/courier_main.cpp] +[import ../example/mitchell02/courier_main.cpp] [mitchell02_courier_main] [endsect] [section \[Mitchell02\] Stack: Simple stack dispenser] -[/ import ../example/mitchell02/stack.cpp] +[import ../example/mitchell02/stack.cpp] [mitchell02_stack] [endsect] [section \[Mitchell02\] Simple Queue: Simple queue dispenser] -[/ import ../example/mitchell02/simple_queue.cpp] +[import ../example/mitchell02/simple_queue.cpp] [mitchell02_simple_queue] [endsect] [section \[Mitchell02\] Customer Manager: Contracts instead of Defensive Programming] -[/ import ../example/mitchell02/customer_manager.hpp] +[import ../example/mitchell02/customer_manager.hpp] [mitchell02_customer_manager_header] -[/ import ../example/mitchell02/customer_manager.cpp] +[import ../example/mitchell02/customer_manager.cpp] [mitchell02_customer_manager] -[/ import ../example/mitchell02/customer_manager_main.cpp] +[import ../example/mitchell02/customer_manager_main.cpp] [mitchell02_customer_manager_main] [endsect] [section \[Mitchell02\] Observer: Contracts for pure virtual functions] -[/ import ../example/mitchell02/observer/observer.hpp] +[import ../example/mitchell02/observer/observer.hpp] [mitchell02_observer_header] -[/ import ../example/mitchell02/observer/subject.hpp] +[import ../example/mitchell02/observer/subject.hpp] [mitchell02_subject_header] -[/ import ../example/mitchell02/observer_main.cpp] +[import ../example/mitchell02/observer_main.cpp] [mitchell02_observer_main] [endsect] [section \[Mitchell02\] Counter: Subcontracting and virtual specifiers (final, override, new, and pure virtual)] -[/ import ../example/mitchell02/counter/push_button.hpp] +[import ../example/mitchell02/counter/push_button.hpp] [mitchell02_push_button_header] -[/ import ../example/mitchell02/counter/decrement_button.hpp] +[import ../example/mitchell02/counter/decrement_button.hpp] [mitchell02_decrement_button_header] -[/ import ../example/mitchell02/counter/counter.hpp] +[import ../example/mitchell02/counter/counter.hpp] [mitchell02_counter_header] -[/ import ../example/mitchell02/counter_main.cpp] +[import ../example/mitchell02/counter_main.cpp] [mitchell02_counter_main] [endsect] [section \[Stroustrup97\] String: Throw when contract is broken] -[/ import ../example/stroustrup97/string.hpp] +[import ../example/stroustrup97/string.hpp] [stroustrup97_string_header] -[/ import ../example/stroustrup97/string.cpp] +[import ../example/stroustrup97/string.cpp] [stroustrup97_string] -[/ import ../example/stroustrup97/string_main.cpp] +[import ../example/stroustrup97/string_main.cpp] [stroustrup97_string_main] [endsect] [section \[Cline90\] Vector: Comparison with A++ proposed syntax] -[/ import ../example/cline90/vector.hpp] -[/ import ../example/cline90/vector_main.cpp] -[/ import ../example/cline90/vector_app.hpp] +[import ../example/cline90/vector.hpp] +[import ../example/cline90/vector_main.cpp] +[import ../example/cline90/vector_app.hpp] [table [ [This Library (C++03)] [A++ Proposal (not part of C++)] ] [ [[cline90_vector_header]] [[cline90_vector_app_header]] ] @@ -300,17 +300,17 @@ A comparison between this library and A++ syntax. [endsect] [section \[Cline90\] Stack: Function-Try blocks and exception specifications] -[/ import ../example/cline90/stack.cpp] +[import ../example/cline90/stack.cpp] [cline90_stack] [endsect] [section \[Cline90\] Vector-Stack: Subcontracting from Abstract Data Type (ADT)] -[/ import ../example/cline90/vstack.cpp] +[import ../example/cline90/vstack.cpp] [cline90_vstack] [endsect] [section \[Cline90\] Calendar: A very simple calendar] -[/ import ../example/cline90/calendar.cpp] +[import ../example/cline90/calendar.cpp] [cline90_calendar] [endsect] diff --git a/doc/qbk/full_table_of_contents.qbk b/doc/qbk/full_table_of_contents.qbk deleted file mode 100644 index 4188126..0000000 --- a/doc/qbk/full_table_of_contents.qbk +++ /dev/null @@ -1,248 +0,0 @@ - -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - -[section Full Table of Contents] - -[link contract__.introduction Introduction] - -[link contract__.full_table_of_contents Full Table Of Contents] - -[link contract__.getting_started Getting Started] -[: - [link contract__.getting_started.this_documentation This Documentation] [br] - [link contract__.getting_started.compilers_and_platforms Compilers and Platforms] [br] - [link contract__.getting_started.installation Installation] [br] - [link contract__.getting_started.disable_contract_compilation Disable Contract Compilation] [br] -] - -[link contract__.contract_programming_overview Contract Programming Overview] -[: - [link contract__.contract_programming_overview.assertions Assertions] [br] - [link contract__.contract_programming_overview.benefits Benefits] [br] - [link contract__.contract_programming_overview.costs Costs] [br] - [link contract__.contract_programming_overview.free_function_calls Free Function Calls] [br] - [link contract__.contract_programming_overview.member_function_calls Member Function Calls] [br] - [link contract__.contract_programming_overview.constructor_calls Constructor Calls] [br] - [link contract__.contract_programming_overview.destructor_calls Destructor Calls] [br] - [link contract__.contract_programming_overview.constant_correctness Constant-Correctness] [br] - [link contract__.contract_programming_overview.specification_vs__implementation Specification vs. Implementation] [br] - [link contract__.contract_programming_overview.broken_contracts Broken Contracts] [br] - [link contract__.contract_programming_overview.features Features] [br] -] - -[link contract__.tutorial Tutorial] -[: - [link contract__.tutorial.free_functions Free Functions] [br] - [link contract__.tutorial.preconditions Preconditions] [br] - [link contract__.tutorial.postconditions__result_and_old_values_ Postconditions (Result and Old Values)] [br] - [link contract__.tutorial.classes_and_class_invariants Classes and Class Invariants] [br] - [link contract__.tutorial.constructors Constructors] [br] - [link contract__.tutorial.destructors Destructors] [br] - [link contract__.tutorial.member_functions Member Functions] [br] - [link contract__.tutorial.inheritance_and_subcontracting Inheritance and Subcontracting] [br] - [link contract__.tutorial.class_templates Class Templates] [br] - [link contract__.tutorial.function_templates Function Templates] [br] - [link contract__.tutorial.forward_declarations_and_body_definitions Forward Declarations and Body Definitions] [br] -] - -[link contract__.advanced_topics Advanced Topics] -[: - [link contract__.advanced_topics.commas_and_leading_symbols_in_macros Commas and Leading Symbols in Macros] [br] - [link contract__.advanced_topics.static_assertions Static Assertions] [br] - [link contract__.advanced_topics.constant_assertions Constant Assertions] [br] - [link contract__.advanced_topics.select_assertions Select Assertions] [br] - [link contract__.advanced_topics.assertion_statements Assertion Statements] [br] - [link contract__.advanced_topics.assertion_requirements Assertion Requirements] [br] - [link contract__.advanced_topics.old_of_requirements Old-Of Requirements] [br] - [link contract__.advanced_topics.old_and_result_value_copies Old and Result Value Copies] [br] - [link contract__.advanced_topics.pure_virtual_functions Pure Virtual Functions] [br] - [link contract__.advanced_topics.subcontracting_preconditions Subcontracting Preconditions] [br] - [link contract__.advanced_topics.static_member_functions Static Member Functions] [br] - [link contract__.advanced_topics.volatile_member_functions Volatile Member Functions] [br] - [link contract__.advanced_topics.operators Operators] [br] - [link contract__.advanced_topics.nested_classes Nested Classes] [br] - [link contract__.advanced_topics.friends Friends] [br] - [link contract__.advanced_topics.template_specializations Template Specializations] [br] - [link contract__.advanced_topics.exception_specifications_and_function_try_blocks Exception Specifications and Function-Try Blocks] [br] - [link contract__.advanced_topics.specifying_types__no_boost_typeof_ Specifying Types (no Boost.Typeof)] [br] - [link contract__.advanced_topics.block_invariants_and_loop_variants Block Invariants and Loop Variants] [br] - [link contract__.advanced_topics.contract_broken_handlers__throw_on_failure_ Contract Broken Handlers (Throw on Failure)] [br] -] - -[link contract__.virtual_specifiers Virtual Specifiers] -[: - [link contract__.virtual_specifiers.final_classes Final Classes] [br] - [link contract__.virtual_specifiers.final_member_functions Final Member Functions] [br] - [link contract__.virtual_specifiers.overriding_member_functions Overriding Member Functions] [br] - [link contract__.virtual_specifiers.new_member_functions New Member Functions] [br] -] - -[link contract__.concepts Concepts] -[: - [link contract__.concepts.class_templates Class Templates] [br] - [link contract__.concepts.function_templates Function Templates] [br] - [link contract__.concepts.concept_definitions__not_implemented_ Concept Definitions (Not Implemented)] [br] -] - -[link contract__.named_parameters Named Parameters] -[: - [link contract__.named_parameters.overview Overview] [br] - [link contract__.named_parameters.named_function_parameters Named Function Parameters] [br] - [link contract__.named_parameters.deduced_function_parameters Deduced Function Parameters] [br] - [link contract__.named_parameters.member_function_parameters Member Function Parameters] [br] - [link contract__.named_parameters.constructor_parameters Constructor Parameters] [br] - [link contract__.named_parameters.class_template_parameters Class Template Parameters] [br] - [link contract__.named_parameters.concepts Concepts] [br] - [link contract__.named_parameters.parameter_identifiers Parameter Identifiers] [br] -] - -[link contract__.examples Examples] -[: - [link contract__.examples.__n1962___vector__comparison_with_c___proposed_syntax \[N1962\] Vector: Comparison with C++ proposed syntax] [br] - [link contract__.examples.__n1962___circle__subcontracting \[N1962\] Circle: Subcontracting] [br] - [link contract__.examples.__n1962___factorial__recursion_and_assertion_computational_complexity \[N1962\] Factorial: Recursion and assertion computational complexity] [br] - [link contract__.examples.__n1962___equal__operators \[N1962\] Equal: Operators] [br] - [link contract__.examples.__n1962___sum__separated_body_definitions \[N1962\] Sum: Separated body definitions] [br] - [link contract__.examples.__n1962___square_root__default_parameters_and_comparison_with_d_syntax \[N1962\] Square Root: Default parameters and comparison with D syntax] [br] - [link contract__.examples.__n1962___block__block_invariants \[N1962\] Block: Block invariants] [br] - [link contract__.examples.__n2081___add__generic_addition_algorithm \[N2081\] Add: Generic addition algorithm] [br] - [link contract__.examples.__n2081___advance__concept_based_iterator_overloading__emulated_using_tags_ \[N2081\] Advance: Concept-based iterator overloading (emulated using tags)] [br] - [link contract__.examples.__n2081___find__generic_find_algorithm \[N2081\] Find: Generic find algorithm] [br] - [link contract__.examples.__n2081___apply__overloaded_invocation_of_functors \[N2081\] Apply: Overloaded invocation of functors] [br] - [link contract__.examples.__n2081___for_each__generic_for_each_algorithm \[N2081\] For Each: Generic for-each algorithm] [br] - [link contract__.examples.__n2081___transform__generic_binary_transformation_algorithm \[N2081\] Transform: Generic binary transformation algorithm] [br] - [link contract__.examples.__n2081___count__generic_counting_algorithm \[N2081\] Count: Generic counting algorithm] [br] - [link contract__.examples.__n2081___convert__conversion_between_two_types \[N2081\] Convert: Conversion between two types] [br] - [link contract__.examples.__n2081___equal__generic_equality_comparison \[N2081\] Equal: Generic equality comparison] [br] - [link contract__.examples.__n2081___less_equal__generic_less_than_or_equal_to_comparison \[N2081\] Less Equal: Generic less-than or equal-to comparison] [br] - [link contract__.examples.__n2081___de_ref__generic_iterator_dereferencing \[N2081\] De-Ref: Generic iterator dereferencing] [br] - [link contract__.examples.__n2081___min__generic_minimum_algorithm \[N2081\] Min: Generic minimum algorithm] [br] - [link contract__.examples.__meyer97___stack4__comparison_with_eiffel_syntax \[Meyer97\] Stack4: Comparison with Eiffel Syntax] [br] - [link contract__.examples.__meyer97___stack3__error_codes_instead_of_preconditions \[Meyer97\] Stack3: Error codes instead of preconditions] [br] - [link contract__.examples.__meyer97___gcd__loop_variants_and_invariants_plus_comparison_with_eiffel_syntax \[Meyer97\] GCD: Loop variants and invariants plus comparison with Eiffel syntax] [br] - [link contract__.examples.__meyer97___max_array__nested_loop_variants_and_invariants \[Meyer97\] Max-Array: Nested loop variants and invariants] [br] - [link contract__.examples.__mitchell02___name_list__relaxed_subcontracts \[Mitchell02\] Name List: Relaxed subcontracts] [br] - [link contract__.examples.__mitchell02___dictionary__simple_key_value_map \[Mitchell02\] Dictionary: Simple key-value map] [br] - [link contract__.examples.__mitchell02___courier__subcontracting_and_static_class_invariants \[Mitchell02\] Courier: Subcontracting and static class invariants] [br] - [link contract__.examples.__mitchell02___stack__simple_stack_dispenser \[Mitchell02\] Stack: Simple stack dispenser] [br] - [link contract__.examples.__mitchell02___simple_queue__simple_queue_dispenser \[Mitchell02\] Simple Queue: Simple queue dispenser] [br] - [link contract__.examples.__mitchell02___customer_manager__contracts_instead_of_defensive_programming \[Mitchell02\] Customer Manager: Contracts instead of Defensive Programming] [br] - [link contract__.examples.__mitchell02___observer__contracts_for_pure_virtual_functions \[Mitchell02\] Observer: Contracts for pure virtual functions] [br] - [link contract__.examples.__mitchell02___counter__subcontracting_and_virtual_specifiers__final__override__new__and_pure_virtual_ \[Mitchell02\] Counter: Subcontracting and virtual specifiers (final, override, new, and pure virtual)] [br] - [link contract__.examples.__stroustrup97___string__throw_when_contract_is_broken \[Stroustrup97\] String: Throw when contract is broken] [br] - [link contract__.examples.__cline90___vector__comparison_with_a___proposed_syntax \[Cline90\] Vector: Comparison with A++ proposed syntax] [br] - [link contract__.examples.__cline90___stack__function_try_blocks_and_exception_specifications \[Cline90\] Stack: Function-Try blocks and exception specifications] [br] - [link contract__.examples.__cline90___vector_stack__subcontracting_from_abstract_data_type__adt_ \[Cline90\] Vector-Stack: Subcontracting from Abstract Data Type (ADT)] [br] - [link contract__.examples.__cline90___calendar__a_very_simple_calendar \[Cline90\] Calendar: A very simple calendar] [br] -] - -[link contract__.grammar Grammar] -[: - [link contract__.grammar.preprocessor_dsel Preprocessor DSEL] [br] - [link contract__.grammar.differences_with_c___syntax Differences with C++ Syntax] [br] - [link contract__.grammar.macro_interface Macro Interface] [br] - [link contract__.grammar.lexical_conventions Lexical Conventions] [br] - [link contract__.grammar.class_declarations Class Declarations] [br] - [link contract__.grammar.base_classes Base Classes] [br] - [link contract__.grammar.template_specializations Template Specializations] [br] - [link contract__.grammar.template_parameters Template Parameters] [br] - [link contract__.grammar.concepts Concepts] [br] - [link contract__.grammar.types Types] [br] - [link contract__.grammar.function_declarations Function Declarations] [br] - [link contract__.grammar.result_type Result Type] [br] - [link contract__.grammar.function_and_operator_names Function and Operator Names] [br] - [link contract__.grammar.exception_specifications Exception Specifications] [br] - [link contract__.grammar.member_initializers Member Initializers] [br] - [link contract__.grammar.function_parameters Function Parameters] [br] - [link contract__.grammar.result_and_old_values Result and Old Values] [br] - [link contract__.grammar.class_invariants Class Invariants] [br] - [link contract__.grammar.assertions Assertions] [br] - [link contract__.grammar.loop_variants Loop Variants] [br] - [link contract__.grammar.named_parameter_declarations Named Parameter Declarations] [br] - [link contract__.grammar.terminals Terminals] [br] - [link contract__.grammar.alternative_assertion_syntax__not_implemented_ Alternative Assertion Syntax (Not Implemented)] [br] -] - -[link contract__.no_variadic_macros No Variadic Macros] -[: - [link contract__.no_variadic_macros.sequence_syntax Sequence Syntax] [br] - [link contract__.no_variadic_macros.commas_and_leading_symbols_in_macros Commas and Leading Symbols in Macros] [br] -] - -[link reference Reference] -[: - [funcref contract::block_invariant_broken] [br] - [classref contract::broken] [br] - [classref contract::broken_contract_handler] [br] - [funcref contract::class_invariant_broken_on_entry] [br] - [funcref contract::class_invariant_broken_on_exit] [br] - [funcref contract::class_invariant_broken_on_throw] [br] - [classref contract::copy] [br] - [enumref contract::from] [br] - [classref contract::has_oldof] [br] - [funcref contract::loop_variant_broken] [br] - [funcref contract::postcondition_broken] [br] - [funcref contract::precondition_broken] [br] - [funcref contract::set_block_invariant_broken] [br] - [funcref contract::set_class_invariant_broken] [br] - [funcref contract::set_class_invariant_broken_on_entry] [br] - [funcref contract::set_class_invariant_broken_on_exit] [br] - [funcref contract::set_class_invariant_broken_on_throw] [br] - [funcref contract::set_loop_variant_broken] [br] - [funcref contract::set_postcondition_broken] [br] - [funcref contract::set_precondition_broken] [br] - [macroref CONTRACT_BLOCK_INVARIANT] [br] - [macroref CONTRACT_BLOCK_INVARIANT_TPL] [br] - [macroref CONTRACT_CLASS] [br] - [macroref CONTRACT_CLASS_INVARIANT] [br] - [macroref CONTRACT_CLASS_INVARIANT_TPL] [br] - [macroref CONTRACT_CLASS_TPL] [br] - [macroref CONTRACT_CONFIG_ARRAY_DIMENSION_MAX] [br] - [macroref CONTRACT_CONFIG_DO_NOT_SUBCONTRACT_PRECONDITIONS] [br] - [macroref CONTRACT_CONFIG_FUNCTION_ARITY_MAX] [br] - [macroref CONTRACT_CONFIG_INHERITANCE_MAX] [br] - [macroref CONTRACT_CONFIG_NO_BLOCK_INVARIANTS] [br] - [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS] [br] - [macroref CONTRACT_CONFIG_NO_LOOP_VARIANTS] [br] - [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS] [br] - [macroref CONTRACT_CONFIG_NO_PRECONDITIONS] [br] - [macroref CONTRACT_CONFIG_OLDOF_MAX] [br] - [macroref CONTRACT_CONFIG_PRECONDITIONS_DISABLE_NO_ASSERTION] [br] - [macroref CONTRACT_CONFIG_REPORT_BASE_PRECONDITION_FAILURE] [br] - [macroref CONTRACT_CONFIG_THREAD_SAFE] [br] - [macroref CONTRACT_CONSTRUCTOR] [br] - [macroref CONTRACT_CONSTRUCTOR_ARG] [br] - [macroref CONTRACT_CONSTRUCTOR_BODY] [br] - [macroref CONTRACT_CONSTRUCTOR_TPL] [br] - [macroref CONTRACT_DESTRUCTOR] [br] - [macroref CONTRACT_DESTRUCTOR_BODY] [br] - [macroref CONTRACT_DESTRUCTOR_TPL] [br] - [macroref CONTRACT_FREE_BODY] [br] - [macroref CONTRACT_FUNCTION] [br] - [macroref CONTRACT_FUNCTION_TPL] [br] - [macroref CONTRACT_LIMIT_CONSTRUCTOR_TRY_BLOCK_CATCHES] [br] - [macroref CONTRACT_LIMIT_NESTED_SELECT_ASSERTIONS] [br] - [macroref CONTRACT_LIMIT_OLDOFS] [br] - [macroref CONTRACT_LOOP] [br] - [macroref CONTRACT_LOOP_VARIANT] [br] - [macroref CONTRACT_LOOP_VARIANT_TPL] [br] - [macroref CONTRACT_MEMBER_BODY] [br] - [macroref CONTRACT_OLDOF] [br] - [macroref CONTRACT_PARAMETER] [br] - [macroref CONTRACT_PARAMETER_BODY] [br] - [macroref CONTRACT_PARAMETER_TYPEOF] [br] - [macroref CONTRACT_TEMPLATE_PARAMETER] [br] -] - -[link contract__.release_notes Release Notes] - -[link contract__.bibliography Bibliography] - -[link contract__.acknowledgments Acknowledgments] - -[endsect] - diff --git a/doc/qbk/getting_started.qbk b/doc/qbk/getting_started.qbk index b9436bf..3e3d580 100644 --- a/doc/qbk/getting_started.qbk +++ b/doc/qbk/getting_started.qbk @@ -7,123 +7,93 @@ [section Getting Started] -This section explains how to setup a system to use this library. +This section explains how to get oriented in order to start using this library. [section This Documentation] Programmers should have enough knowledge to use this library after reading the __Introduction__, __Getting_Started__, and __Tutorial__ sections. The other sections can be consulted to gain a more in depth knowledge of the library. -Some footnotes are marked by the word "*Rationale*". They explain reasons behind decisions made during the design and implementation of this library. +Some footnotes are marked by the word "*Rationale*". +These explain reasons behind decisions made during the design and implementation of this library. -In most of the examples presented in this documentation the Boost.Detail/LightweightTest macro `BOOST_TEST` is used to assert test conditions (see also =boost/detail/lightweight_test.hpp=). -The `BOOST_TEST` macro is conceptually similar to C++ `assert` but a failure of the checked condition does not abort the program, instead it makes `boost::report_errors` return a non-zero program exit code. +In most of the examples presented in this documentation the Boost.Detail/LightweightTest macroo `BOOST_TEST` and `BOOST_TEST_EQ` are used to test predicates and equality conditions respectively. +These macros are conceptually similar to C-style `assert` macro but they exit the program with a non-zero exit code via `boost::report_errors`, instead of aborting the program. +See =boost/detail/lightweight_test.hpp= for more information. [footnote *Rationale.* -Using Boost.Detail/LightweightTest allows to add the examples to the library regression tests so to make sure that they always compile and run correctly. +Using Boost.Detail/LightweightTest allows to add the examples from this documentation to the library regression tests so to make sure that they always compile and run correctly. +Technically, Boost.Detail/LightweightTest is part of __Boost__'s non-public API so it should not be directly used by users outside __Boost__ (see __Boost_Test__ instead), but it is common practice to use it in the development and testing of other libraries like this one. ] [endsect] [section Compilers and Platforms] -The implementation of this library uses preprocessor and template meta-programming (as supported by __Boost_Preprocessor__ and __Boost_MPL__ respectively), templates with partial specializations and function pointers (similarly to __Boost_Function__), and local functions (as supported by __Boost_LocalFunction__). -The authors originally developed and tested the library on: +In general, this library requires a C++ compiler with a sound support of __SFINAE__ and other template meta-programming techniques as per the __CXX03__ standard. +See the __Without_CXX11__ section for information on how to use this library without __CXX11__ features: -# GCC 4.5.3 on Cygwin (with and without __CXX11__ features enabled =-std=c++0x=). -[footnote -When using GCC to compile large projects that use this library, it might be necessary to appropriately set the `--param gcc-min-expand` option to avoid internal compiler errors due to excessive virtual memory usage. -] +* In theory, it is possible to use this library without __CXX11__ lambda functions. +However, in that case a large amount of boiler-plate code is required to program separate functions to specify preconditions and postconditions (so using this library without __CXX11__ lambda functions is not recommended). +* It is possible to use this library without __CXX11__ (or __CXX99__) variadic macros. +In this case, some (smaller) amount of boiler-plate code is required to manually program the code otherwise expanded by the variadic macros. +* It is always possible to use this library without __CXX11__ auto declarations. +Most of the examples in this documentation use auto declarations only for simplicity and because they make the code more readable. -# Microsoft Visual C++ (MSVC) 8.0 on Windows XP and Windows 7. +The authors originally developed and tested this library on: -At present, the library has not been tested on other compilers or platforms. +* __Clang__ 3.4.2 on Cygwin (with __CXX11__ features enabled =-std=c++11=). +* _GCC__ 4.8.3 on Cygwin (with __CXX11__ features enabled =-std=c++11=). +* Microsoft Visual C++ (__MSVC__) 10.0 on Windows. + +At present, this library has not been tested on other compilers or platforms. [endsect] +[section Files and Names] + +The directory structure of this library's files is as follow: + + +[pre +doc/ + html/ # This documentation. +example/ # Examples (including the ones listed in this documentation). +include/ # Header files. + boost/ + contract.hpp + contract/ + core/ + aux_/ +test/ # Tests. +] + +All headers required by this library can be included at once by: + + #include + +Alternatively, all headers =boost/contract/*.hpp= are independent from one another and they can selectively included one at the time based on the specific API required from this library. +Headers in =boost/contract/core/= are also part of this library public API but they are not independent from other public headers (in general, these headers will be automatically included by including other public headers of this library). + +Header files in =boost/contract/aux_/=, names in the `boost::contract::aux` namespace, names starting with `boost_contract_aux...` and `BOOST_CONTRACT_AUX...` in any namespace are all part of this library private API and should never be used directly in user code. + +Names starting with `BOOST_CONTRACT_ERROR...` are used by this library to report compile-time errors (so spotting these names in error messages reported by the compiler might help in resolving errors). + +[endsect] + + [section Installation] -This library is composed of header files only. -Therefore there is no pre-compiled object file which needs to be installed or linked. -Programmers can simply instruct the C++ compiler where to find the library header files and they can start compiling code using this library. - -[important -This library extensively uses __Boost__ libraries. -__Boost__ version 1.50 must be properly installed in order for this library to compile. -] - -Let ['=ROOT=] be the root directory of this library installation then the directory structure is as follow: - -[pre -['ROOT]/ - doc/ - html/ # This documentation. - example/ # Examples using this library. - include/ # This library source files (headers only). -] - -For example, the following commands can be used to compile code using this library: -[footnote -For convenience, a =Jamfile.v2= file is provided in the example directory that can be used to compile and test all the examples using __Boost_Jam__. -However, it is not necessary to use __Boost_Jam__ to compile code that uses this library. -] - -[pre -$ g++ -I ['ROOT]/include ... # For GCC. -> cl /I ['ROOT]\include ... # For MSVC. -] - -All necessary library headers are included in the source code by the following instruction (it is not necessary to include single headers separately): - - #include // Include this library headers. - -The following symbols are part of the library private interface, they are not documented, and they should not be directly used by programmers: -[footnote -*Rationale.* -This library concatenates symbols specified by programmers (e.g., the function name) with other symbols (e.g., special prefixes and line numbers) to make internal symbols with unique names to avoid name clashes. -These symbols are separated by the letter `X` when they are concatenated so they read more easily during debugging (unfortunately, the underscore character `_` could not be used instead of the letter `X` because if the original symbol already contained a leading or trailing underscore, the concatenation could result in a symbol with double underscores `__` which is reserved by the C++ standard). -The ["aux] symbols are internal to the implementation of this library. -The ["detail] symbols are not officially part of the library public interface and they are not documented however they constitute a separate set of standalone libraries that could be added to the library public interface in the future. -] - -* Any symbol defined by files within the =contract/aux_/= or =contract/detail/= directories (these header files should not be directly included by programmers). -* Any symbol within the `contract::aux` or `contract::detail` namespace. -* Any symbol prefixed by `contract_aux_...` or `contract_detail_...` (regardless of its namespace). -* Any symbol prefixed by `CONTRACT_AUX_...` or `CONTRACT_DETAIL_...` (regardless of its namespace). - -Symbols starting with `ERROR_...` are used to report compile-time errors via static assertions and programmers should not use these symbols to define macros or other constructs in the global namespace. +TODO [endsect] [section Disable Contract Compilation] -Some of the library behaviour can be customized at compile-time by defining special /configuration macros/ (see [headerref contract/config.hpp]). -In particular, the following configuration macros can be used to selectively turn on or off contract compilation and the related run-time checks: +Some behaviour of this library can be customized at compile-time by defining special /configuration macros/ (see [headerref boost/contract/config.hpp]). -* Defining the [macroref CONTRACT_CONFIG_NO_PRECONDITIONS] macro turns off compilation and run-time checking of all preconditions. -* Defining the [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS] macro turns off compilation and run-time checking of all postconditions. -* Defining the [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS] macro turns off compilation and run-time checking of all class invariants. -* Defining the [macroref CONTRACT_CONFIG_NO_BLOCK_INVARIANTS] macro turns off compilation and run-time checking of all block invariants. -* Defining the [macroref CONTRACT_CONFIG_NO_LOOP_VARIANTS] macro turns off compilation and run-time checking of all loop variants. - -By default, all contracts are compiled and checked at run-time (i.e., all the macros above are not defined). - -[important -In Contract Programming, it is usually important to selectively turn off contract compilation to reduce run-time, binary size, and compilation-time overhead associated with the contracts (see __Meyer97__). -This library guarantees zero run-time and binary size overhead when all contracts are all turned off (however, even when contracts are all turned off there is a limited compile-time overhead associated with expanding the contract macros to generate the original class and function declarations). -Note that when contracts are turned off their assertions are completely ignored by the compiler so the assertion code might not even be syntactically correct. -] - -For example, the following commands compile and check preconditions and class invariants, but they do not compile and check postconditions, block invariants, and loop variants: - -[pre -$ g++ -DCONTRACT_CONFIG_NO_POSTCONDITONS -DCONTRACT_CONFIG_NO_BLOCK_INVARIANTS -DCONTRACT_CONFIG_NO_LOOP_VARIANTS ... # For GCC. -> cl /DCONTRACT_CONFIG_NO_POSTCONDITONS /DCONTRACT_CONFIG_NO_BLOCK_INVARIANTS /DCONTRACT_CONFIG_NO_LOOP_VARIANTS ... # For MSVC. -] - -Other configuration macros are provided to customize other aspects of the library. -For example, the [macroref CONTRACT_CONFIG_FUNCTION_ARITY_MAX] macro is used to specify the maximum number of function parameters and the [macroref CONTRACT_CONFIG_INHERITANCE_MAX] macro is used to specify the maxim number of base classes. -All configuration macros have appropriate default values when they are left undefined by programmers. +In particular, defining the macros [macroref BOOST_CONTRACT_NO_PRECONDITIONS], [macroref BOOST_CONTRACT_NO_POSTCONDITIONS], and [macroref BOOST_CONTRACT_NO_INVARIANTS] disables run-time checking of all preconditions, postconditions, and class invariants respectively. +By default, all contracts are checked at run-time (i.e., all these macros are not defined). [endsect] diff --git a/doc/qbk/grammar.qbk b/doc/qbk/grammar.qbk index 2ba975e..c9d56bb 100644 --- a/doc/qbk/grammar.qbk +++ b/doc/qbk/grammar.qbk @@ -5,14 +5,6 @@ [/ http://www.boost.org/LICENSE_1_0.txt) ] [/ Home at http://sourceforge.net/projects/contractpp ] -[def __using_directive__ [link using_directive_anchor [^['using-directive]]]] -[def __namespace_alias__ [link namespace_alias_anchor [^['namespace-alias]]]] -[def __typedef_declaration__ [link typedef_declaration_anchor [^['typedef-declaration]]]] -[def __using_alias__ [link using_alias_anchor [^['using-alias]]]] -[def __using_declaration__ [link using_declaration_anchor [^['using-declaration]]]] -[def __static_select_assertion__ [link static_select_assertion_anchor [^['static-select-assertion]]]] -[def __alias__ [link alias_anchor [^['alias]]]] -[def __auto_type__ [link auto_type [^['auto-type]]]] [def __assertion__ [link assertion_anchor [^['assertion]]]] [def __assertion_condition__ [link assertion_condition_anchor [^['assertion-condition]]]] [def __assertion_expression__ [link assertion_expression_anchor [^['assertion-expression]]]] @@ -23,12 +15,7 @@ [def __class_invariant__ [link class_invariant_anchor [^['class-invariant]]]] [def __class_invariants__ [link class_invariants_anchor [^['class-invariants]]]] [def __concepts__ [link concepts_anchor [^['concepts]]]] -[def __exception_specs__ [link exception_specs_anchor [^['exception-specs]]]] -[def __function_parameter__ [link function_parameter_anchor [^['function-paramter]]]] -[def __classifiers__ [link classifiers_anchor [^['classifiers]]]] -[def __cv_qualifiers__ [link cv_qualifiers_anchor [^['cv-qualifiers]]]] -[def __ref_qualifiers__ [link ref_qualifiers_anchor [^['ref-qualifiers]]]] -[def __virt_specifiers__ [link virt_specifiers_anchor [^['virt-specifiers]]]] +[def __exception_specifications__ [link exception_specifications_anchor [^['exception-specifications]]]] [def __function_declaration__ [link function_declaration_anchor [^['function-declaration]]]] [def __function_name__ [link function_name_anchor [^['function-name]]]] [def __function_parameters__ [link function_parameters_anchor [^['function-parameters]]]] @@ -48,26 +35,22 @@ [def __operator_name__ [link operator_name_anchor [^['operator-name]]]] [def __positional_function_parameter__ [link positional_function_parameter_anchor [^['positional-function-parameter]]]] [def __positional_function_parameters__ [link positional_function_parameters_anchor [^['positional-function-parameters]]]] -[def __template_parameter__ [link template_parameter_anchor [^['positional-template-parameter]]]] -[def __type_template_parameter__ [link type_template_parameter_anchor [^['type-template-parameter]]]] -[def __value_template_parameter__ [link value_template_parameter_anchor [^['value-template-parameter]]]] -[def __template_template_parameter__ [link template_template_parameter_anchor [^['template-template-parameter]]]] -[def __oldof_assertions__ [link oldof_assertions_anchor [^['oldof-assertions]]]] -[def __return_type__ [link return_type_anchor [^['return-type]]]] -[def __cv_qualifier__ [link cv_qualifier_anchor [^['cv-qualifier]]]] +[def __positional_template_parameter__ [link positional_template_parameter_anchor [^['positional-template-parameter]]]] +[def __positional_template_parameters__ [link positional_template_parameters_anchor [^['positional-template-parameters]]]] +[def __positional_template_template_parameter__ [link positional_template_template_parameter_anchor [^['positional-template-template-parameter]]]] +[def __positional_type_template_parameter__ [link positional_type_template_parameter_anchor [^['positional-type-template-parameter]]]] +[def __positional_value_template_parameter__ [link positional_value_template_parameter_anchor [^['positional-value-template-parameter]]]] +[def __result_oldof_assertions__ [link result_oldof_assertions_anchor [^['result-oldof-assertions]]]] +[def __result_type__ [link result_type_anchor [^['result-type]]]] [def __select_assertion__ [link select_assertion_anchor [^['select-assertion]]]] [def __template_parameters__ [link template_parameters_anchor [^['template-parameters]]]] -[def __template_specialization_arguments__ [link template_specialization_arguments_anchor [^['template-specialization-arguments]]]] +[def __template_specializations__ [link template_specializations_anchor [^['template-specializations]]]] [def __type_keyword__ [link type_keyword_anchor [^['type-keyword]]]] [def __type_qualifier__ [link type_qualifier_anchor [^['type-qualifier]]]] [def __wrapped_type__ [link wrapped_type_anchor [^['wrapped-type]]]] -[def __capture_boolean_expression__ [link capture_boolean_expression_anchor [^[*capture-boolean-expression]]]] -[def __capture__ [link capture_anchor [^[*capture]]]] -[def __name__ [link name_anchor [^[*name]]]] -[def __new_name__ [link new_name_anchor [^[*new-name]]]] [def __boolean_expression__ [link boolean_expression_anchor [^[*boolean-expression]]]] -[def __boolean_expression_of_inscope_variables__ [link boolean_expression_of_inscope_variables_anchor [^[*boolean-expression-of-inscope-variables]]]] +[def __boolean_expression_using_inscope_variables__ [link boolean_expression_using_inscope_variables_anchor [^[*boolean-expression-using-inscope-variables]]]] [def __boost_concept__ [link boost_concept_anchor [^[*boost-concept]]]] [def __catch_declaration__ [link catch_declaration_anchor [^[*catch-declaration]]]] [def __catch_instructions__ [link catch_instructions_anchor [^[*catch-instructions]]]] @@ -82,21 +65,22 @@ [def __member_initializer__ [link member_initializer_anchor [^[*member-initializer]]]] [def __named_argument_identifier_name__ [link named_argument_identifier_anchor [^[*named-argument-identifier]]]] [def __named_parameter_identifier_namespace__ [link named_parameter_identifier_namespace_anchor [^[*named-parameter-identifier-namespace]]]] +[def __namespace_alias__ [link namespace_alias_anchor [^[*namespace-alias]]]] [def __natural_expression__ [link natural_expression_anchor [^[*natural-expression]]]] [def __natural_expression_using_inscope_variables__ [link natural_expression_using_inscope_variables_anchor [^[*natural-expression-using-inscope-variables]]]] [def __new_type_name__ [link new_type_name_anchor [^[*new-type-name]]]] [def __oldof_expression__ [link oldof_expression_anchor [^[*oldof-expression]]]] [def __operator_identifier__ [link operator_identifier_anchor [^[*operator-identifier]]]] [def __operator_symbol__ [link operator_symbol_anchor [^[*operator-symbol]]]] +[def __parameter_default__ [link parameter_default_anchor [^[*parameter-default]]]] [def __parameter_name__ [link parameter_name_anchor [^[*parameter-name]]]] -[def __default_argument__ [link default_argument_anchor [^[*default-argument]]]] -[def __cxx_template_parameter__ [link cxx_template_parameter_anchor [^[*c++-template-parameter]]]] -[def __template_specialization_argument__ [link template_specialization_argument_anchor [^[*template-specialization-argument]]]] +[def __template_parameter__ [link template_parameter_anchor [^[*template-parameter]]]] +[def __template_specialization__ [link template_specialization_anchor [^[*template-specialization]]]] [def __type__ [link type_anchor [^[*type]]]] [def __typedef_type__ [link typedef_type_anchor [^[*typedef-type]]]] [def __unary_boolean_metafunction__ [link unary_boolean_metafunction_anchor [^[*unary-boolean-metafunction]]]] +[def __using_directive__ [link using_directive_anchor [^[*using-directive]]]] [def __variable_name__ [link variable_name_anchor [^[*variable-name]]]] -[def __attributes__ [link attributes_anchor [^[*attributes]]]] [section Grammar] @@ -182,14 +166,14 @@ This very simple macro already shows fundamental differences between the syntax The following is a summary of all the differences between the syntax of this library macros and the usual C++ class and function declaration syntax. [table -[ [#] [Syntactic Element] [Syntax Differences] ] +[ [Rule] [Syntactic Element] [Syntax Differences] ] [ [1] [Template Declarations] [ Use round parenthesis `template( `[^['template-parameters]]` )` instead of angular parenthesis `template< `[^['template-parameters]]` >` to declare templates (note that template instantiations are not template declarations and they use angular parenthesis as usual). ] ] [ [2] [Template Specializations] [ -Use round parenthesis [^['template-name]]`( `[^['template-specialization-arguments]]` )` instead of angular parenthesis [^['template-name]]`< `[^['template-specialization-arguements]]` >` after a class template name to specify the arguments of the template specialization. +Use round parenthesis `( `[^['template-specializations]]` )` instead of angular parenthesis `< `[^['template-specializations]]` >` after a class template name to specify template specialization arguments. ] ] -[ [3] [Class and Function Names, and Operators] [ +[ [3] [Class, Function, and Operator Names] [ Wrap class and function declaration names within round parenthesis `(`[^['class-name]]`)` and `(`[^['function-name]]`)`. Use `operator(`[^['symbol]]`)(`[^['arbitrary-name]]`)` for operators (allowed but not required for `operator new`, `operator delete`, and implicit type conversion operators for fundamental types with no symbol). Always use `operator comma` for comma operator. @@ -198,23 +182,37 @@ Memory member operators must always be explicitly declared `static`. [ [4] [Base Classes] [ Use `extends( `[^['base-classes]]` )` instead of the column symbol `: `[^['base-classes]] to inherit from base classes. ] ] -[ [5] [Default Arguments] [ -Use `default `[^['default-argument]] instead of the assignment symbol `= `[^['default-argument]] to specify default arguments for template and function parameters. +[ [5] [Default Parameters] [ +Use `default `[^['parameter-default]] instead of the assignment symbol `= `[^['parameter-default]] to specify template and function parameter default values. ] ] -[ [6] [Result and Parameter Types] [ +[ [6] [Member Access Levels] [ +Always specify the access level `public`, `protected`, or `private` (note no trailing comma `:`) for every constructor, destructor, member function, and nested class declaration. +] ] +[ [7] [Result and Parameter Types] [ Wrap function result and parameter types within round parenthesis `(`[^['type]]`)`. -The wrapping parenthesis are allowed but not required for fundamental types containing only alphanumeric tokens (e.g., `(const unsigned int)` and `const unsigned int` are both allowed and equivalent, but only `(int&)` and not `int&` is allowed because of the non-alphanumeric symbol `&`, furthermore only `(mytype)` is allowed because `mytype` is not a fundamental type). +The wrapping parenthesis are allowed but not required for fundamental types containing only alphanumeric tokens (e.g., both `(const unsigned int)` and `const unsigned int` are allowed, only `(int&)` and not `int&` is allowed because of the non-alphanumeric symbol `&`, only `(mytype)` is allowed because `mytype` is not a fundamental type). ] ] -[ [7] [Member Initializers] [ -Use `initialize( `[^['member-initializers]]` )` instead of the column symbol `: `[^['member-initializers]] to specify a constructor's member initializers. +[ [8] [Member Initializers] [ +Use `initialize( `[^['member-initializers]]` )` instead of the column symbol `: `[^['member-initializers]] to specify constructor member initializers. ] ] -[ [8] [Commas and Leading Symbols] [ -Syntactic elements containing commas and leading non-alphanumeric symbols must be wrapped within extra round parenthesis `(...)` (e.g., `'a'`, `"abc"`, and `1.23` are non-alphanumeric because of `'`, `"`, `.` respectively so they need to be wrapped as `('a')`, `("abc")`, and `(1.23)` if used within this library syntax as default parameters, etc.). +[ [9] [Empty Lists] [ +Specify empty lists (parameters, exception specifications, template specializations, etc) using `( void )` instead of `( )` or `< >`. +] ] +[ [10] [Commas and Leading Symbols] [ +Syntactic elements containing commas and leading non-alphanumeric symbols must be wrapped within extra round parenthesis `(...)`. +(Note that `'a'`, `"abc"`, `1.23`, etc are not alphanumeric so they need to be wrapped as `('a')`, `("abc")`, `(1.23)`, etc when specified as default parameters or similar.) ] ] ] [important -In general, every token which is not a known keyword (e.g., `int` is a known keyword but the function name is not) or that contains a non-alphanumeric symbol (e.g., `int&`) must be wrapped within round parenthesis `(...)` unless it is the very last token of a syntactic element (e.g., the function parameter name). +In general, every token which is not a known keyword (`int` is a known keyword but the function name is not) or that contains a non-alphanumeric symbol (e.g., `int&`) must be wrapped within round parenthesis `(...)` unless it is the very last token of a syntactic element (e.g., the function parameter name). +] + +Sometimes the C++ syntax allows to equivalently specify elements in different orders (e.g., `const volatile` and `volatile const` are both allowed for member functions and they have the same meaning). +The syntax of this library requires instead to specify the elements exactly in the order listed by this grammar (e.g., only `const volatile` is allowed for member functions). +[footnote +*Rationale.* +This library macros could be implemented to allow to specify syntactic elements in different orders but that would complicate the macro implementation and this grammar with no additional feature for the user. ] [endsect] @@ -223,46 +221,37 @@ In general, every token which is not a known keyword (e.g., `int` is a known key This library uses the following macros. - // Class declarations. + ``[macroref CONTRACT_CLASS]``(__class_declaration__) + ``[macroref CONTRACT_CLASS_TPL]``(__class_declaration__) + + ``[macroref CONTRACT_CLASS_INVARIANT]``(__class_invariants__) + ``[macroref CONTRACT_CLASS_INVARIANT_TPL]``(__class_invariants__) + + ``[macroref CONTRACT_FUNCTION]``(__function_declaration__) + ``[macroref CONTRACT_FUNCTION_TPL]``(__function_declaration__) + ``[macroref CONTRACT_CONSTRUCTOR]``(__function_declaration__) + ``[macroref CONTRACT_CONSTRUCTOR_TPL]``(__function_declaration__) + ``[macroref CONTRACT_DESTRUCTOR]``(__function_declaration__) + ``[macroref CONTRACT_DESTRUCTOR_TPL]``(__function_declaration__) + + ``[macroref CONTRACT_FREE_BODY]``(__function_name__) + ``[macroref CONTRACT_MEMBER_BODY]``(__function_name__) + ``[macroref CONTRACT_CONSTRUCTOR_BODY]``(__class_type__, __class_name__) + ``[macroref CONTRACT_DESTRUCTOR_BODY]``(__class_type__, ~__class_name__) + + ``[macroref CONTRACT_BLOCK_INVARIANT]``(__assertions__) + ``[macroref CONTRACT_BLOCK_INVARIANT_TPL]``(__assertions__) + + ``[macroref CONTRACT_LOOP]``(__loop_declaration__) + ``[macroref CONTRACT_LOOP_VARIANT]``(__loop_variant__) + ``[macroref CONTRACT_LOOP_VARIANT_TPL]``(__loop_variant__) - ``[macroref BOOST_CONTRACT_CLASS]``(__class_declaration__) - ``[macroref BOOST_CONTRACT_CLASS_TPL]``(__class_declaration__) + ``[macroref CONTRACT_CONSTRUCTOR_ARG]``(__parameter_name__) + ``[macroref CONTRACT_PARAMETER_TYPEOF]``(__parameter_name__) + ``[macroref CONTRACT_PARAMETER]``(__named_parameter_declaration__) + ``[macroref CONTRACT_TEMPLATE_PARAMETER]``(__named_parameter_declaration__) + ``[macroref CONTRACT_PARAMETER_BODY]``(__function_name__) - // Class invariants. - - ``[macroref BOOST_CONTRACT_INVARIANT]``(__assertions__) - ``[macroref BOOST_CONTRACT_INVARIANT_TPL]``(__assertions__) - - ``[macroref BOOST_CONTRACT_STATIC_INVARIANT]``(__assertions__) - ``[macroref BOOST_CONTRACT_STATIC_INVARIANT_TPL]``(__assertions__) - - ``[macroref BOOST_CONTRACT_INVARIANT_VOLATILE]``(__assertions__) - ``[macroref BOOST_CONTRACT_INVARIANT_VOLATILE_TPL]``(__assertions__) - - // Constructor declarations. - - ``[macroref BOOST_CONTRACT_CONSTRUCTOR]``(__function_declaration__) - ``[macroref BOOST_CONTRACT_CONSTRUCTOR_TPL]``(__function_declaration__) - ``[macroref BOOST_CONTRACT_CONSTRUCTOR_BODY]``(__class_type__, __class_name__) - - // Destructor declarations. - - ``[macroref BOOST_CONTRACT_DESTRUCTOR]``(__function_declaration__) - ``[macroref BOOST_CONTRACT_DESTRUCTOR_TPL]``(__function_declaration__) - ``[macroref BOOST_CONTRACT_DESTRUCTOR_BODY]``(__class_type__, ~__class_name__) - - // Member function (and member operator) declarations. - - ``[macroref BOOST_CONTRACT_MEMBER]``(__function_declaration__) - ``[macroref BOOST_CONTRACT_MEMBER_TPL]``(__function_declaration__) - ``[macroref BOOST_CONTRACT_MEMBER_BODY]``(__function_name__) - - // Free function (and free operator) declarations. - - ``[macroref BOOST_CONTRACT_FUNCTION]``(__function_declaration__) - ``[macroref BOOST_CONTRACT_FUNCTION_TPL]``(__function_declaration__) - ``[macroref BOOST_CONTRACT_FUNCTION_BODY]``(__function_name__) - The macros with the trailing `_TPL` must be used when the enclosing scope is type-dependent (e.g., within templates). [endsect] @@ -272,42 +261,31 @@ The macros with the trailing `_TPL` must be used when the enclosing scope is typ The following conventions are used to express this grammar. [table -[ [Lexical Expression] [Meaning] [Text] ] -[ [[^symbol[':]]] [ -The specified symbol is defined by the symbols following the semicolon `:` (symbol definition). ][ -Semicolon in italic font. -] ] -[ [[^['[]symbols['\]]]] [ -Either `symbols` or nothing (optional symbols). ] [ -Angular brackets in italic font. +[ [Lexical Expression] [Meaning] ] +[ [[^['[]tokens['\]]]] [ +Either `tokens` or nothing (optional tokens). ] ] [ [[^['{]expression['}]]] [ -The result of the enclosed expression `expression` (evaluation order). ] [ -Curly brackets in italic font. +The result of the enclosed expression `expression` (evaluation order). ] ] -[ [[^symbol1 ['|] symbol2]] [ -Either `symbol1` or `symbol2` (["or] operation). ] [ -Vertical bar in italic font. +[ [[^tokens1 ['|] tokens2]] [ +Either `tokens1` or `tokens2` (["or] operation). ] ] -[ [[^symbol['*]]] [ -`symbol` repeated zero or more times (repetition starting from zero). ] [ -Asterisk in italic font. +[ [[^tokens['*]]] [ +`tokens` repeated zero or more times (repetition starting from zero). ] ] -[ [[^symbol['+]]] [ -`symbol` repeated one or more times (repetition starting from one). ] [ -Plus in italic front. +[ [[^tokens['+]]] [ +`tokens` repeated one or more times (repetition starting from one). ] ] -[ [[^symbol[', ...]]] [ -A comma separated list of symbols that could also contain a single symbol (e.g., `symbol1` or `symbol1, symbol2` or `symbol1, symbol2, symbol3`). ] [ -Comma and three dots in italic font. +[ [[^token, ...]] [ +A comma separated list of tokens that could also have one single element (i.e., `token` or `token1, token2` or `token1, token2, token3`). +See the __No_Variadic_Macros__ section for compilers that do not support variadic macros. ] ] -[ [[^[*symbol]]] [ -Terminal symbol (defined outside this grammar). ] [ -Dash separated words in bold font. +[ [[^[*tokens]]] [ +Terminal symbols (in bold font). ] ] -[ [[^['symbols]]] [ -Non-terminal symbol (defined within this grammar). ] [ -Dash separated words in italic font. +[ [[^['tokens]]] [ +Non-terminal symbols (in italic font). ] ] ] @@ -315,370 +293,349 @@ Dash separated words in italic font. [section Class Declarations] - __class_declaration__``/:/ [#class_declaration_anchor]`` - ``/[/````/[/``export``/]/`` template( ``/[/``__template_parameters__``/]/`` )``/]/`` - ``/[/``friend``/]/`` ``/{/``class ``/|/`` struct``/}/`` ``/[/``verbatim(__attributes__)``/]/`` (__class_name__)``/[/``( __template_specialization_arguments__ )``/]/`` - ``/[/``final``/]/`` ``/[/``extends( __base_classes__ )``/]/`` - -[endsect] - -[section Template Parameters] - - __template_parameters__``/:/ [#template_parameters_anchor]`` - __template_parameter__``/, .../`` - - __template_parameter__``/:/ [#template_parameter_anchor]`` - __type_template_parameter__ ``/|/`` - __value_template_parameter__ ``/|/`` - __template_template_parameter__ - - __type_template_parameter__``/:/ [#type_template_parameter_anchor]`` - ``/{/``class ``/|/`` typename``/}/````/[/``...``/]/`` ``/[/``__parameter_name__``/]/`` - ``/[/``, default __default_argument__``/]/`` - - __value_template_parameter__``/:/ [#value_template_parameter_anchor]`` - __wrapped_type__ ``/[/``__parameter_name__``/]/`` - ``/[/``, default __default_argument__``/]/`` - - __template_template_parameter__``/:/ [#template_template_parameter_anchor]`` - template( ``/[/``__cxx_template_parameter__``/, .../````/]/`` ) class ``/[/``__parameter_name__``/]/`` - ``/[/``, default __default_argument__``/]/`` - -Note how this syntax allows to specify __CXX11__ variadic templates as usual using ellipses `...` after `typename` or `class` and before the type template parameter name (e.g., `typename... Args` or `class... Args`). - -If present, default parameters must be specified at the end of the parameter list as usual in C++. - -Note that if `typename` appears within __wrapped_type__ for a value template parameter then it will be wrapped within parenthesis (e.g., `(typename std::map) Map`) so it is syntactically distinguishable from the `typename` leading a type template parameter. - -[endsect] - -[section Template Specializations] - - __template_specialization_arguments__``: [#template_specialization_arguments_anchor]`` - __template_specialization_argument__``/, .../`` + __class_declaration__``: [#class_declaration_anchor]`` + ``/[/````/[/``export``/]/`` template( __template_parameters__ ) ``/[/``requires( __concepts__ )``/]/````/]/`` + ``/[/``friend``/]/`` ``/{/``class ``/|/`` struct``/}/`` (__class_name__)``/[/``( __template_specializations__ )``/]/`` ``/[/``final``/]/`` + ``/[/``extends( __base_classes__ )``/]/`` [endsect] [section Base Classes] - __base_classes__``/:/ [#base_classes_anchor]`` - ``/[/``public ``/|/`` protected ``/|/`` private``/]/`` ``/[/``virtual``/]/`` __class_type__``/, .../`` + __base_classes__``: [#base_classes_anchor]`` + ``/[/``public ``/|/`` protected ``/|/`` private``/]/`` ``/[/``virtual``/]/`` __class_type__, ... -Note that when specified, `virtual` must appear after the inheritance access level for a base class (as with usual C++ base class declarations). +Note that when specified, `virtual` must appear after the inheritance access level for a base class. + +[endsect] + +[section Template Specializations] + + __template_specializations__``: [#template_specializations_anchor]`` + __template_specialization__, ... + +[endsect] + +[section Template Parameters] + + __template_parameters__``: [#template_parameters_anchor]`` + void ``/|/`` + __positional_template_parameters__ ``/|/`` + __named_template_parameters__ + + __positional_template_parameters__``: [#positional_template_parameters_anchor]`` + __positional_template_parameter__, ... + __positional_template_parameter__``: [#positional_template_parameter_anchor]`` + __positional_type_template_parameter__ ``/|/`` + __positional_value_template_parameter__ ``/|/`` + __positional_template_template_parameter__ + __positional_type_template_parameter__``: [#positional_type_template_parameter_anchor]`` + ``/{/``class ``/|/`` typename``/}/`` __parameter_name__ + ``/[/``, default __parameter_default__``/]/`` + __positional_value_template_parameter__``: [#positional_value_template_parameter_anchor]`` + __wrapped_type__ __parameter_name__ + ``/[/``, default __parameter_default__``/]/`` + __positional_template_template_parameter__``: [#positional_template_template_parameter_anchor]`` + template( __template_parameter__, ... ) class __parameter_name__ + ``/[/``, default __parameter_default__``/]/`` + + __named_template_parameters__``: [#named_template_parameters_anchor]`` + ``/[/``using namespace __named_parameter_identifier_namespace__,``/]/`` + __named_type_template_parameter__, ... + __named_type_template_parameter__``: [#named_type_template_parameter_anchor]`` + ``/[/``deduce``/]/`` in ``/{/``class ``/|/`` typename``/}/`` + ``/[/``requires(__unary_boolean_metafunction__)``/]/`` __parameter_name__ + ``/[/``, default __parameter_default__``/]/`` + +Note that if `typename` appears within __wrapped_type__ for a value template parameter then it will be wrapped within parenthesis `(typename ...)` so it is syntactically distinguishable from the `typename` leading a type template parameter. + +Unfortunately, named template parameters only support type template parameters. +Named value template parameters and named template template parameters are not supported because they are not supported by __Boost_Parameter__ but if they were ever supported, they could follow this syntax: + + __named_template_parameters__``:`` + __named_template_parameter__, ... + __named_template_parameter__``: [#named_template_parameter_anchor]`` + __named_type_template_parameter__ ``/|/`` + __named_value_template_parameter__ ``/|/`` + __named_template_template_parameter__ + __named_value_template_parameter__``: [#named_value_template_parameter_anchor]``// Not supported. + ``/[/``deduce``/]/`` in + ``/{/``__wrapped_type__ ``/|/`` auto ``/|/`` requires(__unary_boolean_metafunction__)``/}/`` __parameter_name__ + ``/[/``, default __parameter_default__``/]/`` + __named_template_template_parameter__``: [#named_template_template_parameter_anchor]``// Not supported. + ``/[/``deduce``/]/`` in template( __positional_template_parameter__, ... ) class + ``/[/``requires(__unary_boolean_metafunction__)``/]/`` __parameter_name__ + ``/[/``, default __parameter_default__``/]/`` + + template( // For example... + // Named type template parameter (supported). + in typename requires(is_const<_>) T, default int + // Named value template parameter (not supported). + , in requires(is_converible<_, T>) val, default 0 + // Named template template parameter (not supported). + , in template( + typename A + , template( + typename X + , typename Y, default int + ) class B, default b + ) class requires(pred1< _ >) Tpl, default tpl + ) + +[endsect] + +[section Concepts] + + __concepts__``: [#concepts_anchor]`` + __boost_concept__, ... [endsect] [section Types] - __wrapped_type__``/:/ [#wrapped_type_anchor]`` - (__type__``/[/``...``/]/``) ``/|/`` __fundamental_type__ ``/|/`` decltype(__expression__) + __wrapped_type__``: [#wrapped_type_anchor]`` + __fundamental_type__ ``/|/`` (__fundamental_type__) ``/|/`` (__type__) - __fundamental_type__``/:/ [#fundamental_type_anchor]`` - ``/{/``const ``/|/`` volatile ``/|/`` long ``/|/`` short ``/|/`` signed ``/|/`` unsigned ``/|/`` - void ``/|/`` bool ``/|/`` char ``/|/`` char16_t ``/|/`` char32_t ``/|/`` double ``/|/`` float ``/|/`` int ``/|/`` wchar_t``/}+/`` - - __auto_type__``/:/ [#auto_type_anchor]`` - auto ``/|/`` __wrapped_type__ + __fundamental_type__``: [#fundamental_type_anchor]`` + __type_qualifier__``/*/`` __type_keyword__ __type_qualifier__``/*/`` + __type_qualifier__``: [#type_qualifier_anchor]`` + const ``/|/`` volatile ``/|/`` long ``/|/`` short ``/|/`` signed ``/|/`` unsigned + __type_keyword__``: [#type_keyword_anchor]`` + void ``/|/`` bool ``/|/`` char ``/|/`` double ``/|/`` float ``/|/`` int ``/|/`` wchar_t ``/|/`` size_t ``/|/`` ptrdiff_t -This is the syntax used to specify types of different entities such as the function return type, the function parameter types, the types of value template parameters, etc. -The usual constraints of C++ for qualified fundamental type apply (it invalid to specify `int int`, `long int long`, `unsigned void`, etc). - -As indicated by the syntax above, extra parenthesis around the specified type are always allowed but they are required only for user-defined types `(mytype)` and types containing non-alphanumeric symbols `(int&)`, `(std::size_t)`, `(int&&)`, etc. -However, the parenthesis are optional for fundamental types containing no symbol (e.g., `unsigned long int const` and `(unsigned long int const)` can be equivalently used) and `decltype` (e.g., `decltype(x)` and `(decltype(x))` can be equivalently used). - -Note that the type wrapped within parenthesis can contain trailing ellipses in case it is the type specified for a variadic template (e.g., `(Args...)`). +This is the syntax used to specify the function result type, the function parameter types, the types of value template parameters, etc. +As indicated by the syntax, extra parenthesis around the specified type are always allowed but they are required only for user-defined types `(mytype)` and types containing non-alphanumeric symbols `(int&)` while the parenthesis are optional for fundamental types containing no symbol `unsigned long int const` (or equivalently `(unsigned long int const)`). [endsect] [section Function Declarations] - __function_declaration__``/:/ [#function_declaration_anchor]`` - ``/[/``verbatim(__attributes__)``/]/`` - ``/[/````/[/``export``/]/`` ``/[/``template( ``/[/``__template_parameters__``/]/`` )``/]/`` - __classifiers__ ``/[/``__return_type__``/]/`` __function_name__ ( __function_parameters__ ) - __cv_qualifiers__ __ref_qualifiers__ __exception_specs__ - ``/[/``return __wrapped_type__``/]/`` __virt_specifiers__ - ``/[/``precondition( __assertions__ )``/]/`` - ``/[/``postcondition( __oldof_assertions__ )``/]/`` - -This is the syntax used to declare all functions: Free functions, member functions, constructors, destructors, and operators. -The usual constraints of C++ function declarations apply (it is not possible to declare a static virtual member function, only constructors can use the class name as the function name, constructors and destructors have no result type, etc). - -[endsect] - -[section Classifiers (`static`, `virtual`, etc.)] - - __classifiers__``/:/ [#classifiers_anchor]`` + __function_declaration__``: [#function_declaration_anchor]`` + ``/[/``public ``/|/`` protected ``/|/`` private``/]/`` + ``/[/````/[/``export``/]/`` ``/[/``template( __template_parameters__ ) ``/[/``requires( __concepts__ )``/]/````/]/`` ``/[/``explicit``/]/`` ``/[/``inline``/]/`` ``/[/``extern``/]/`` ``/[/``static``/]/`` ``/[/``virtual``/]/`` ``/[/``friend``/]/`` + ``/[/``__result_type__``/]/`` __function_name__ ( __function_parameters__ ) + ``/[/``requires( __concepts__ )``/]/`` + ``/[/``const``/]/`` ``/[/``volatile``/]/`` ``/[/``override ``/|/`` new``/]/`` ``/[/``final``/]/`` + ``/[/``throw( __exception_specifications__ )``/]/`` + ``/[/``precondition( __assertions__ )``/]/`` + ``/[/``postcondition( __result_oldof_assertions__ )``/]/`` + ``/[/``__member_initializers__``/]/`` +This is the syntax used to declare all functions: Free functions, member functions, constructors, destructors, and operators. +The usual constraints of C++ function declarations apply: It is not possible to declare a static virtual member function, only constructors can use the class name as the function name, constructors and destructors have no result type, etc. The `static` specifier can only be used for member functions (because it was deprecated for free functions from C to __CXX03__). - -[note -C++ automatically promotes the memory member operators `operator new`, `operator delete`, `operator new[]`, and `operator delete[]` to be static members so the `static` specifier is allowed but optional for declarations of these member operators. -This library cannot automatically perform such a promotion so the `static` specifier is always required by this library for declarations of memory member operators. -] +The `volatile` specifier must always appear after `const` when they are both specified. [endsect] -[section Return Type] +[section Result Type] - __return_type__``/:/ [#return_type_anchor]`` - __auto_type__ + __result_type__``: [#result_type_anchor]`` + __wrapped_type__ -As always with this syntax's wrapped types, note that fundamental types containing no symbol can be specified without extra parenthesis (`void`, `bool`, `int`, `unsigned long const`, `decltype(...)`, etc.). - -__CXX11__ trailing return types can be specified using `auto` for the return type and then using `return __wrapped_type__` after the function parameters (instead of the usual `->` syntax). -Contrary to when `return` is used to specify a return value within a function definition, in this case `return` is followed by a type expression (and not by a value expression) as it is specifying the return type (and not the return value). -On compilers that support __CXX14__ automatic return type deduction, the trailing return type `return __wrapped_type__` is optional when the return type is `auto`. +Note that fundamental types containing no symbol can be specified without extra parenthesis: `void`, `bool`, `int`, `unsigned long const`, etc. [endsect] [section Function and Operator Names] - __function_name__``/:/ [#function_name_anchor]`` + __function_name__``: [#function_name_anchor]`` (__function_identifier__) ``/|/`` (__class_name__) ``/|/`` (~__class_name__) ``/|/`` __operator_name__ - __operator_name__``/:/ [#operator_name_anchor]`` + __operator_name__``: [#operator_name_anchor]`` operator(__operator_symbol__)(__operator_identifier__) ``/|/`` operator __fundamental_type__ ``/|/`` - operator new ``/|/`` operator delete + operator new ``/|/`` operator delete ``/|/`` operator comma Names for free functions, member functions, constructors, and destructors are specified as usual but wrapped within parenthesis. -Operator names are specified wrapping within parenthesis the usual operator symbol followed by an arbitrary but alphanumeric identifier, for example: +Operator names are specified wrapping within parenthesis the usual operator symbol followed by an arbitrary but alphanumeric identifier: + operator([])(at) operator(+)(plus) - operator("")(literal) - operator(())(call) - operator(,)(comma) - operator(new[])(new_array) operator(delete[])(delete_array) -Names for implicit type conversion operators use the same syntax, for example: +Implicit type conversion operators use the same syntax: operator(int*)(int_ptr) operator(mytype const&)(mytype_const_ref) operator(std::map)(std_map) -However, if the type is a fundamental type containing no symbol, the parenthesis and alphanumeric identifier are optional, for example: +However, if the type is a fundamental type containing no symbol, the identifier is optional: - operator const int // OK. - operator(const int)(const_int) // Also allowed (but less readable). + operator(const int)(const_int) // Allowed but... + operator const int // ... more readable. -Similarly, the parenthesis and alphanumeric identifier are optional for the `new` and `delete` operators: +Similarly, the parenthesis and identifier are optional for the `new` and `delete` operators: - operator new // OK. - operator(new)(new_ptr) // Also allowed (but less readable). + operator(new)(new_ptr) // Allowed but... + operator new // ... more readable. - operator delete // OK. - operator(delete)(delete_ptr) // Also allowed (but less readable). + operator(delete)(delete_ptr) // Allowed but... + operator delete // ... more readable. -[endsect] - -[section Function Parameters] +Finally, the comma symbol `,` cannot be used to specify the comma operator +[footnote +*Rationale.* +Within macros a comma `,` has the special meaning of separating the macro parameters so it cannot be used to indicate the comma operator otherwise `operator(,)(mycomma)` and `operator(std::map)(stdmap)` could not be distinguished from one another by the preprocessor. +] +so the specifier `comma` must always be used to name the comma operator: - __function_parameters__``/:/ [#function_parameters_anchor]`` - ``/[/``__function_parameter__``/, .../````/]/`` ``/[/``...``/]/`` ``/|/`` void - - __function_parameter__``/:/ [#function_parameter_anchor]`` - ``/[/``auto ``/|/`` register``/]/`` ``/{/``__wrapped_type__ ``/[/``__parameter_name__``/]/`` ``/|/`` __type__``/}/`` - ``/[/``, default __default_argument__``/]/`` + operator comma // OK. + operator(,)(comma) // Error. -The parenthesis around the parameter type are always allowed but when the parameter name is not specified they are necessary only if the type contains unwrapped commas. - -This syntax allows to specify variadic functions as usual in C++ using ellipses `...` at the end of the parameter list. - -The storage classifier `auto` is supported by this library but it is deprecated in __CXX11__ (so use it with the usual care when writing code portable to __CXX11__). - -If present, default parameters must be specified at the end of the parameter list as usual in C++. - -[endsect] - -[section Constant/Volatile Qualifiers] - - __cv_qualifiers__``/:/ [#cv_qualifiers_anchor]`` - ``/[/``const ``/|/`` volatile ``/|/`` const volatile ``/|/`` volatile const``/]/`` - -[endsect] - -[section Reference Qualifiers] - - __ref_qualifiers__``/:/ [#ref_qualifiers_anchor]`` - ``/[/``ref ``/[/``fef``/]/````/]/`` - -Member functions are qualified as lvalue references using `ref` (instead of C++11 usual `&`) and as rvalue references using `ref ref` (instead of C++11 usual `&&`). +C++ automatically promotes the memory member operators `operator new`, `operator delete`, `operator new[]`, and `operator delete[]` to be static members so the `static` specifier is allowed but optional for these member operators. +This library cannot automatically perform such a promotion so the `static` specifier is always required by this library for the memory member operators. [endsect] [section Exception Specifications] - __exception_specs__``/:/ [#exception_specs_anchor]`` - ``/[/``noexcept``/[/``(__constant_boolean_expression__)``/]/`` ``/|/`` throw( ``/[/``__exception_type__``/, .../````/]/`` )``/]/`` + __exception_specifications__``: [#exception_specifications_anchor]`` + void | __exception_type__, ... -Exception specifications apply only to exceptions thrown by the function body and not to exceptions thrown by the contracts themselves (if any) and by the contract checking code generated by this library's macros. +Note that the syntax `throw( void )` is used instead of `throw( )` for no-throw specifications. + +Exception specifications apply only to exceptions thrown by the function body and not to exceptions thrown by the contracts themselves (if any) and by the contract checking code generated by this library macros. [endsect] -[section Virtual Specifiers] +[section Member Initializers] - __virt_specifiers__``/:/ [#virt_specifiers_anchor]`` - ``/[/``final ``/|/`` override ``/|/`` final override ``/|/`` override``/]/`` + __member_initializers__``: [#member_initializers_anchor]`` + ``/[/``try``/]/`` initialize( __member_initializer__, ... ) + ``/{/``catch(__catch_declaration__) ( __catch_instructions__ )``/}*/`` + +As indicated by this syntax, it is possible to specify function-try blocks for constructor member initializers: + + struct vector_error { ... }; + + CONTRACT_CONSTRUCTOR( // Constructor with member initializers. + explicit (vector) ( int count ) + precondition( count >= 0 ) + postcondition( size() == count ) + + try initialize( ptr_(new T[count]) ) + catch(std::bad_alloc& ex) ( + std::cerr << "not enough memory for " << count << " elements vector: " << ex.what() << std::endl; + throw vector_error(1); + ) catch(std::exception& ex) ( + std::cerr << "error for " << count << " elements vector: " << ex.what() << std::endl; + throw vector_error(2); + ) catch(...) ( + std::cerr << "unknown error for " << count << " elements vector" << std::endl; + throw vector_error(3); + ) + ) { // Above function-try block only applies to exceptions thrown by the body (and not by the contracts). + ... + } + +For functions other than constructors and for constructors without member initializers, function-try blocks are programmed outside the macros and around the body definition as usual. +As specified by __N1962__, function-try blocks apply only to exceptions thrown by the function body and not to exceptions thrown by the contracts themselves (if any) and by the contract checking code generated by the library macros. + +Member initializers (and their function-try blocks) are part of the constructor definition and not of the constructor declaration. +However, __CXX03__ lack of delegating constructors requires member initializers (and their function-try blocks) to be specified within this library macros and constructors must be defined together with their declarations when they use member initializers. + +[endsect] + +[section Function Parameters] + + __function_parameters__``: [#function_parameters_anchor]`` + void ``/|/`` + __positional_function_parameters__ ``/|/`` + __named_function_parameters__ + + __positional_function_parameters__``: [#positional_function_parameters_anchor]`` + __positional_function_parameter__, ... + __positional_function_parameter__``: [#positional_function_parameter_anchor]`` + ``/[/``auto ``/|/`` register``/]/`` __wrapped_type__ __parameter_name__ + ``/[/``, default __parameter_default__``/]/`` + + __named_function_parameters__``: [#named_function_parameters_anchor]`` + ``/[/``using namespace __named_parameter_identifier_namespace__,``/]/`` + __named_function_parameter__, ... + __named_function_parameter__``: [#named_function_parameter_anchor]`` + ``/[/``deduce``/]/`` ``/{/``in ``/|/`` out ``/|/`` in out``/}/`` + ``/{/``__wrapped_type__ ``/|/`` auto ``/|/`` requires(__unary_boolean_metafunction__)``/}/`` __parameter_name__ + ``/[/``, default __parameter_default__``/]/`` + +Note that the positional parameter storage classifier `auto` is supported by this library because it is part of __CXX03__ (but the `auto` keyword changed meaning in __CXX11__ so use it with the usual care when writing code portable to __CXX11__). + +[endsect] + +[section Result and Old Values] + + __result_oldof_assertions__``: [#result_oldof_assertions_anchor]`` + ``/[/``auto __variable_name__ = return,``/]/`` + ``/[/``__oldof_declaration__, ...``/]/`` + __assertion__, ... + + __oldof_declaration__``: [#oldof_declaration_anchor]`` + ``/{/``auto ``/|/`` __wrapped_type__``/}/`` __variable_name__ = ``[macroref CONTRACT_OLDOF]`` __oldof_expression__ + +If present, result and old-of declarations should appear at the very beginning of the postconditions because they will always be visible to all assertions plus these declarations cannot be nested (within select-assertions, etc). + +The result declaration type is always `auto` because the function result type is know and already specified by the function declaration (so no result type deduction is ever needed). +The old-of declaration type is automatically deduced (using __Boost_Typeof__) when its type is specified `auto` instead of __wrapped_type__. +The macro `CONTRACT_OLDOF` does not require but allows parenthesis around the value expression __oldof_expression__ (this is as specified for the `oldof` operator in __N1962__ and similar to the `sizeof` operator which requires parenthesis when applied to a type expression `sizeof(size_type)` but not when applied to a value expression `sizeof size()`). +For example, all the followings are valid: + + auto old_size = CONTRACT_OLDOF size() + auto old_size = CONTRACT_OLDOF(size()) // Extra parenthesis around expression (optional). + (size_type) old_size = CONTRACT_OLDOF size() // Do not use Boost.Typeof. + (size_type) old_size = CONTRACT_OLDOF(size()) // No Boost.Typeof and extra parenthesis. + +If an old-of copy is performed on a type that is not __ConstantCopyConstructible__, the old-of declaration itself will not fail compilation but it will produce an old variable that will cause a compiler-error as soon as it is used in an assertion (unless the assertion specifies a requirement using a properly specialized [classref contract::has_oldof] trait). + +[endsect] + +[section Class Invariants] + + __class_invariants__``: [#class_invariants_anchor]`` + void ``/|/`` __class_invariant__, ... + + __class_invariant__``: [#class_invariant_anchor]`` + __assertion__ ``/|/`` + static class( void ``/|/`` __assertion__, ... ) ``/|/`` + volatile class( void ``/|/`` __assertion__, ... ) + +Volatile class invariants are assumed to have the same assertions as non-volatile class invariants unless they are explicitly specified. +Static class invariants are assumed to assert nothing unless they are explicitly specified. [endsect] [section Assertions] - __assertions__``/:/`` - ``/[/``__assertion__``[', ...[,\]]````/]/`` // An optional ending comma `,` always allowed (like in C++ enumeration declarations). - - __assertion__``/:/`` - __alias__ ``/|/`` - - __auto_type__ __new_name__ = return ``/|/`` // Return value declarations allowed only in postconditions. - __auto_type__ __new_name__ = CONTRACT_OLDOF __oldof_expression__ ``/|/`` // Old value declarations allowed only in postconditions. + __assertions__``: [#assertions_anchor]`` + __assertion__, ... + __assertion__``: [#assertion_anchor]`` + using __using_directive__ ``/|/`` + namespace __namespace_alias__ ``/|/`` + typedef __typedef_type__ __new_type_name__ ``/|/`` + __assertion_condition__ + __assertion_condition__``: [#assertion_condition_anchor]`` + __assertion_expression__ ``/|/`` + __select_assertion__ + __assertion_expression__``: [#assertion_expression_anchor]`` __boolean_condition__ ``/|/`` - - __select_assertion__ ``/|/`` - __static_select_assertion__ - - __boolean_condition__``/:/`` + static_assert(__constant_boolean_expression__, __constant_string_literal__) + ``/[/``, requires __constant_boolean_expression__``/]/`` + __select_assertion__``: [#select_assertion_anchor]`` + if(__boolean_condition__) ( __assertion_condition__, ... ) + ``/[/``else ( __assertion_condition__, ... )``/]/`` + + __boolean_condition__``: [#boolean_condition_anchor]`` __boolean_expression__ ``/|/`` - const( ``/[/````/[/``__wrapped_type__``/]/`` __capture__``/, .../````/]/`` ) __capture_boolean_expression__ - - __select_assertion__``/:/`` - if(__boolean_condition__) ``/{/``( __assertions__ ) ``/|/`` ``/[/``__assertion__``/]/``,``/}/`` - ``/[/``else ``/{/``( __assertions__ ) ``/|/`` ``/[/``__assertion__``/]/``,``/}/````/]/`` - ``/[/``__assertion__``/]/`` // This makes comma `,` after select assertion always optional. + const( __inscope_variables__ ) __boolean_expression_using_inscope_variables__ + __inscope_variables__``: [#inscope_variables_anchor]`` + ``/[/``__wrapped_type__``/]/`` __inscope_variable__, ... - __static_select_assertion__``/:/`` - static if(__constant_boolean_expression__) ``/{/``( __assertions__ ) ``/|/`` ``/[/``__assertion__``/]/``,``/}/`` - ``/[/``else ``/{/``( __assertions__ ) ``/|/`` ``/[/``__assertion__``/]/``,``/}/````/]/`` - ``/[/``__assertion__``/]/`` // This makes comma `,` after select assertion always optional. - - __alias__``/:/ [#alias_anchor]`` - __namespace_alias__ ``/|/`` __using_directive__ ``/|/`` __using_declaration__ ``/|/`` __using_alias__ ``/|/`` __typedef_declaration__ - - __namespace_alias__``/:/`` - namespace (__new_name__) as __name__ - - __using_directive__``/:/`` - using namespace __name__ - - __using_declaration__``/:/`` - using {``/[/``typename``/]/`` __name__ ``/|/`` (``/[/``typename``/]/`` __name__)} - - __using_alias__``/:/`` - ``/[/``template( ``/[/``__cxx_template_parameter__, ...``/]/`` )``/]/`` - using (__new_name__) as {__type__ | (__type__)} - - __typedef_declaration__``/:/`` - typedef __wrapped_type__ __new_name__ - -Parenthesis around __boolean_expression__ are always allowed here but they are actually required only when __boolean_expression__ starts with a non-alphanumeric symbol (e.g., `(!vector.empty())`) or it contains unwrapped commas `,`. -Parenthesis around __capture_boolean_expression__ are always allowed but they are actually required only when __capture_boolean_expression__ contains unwrapped commas `,`. -However, these parenthesis cannot be used when the assertion is used as the single statement of a static selection assertion or a selection assertion `if` or `else`, double parenthesis or `bool` must be used in this case, for example (and similarly for `static if`): - - if(c) (map::key_size > 16) // Error (this is interpreted as a select assertion with two `if` assertions `matp::key_size > 16`). - if(c) ( (map::key_size > 16) ) // OK. - if(c) bool(map::key_size > 16) // Also OK. - -It is not possible to explicitly specify the capture types (these types are always automatically deduced using Boost.Typeof native or emulation support of type-of). -[footnote -*Rationale.* -Previous version of this library allowed to optionally specify these types for compilers that did not support type-of. -However, C++11 now supports native type-of via the `decltype` operator and most modern C++03 compiler support either native type-of as an extension of type-of emulation via the __Boost_Typeof__ library. -Automatically return value declaration, old value declaration, and __constant_assertion__ capture types simplifies the implementation of this library and the syntax of this library macros for the user. -Therefore, this library now require support for native of emulation type-of emulation via __Boost_Typeof__. -] - -When listing one assertion after another, a comma after __select_assertion__ and __static_select_assertion__ is allowed but it is always optional (similarly to a semicolon `;` after a C++ if-else-statement which is also always optional). -In general, select assertions and static select assertions follow a syntax similar to C++ if-else-statement but where curly brackets `{ ... }` are replaced by parenthesis `( ... )` and semicolons `;` by commas `,`. -For example, all the following are valid: - - if(c) ( t1, t2``/[/``,``/]/`` ), // This cannot be followed by an `else`. - - if(c), - if(c) t1, - if(c) ( t1, t2``/[/``,``/]/`` ) - // All of the above combined with all below: - else, - else e1, - else ( e1, e2``/[/``,``/]/`` ) - else ( e1, e2``/[/``,``/]/`` ), - - // These are invalid instead: - if(c) ( t1, t2``/[/``,``/]/`` ), else - if(c) else ... // this is invalid - -Note that static select assertions are useful in generic programming to selectively check some assertions only when the types involved fulfill all operations required for the assertion checking. - -[endsect] - -[section Aliases] - - __alias__``/:/ [#alias_anchor]`` - __namespace_alias__ ``/|/`` __using_directive__ ``/|/`` __using_declaration__ ``/|/`` __using_alias__ ``/|/`` __typedef_declaration__ - - __namespace_alias__``/:/`` - namespace (__new_name__) as __name__ - - __using_directive__``/:/`` - using namespace __name__ - - __using_declaration__``/:/`` - using {``/[/``typename``/]/`` __name__ ``/|/`` (``/[/``typename``/]/`` __name__)} - - __using_alias__``/:/`` - ``/[/``template( ``/[/``__cxx_template_parameter__, ...``/]/`` )``/]/`` - using (__new_name__) as {__type__ | (__type__)} - - __typedef_declaration__``/:/`` - typedef __wrapped_type__ __new_name__ - -In __using_declaration__, parenthesis around __name__ are always allowed here but they are actually required only when __name__ contains unwrapped commas `,`. -As usual in C++, __name__ can be prefixed by `typename` if that it is needed to resolve dependent names. - -In __using_alias__, parenthesis around __type__ are always allowed here but they are actually required only when __type__ contains unwrapped commas `,`. - -For example, all the aliases above can be used to simplify and short types and names used to program assertions (aliases do not alter the run-time state of the program so they can be safely used to program assertions). - -[endsect] - - -[section Preconditions] - - __assertions__``/:/ [#assertions_anchor]`` - ``/[/``__aliasing__``/, .../````/]/`` - __assertion__``/, .../`` - - __aliasing__``/:/`` - using ``/[/``namespace``/]/`` __used_identifier__ ``/|/`` - namespace __original_namespace__ = __new_namespace__ ``/|/`` - typedef __original_type__ __new_type__ ``/|/`` - template< ``/[/``__cxx_template_parameter__``/, .../````/]/`` > using __template_alias__ = __new_type__ - - __assertion__``/:/`` - __boolean_condition__ ``/|/`` - __select_assertion__ ``/|/`` - __static_selection_assertion__ - - __boolean_condition__``/:/`` - __boolean_expression__ ``/|/`` - const( __inscope_variable__``/, .../`` ) __boolean_expression_of_inscope_variables__ - - __select_assertion__``/:/`` - if(__boolean_condition__) ( __assertion__``/, .../`` ) - ``/[/``else ( __assertion__``/, .../`` )``/]/`` - - __static_select_assertion__``/:/`` - static if(__constant_boolean_expression__) ( __assertion__``/, .../`` ) - ``/[/``else ( __assertion__``/, .../`` )``/]/`` - -Some basic aliases are allowed at the local scope where the assertions are being declared in case they are ever needed to simplify the names used in the assertions. -Specifically, using directives, namespace aliases, typedefs, and template aliases are allowed (these will always affect all assertions within the given preconditions, postconditions, etc so it is recommended to always use these statement at the very beginning before the actual assertion conditions). -Note that these aliases have no effect on the program run-time state and therefore they do not compromise the contract constant-correctness requirement. +Some basic name manipulations are allowed at the local scope where the assertions are being declared in case they are ever needed to simplify the assertion expressions. +Specifically, using-directives, namespace-aliases, and type-definitions are allowed (these will always affect all assertions within the given preconditions, postconditions, etc so it is recommended to always use these statement at the very beginning before the actual assertion conditions). +Note that these name manipulations have no effect on the program run-time state and therefore they do not compromise the contract constant-correctness requirement. As indicated by the grammar above, it is not possible to specify assertion requirements (using `requires`) for the entire select assertion if-then-else expression. Eventual assertion requirements must be specified for the single assertions within the select assertion if-then-else statement and they will never disable compilation and checking of the select assertion if-condition. @@ -692,58 +649,22 @@ The type of the in-scope variable __inscope_variable__ is optional and it is aut [endsect] -[section Postconditions] +[section Loop Variants] - __postconditions__``/:/ [#postconditions_anchor]`` - ``/[/``__alias__``/, .../````/]/`` - ``/[/``auto __new_name__ = return``/,/````/]/`` - ``/[/``auto __new_name__ = ``[macroref BOOST_CONTRACT_OLDOF]`` __oldof_expression__``/, .../````/]/`` - ``/[/``assertion``/, .../````/]/`` - ``/[,/````/]/`` + __loop_variant__``: [#loop_variant_anchor]`` + __natural_expression__ ``/|/`` + const( __inscope_variables__ ) __natural_expression_using_inscope_variables__ -If present, aliases should appear at the very top because they will always apply to all return value declaration, old value declarations, and assertions. -If present, return and old value declarations should appear before any assertion because they will always be visible to all assertions (instead the relative order between return value and old value declaration does not matter). -[footnote -*Rationale.* -This fixed ordering (which also implies that aliases, return value declarations, and old value declarations cannot be nested within select assertions and static select assertions) simplifies somewhat the implementation of this library while posing no significant limitation to users. -] - -When present, there can be only one return value declaration (that is because a function only has one return value). - -Both return value and old value declarations must use `auto` for automatic type deduction (no type can be explicitly specified here). -[footnote -*Rationale.* -Previous version of this library allowed to optionally specify these types for compilers that did not support type-of. -However, C++11 now supports native type-of via the `decltype` operator and most modern C++03 compiler support either native type-of as an extension of type-of emulation via the __Boost_Typeof__ library. -Automatically return value declaration, old value declaration, and __constant_assertion__ capture types simplifies the implementation of this library and the syntax of this library macros for the user. -Therefore, this library now require support for native of emulation type-of emulation via __Boost_Typeof__. -] - -An optional comma `,` is always allowed (but never required) after the very last precondition statement (this is similar to the trailing optional comma `,` allowed after the last C++ `enum` value declaration which makes it easier to indent an maintain the code). - -===== - -The macro [macroref CONTRACT_OLDOF] allows but does not require parenthesis around the value expression __oldof_expression__, for example the following are both valid: -[footnote -*Rationale*. -This is as specified for the `oldof` operator in __N1962__ and similar to the `sizeof` operator which requires parenthesis when applied to a type expression `sizeof(size_type)` but not when applied to a value expression `sizeof size()`. -] - - auto old_size = CONTRACT_OLDOF size() // OK. - auto old_size = CONTRACT_OLDOF(size()) // Also allowed (but less readable). - -If the macro [macroref CONTRACT_OLDOF] is applied to the value of a type that is not __ConstantCopyConstructible__, the related old value declaration will not fail but it will produce an old value that will cause a compiler-error as soon as it is used in an assertion (unless the assertion is guarded by a `static if` using the properly specialized [classref contract::has_oldof] trait). +A loop variant must specify a non-negative integral expression that monotonically decreases at each subsequent loop iteration (the library will automatically check these two conditions at each loop iteration and terminate the loop if they are not met by calling the loop variant broken handler). +The loop variant can be specified using a constant-expression `const( ... ) `[^['expression]] so to fully enforce the contract constant-correctness requirement. [endsect] -[section Class Invariants] +[section Named Parameter Declarations] - __class_invariants__``/:/ [#class_invariants_anchor]`` - ``/[/``__aliasing__``/, .../````/]/`` - __assertion__ - -Volatile class invariants are assumed to have the same assertions as non-volatile class invariants unless they are explicitly specified. -Static class invariants are assumed to assert nothing unless they are explicitly specified. + __named_parameter_declaration__``: [#named_parameter_declaration_anchor]`` + ``/[/``namespace(__named_parameter_identifier_namespace__)``/]/`` + ``/[/``(__named_argument_identifier_name__)``/]/`` __parameter_name__ [endsect] @@ -759,7 +680,7 @@ Static class invariants are assumed to assert nothing unless they are explicitly [A boolean expression: `x == 1`.] [Wrap value within parenthesis: `(vey_sizeof::value)`.] ] [ -[__boolean_expression_of_inscope_variables__[#boolean_expression_of_inscope_variables_anchor]] +[__boolean_expression_using_inscope_variables__[#boolean_expression_using_inscope_variables_anchor]] [A boolean expression that only uses in-scope variables captured as constants by a constant expression `const( ... ) `[^['expression]].] [Wrap value within parenthesis: `(key_sizeof::value + x)`.] ] [ @@ -855,11 +776,11 @@ Static class invariants are assumed to assert nothing unless they are explicitly [A function or template parameter name: `value`, `T`.] [Never the case.] ] [ -[__cxx_template_parameter__[#cxx_template_parameter_anchor]] +[__template_parameter__[#template_parameter_anchor]] [A usual C++ type template parameter, value template parameter, or template template parameter): `typename T`, `class U`, `int Number`, `T Value`, `template< typename X, class Y > class Template`.] [Do nothing: `std::map Default`, `template< typename X, class Y > class Template`.] ] [ -[__template_specialization_argument__[#template_specialization_argument_anchor]] +[__template_specialization__[#template_specialization_anchor]] [A template specialization argument (type, value, etc) that follow the class name in the declaration to specialize a template: `void (int, T)`.] [Wrap types within parenthesis: `(std::map)`.] ] [ @@ -882,10 +803,6 @@ Static class invariants are assumed to assert nothing unless they are explicitly [__variable_name__[#variable_name_anchor]] [A valid name to use to declare a variable: `result`, `old_size`.] [Never the case.] -] [ -[__attributes__[#attributes_anchor]] -[Compiler-specific attributes like MSVC `__declspec(export)` and `__declspec(import)`, or G++ `__attribute__((visibility("default")))`, or C++11 `[[`[^['compiler-attribute]]`]]`.] -[Do nothing.] ] ] @@ -911,12 +828,14 @@ CONTRACT_CLASS( template( typename T ) class (vector) ) { -public: - CONTRACT_MEMBER_TPL( - (iterator) (erase) ( (iterator) where ) + ... + + CONTRACT_FUNCTION_TPL( + public (iterator) (erase) ( (iterator) where ) precondition( not empty(), - where != end() + where != end(), + static_assert(sizeof(T) >= sizeof(int), "large enough") ) postcondition( auto result = return, @@ -926,39 +845,41 @@ public: result == end() ) ) - ) ; - - ... + ) { + return vector_.erase(where); + } }; `` ] [`` CONTRACT_CLASS( template( typename T ) class (vector) ) { -public: - CONTRACT_MEMBER_TPL( - (iterator) (erase) ( (iterator) where ) + ... + + CONTRACT_FUNCTION_TPL( + public (iterator) (erase) ( (iterator) where ) precondition( assert(not empty()) assert(where != end()) + static_assert(sizeof(T) >= sizeof(int), "large enough") ) postcondition( - const(auto result = return) - const(auto old_size = CONTRACT_OLDOF size()) + decl(auto result = return) + decl(auto old_size = CONTRACT_OLDOF size()) assert(size() == old_size - 1) if(const(this, this->empty())) ( assert(result == end()) ) ) - ) ; - - ... + ) { + return vector_.erase(where); + } }; ``] ] ] -An advantage of this alternative syntax is that it does not require commas `,` at the end of each assertion (but it still does not allow for semicolon `;` at the end of each assertion as usual C++ statement syntax would require). -However, when compared with this library syntax, the alternative syntax is overall more verbose, it uses more parenthesis, it deviates more from __N1962__ and __Eiffel__ because of its explicit use of `assert(...)` (even if that makes it more similar to __D__'s syntax). +An advantage of this alternative syntax is that it does not require commas at the end of each assertion. +However, when compared with this library syntax, the alternative syntax is overall more verbose, it uses more parenthesis, it deviates more from __N1962__ and __Eiffel__ (even if it is more similar to __D__), and it looks less readable at least because of `decl(...)` (in many ways this alternative syntax is equivalent to the already supported sequencing syntax from the __No_Variadic_Macros__ section with the addition of ["decoration identifiers] like `assert` which might make the code more readable but are not needed syntactically). Therefore, the authors opted for implementing the syntax on the left hand side. [endsect] diff --git a/doc/qbk/introduction.qbk b/doc/qbk/introduction.qbk index 6837d0f..7f7398c 100644 --- a/doc/qbk/introduction.qbk +++ b/doc/qbk/introduction.qbk @@ -7,94 +7,45 @@ [section Introduction] -[@http://en.wikipedia.org/wiki/Design_by_contract Contract Programming] (CP) allows to specify preconditions, postconditions, and class invariants that are automatically checked when functions are executed at run-time. +Contract Programming allows to specify preconditions, postconditions, and class invariants that are automatically checked when functions are executed at run-time. These conditions assert program specifications within the source code itself allowing to find bugs more quickly during testing, making the code self-documenting, and increasing overall software quality. -Contract Programming is also known as Design by Contract (DbC) -[footnote -Design by Contract is a registered trademark of [@http://en.wikipedia.org/wiki/Eiffel_Software Eiffel Software]. -] -and it was first introduced by the __Eiffel__ programming language (see __Meyer97__). -All Contract Programming features of the __Eiffel__ programming language are supported by this library, among others (see also the __Features__ section): +The following example shows how to use this library to program contracts for the [@http://www.sgi.com/tech/stl/BackInsertionSequence.html `std::vector::push_back`] member function (for simplicity, the full contracts are not programmed here, see the __Examples__ section for a fully contracted version of `std::vector`). +In order to illustrate subcontracting, this `vector` class inherits from the (somewhat arbitrary) `pushable` base class (see also [@../../example/features/push_back.cpp =push_back.cpp=]): -# Support for preconditions, postconditions, class invariants, block invariants, and loop variants. -# Subcontract derived classes (with support for pure virtual functions and multiple inheritance). -# Access expression old values and function return value in postconditions. -# Optional compilation and checking of preconditions, postconditions, class invariants, block invariants, and loop variants. -# Customizable actions on contract assertion failure (terminate by default but it can throw, exit, etc). +[import ../example/features/push_back.cpp] +[push_back] -In addition, this library supports virtual specifiers, concept checking, and named parameters which together with contracts specify requirements of the program interface. -This library is implemented for the __CXX03__ standard and it does not require __CXX11__. +This library executes the following steps when the `vector::push_back` function above is called at run-time (see also the __Contract_Programming_Overview__ section): -[heading An Example] +* First, the class invariants and the function preconditions are checked. +* Then, the function body following the contract declaration is executed. +* Last, the class invariants and the function postconditions are checked. +* When subcontracting (like in the example above), this library will automatically check derived and base preconditions in __OR__, derived and base postconditions in __AND__, derived and base class invariants in __AND__. -The example below shows how to use this library to program contracts for the C++ Standard Template Library (STL) member function [@http://www.sgi.com/tech/stl/BackInsertionSequence.html `std::vector::push_back`] (in order to illustrate subcontracting, the `vector` class inherits from the somewhat arbitrary `pushable` base class). -The syntax used by this library is compared side-by-side with the syntax proposed by __N1962__ for adding Contract Programming to C++ (see also [@../../example/contracts/push_back.cpp =push_back.cpp=] and [@../../example/contracts/pushable.hpp =pushable.hpp=]): - -[import ../example/contracts/push_back.cpp] -[import ../example/contracts/push_back_lines.cpp] -[import ../example/contracts/push_back_npaper.cpp] -[table - [ [#] [This Library (C++03)] [N1962 and N2081 Proposals (not adopted by C++11) -[footnote -Unfortunately, the Contract Programming proposal __N1962__ and the concept proposal __N2081__ were never adopted by the C++ standard so the example on the right hand side will not compile. -] - ] ] - [ [[push_back_lines]] [[push_back]] [[push_back_npaper]] ] -] - -Classes and functions are declared using the [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] macros respectively. -Class invariants must appear at the very beginning of the class definition and they are specified using the [macroref CONTRACT_CLASS_INVARIANT] macro. -The `TPL` postfixes indicate versions of the macros that need to be used within templates. - -Note the following differences between the syntax used by this library macros and the usual C++ declaration syntax (see the __Differences_with_CXX_Syntax__ section for a complete list): - -* Round parenthesis `template( ... )` are used instead of angular parenthesis `template< ... >` to declare templates (line 7). -* Similarly to __N2081__, the specifier `requires( ... )` is used to specify concepts to check (line 7). -* The class and function names are wrapped within round parenthesis `(vector)` and `(push_back)` (lines 8 and 18). -* The specifier `extends( ... )` is used instead of the column symbol `:` to inherit from base classes (line 8). -This automatically subcontracts `vector` from `pushable` (when subcontracting, derived and base preconditions are checked in __logic_or__, derived and base postconditions are checked in __logic_and__, derived and base class invariants are checked __logic_and__). -* The access level `public`, `protected`, or `private` must always be specified for member functions but without the trailing column symbol `:` (line 18). -* The function result and parameter types are wrapped within round parenthesis `(T const&)` (line 18). -The parenthesis are allowed but not required for fundamental types that contain no symbol (e.g., the function result type `void` at line 18, but also `bool`, `unsigned int const`, etc). -* Similarly to __CXX11__, the specifier `override` is used to check that a member function is indeed overriding a base member function (line 18). -* The specifiers `precondition( ... )` and `postcondition( ... )` are used to program function preconditions and postconditions (lines 19 and 22). -Furthermore, the [macroref CONTRACT_OLDOF] macro can be used within postconditions to declare variables and initialize them to old values that the specified expressions had before executing the function body (line 23). -* Class invariants, preconditions, and postconditions assert boolean expressions separated by commas `,` (lines 11, 20, and 24). - -Finally, note that the class and function definitions are programmed outside the macros so they retain their usual C++ syntax (e.g., the function body at line 27). - -The library executes the following steps when the `push_back` function is called at run-time (see also the __Contract_Programming_Overview__ section): - -# First, the class invariants and the function preconditions are checked. -# Then, the function body is executed. -# Last, the class invariants and the function postconditions are checked. - -For example, if there is a bug in the function caller for which `push_back` is called when `size` is equal to `max_size` then the execution of the program will be interrupted reporting a failure of the first assertion in the preconditions and it will be evident that the bug is in the caller: +For example, if there is a bug in the function caller for which `push_back` is called when `size` is equal to `max_size` then the execution of the program will terminate with an error message similar to the following, thus it will be evident the bug is in the caller: [pre - precondition number 1 "size() < max_size()" failed: file "push_back.cpp", line 26 + precondition assertion "size() < max_size()" failed: file "push_back.cpp", line 33 ] -Instead, if there is a bug in the `push_back` implementation for which `size` is not increased by one after `value` is added to `vector` by the function body then the execution will be interrupted reporting a failure of the first assertion in the postconditions and it will be evident that the bug is in `push_back` body: +Instead, if there is a bug in the `push_back` implementation for which `size` is not increased by `1` after `value` is added to `vector` by the function body then the execution will terminate with an error message similar to the following, thus it will be evident the bug is in the `push_back` body: [pre - postcondition number 1 "size() == old_size + 1" failed: file "push_back.cpp", line 26 + postcondition assertion "size() == *old_size + 1" failed: file "push_back.cpp", line 36 ] -By default, when assertions fail this library prints the above error messages to the standard error `std::cerr` and it terminates the program calling `std::terminate` (this behaviour can be customized to throw an exception, exit the program, etc, see the __Broken_Contracts__ section). -Note that the library error messages contain enough information to uniquely identify the contract failure: Assertion type (class invariant, precondition, postcondition, etc), assertion number, asserted expression, file name, and line number. -(The line number refers to the single line on which each macro expands so it will be the same for class invariants, preconditions, and postconditions of a given class or function but it can still be used together with the assertion number to uniquely identity which assertion failed.) +By default, when an assertion fails this library prints an error message the standard error `std::cerr` and then it terminates the program calling `std::terminate` (but this behaviour can be customized to any user-defined action including throwing an exception, see the __Contract_Failure_Handlers__ section). +Note that the error message printed by this library contains information to easily and uniquely identify the assertion that failed. +[footnote +*Rationale.* +The assertion failure message generated by this library follows a format similar to the message printed by __Clang__ when the C-style `assert` macro fails. +] -[heading Language Support] - -This library suffers of two limitations: - -# The unusual syntax used to declare classes and functions within the macros which causes cryptic compiler errors when not used correctly (syntax error checking and reporting could be somewhat improved in future revisions of the library but there are fundamental limitations on what can be done using the preprocessor, see also the [link syntax_error_warning_anchor Grammar] section). -# High compilation times (the authors will try to reduce compilation times in future revisions of the library, see also the [link compilation_time_warning_anchor Cost] section). - -With the addition of contracts, concepts, and named parameters, C++ could introduce formal program specification into main-stream programming. -The authors wish the work done in developing this library will persuade the C++ community and the C++ standard committee to add these features to the core language so to support formal program specification without the unusual macro syntax and avoiding high compilation times (unfortunately, this has not been the direction taken for __CXX11__ with the rejection of the concept proposal __N2081__ and the lack of consideration for the Contract Programming proposal __N1962__, but there might still be hope for C++1x with x > 1). +[note +C++11 lambda functions are required to use this library without having to write a significant amount of boiler-plate code (but see also __No_Lambda_Functions). +Other C++11 features (like auto declarations) are not really necessary even if they are sometime used in this documentation for convenience. +] [endsect] diff --git a/doc/qbk/tutorial.qbk b/doc/qbk/tutorial.qbk index de272d8..7319140 100644 --- a/doc/qbk/tutorial.qbk +++ b/doc/qbk/tutorial.qbk @@ -1,489 +1,502 @@ -[/ Copyright (C) 2008-2012 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) ] -[/ Home at http://sourceforge.net/projects/contractpp ] - [section Tutorial] -This section explains how to program contracts using this library. -See the __Grammar__ section for a complete guide on this library syntax. +This section gives an introduction on how to program contracts using this library. + +[import ../example/features/identifiers.cpp] [section Free Functions] -Consider the following free function `postinc` which performs a post-increment on its parameter (see also [file example/contracts no_contract_postinc.cpp]): +Consider the following free function `inc` which increments its argument by `1` and returns the value its argument had before the increment (this function is equivalent to the usual C++ operator `int operator++(int& x, int)`). +Let's write the contract for such a function using code comments (see also [@../../example/features/inc_no_contract.cpp =inc_no_contract.cpp=]): -[import ../example/contracts/no_contract_postinc.cpp] -[no_contract_postinc] +[import ../../example/features/inc_no_contract.cpp] +[inc_no_contract] -Let's now program the function declaration using the [macroref CONTRACT_FUNCTION] macro but without programming the contract yet (see also [file example/contracts no_pre_post_postinc.cpp]): +The precondition states that the argument to increment must be smaller than the maximum allowable value of its type (otherwise the increment will go out-of-range). +The postconditions state that the argument was actually incremented by `1` and that the function return value is equal to the argument before it was incremented. -[import ../example/contracts/no_pre_post_postinc.cpp] -[no_pre_post_postinc] +Now let's program this function and its contract using the [funcref boost::contract::function] function from this library (see also [@../../example/features/inc.cpp =inc.cpp=]): -All necessary header files for this library are included by `#include ` (see also the __Getting_Started__ section). +[import ../../example/features/inc.cpp] +[inc] -The function body is programmed outside the library macro. -Therefore, while this library alters the function declaration syntax, it does not change the syntax used to implement the function. +All necessary header files of this library are included by `#include `. +Alternatively, programmers can selectively include only the header files they actually need among =boost/contract/*.hpp= (see also __Getting_Started__). -The function name `(postinc)` must always be wrapped within parenthesis so it can be passed to this library macros. +It is possible to specify both preconditions and postconditions for free functions (see also __Preconditions__ and __Postconditions__). -The function result and parameter types must be wrapped within parenthesis unless they are fundamental types containing no symbol (symbols are tokens different from the alphanumeric tokens `a-z`, `A-Z`, `0-9`). -In this example, the result type `int const` is a fundamental type and it contains no symbol so the parenthesis around it `(int const)` are allowed but not required. -[footnote -In the examples presented in this documentation, extra parenthesis are in general avoided unless strictly required (for example, extra parenthesis around fundamental types containing no symbol `void`, `bool`, `unsigned int const`, etc are always omitted). -In the authors' opinion, the syntax is more readable with lesser parenthesis. -However, other programmers might find it more readable to always specify extra parenthesis around result and parameter types for consistency even when they are not strictly required. +[funcref boost::contract::function] returns an RAII object (that can be assigned to a local variable of explicit type [classref boost::contract::guard] when programmers are not using C++11 auto declarations). +The free function body is programmed right after the declaration of this RAII object. +At construction, this RAII object does the following: + +# Check preconditions, by calling the functor [^['f]]`()` passed to `.precondition(`[^['f]]`)`. + +At destruction instead: + +# If the function body did not throw an exception: + # Check postconditions, by calling the functor [^['g]]`()` passed to `.postcondition(`[^['g]]`)`. + +This ensures that free function contracts are correctly checked at run-time (see also __Function_Calls__). + +[note +A free function can avoid calling [funcref boost::contract::function] for efficiency but only when it has no preconditions and no postconditions. ] -Instead, the parameter type `int&` is a fundamental type but it contains the reference symbol `&` so it must be wrapped within parenthesis `(int&)`. - -[important -In general, every token which is not a known keyword (`int` is a known keyword but the function name is not) or that contains a non-alphanumeric symbol (e.g., `int&`) must be wrapped within round parenthesis `(...)` unless it is the very last token of a given syntactic element (e.g., the function parameter name `value` is the last token of the parameter declaration). -[footnote -*Rationale.* -This library uses preprocessor meta-programming to parse declarations and contracts of classes and functions. -The preprocessor cannot parse a token if it is not known a priori or if it contains symbols, unless such a token is wrapped within round parenthesis `()`. -For example, the function name is arbitrary, it cannot be known a priori, so it must always be wrapped within parenthesis. -If a type is a fundamental type then it is known a priori (because it is composed of known C++ keywords `int`, `const`, `unsigned`, etc), and if the fundamental type also contains no symbols (`&`, `*`, etc) then the parenthesis around such a type are optional. -] - -See the __Grammar__ section for more information. -] - -Each function parameter must always specify both its type and its name (parameter names can instead by omitted in usual C++ declarations). -[footnote -*Rationale.* -It would be possible to modify the library syntax to make parameter names optional but that will complicate the library implementation without adding any feature for programmers. -] -As usual, additional parameters can be specified separated by commas `,` on compilers that support variadic macros (these include most modern compilers, MSVC, GCC, and all __CXX11__ compilers, see the __No_Variadic_Macros__ section for compilers that do not support variadic macros). -The configuration macro [macroref CONTRACT_CONFIG_FUNCTION_ARITY_MAX] indicates the maximum number of function parameters that can be specified. -An empty parameter list must be specified using `void` (this is similar to the usual C++ syntax that allows to declare a function with no parameter using [^['result-type function-name ]]`( void )`). -[footnote -*Rationale.* -Unfortunately, it is not possible to specify an empty parameter list simply as [^['result-type function-name ]]`( )` because the preprocessor can only parse `( )` if empty macro parameters are supported. -Empty macro parameters together with variadic macros where added to __C99__ and the preferred syntax of this library uses variadic macros. -However, not all compilers (notably MSVC) that support variadic macros also correctly support empty macro parameters so `( void )` is always used instead of `( )` to increase portability. -] -Default parameter values can be specified using `, default `[^['default-value]] immediately following the parameter name. -The storage classifiers `auto` and `register` can be specified as usual as part of the parameter type. -[footnote -Note that the `auto` storage classifier in deprecated by __CXX11__ so it should be used with the usual care when writing programs that should be portable from __CXX03__ to __CXX11__. -] -Functions can be overloaded by specifying different parameter types and they can recursively call themselves as usual. - -For example, the following function `postinc` is overloaded to work on `long` instead of `int` numbers, it is implemented using recursion, it increments the specified number by `offset` which is stored into a register variable and it has a default value of `1` (see also [file example/contracts params_postinc.cpp]): - -[import ../example/contracts/params_postinc.cpp] -[params_postinc] -[params_postinc_call] - -Function and array types cannot be directly used as function parameter types within the contract macros but extra `typedef` declarations can be used to workaround this limitation (for multi-dimensional arrays, the maximum number of supported array dimensions is specified by the [macroref CONTRACT_CONFIG_ARRAY_DIMENSION_MAX] macro). -For example (see also [file example/contracts params_funcptr_array_apply.cpp]): - -[import ../example/contracts/params_funcptr_array_apply.cpp] -[params_funcptr_array_apply] -[params_funcptr_array_apply_call] - -Spaces and new-lines make no syntactical difference and they can be used freely within this library macros. -[footnote -An MSVC preprocessor bug requires to use at least one space or newline to separate a parameter name from its type even when the parameter type is wrapped within parenthesis. -] -The following aesthetic conventions are followed in this documentation (because the authors think they improve readability): - -# Round parenthesis are spaced when a list of tokens is expected (e.g., the function parameter list): `( `[^['token1]]` )`, `( `[^['token1]]`, `[^['token2]]` )`, `( `[^['token1]]`, `[^['token2]]`, `[^['token3]]` )`, etc. -# Round parenthesis are not spaced when only a single token is expected (e.g., the function name): `(`[^['token]]`)`. [endsect] +The same considerations also apply to private and protected member functions because their contracts are also programmed using [funcref boost::contract::function] like for free functions (see also __Private_and_Protected_Functions__). + [section Preconditions] -Let's program the preconditions of `postinc` (see also [file example/contracts pre_only_postinc.cpp]): +When preconditions are specified, they are programmed using a functor that can be called with no parameter [^['f]]`()` and it is passed to `.precondition(`[^['f]]`)`. +Contracts that do not have preconditions simply do not call `.precondition(...)`. + +C++11 lambda functions are very convenient to program preconditions, but any other nullary functor can be used (see also __No_Lambda_Functions__). +[footnote +C++11 lambda functions with no parameters can be programmed as `[...] () { ... }` but also equivalently as `[...] { ... }`. +This second from is often used in this documentation omitting the empty parameter list `()` for brevity. +] +For example, for a free function contract (but same for all other contracts): + + auto c = boost::contract::function() // Same for all other contracts. + .precondition([&] { // Capture by reference or value... + BOOST_CONTRACT_ASSERT(...); // ...but should not modify captures. + ... + }) + ... + ; + +The precondition functor should capture all the variables that it needs to assert the preconditions. +These variables can be captured by value when the overhead associated with copying such variables is acceptable (but in this documentation preconditions often capture these variables by reference to avoid such overhead). +In any case, precondition assertions should not modify the value of the captured variables, even when those are captured by reference (see also __Constant_Correctness__). + +Any code can be programmed for the precondition functor, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex preconditions that might be buggy and slow to execute at run-time). +It is also recommended to use the [macroref BOOST_CONTRACT_ASSERT] macro to program the assertions because it enables this library to print very informative error messages when the asserted conditions are evaluated to be false at run-time (this is not a variadic macro, but see also __No_Macros__): -[import ../example/contracts/pre_only_postinc.cpp] -[pre_only_postinc] + BOOST_CONTRACT_ASSERT(``/boolean-condition/``) + // Or, if condition has commas `,` not already within parenthesis `(...)`. + BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) -In this example, the preconditions assert only one boolean condition but additional boolean conditions can be listed separated by commas `,`. -Preconditions are automatically checked by the library when the `postinc` function is called, immediately before the body is executed (i.e., at function /entry/). -See also the __Free_Function_Calls__ section. +This library will automatically call [funcref boost::contract::precondition_failed] if any of the [macroref BOOST_CONTRACT_ASSERT] macro conditions are `false` and also if the precondition functor call throws any exception (by default, this terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.). -Contracts are supposed to check but not to modify the state of the program (see the __Constant_Correctness__ section). -Therefore, this library evaluates all contract conditions in constant-correct context. -Specifically, in this example the type of `value` is automatically promoted from `int&` to `int const&` within the preconditions and an attempt to modify `value` within the preconditions will correctly generate a compile-time error. - -[endsect] - -[section Postconditions (Result and Old Values)] - -Let's program the postconditions of `postinc` completing the contract (see also [file example/contracts post_also_postinc.cpp]): - -[import ../example/contracts/post_also_postinc.cpp] -[post_also_postinc] - -Postconditions are automatically checked by the library when the `postinc` function is called, immediately after the body is executed but only if the body does not throw an exception (i.e., at function /normal exit/). -See also the __Free_Function_Calls__ section. - -Postconditions can access the function return value by declaring a variable of type `auto` -[footnote -*Rationale.* -The __CXX11__ `auto` declaration syntax is adopted for postcondition return value declarations however this library knows the result type because it is specified in the function declaration within the macros so no type deduction is actually used to implement auto declarations of return values. -Similarly, the __CXX11__ `auto` declaration syntax is adopted for postcondition old value declarations however this library deduces the type of old value expressions using __Boost_Typeof__ so no __CXX11__ feature is actually needed (in this case programmers can optionally specify the old value type so to not use __Boost_Typeof__ as explained in the __Advanced_Topics__ section). -] -and assigning it to the `return` keyword (the variable name is arbitrary but `result` is often used). - -Postconditions can also access the /old value/ that an expression had just before the body was executed. -This is done by declaring a variable of type `auto` and assigning it to [macroref CONTRACT_OLDOF] [^['expression]] (the variable name is arbitrary but the `old_` prefix is often used). -Before executing the function body, the library automatically copies (once) the value of the specified expression into a variable with the specified name which is then made available to the postconditions. -Therefore, the type of an old value expression must have a copy constructor (or, more precisely, it must be be __ConstantCopyConstructible__), otherwise the library will generate a compile-time error. -The parenthesis around the expression passed to the [macroref CONTRACT_OLDOF] macro are allowed but not required (in this example, `CONTRACT_OLDOF(value)` could have been equivalently used instead of `CONTRACT_OLDOF value` but the latter was preferred because of lesser parenthesis). -In this sense, the syntax of the `CONTRACT_OLDOF` macro resembles the syntax of the `sizeof` operator which also allows but does not require parenthesis when applied to value expressions (i.e., `sizeof value` and `sizeof(value)` are both valid). -[footnote -*Rationale.* -This is also the syntax specified by __N1962__ for the `oldof` operator which is the equivalent of the `CONTRACT_OLDOF` macro. -] -(The maximum number of supported and possible old value declarations is specified by the [macroref CONTRACT_CONFIG_OLDOF_MAX] and [macroref CONTRACT_LIMIT_OLDOFS] macros respectively.) - -Postconditions always access result and old values in constant-correct context so that contracts cannot modify the state of the program (see the __Constant_Correctness__ section). - -In general, it is recommended to specify multiple assertions separated by commas and not to group them together into a single condition using the operator `and` (or `&&`). -This is because if assertion conditions are programmed together using `and` then it will not be clear which assertion condition actually failed in case the contract is broken. -For example, if in the code above we programmed one single postcondition `(value == old_value + 1) and (result == old_value)` then in case the postcondition failed we would not know which condition failed `value == old_value + 1` or `result == old_value`. +Preconditions can be specified before or after postconditions (by calling `.precondition(...)` before or after `.postcondition(...)`). +This library will generate a compile-time error if preconditions are specified multiple times for the same contract. [note -All tokens must be specified in the fixed order listed in the __Grammar__ section (it is not possible to specify postconditions before preconditions, `volatile` before `const` for member functions, etc). -[footnote -*Rationale.* -This library macros could have been implemented to allow to mix the order of some tokens (preconditions and postconditions, `volatile` and `const`). -However, that would have complicated the macro implementation without any added functionality for the user. -] +Contracts are most useful when the assertions only use public members that are accessible to the caller so the caller can properly check and use the contract. +In particular, preconditions of a public member function or constructor that use non-public members are essentially incorrect because they cannot be fully checked by the caller (in fact, Eiffel generates a compile-time error in this case). + +This library leaves it up to the programmers to only use public members when programming contracts and especially when programming preconditions (see also __Specification_and_Implementation__). ] [endsect] -[section Classes and Class Invariants] +[section Postconditions] -Consider the following class `ivector` which is a vector of integers with a constructor, destructor, and the `push_back` member function (see also [file example/contracts no_contract_ivector.cpp]): +When postconditions are specified, they are programmed using a functor that can be called with no parameter [^['g]]`()` and it is passed to `.postcondition(`[^['g]]`)`. +Contracts that do not have postconditions simply do not call `.postcondition(...)`. -[import ../example/contracts/no_contract_ivector.cpp] -[no_contract_ivector] +C++11 lambda functions are very convenient to program postconditions, but any other nullary functor can be used (see also __No_Lambda_Functions__). +For example, for a free function contract (but same for all other contracts): -Let's program the class declaration and the class invariants using the [macroref CONTRACT_CLASS] and [macroref CONTRACT_CLASS_INVARIANT] macros respectively (see also [file example/contracts class_ivector.cpp]): + auto c = boost::contract::function() // Same for all other contracts. + ... + .postcondition([&] { // Capture by reference... + BOOST_CONTRACT_ASSERT(...); // ...but should not modify captures. + ... + }) + ; -[import ../example/contracts/class_ivector.cpp] -[class_ivector_classinv] +The postcondition functor should capture all variables that it needs to assert the postconditions. +In general, these variables should be captured by reference and not by value (because postconditions need to access the value these variables will have at function exit, and not the value these variables had when the postcondition functor was first constructed). +Postconditions can also capture return and old values (see also __Return_Value__ and __Old_Values__). +In any case, postcondition assertions should not modify the value of the captured variables (see also __Constant_Correctness__). -A class must always be declared using the [macroref CONTRACT_CLASS] macro in oder to later be able to program contracts for its constructors, destructor, and member functions. -Similarly to function names, the class name must always be wrapped within parenthesis `(ivector)` (because the class name is not a known keyword and it is not the last element of the class declaration syntax for example when base classes and are specified after the class name). -Only constructors, destructors, and member functions that are public check the class invariants while the ones that are either protected or private do not (see the __Contract_Programming_Overview__ section). -The class invariant must always be specified for a class declared using the [macroref CONTRACT_CLASS] macro and it must appear at the very beginning of the class definition (no statement can precede the [macroref CONTRACT_CLASS_INVARIANT] macro, not even a `typedef` or a `friend` declaration). -If a class has no class invariant, the class invariants must be specified `void`: +Any code can be programmed for the postcondition functor, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex postconditions that might be buggy and slow to execute at run-time). +It is also recommended to use the [macroref BOOST_CONTRACT_ASSERT] macro to program the assertions because it enables this library to print very informative error messages when the asserted conditions are evaluated to be false at run-time (this is not a variadic macro, but see also __No_Macros__): - CONTRACT_CLASS( - class (ivector) - ) { - CONTRACT_CLASS_INVARIANT( void ) // No class invariant. + BOOST_CONTRACT_ASSERT(``/boolean-condition/``) + // Or, if condition has commas `,` not already within parenthesis `(...)`. + BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) - // ... +This library will automatically call [funcref boost::contract::postcondition_failed] if any of the [macroref BOOST_CONTRACT_ASSERT] macro conditions are `false` and also if the postcondition functor call throws any exception (by default, this terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.). -Using the same macro, this library also allows to specify contracts for `struct`: +Postconditions can be specified before or after preconditions (by calling `.postcondition(...)` before or after `.precondition(...)`). +This library will generate a compile-time error if postconditions are specified multiple times for the same contract. + +[endsect] + +[section Return Value] + +When the function non-void return value is used in postconditions, programmers are responsible to declare a local variable before the contract and to assign it to the return value at function exit (when the function does not throw an exception). +[footnote +The name of the local variable that holds the return value is arbitrary, but `result` is often used in this documentation. +] +For example, for a free function contract (but same for all other contracts): + + ``/return-type/`` result; // Must be assigned to return value. + auto c = boost::contract::function() // Same for all other contracts. + ... + .postcondition([&] { // Also capture `result` reference... + ... // ...but should not modify captures. + }) + ; + +At any point where the enclosing function returns, programmers are responsible to assign the result variable to the expression being returned. +This can be easily done by making sure that /all/ the `return` statements in the function are of the form: + + return result = ``/expression/``; // Assign `result` at each return. + +The functor used to program postconditions should capture the result variable by reference (because postconditions must access the value this variable will have at function exit, and not the value this variable had when the postcondition functor was first constructed). +The return value should never be used in preconditions (because the return value is not yet evaluated and set when preconditions are checked, see also __Assertions__). +In any case, programmers should not modify the result variable in the contract assertions (see also __Constant_Correctness__). + +It is also possible to declared result variables using `boost::optional` when the return type does not have a default constructor, or if the default constructor is too expensive to execute, etc. (see also __Optional_Return_Value__). + +Virtual and overriding public member functions must always declare and use a result variable even when that is not directly used in postconditions (see also __Virtual_Public_Functions__ and __Overriding_Public_Functions__). + +[endsect] + +[section Old Values] + +When old values are used in postconditions, programmes are responsible to declare local variables before the contract and to assign them to the related expressions via the [macroref BOOST_CONTRACT_OLDOF] macro. +[footnote +The name of the local variable that holds an old value is arbitrary, but `old_`[^['name]] is often used in this documentation. +] +For example, for a free function contract (but same for all other contracts): + + ... + boost::shared_ptr<``/type/`` const> old_``/name/`` = BOOST_CONTRACT_OLDOF(``/expression/``); + auto c = boost::contract::function() // Or some other contract object. + ... + .postcondition([&] { // Capture by reference... + ... // ...but should not modify captures. + }) + ; + +Old values are handled as smart pointers to `const` values (so they cannot be mistakenly changed by the contract assertions, see also __Constant_Correctness__). [footnote *Rationale.* -There is no need for a `CONTRACT_STRUCT` macro because this library macros can parse the class declaration and distinguish between the `struct` and `class` specifiers. +`boost::shared_ptr` was used instead of `std::shared_ptr` because this library is designed to work well with Boost and technically to not require C++11 (even if the use of this library without C++11 lambda functions requires programmer to write a fare amount of boiler-plate code). ] +Therefore, old values must be dereferenced using `operator*` or `operator->` when they are used in postconditions (otherwise the compiler will most likely error). +This library ensures that old value smart pointers are not null by the time postconditions are checked so programmers can always safely dereference old value pointers in postconditions without any extra checking. - CONTRACT_CLASS( - struct (ivector) // Structs with contracts. - ) { - // ... +Old values should never be used in preconditions (because old values are same as original values when preconditions are checked, see also __Assertions__). +In fact, this library does not even guarantee that old value pointers are always not null when precondition functors are called (for example, when postcondition contract checking is disabled using [macroref BOOST_CONTRACT_CONFIG_NO_POSTCONDITONS], when checking an overridden virtual function contract via subcontracting, etc.). +Finally, see __Old_Values_at_Body__ for always delaying the assignment of old values until after preconditions (and possibly class invariants) have been checked first (in case it is important to simplify old value expressions programming them under the assumption that precondition and class invariant conditions are satisfied already). -The usual differences between `struct` and `class` also apply when this library is used (i.e., default member and inheritance access levels are `public` for `struct` and `private` for `class`). +This library ensures that old values are only copied once by the [macroref BOOST_CONTRACT_OLDOF] macro that they are actually never copied when postcondition contract checking is disabled by the [macroref BOOST_CONTRACT_CONFIF_NO_POSTCONDITIONS] configuration macro. + +[macroref BOOST_CONTRACT_OLDOF] is actually a variadic macro and it takes an extra parameter when used in virtual or overriding public functions (see also __Virtual_Public_Functions__ and __Overriding_Public_Functions__, and see __No_Macros__ to program old values without using macros). + +In the rest of this documentation, C++11 auto declarations will be often used for old values instead of explicitly writing the `boost::shared_ptr<... const>` type. +This is done just for convenience, and programmers can alway explicitly specify the declaration type if they are not using C++11 auto declarations. + +[endsect] + +[section Class Invariants] + +When class invariants are specified, they are programmed in a public `const` member function named `invariant` taking no argument and returning `void`. +Classes that do not have invariants, simply do not declare an `invariant` member function. +[footnote +This library uses template meta-programming (SFINAE-based introspection techniques) to check invariants only for classes that declare a member function named `invariant`. +] +For example: + + class a { + public: // Must be public. + void invariant() const { // Must be const. + BOOST_CONTRACT_ASSERT(...); + ... + } + + ... + }; + + +This member function must be `const` because contracts should not modify the object state (see also __Constant_Correctness__). +This library will generate a compile-time error if the `const` qualifier is missing (unless [macroref BOOST_CONTRACT_CONFIG_PERMISSIVE] is set). + +Any code can be programmed in the `invariant` function, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex invariants that might be buggy and slow to execute at run-time). +It is also recommended to use the [macroref BOOST_CONTRACT_ASSERT] macro to program the assertions because it enables this library to print very informative error messages when the asserted conditions are evaluated to be false at run-time (this is not a variadic macro, but see also __No_Macros__): + + BOOST_CONTRACT_ASSERT(``/boolean-condition/``) + // Or, if condition has commas `,` not already within parenthesis `(...)`. + BOOST_CONTRACT_ASSERT((``/boolean-condition/``)) + +This library will automatically call [funcref boost::contract::entry_invariant_failed] or [funcref boost::contract::exit_invariant_failed] if any of the [macroref BOOST_CONTRACT_ASSERT] macro conditions are `false` and also if the `invariant` function throws an exception (by default, this terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.). + +See __Access__ to avoid making `invariant` a public member function (e.g., in cases when all public members of a class must be controlled exactly). +Set the [macroref BOOST_CONTRACT_CONFIG_INVARIANT] configuration macro to use a name different from `invariant` (e.g., because `invariant` clashes with other names in the user-defined class). + +Furthermore, see __Static_Public_Functions__ and __Volatile_Public_Functions__ for programming class invariants for `static` and `volatile` public member function calls respectively. [note -Unfortunately, this library does not allow to specify contracts for `union`. -[footnote -*Rationale.* -The authors have not fully investigated if this library could be extended to specify contracts for unions. -It is possible that future revisions of this library will support contracts for unions (see also [@http://sourceforge.net/apps/trac/contractpp/ticket/50 Ticket 50]). +No contracts are checked (not event class invariants) when a data member is accessed directly (this is different from Eiffel where even accessing public data members checks class invariants). +Therefore, it might be best for both `class`es and `struct`s to have no mutable public data members and to access data members publicly only via appropriate public member functions that can check the class invariants. ] -] - -No contracts are checked (not event the class invariants) when a data member is accessed directly so it might be best for both classes and structs to have no non-constant public data member (but access all data members via appropriate member functions that can check the class and sturct contracts). [endsect] [section Constructors] -Let's program the `ivector` class constructor and its contract using the [macroref CONTRACT_CONSTRUCTOR] macro (see also [file example/contracts class_ivector.cpp]): +Contracts for constructors are programmed using the [funcref boost::contract::constructor] function and the [classref boost::contract::constructor_precondition] base class. +For example (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): -[class_ivector_constructor] +[unique_identifiers_constructor] -Constructor, destructor, and member function declarations must always repeat their access level `public`, `protected`, or `private` -[footnote -*Rationale* -This library needs to know each member access level because in Contract Programming only public members are supposed to check class invariants while protected and private members only check preconditions and postconditions but not the class invariants. -Unfortunately, in C++ it is not possible for a member to introspect its access level using template meta-programming. -Therefore, this library requires the access level to be specified within the macros and it uses preprocessor meta-programming to detect it. -Furthermore, given that the access level is has to be specified, the [macroref CONTRACT_FUNCTION] macro also uses it to differentiate between free and member functions so no additional macro `CONTRACT_MEMBER` is needed. -] -which is specified without the usual trailing column symbol `:`. -(This use of `public`, `protected`, and `private` resembles __Java__'s syntax.) +It is not possible to specify preconditions using `.precondition(...)` for constructors (the library will generate a compile-time error if `.precondition(...)` is used on the object returned by [funcref boost::contract::constructor]). +Constructor preconditions are specified using the [classref boost::contract:constructor_precondition] base class instead (see also __Preconditions__). +Programmes should not access the object `this` from constructor preconditions (because the object does not exists yet before the constructor body is executed, see also __No_Lambda_Functions__). +Constructors without preconditions simply do not explicitly initialize the [classref boost::contract::constructor_precondition] base (the base default constructor is used instead and that checks no contract). +When [classref boost::contract::constructor_precondition] is used: -The constructor name `(ivector)` and the non-fundamental parameter type `(size_type)` must be wrapped within parenthesis (because they are not known keywords and they are not at the end of a syntactic element). - -Member initializers are programed as a comma-separated list but using the specifier [^initialize( /expression1/, /expression2/, ... )] instead of the usual column symbol [^: /expression1/, /expression2/, ...]. -When specified, they must appear at the very end of constructor declarations (after both preconditions and postcondition if present). +* It must be specified as the /first/ class in the inheritance list (so constructor preconditions are checked before initializing any other base or member). +* Its inheritance level should always be `private` (so this extra base class does not alter the public inheritance tree of the derived class). +* It takes the derived class as template parameter (the Curiously Recursive Template Pattern (CRTP) is used here to avoid ambiguity errors with multiple inheritance). [footnote *Rationale.* -Member initializers are specified after the preconditions and postconditions because they are part of the constructor definition while preconditions and postconditions are part of the constructor declaration. +The [classref boost::contract::constructor_precondition] takes the derived class as its template parameter so the instantiated template type is unique for each derived class always avoiding base class ambiguities even in case of multiple inheritance. +Virtual inheritance cannot be used resolve such ambiguities because virtual bases are initialized only once by the out-most deriving class, and that would not allow to properly check preconditions of all base classes. ] -Unfortunately, when member initializers are specified, the constructor body must be defined together with its declaration and contract (see the __Forward_Declarations_and_Body_Definitions__ section). -There is no object before the constructor body is executed, therefore this library will generate a compile-time error if either preconditions or postcondition old value expressions try to access the object `this`. -For the same reason, only static class invariants are checked at entry of public constructors (non-static class invariants are checked at public constructor normal exit but not at entry). -Finally, preconditions are checked before member initializers are executed (so the initializers can rely on preconditions for validating constructor arguments). -See also the __Constructor_Calls__ section. +It is possible to specify postconditions for constructors (see also __Postconditions__). +Programmers should not access the old value of the object `this` in constructor postconditions (because the object did not exist yet before the constructor body was executed, see also __No_Lambda_Functions__). +[funcref boost::contract::constructor] takes `this` as a parameter because constructors check class invariants (see also __Class_Invariants__). + +[funcref boost::contract::constructor] returns an RAII object (that can be assigned to a local variable of explicit type [classref boost::contract::guard] when programmers are not using C++11 auto declarations). +The constructor body is programmed right after the declaration of this RAII object. +At construction, this RAII object does the following: + +# Check static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()` (but not non-static class invariants because the object does not exists yet). + +At destruction instead: + +# Check static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()`. +# If the constructor body did not throw an exception: + # Check non-static class invariants, by calling `this->invariant()`. + # Check postconditions, by calling the functor ['[^g]]`()` passed to `.postcondition(`['[^g]]`)`. + +This together with C++ construction mechanism of base classes and the use of [classref boost::contract::constructor_precondition] ensures that the constructor contracts are correctly checked at run-time (see also __Constructor_Calls__). + +[note +A constructor can avoid calling [funcref boost::contract::constructor] for efficiency but only when it has no postconditions and its class has no invariants. +(Even if [funcref boost::contract::constuctor] is not used, the constructor's class can still have bases because their contracts are always checked by C++ construction mechanism.) +] + +Private and protected constructors can omit [funcref boost::contract::constructor] because they are not part of the public interface of the class so they are not required to check class invariants (see also __Constructor_Calls__). +They could still use [classref boost::contract::constructor_precondition] to check preconditions before member initializations, and use [funcref boost::contract::function] to just check postconditions instead. [endsect] [section Destructors] -Let's program the `ivector` class destructor using the [macroref CONTRACT_DESTRUCTOR] macro (see also [file example/contracts class_ivector.cpp]): +Contracts for destructors are programmed using the [funcref boost::contract::destructor] function. +For example (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): -[class_ivector_destructor] +[unique_identifiers_destructor] -The destructor access level `public`, `protected`, or `private` must always be specified. -The destructor name `(~ivector)` must be wrapped within parenthesis. -The destructor empty parameter list must be specified using `void` (same as for constructors, member functions, and free functions with no parameters). +It is not possible to specify preconditions for destructors (the library will generate a compile-time error if `.precondition(...)` is used here because destructors can be called at any time after construction so they have no precondition). +It is possible to specify postconditions for destructors (see also __Postconditions__ and see __Static_Public_Functions__ for an example). +Programmers should not access the object `this` in destructor postconditions (because the object no longer exists after the destructor body has been executed, see also __No_Lambda_Functions__). +[funcref boost::contract::destructor] takes `this` as a parameter because destructors check class invariants (see also __Class_Invariants__). -Destructors have no parameter and there is no object after the destructor body is executed. -Therefore, destructors cannot specify neither preconditions nor postconditions. -[footnote -Future revisions of this library might implement static postconditions for destructors (see the __Destructor_Calls__ section). -] -However, it is still necessary to contract (at least public) destructors so they check static and non-static class invariants at entry, and non-static class invariants at exit. -See also the __Destructor_Calls__ section. +[funcref boost::contract::destructor] returns an RAII object (that can be assigned to a local variable of explicit type [classref boost::contract::guard] when programmers are not using C++11 auto declarations). +The destructor body is programmed right after the declaration of this RAII object. +At construction, this RAII object does the following: -[important -Only members declared using this library macros check the class invariants. -Therefore, at least all public members of a class with non-empty class invariants should be declared using this library macros even when they have no preconditions and no postconditions so that they check the class invariants (that is the case for public destructors). -] +# Check static and non-static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()`. -In general, there is no need to use this library macros to declare free functions, constructors, destructors, and member function only when: +At destruction instead: -# A free function has no preconditions and no postconditions. -# A private or protected constructor, destructor, or member function has no preconditions and no postconditions (regardless of class invariants because private and protected members never check class invariants). -# A public constructor, destructor, or member function has no preconditions, no postconditions, and its class has no class invariants. +# Check static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()`. +# If the destructor body threw an exception: + # Check non-static class invariants, by calling `this->invariant()` (because the object was not successfully destructed). +# Else: + # Check postconditions, by calling the functor ['[^g]]`()` passed to `.postcondition(`['[^g]]`)`. -[endsect] - -[section Member Functions] - -Let's program the member function `ivector::push_back` and its contract using the [macroref CONTRACT_FUNCTION] macro (see also [file example/contracts class_ivector.cpp]): - -[class_ivector_member] - -The member function access level `public`, `protected`, or `private` must always be specified. -The member function name `(push_back)` must be wrapped within parenthesis. -The member function result type `void` and parameter type `int const` can but do not have to be wrapped within parenthesis (because they are both fundamental types containing no symbol). - -Public non-static member functions check static and non-static class invariants at both entry and exit. -Preconditions are checked at entry and postconditions are checked at normal exit. -Both preconditions and postconditions can access the object and the member function parameters in constant-correct context. -Postconditions can declare return and old value variables (again, in constant-correct context). -See also the __Member_Function_Calls__ section. +This together with C++ destruction mechanism of base classes ensures that destructor contracts are correctly checked at run-time (see also __Destructor_Calls__). [note -Contracts are most useful when the assertions only use public members that are accessible from the caller so the caller can properly verify and use the contract. -In particular, preconditions of a member function or constructor that use non-public members are essentially incorrect because they cannot be verified by the caller before calling the function (in fact, __Eiffel__ generates a compile-time error in this case). - -This library leave it up to programmers to only use public members when programming contracts and especially when programming preconditions (see the __Specification_vs__Implementation__ section). +A destructor can avoid calling [funcref boost::contract::destructor] for efficiency but only when it has no postconditions and its class has no invariants. +(Even if [funcref boost::contract::destructor] is not used, the destructor's class can still have bases because their contracts are always checked by C++ destruction mechanism.) ] +Private and protected destructors can omit [funcref boost::contract::destructor] because they are not part of the public interface of the class so they are not required to check class invariants (see also __Destructor_Calls__). +They could use [funcref boost::contract::function] to just check postconditions instead. + [endsect] -[section Inheritance and Subcontracting] +[section Public Functions] -Consider the following class `unique_identifiers` which is a collection of unique integral identifiers (see also [file example/contracts subcontract_identifiers.cpp]): +Contracts for public member functions are programmed using the [funcref boost::contract::public_function] function. -[import ../example/contracts/subcontract_identifiers.cpp] -[subcontract_identifiers_unique] +Let's first consider public member functions that are not static, not virtual, and do not override any function from base classes. +For example, the following such a function `find` is declared as a member of the `unique_identifiers` class (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): -Reading the contracts we can understand the semantics of the class operation (even if we do not consult the class implementation): +[unique_identifiers_find] -# The collection is constructed with zero size as specified by the constructor postconditions. -Consistently, the class invariants assert that the class size must never be negative (but it can be zero). -# The member function `unique_identifiers::add` allows to add an integral identifier to the collection. -The preconditions assert that the specified identifier must not already be part of the collection making sure that duplicate identifiers are never added. -# If the specified identifier was not already part of the collection (`old_found` is `false`) then the postconditions assert that the identifier is added and consequently that the size of the collection increased by one. -Note that both postconditions are trivially `true` if instead the identifier was already part of the collection (`old_found` is `true`). -We call these type of assertions that are "guarded" by an activation condition /select assertions/ (here we have used the C++ ternary operator `?:` to program select assertions, the __Advanced_Topics__ section will introduce an alternative construct for select assertions). +It is possible to specify both preconditions and postconditions for public member functions (see also __Preconditions__ and __Postconditions__). +[funcref boost::contract::public_function] takes `this` as a parameter because public member functions check class invariants (see also __Class_Invariants__). -Let's assume that we want to derive from `unique_identifiers` another type of collection `duplicate_identifiers` which instead allows to add duplicate identifiers (see also [file example/contracts subcontract_identifiers.cpp]): +[funcref boost::contract::public_function] returns an RAII object (that can be assigned to a local variable of explicit type [classref boost::contract::guard] when programmers are not using C++11 auto declarations). +The public member function body is programmed right after the declaration of this RAII object. +At construction, this RAII object does the following: -[subcontract_identifiers_duplicate] +# Check static and non-static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()`. +# Check preconditions, by calling the functor ['[^f]]`()` passed to `.precondition(`['[^f]]`)`. -The derived class `duplicate_identifiers` publicly inherits from the base class `unique_identifiers` using the specifier [^extends( /base1/, /base2/, ... )] instead of the usual column symbol [^: /base1/, /base2/, ...]. (This use of `extends` resembles __Java__'s syntax.) -As usual, the inheritance access level `public`, `protected`, or `private` is optional and it defaults to `public` for `struct` and to `private` for `class`. -Virtual base classes can also be specified but `virtual` must always be specified after the inheritance access level `public`, `protected`, or `private` if present. -Multiple base classes (`base1`, `base2`, etc) can be specified for multiple-inheritance (the configuration macro [macroref CONTRACT_CONFIG_INHERITANCE_MAX] indicates the maximum number of base classes that can be specified). +At destruction instead: + +# Check static and non-static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()` (even if the function body threw an exception). +# If the function body did not throw an exception: + # Check postconditions, by calling the functor ['[^g]]`()` passed to `.postcondition(`['[^g]]`)`. + +This ensures that public member function contracts are correctly checked at run-time (see also __Public_Function_Calls__). [note -This library automatically subcontracts the derived class when one or more base classes are specified (see the __Contract_Programming_Overview__ section). -] - -Let's assume that a `duplicate_identifers` object is constructed with identifier `123` and that we try to add the identifier `123` again: - -[subcontract_identifiers_duplicate_add] - -Reading both the derived and base class contracts, we can understand the semantics of the derived class operation (even if we do not consult the base and derived class implementations): - -# The `duplicate_identifiers` constructor creates a collection with size one as specified by the constructor postconditions. -Therefore, the `duplicate_identifiers` class invariants assert that size is always positive. -Subcontracting automatically checks the `unique_identifiers` base class invariants in __logic_and__ with the `duplicate_identifiers` derived class invariants thus class invariants can only be strengthened by derived classes (this is necessary because the derived class can be used whenever the base class is used therefore the derived class must satisfy the base class invariants at all times, see also the __substitution_principle__ and the __Contract_Programming_Overview__ section). -# Subcontracting automatically checks the `unique_identifiers::add` overridden preconditions in __logic_or__ with the `duplicate_identifiers::add` overriding preconditions thus preconditions can only be weakened by overriding member functions (this is necessary because the overriding member function can be called under the conditions for which the overridden function is called, see also the __substitution_principle__ and the __Member_Function_Calls__ section). -Indeed, in this example the `unique_identifiers::add` preconditions fail (because `123` is already in the collection) but the `derived_identifiers::add` preconditions pass so the __logic_or__ of the two sets of preconditions passes and the call `ids.add(123)` is a valid call. -# Subcontracting automatically checks the `unique_identifiers::add` overridden postconditions in __logic_and__ with the `duplicate_identifiers::add` overriding postconditions thus postconditions can only be strengthen by overriding member functions (this is necessary because the overriding function can be called in any context in which the overridden function is called, see also the __substitution_principle__ and the __Member_Function_Calls__ section). -Indeed, in this example the `unique_identifiers::add` postconditions pass because the identifier `123` was already added (`old_found` is `true`) and `unique_identifiers::add` select assertions trivially return `true`. -The `duplicate_identifiers::add` postconditions are then checked in __logic_and__ and they correctly assert that the collection size did not change given that `123` was already added. -Therefore, the call `ids.add(123)` is valid but adds no identifier. - -Finally, note that within the body of overriding functions it is necessary to use the [macroref CONTRACT_MEMBER_BODY] macro to call the overridden function as in `unique_identifiers::CONTRACT_MEMBER_BODY(add)(id)`. - -[warning -Unfortunately, invoking the overridden function from within the overriding function body without using [macroref CONTRACT_MEMBER_BODY] results in infinite recursion. -[footnote -*Rationale*. -In this case, the library implementation will recursively check contracts of the overriding function forever (in all other cases, this library is able to avoid infinite recursions due to contract checking). -] -This limitation might be removed in future revisions of this library (see also [@https://sourceforge.net/apps/trac/contractpp/ticket/46 Ticket 46]). +A public member function can avoid calling [funcref boost::contract::public_function] for efficiency but only when it has no preconditions and no postconditions, it is not virtual, it does not override any virtual function, and its class has no invariant. ] [endsect] -[section Class Templates] +[section Virtual Public Functions] -Let's program a class template `vector` similar to the class `ivector` we have seen before but that works on a generic value type `T` and not just on `int` (see also [file example/contracts class_template_vector.cpp] and [file example/contracts pushable.hpp]): +Let's now consider public member functions that are virtual but that still do not override any function from base classes. +For example, the following such a function `push_back` is declared as a member of the `unique_identifiers` class (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): -[import ../example/contracts/class_template_vector.cpp] -[class_template_vector] +[unique_identifiers_push_back] -(The specifications of the code in this example are not fully programmed, in particular concepts, see the __Concepts__ section, and assertion requirements, see the __Advanced_Topics__ section, have been omitted for simplicity.) +Public virtual functions must declare an extra trailing parameter of type [classref boost::contract::virtual_]`*` and assign it to `0` by default (i.e., null). +Because this extra parameter is the last one and it has a default value, it does not alter the calling interface of the virtual function and callers will essentially never have to deal with it explicitly (a part from when manipulating the virtual function type for function pointer type-casting, etc.). +Programmers must pass the extra virtual parameter as the very first argument to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls in the virtual function. +[footnote +*Rationale.* +The [classref boost::contract::virtual_]`*` optional parameter is used by this library to determine that a function is virtual (in C++ it is not possible to introspect if a function has been declared `virtual`). +Furthermore, this parameter is used by this library to pass result and old values that are evaluated by overriding function to the overridden virtual functions, and also to check preconditions and postconditions (but without executing the body) of the overridden virtual functions when subcontracting. +] -Note that templates are declared using the specifier `template( typename T, ... )` which uses round parenthesis instead of the usual angular parenthesis `template< typename T, ... >`. -However, after a template is declared using round parenthesis, angular parenthesis are used as usual to instantiate the template (e.g., the base class `pushable`). +Furthermore, for non-void public virtual functions, programmers must pass a reference to the function return value as the second argument to [funcref boost::contract::public_function]. +In this case the functor specified to `.postcondition(...)` takes a single parameter (possibly as a constant reference `const&`) to the return value (this library will generate a compile-time error otherwise). +[footnote +*Rationale.* +The functor passed to `.postcondition(...)` takes the extra return value parameter because that is used by this library to pass the return value evaluated by the overriding function to all its overridden virtual functions when subcontracting. +] [important -Within a type-dependent scope (e.g., within the class template of the above example) the special macros with the `_TPL` postfix must be used instead of the macros we have seen so far. +It is the responsibility of the programmers to pass the virtual extra parameter to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls, and also to pass the return value reference to [funcref boost::contract::public_function] for non-void functions. +This library cannot automatically generate compile-time errors if programmers fail to do so, but in general contract checking will not correctly work at run-time in such cases. + +['Remember: When "`v`" is present, always pass it to old-of macros and contract-function calls; Always pass result after "`v`" for non-void functions.] +] + +For the rest, the same considerations made in __Public_Functions__ apply. + +[endsect] + +[section Overriding Public Functions (Subcontracting)] + +Let's now consider public member functions (virtual or not) that override public virtual functions from one or more public base class. +For example, the following such a function `push_back` is declared as a member of the `identifiers` derived class and it overrides `push_back` from the `unique_identifiers` base class (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): +[footnote +In this document, overriding functions are often marked with the `/* override */` comment. +On compilers that support C++11 virtual specifiers `override` can be used instead (`override` is not used in the documentation only because virtual specifiers are not widely supported yet, even by compilers that support other C++11 features like lambda functions). +] + +[identifiers_push_back] + +(See the __Base_Types__ section below for more information about [macroref BOOST_CONTRACT_BASE_TYPES] and `base_types`.) + +Overriding public functions must always list the extra trailing parameter of type [classref boost::contract::virtual_]`*` with `0` default value, even when they are not declared `virtual` (because this parameter is present in the signature of the virtual function being overridden from base classes). +Programmers must pass the extra virtual parameter as the very first argument to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls in the overriding function (as for non-overriding virtual public functions discussed above). + +For overriding functions, [funcref boost::contract::public_function] takes an explicit template argument `override_`[^['function-name]] that must be defined at class scope using [macroref BOOST_CONTRACT_OVERRIDE][^(['function-name])] (see right after the function). +When called from overriding public functions, [funcref boost::contract::public_function] also take a pointer to the enclosing function, the object `this` (because overriding public functions check class invariants), and references to each function argument in the order they appear in the function declaration. [footnote *Rationale.* -The library must know if the enclosing scope is a template so it knows when to prefix nested type expressions with `typename` (because __CXX03__ does not allow to use `typename` outside templates). -This constraints could be relaxed on future revisions of this library for __CXX11__ compilers (because __CXX11__ allows to use `typename` more freely). -Earlier versions of this library did not require to use the special `_TPL` macros within templates because the library internally implemented every contracted function using a template function, possibly with dummy template parameters, even if the original function was not a template so `typename` could always be used by the library. -The dummy template parameters were hidden to the user so this approach did not change the user API and had the benefit of not requiring the `_TPL` macros. -However, this approach increased compilation time because of the extra templates that it introduced so the current revision of the library uses the `_TPL` macros. -] -(The same applies to function templates, see below.) +The object `this` is passed after the function pointer to follow `bind`'s syntax. +The function pointer and references to all function arguments are needed for overriding virtual public functions because this library has to call overridden virtual public functions to check their contracts for subcontracting (even if without executing their bodies). ] -In the example above, the enclosing class template `vector` is not declared using the [macroref CONTRACT_CLASS_TPL] macro because its enclosing scope is not type-dependent (it is the global namespace). -Within such a class template however, all contract macros must use the `_TPL` postfix so [macroref CONTRACT_CLASS_INVARIANT_TPL], [macroref CONTRACT_CONSTRUCTOR_TPL], [macroref CONTRACT_DESTRUCTOR_TPL], and [macroref CONTRACT_FUNCTION_TPL] must be used to specify class invariants, declare constructors, declare the destructor, and declare member functions respectively. -In general, the [macroref CONTRACT_CLASS_TPL] macro is used when declaring a class nested within a class template (see the __Advanced_Topics__ section). - -This libraries supports all the different kinds of template parameters that C++ supports: type template parameters, value template parameters, and template template parameters. - -* Type template parameters can be prefixed by either `typename` or `class` as usual, `typename A` or `class C`. -* The type of value template parameters must be wrapped within parenthesis `(A) D` but the parenthesis are optional for fundamental types that contain no symbol `int B`. -* Template template parameters use round parenthesis for their template specifier but then their inner template parameters are specified using the usual C++ syntax `template( typename X, template< ... > class Y, ... ) class E`. - -Default template parameters are specified using `, default `[^['default-value]] right after the template parameter declaration. -For example (see also [file example/contracts template_params.cpp]): - -[import ../example/contracts/template_params.cpp] -[template_params_class] - -Finally, the syntax `template( void )` is used instead of the usual `template< >` to specify a template with no template parameters (this is typically used for template specializations, see the __Advanced_Topics__ section). - -[endsect] - -[section Function Templates] - -Let's program a function template `postinc` similar to the function `postinc` that we have seen before but that works on a generic type `T` and not just on `int` (see also [file example/contracts function_template_postinc.cpp]): - -[import ../example/contracts/function_template_postinc.cpp] -[function_template_postinc] - -(The specifications of the code in this example are not fully programmed, in particular concepts, see the __Concepts__ section, and assertion requirements, see the __Advanced_Topics__ section, have been omitted for simplicity.) - -Type, value, and template template parameters are specified for function templates using the same syntax used for class template parameters, for example (see also [file example/contracts template_params.cpp]): - -[template_params_function] - -Note that as usual, function templates cannot have default template parameters in __CXX03__. - -[endsect] - -[section Forward Declarations and Body Definitions] - -This library supports contracts for classes and functions that have forward declarations. -Furthermore, the function body definition can be deferred and separated from the function declaration and its contracts. -For example (see also [file example/contracts body_natural.hpp], [file example/contracts body_natural_impl.hpp], and [file example/contracts body_natural.cpp]): - -[import ../example/contracts/body_natural.hpp] -[body_natural] - -In this example, the class `natural` and the function `less` are first forward declared and later declared. -Note that the contracts can be specified only once and together with the class or function declaration (not with the forward declarations that can be many). +Furthermore, for non-void overriding public functions, programmers must pass a reference to the function return value as the second argument to [funcref boost::contract::public_function] (this library will generate a compile-time error otherwise). +[footnote +*Rationale.* +Again, the extra return value parameter is used to pass the return value to the overridden virtual public functions when subcontracting. +However, in this case the library has also the function pointer so it will generate a compile-time error if the function is non-void and programmers forget to specify the extra return value parameter (this extra error checking was not possible instead for non-overriding virtual public functions because their contracts do not use the function pointer, see also __Virtual_Public_Functions__). +] +In this case the functor specified to `.postcondition(...)` takes a single parameter (possibly as a constant reference `const&`) to the return value (this library will generate a compile-time error otherwise). [important -This library forces to specify contracts with the function and class declarations and not with their definitions. -This is correct because contracts are part of the program specifications (declarations) and not of the program implementation (definitions), see also the __Specification_vs__Implementation__ section. +['Remember: When "`v`" is present, always pass it to old-of macros and contract-function calls; Always pass result after "`v`" for non-void functions.] ] -Note that as usual in C++, not all functions need to be defined when they are first declared. -In this example, `less` and `natural::get` are defined together with their declarations and contracts while the other function bodies are defined separately. +[funcref boost::contract::public_function] returns an RAII object (that can be assigned to a local variable of explicit type [classref boost::contract::guard] when programmers are not using C++11 auto declarations). +The public member function body is programmed right after the declaration of this RAII object. +At construction, this RAII object doe the following: -The definitions of the free function `greater`, the constructor `natural::natural`, the destructor `natural::~natural`, and the member function `natural::equal` are deferred and separated from their declarations and contracts. -In fact, a semicolon `;` is specified right after the contract declaration macros instead of programming the function bodies. -As usual in C++, the semicolon `;` indicates that the function body definition is deferred and it will appear at some other point in the program (often in a =.cpp= file that can be compiled separately). -In this example, the deferred functions are templates or template members therefore the definitions where programmed in a header file that must be made available when the template declarations are compiled (see also [file example/contracts body_natural_impl.hpp]): -[footnote -In principle, this library supports `export` templates that can be used to program template definitions separately from their declarations and in files that can be pre-compiled. -However, `export` templates are not supported by most __CXX03__ compilers (in fact, [@http://www.comeaucomputing.com/4.0/docs/userman/export.html Comeau] might be the only compiler that supports them), they were removed from __CXX11__, and they are an untested feature of this library. -Instead of using `export` templates, it is common practise in C++ to program both template declarations and definitions together so they can be compiled correctly. -In this example, the authors have used a separate header file `..._impl.hpp` to logically separate template declarations and definitions but the header is included at the bottom of the declaration header file so the definitions are always available together with their declarations. -] +# Check static and non-static class invariants for all overridden bases and for the derived class, by calling [^['typeof](['overridden_base])]`::static_invariant()` __AND__ [^['overridden_base]]`.invariant()` __AND__... [^['typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()`. +# Check preconditions for all overridden base functions and for the overriding derived function in __OR__ with each other, by calling functors [^['f1]]`()` __OR__... [^['fn]]`()` passed to `.precondition(`[^['f1]]`)`, ..., `.precondition(`[^['fn]]`)` for all of the overridden and overriding functions respectively. -[import ../example/contracts/body_natural_impl.hpp] -[body_natural_impl] +At destruction instead: -The usual C++ syntax is used to define the bodies (in fact this library only alters the syntax of class and function declarations but not the syntax of their definitions). -However, free function, constructor, destructor, and member function names must be specified using the macros [macroref CONTRACT_FREE_BODY], [macroref CONTRACT_CONSTRUCTOR_BODY], [macroref CONTRACT_DESTRUCTOR_BODY], and [macroref CONTRACT_MEMBER_BODY] respectively. +# Check static and non-static class invariants for all overridden bases and for the derived class, by calling [^['typeof](['overridden_base])]`::static_invariant()` __AND__ [^['overridden_base]]`.invariant()` __AND__... [^['typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()` (even if the function body threw an exception). +# If the function body did not throw an exception: + # Check postconditions for all overridden base functions and for the overriding derived function in __AND__ with each other, by calling functors [^['g1]]`()` __AND__... [^['gn]]`()` passed to `.postcondition(`[^['g1]]`)`, ..., `.postcondition(`[^['gn]]`)` for all of the overridden and overriding functions respectively. + +This ensures that overriding public function subcontracts are checked correctly at run-time (see also __Public_Function_Calls__). + +This library will generate a compile-time error if there is no suitable virtual function to overload in any of the public base classes (similar to C++11 `override` virtual specifier, but limited to functions with the extra [classref boost::contract::virtual_]`*` parameter and searched recursively only in `public` base classes passed to [macroref BOOST_CONTRACT_BASE_TYPES]). + +For the rest, the same considerations made in __Virtual_Public_Functions__ apply. + +[endsect] + +[section Base Types (Subcontracting)] + +In order to support subcontracting, this library must be made aware of base classes. +Programmers do that using the [macroref BOOST_CONTRACT_BASE_TYPES] macro to declared a public member type named `base_types` with a `typedef`. +For example (see also [@../../example/features/identifiers.cpp =identifiers.cpp=]): + +[multi_identifiers] + +For convenience, a /local macro/ named `BASES` (any other name can be used) is often used here to avoid repeating the base list twice (first when inheriting `: ...` and then when calling [macroref BOOST_CONTRACT_BASE_TYPES]`(...)`). +Being a local macro, `BASES` must be undefined after it has been used to declare `base_types` (to avoid macro redefinition errors). + +[macroref BOOST_CONTRACT_BASE_TYPES] is a variadic macro and accepts a list of bases separated by commas (see __No_Macros__ to program `base_types` without using macros). +When the extra base [classref boost::contract::constructor_precondition] is used to program constructor preconditions, it must always be private and appear as the very first base (see also __Constructors__). + +[important +Each base passed to [macroref BOOST_CONTRACT_BASE_TYPES] must /explicitly/ specify its inheritance access level `public`, `protected`, or `private` (`virtual` can be specified before or after the access level as usual in C++). [footnote *Rationale.* -Four different body macros are needed because contracts are disabled differently for the different type of functions. -For example, disabling preconditions and postconditions turns off contracts for free functions but not for member functions, disabling class invariants turns off contracts for destructors but not for constructors, etc. +This library explicitly requires the inheritance access level because derived classes must subcontract only from public bases, but not from protected or private bases (see __Public_Function_Calls__). +Therefore, [macroref BOOST_CONTRACT_BASE_TYPES] inspect each inheritance access level (using preprocessor meta-programming) and strips non-public bases from the `base_types` list of bases to consider for subcontracting. ] -The free and member body macros take one parameter which is the function name. -The constructor and destructor body macros take two parameters that are the fully qualified class type (including eventual template parameters as usual) and the class name which must be prefixed by the tilde symbol `~` for destructors as usual. -[footnote -Some compilers accept to repeat template parameter names in the constructor and destructor names. -However, this is not __CXX03__ compliant (and, for example, it was fixed in more recent versions of GCC) therefore programmers are advised to specify the template parameter names only for the class type and not for the constructor and destructor names (this is also why the macros must take a second parameter with the class name instead of just the class type parameter). -] -The class type parameter must be wrapped within extra parenthesis like in this example but only if it contains multiple template parameters (because these use unwrapped commas which cannot be passed within macro parameters, see the beginning of the __Advanced_Topics__ section). +This library will generate a compiler-error if the first base is missing the inheritance access level, but this library is not able to automatically detect if the access level is missing from subsequent bases. -In this example, it was possible to separate the constructor body definition because the constructor did not specify member initializers. +Therefore, it is the responsibility of the programmers to make sure that all bases passed to [macroref BOOST_CONTRACT_BASE_TYPES] explicitly specify their inheritance access level. +(Note that the inheritance access level is instead optional in C++ because `private` is implicitly assumed for `class` types and `public` for `struct` types.) +] -[warning -Unfortunately, when member initializers are specified, the macro [macroref CONTRACT_CONSTRUCTOR_BODY] cannot be used, the constructor body definition cannot be deferred, and the constructor body must be defined together with the constructor declaration and its contract inside the class definition. -[footnote -*Rationale.* -This limitation comes from the fact that __CXX03__ does not support delegating constructors. -If member initializers are specified within the contract, the deferred body will not compile when contract compilation is turned off by the configuration macros. -If instead member initializers are specified with the deferred body definition, the deferred body will not compile when contract compilation is turned on by the configuration macros. -There is no way to reconcile these two conditions without delegating constructors, so definitions cannot be deferred for constructors that specify member initializers. -This limitation could be removed in future revisions of this library for __CXX11__ compilers that support delegating constructors (see also [@http://sourceforge.net/apps/trac/contractpp/ticket/51 Ticket 51]). -] -] +See __Access__ to avoid making `base_types` a public member type (e.g., in cases when all public members of a class must be controlled exactly). +Set the [macroref BOOST_CONTRACT_CONFIG_BASE_TYPES] configuration macro to use a name different from `base_types` (e.g., because `base_types` clashes with other names in the user-defined class). + +[endsect] + +[section Private and Protected Functions] + +Private and protected member functions do not check class invariants (because they are not part of the public class interface) and they do not subcontract (because they are not accessible at the calling site where the __substitution_principle__ applies, see also __Function_Calls__). +Instead, private and protected member functions only check preconditions and postconditions, like free functions do. + +Therefore, [funcref boost::contract::function] is used to program contracts for private and protected functions, like for free functions. +For example (see also [@../../example/features/countdown.cpp =countdown.cpp=]): + +[import ../../example/features/countdown.cpp] +[countdown] + +The same considerations made in __Free_Functions__ apply. [endsect] diff --git a/doc/src/boost.xml b/doc/src/boost.xml old mode 100755 new mode 100644 index 4e55f4d..effced0 --- a/doc/src/boost.xml +++ b/doc/src/boost.xml @@ -2,7 +2,7 @@ + last-revision="$Date$"> The Boost C++ Libraries BoostBook Documentation Subset @@ -37,700 +37,45 @@ The Boost C++ Libraries (BoostBook Subset) - - + - - - - - Christopher - Kohlhoff - - - Portable networking and other low-level I/O, including sockets, timers, hostname resolution, socket iostreams, serial ports, file descriptors and Windows HANDLEs - - - - - - - - Peter - Dimov - - Generalized binders for function/object/pointers and member functions - - - - - - - - Peter - Dimov - - Generalized binders for member functions - - - - - - - - John - Maddock - - - Howard - Hinnant - - Defines types for passing parameters - - - - - - - - Jan - Gaspar - - A STL compliant container also known as ring or cyclic buffer - - - - - - - - Ralf - Grosse-Kunstleve - - - Jens - Maurer - - Help for non-conforming standard libraries - - - - - - - - Nicolai - Josuttis - - - Functional composition adapters for the STL - - - - - - - - John - Maddock - - - Howard - Hinnant - - Empty member optimization - - - - - - - - - Jeremy - Siek - - Tools for generic programming - - - - Boost.Concept_Check - - - - - - - John - Maddock - - - Beman - Dawes - - - Vesa - Karvonen - - - Helps boost library developers adapt to compiler idiosyncrasies; not intended for library users - - - - - - - - Dave - Abrahams - - - Kevlin - Henney - - - Numeric, polymorphic, and lexical casts - - - - - - - - Daryle - Walker - - - Cyclic Redundancy Code - - - - + + + + - - - - - Jeremy - Siek - - - Chuck - Allison - - A runtime sized version of std::bitset - - - - - - - - Samuel - Krempp - - - Type-safe 'printf-like' format operations - - - - - - - - - Beman - Dawes - - - Portable paths, iteration over directories, and other useful filesystem operations - - - - - - - - - - Mark - Rodgers - - Enhanced function object adaptors - - - - - - - - - Jeremy - Siek - - - University of Notre Dame - Team - - Generic graph components and algorithms - - - - - - - - - - various - authors - - - Headers to ease dealing with integral types - - - - - - - - - - Guillaume - Melquiond - - - Hervé - Brönnimann - - - Sylvain - Pion - - - Extends the usual arithmetic functions to mathematical intervals - - - - - - - - - - Daryle - Walker - - - Save I/O state to prevent jumbled data - - - - - - - - Dave - Abrahams - - - Jeremy - Siek - - - John - Potter - - - Adapt a base type into a standard conforming iterator - - - - + + + - - - - - various - authors - - - Several contributions in the domain of mathematics - - - - - - - - Daryle - Walker - - - Greatest common divisor and least common multiple - - - - - - - - Hubert - Holin - - - Octonions - - - - - - - - Hubert - Holin - - - Quaternions - - - - - - - - Hubert - Holin - - - Mathematical special functions such as atanh, sinc, and sinhc - - - - - - - - Aleksey - Gurtovoy - - - Template metaprogramming framework of compile-time algorithms, sequences and metafunction classes - - - - - - - - Ron - Garcia - - - Multidimensional containers and adaptors for arrays of contiguous data - - - - - - - - - Dave - Abrahams - - - Jeremy - Siek - - - Templates ease arithmetic classes and iterators - - - - - - - - - - Fernando - Cacciola - - - Discriminated-union wrapper for optional values - - - - - + + + - - - - - Steve - Cleary - - - Memory pool management - - - - - - - - Vesa - Karvonen - - - Paul - Mensonides - - - Preprocessor metaprogramming tools including repetition and recursion - - - - - - - - - Jeremy - Siek - - Concepts defining interfaces which map key objects to value objects - - - - - - - - - - - Dave - Abrahams - - Reflects C++ classes and functions into Python - - - - - - - - - Paul - Moore - - A rational number class - - - - - - - - - - John - Maddock - - Regular expression library - - - - - - - - Robert - Ramey - - Serialization of C++ objects for persistence and marshalling - - - - + - - - - - - Greg - Colvin - - - Beman - Dawes - - - Peter - Dimov - - - Darin - Adler - - Six smart pointer class templates - - - - - - - - Joel - de Guzman - - - team - - - LL parser framework represents parsers directly as EBNF grammars in inlined C++ - - - - - - - - - - - Gennadiy - Rozental - - Support for simple program testing, full unit testing, and for program execution monitoring - - - - - - - - - Beman - Dawes - - Event timer, progress timer, and progress display classes - - - - - - - - John - Bandela - - Break of a string or other character sequence into a series of tokens - - - - - - - - - - Jaakko - Järvi - - Ease definition of functions returning multiple values, and more - - - - - - - - John - Maddock - - Meta-programming support library. - - - - + + - - - - - Joerg - Walter - - - Mathias - Koch - - Basic linear algebra for dense, packed and sparse matrices - - - - - - - - - - Dave - Abrahams - - - others - - - Class noncopyable plus checked_delete, checked_array_delete, next, prior function templates, plus base-from-member idiom - - - - - - - @@ -749,9 +94,12 @@ - - + + + + + diff --git a/doc/src/boostbook.css b/doc/src/boostbook.css old mode 100755 new mode 100644 index c60e100..d42b3c0 --- a/doc/src/boostbook.css +++ b/doc/src/boostbook.css @@ -1,13 +1,17 @@ -/*============================================================================= - Copyright (c) 2004 Joel de Guzman - http://spirit.sourceforge.net/ - Distributed under the Boost Software License, Version 1.0. (See accompany- - ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +/*============================================================================= +Copyright (c) 2004 Joel de Guzman +http://spirit.sourceforge.net/ + +Copyright 2013 Niall Douglas additions for colors and alignment. +Copyright 2013 Paul A. Bristow additions for more colors and alignments. + +Distributed under the Boost Software License, Version 1.0. (See accompany- +ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ /*============================================================================= - Body defaults +Body defaults =============================================================================*/ body @@ -17,7 +21,7 @@ } /*============================================================================= - Paragraphs +Paragraphs =============================================================================*/ p @@ -28,7 +32,7 @@ } /*============================================================================= - Program listings +Program listings =============================================================================*/ /* Code on paragraphs */ @@ -58,11 +62,11 @@ td .screen { margin: 0pc 0pc 0pc 0pc; - padding: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; } /*============================================================================= - Headings +Headings =============================================================================*/ h1, h2, h3, h4, h5, h6 @@ -72,12 +76,12 @@ font-weight: bold; } - h1 { font: 140% } - h2 { font: bold 140% } - h3 { font: bold 130% } - h4 { font: bold 120% } - h5 { font: italic 110% } - h6 { font: italic 100% } + h1 { font-size: 140%; } + h2 { font-weight: bold; font-size: 140%; } + h3 { font-weight: bold; font-size: 130%; } + h4 { font-weight: bold; font-size: 120%; } + h5 { font-weight: normal; font-style: italic; font-size: 110%; } + h6 { font-weight: normal; font-style: italic; font-size: 100%; } /* Top page titles */ title, @@ -116,13 +120,13 @@ h1 tt.computeroutput { font-size: 140% } h2 tt.computeroutput { font-size: 140% } h3 tt.computeroutput { font-size: 130% } - h4 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 130% } h5 tt.computeroutput { font-size: 130% } h6 tt.computeroutput { font-size: 130% } /*============================================================================= - Author +Author =============================================================================*/ h3.author @@ -131,7 +135,7 @@ } /*============================================================================= - Lists +Lists =============================================================================*/ li @@ -153,7 +157,7 @@ } /*============================================================================= - Links +Links =============================================================================*/ a @@ -167,7 +171,7 @@ } /*============================================================================= - Spirit style navigation +Spirit style navigation =============================================================================*/ .spirit-nav @@ -187,7 +191,7 @@ } /*============================================================================= - Copyright footer +Copyright footer =============================================================================*/ .copyright-footer { @@ -202,10 +206,10 @@ } /*============================================================================= - Table of contents +Table of contents =============================================================================*/ - .toc + div.toc { margin: 1pc 4% 0pc 4%; padding: 0.1pc 1pc 0.1pc 1pc; @@ -218,12 +222,16 @@ float: right; padding: 0.5pc; } - + /* Code on toc */ .toc .computeroutput { font-size: 120% } - + + /* No margin on nested menus */ + + .toc dl dl { margin: 0; } + /*============================================================================= - Tables +Tables =============================================================================*/ .table-title, @@ -282,7 +290,7 @@ } /*============================================================================= - Blurbs +Blurbs =============================================================================*/ div.note, @@ -305,7 +313,7 @@ } /*============================================================================= - Variable Lists +Variable Lists =============================================================================*/ div.variablelist @@ -350,7 +358,7 @@ } /*============================================================================= - Misc +Misc =============================================================================*/ /* Title of books and articles in bibliographies */ @@ -376,7 +384,7 @@ } /*============================================================================= - Colors +Colors =============================================================================*/ @media screen @@ -387,16 +395,16 @@ } /* Syntax Highlighting */ - .keyword { color: #0000AA; } - .identifier { color: #000000; } - .special { color: #707070; } - .preprocessor { color: #402080; } - .char { color: teal; } - .comment { color: #800000; } - .string { color: teal; } - .number { color: teal; } - .white_bkd { background-color: #FFFFFF; } - .dk_grey_bkd { background-color: #999999; } + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } /* Links */ a, a .keyword, a .identifier, a .special, a .preprocessor @@ -462,7 +470,7 @@ } /* Table of contents */ - .toc + div.toc { border: 1px solid #DCDCDC; } @@ -530,7 +538,7 @@ } /* Table of contents */ - .toc + div.toc { border: 1px solid gray; } @@ -568,7 +576,7 @@ } /*============================================================================= - Images +Images =============================================================================*/ span.inlinemediaobject img @@ -577,25 +585,116 @@ } /*============================================================================== - Super and Subscript: style so that line spacing isn't effected, see - http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 +Super and Subscript: style so that line spacing isn't effected, see +http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 ==============================================================================*/ sup, sub { - height: 0; - line-height: 1; - vertical-align: baseline; - _vertical-align: bottom; - position: relative; - +height: 0; +line-height: 1; +vertical-align: baseline; +position: relative; + +} + +/* For internet explorer: */ + +* html sup, +* html sub { +vertical-align: bottom; } sup { - bottom: 1ex; +bottom: 1ex; } sub { - top: .5ex; +top: .5ex; } +/*============================================================================== +Indexes: pretty much the same as the TOC. +==============================================================================*/ + + .index + { + font-size: 80%; + padding-top: 0px; + padding-bottom: 0px; + margin-top: 0px; + margin-bottom: 0px; + margin-left: 0px; + } + + .index ul + { + padding-left: 3em; + } + + .index p + { + padding: 2px; + margin: 2px; + } + + .index-entry-level-0 + { + font-weight: bold; + } + + .index em + { + font-weight: bold; + } + + +/*============================================================================== +Alignment and coloring use 'role' feature, available from Quickbook 1.6 up. +Added from Niall Douglas for role color and alignment. +http://article.gmane.org/gmane.comp.lib.boost.devel/243318 +*/ + +/* Add text alignment (see http://www.w3schools.com/cssref/pr_text_text-align.asp) */ +span.aligncenter +{ + display: inline-block; width: 100%; text-align: center; +} +span.alignright +{ + display: inline-block; width: 100%; text-align: right; +} +/* alignleft is the default. */ +span.alignleft +{ + display: inline-block; width: 100%; text-align: left; +} + +/* alignjustify stretches the word spacing so that each line has equal width +within a chosen fraction of page width (here arbitrarily 20%). +*Not* useful inside table items as the column width remains the total string width. +Nor very useful, except to temporarily restrict the width. +*/ +span.alignjustify +{ + display: inline-block; width: 20%; text-align: justify; +} + +/* Text colors. +Names at http://www.w3.org/TR/2002/WD-css3-color-20020219/ 4.3. X11 color keywords. +Quickbook Usage: [role red Some red text] + +*/ +span.red { inline-block; color: red; } +span.green { color: green; } +span.lime { color: #00FF00; } +span.blue { color: blue; } +span.navy { color: navy; } +span.yellow { color: yellow; } +span.magenta { color: magenta; } +span.indigo { color: #4B0082; } +span.cyan { color: cyan; } +span.purple { color: purple; } +span.gold { color: gold; } +span.silver { color: silver; } /* lighter gray */ +span.gray { color: #808080; } /* light gray */ diff --git a/doc/src/docutils.css b/doc/src/docutils.css old mode 100755 new mode 100644 index 27f4c55..620cf86 --- a/doc/src/docutils.css +++ b/doc/src/docutils.css @@ -1,8 +1,8 @@ /* :Author: David Goodger :Contact: goodger@python.org -:Date: $Date: 2007-11-25 14:34:32 -0500 (Sun, 25 Nov 2007) $ -:Revision: $Revision: 41371 $ +:Date: $Date$ +:Revision: $Revision$ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. diff --git a/doc/src/images/alert.png b/doc/src/images/alert.png old mode 100755 new mode 100644 diff --git a/doc/src/images/blank.png b/doc/src/images/blank.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/1.png b/doc/src/images/callouts/1.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/1.svg b/doc/src/images/callouts/1.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/10.png b/doc/src/images/callouts/10.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/10.svg b/doc/src/images/callouts/10.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/11.png b/doc/src/images/callouts/11.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/11.svg b/doc/src/images/callouts/11.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/12.png b/doc/src/images/callouts/12.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/12.svg b/doc/src/images/callouts/12.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/13.png b/doc/src/images/callouts/13.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/13.svg b/doc/src/images/callouts/13.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/14.png b/doc/src/images/callouts/14.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/14.svg b/doc/src/images/callouts/14.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/15.png b/doc/src/images/callouts/15.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/15.svg b/doc/src/images/callouts/15.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/16.svg b/doc/src/images/callouts/16.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/17.svg b/doc/src/images/callouts/17.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/18.svg b/doc/src/images/callouts/18.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/19.svg b/doc/src/images/callouts/19.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/2.png b/doc/src/images/callouts/2.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/2.svg b/doc/src/images/callouts/2.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/20.svg b/doc/src/images/callouts/20.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/21.svg b/doc/src/images/callouts/21.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/22.svg b/doc/src/images/callouts/22.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/23.svg b/doc/src/images/callouts/23.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/24.svg b/doc/src/images/callouts/24.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/25.svg b/doc/src/images/callouts/25.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/26.svg b/doc/src/images/callouts/26.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/27.svg b/doc/src/images/callouts/27.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/28.svg b/doc/src/images/callouts/28.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/29.svg b/doc/src/images/callouts/29.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/3.png b/doc/src/images/callouts/3.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/3.svg b/doc/src/images/callouts/3.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/30.svg b/doc/src/images/callouts/30.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/4.png b/doc/src/images/callouts/4.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/4.svg b/doc/src/images/callouts/4.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/5.png b/doc/src/images/callouts/5.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/5.svg b/doc/src/images/callouts/5.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/6.png b/doc/src/images/callouts/6.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/6.svg b/doc/src/images/callouts/6.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/7.png b/doc/src/images/callouts/7.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/7.svg b/doc/src/images/callouts/7.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/8.png b/doc/src/images/callouts/8.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/8.svg b/doc/src/images/callouts/8.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/9.png b/doc/src/images/callouts/9.png old mode 100755 new mode 100644 diff --git a/doc/src/images/callouts/9.svg b/doc/src/images/callouts/9.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/caution.png b/doc/src/images/caution.png old mode 100755 new mode 100644 diff --git a/doc/src/images/caution.svg b/doc/src/images/caution.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/draft.png b/doc/src/images/draft.png old mode 100755 new mode 100644 diff --git a/doc/src/images/home.png b/doc/src/images/home.png old mode 100755 new mode 100644 diff --git a/doc/src/images/home.svg b/doc/src/images/home.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/important.png b/doc/src/images/important.png old mode 100755 new mode 100644 diff --git a/doc/src/images/important.svg b/doc/src/images/important.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/next.png b/doc/src/images/next.png old mode 100755 new mode 100644 diff --git a/doc/src/images/next.svg b/doc/src/images/next.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/next_disabled.png b/doc/src/images/next_disabled.png old mode 100755 new mode 100644 diff --git a/doc/src/images/note.png b/doc/src/images/note.png old mode 100755 new mode 100644 diff --git a/doc/src/images/note.svg b/doc/src/images/note.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/prev.png b/doc/src/images/prev.png old mode 100755 new mode 100644 diff --git a/doc/src/images/prev.svg b/doc/src/images/prev.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/prev_disabled.png b/doc/src/images/prev_disabled.png old mode 100755 new mode 100644 diff --git a/doc/src/images/smiley.png b/doc/src/images/smiley.png old mode 100755 new mode 100644 diff --git a/doc/src/images/tip.png b/doc/src/images/tip.png old mode 100755 new mode 100644 diff --git a/doc/src/images/tip.svg b/doc/src/images/tip.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/toc-blank.png b/doc/src/images/toc-blank.png old mode 100755 new mode 100644 diff --git a/doc/src/images/toc-minus.png b/doc/src/images/toc-minus.png old mode 100755 new mode 100644 diff --git a/doc/src/images/toc-plus.png b/doc/src/images/toc-plus.png old mode 100755 new mode 100644 diff --git a/doc/src/images/up.png b/doc/src/images/up.png old mode 100755 new mode 100644 diff --git a/doc/src/images/up.svg b/doc/src/images/up.svg old mode 100755 new mode 100644 diff --git a/doc/src/images/up_disabled.png b/doc/src/images/up_disabled.png old mode 100755 new mode 100644 diff --git a/doc/src/images/warning.png b/doc/src/images/warning.png old mode 100755 new mode 100644 diff --git a/doc/src/images/warning.svg b/doc/src/images/warning.svg old mode 100755 new mode 100644 diff --git a/doc/src/minimal.css b/doc/src/minimal.css old mode 100755 new mode 100644 index 2e5812a..401b73e --- a/doc/src/minimal.css +++ b/doc/src/minimal.css @@ -19,11 +19,4 @@ body { font-family: sans-serif; margin: 1em; } table { margin: 0.5em; } -/******************************************************************************* - Font sizes -*******************************************************************************/ - -p, td, li, blockquote { font-size: 10pt; } -pre { font-size: 9pt; } - /*** end ***/ \ No newline at end of file diff --git a/doc/src/reference.css b/doc/src/reference.css old mode 100755 new mode 100644 diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 841d486..2447010 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -24,6 +24,18 @@ test-suite cline90 : test-suite n1962 : [ subdir-run n1962 : vector ] + [ subdir-run n1962 : sqrt ] + [ subdir-run n1962 : circle ] + [ subdir-run n1962 : equal ] + [ subdir-run n1962 : factorial ] + [ subdir-run n1962 : sum ] +; + +test-suite stroustrup97 : + [ subdir-run stroustrup97 : string ] +; + +test-suite doc : + [ subdir-run doc : push_back ] ; -explicit n1962 ; # TODO: Remove this... diff --git a/example/features/countdown.cpp b/example/features/countdown.cpp new file mode 100644 index 0000000..94e9cc7 --- /dev/null +++ b/example/features/countdown.cpp @@ -0,0 +1,40 @@ + +//[countdown +template +class countdwon { +public: + explicit countdown(T n) : n_(n) {} + + /* ... */ + +protected: + T get() const { // Protected function (like free functions). + int result; + auto c = boost::contract::function() + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result == n_); + }) + ; + + return result = n_; // Function body. + } + +private: + void dec() { // Private function (like free functions). + auto old_n = BOOST_CONTRACT_OLDOF(n_); + auto c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(n_ > std::numeric_limit::min()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(n_ == *old_n - 1); + }) + ; + + --n_; // Function body. + } + + T n_; +}; +//] + diff --git a/example/features/identifiers.cpp b/example/features/identifiers.cpp new file mode 100644 index 0000000..031bcac --- /dev/null +++ b/example/features/identifiers.cpp @@ -0,0 +1,152 @@ + +// Vector of unique integer numbers. +//[unique_identifiers_constructor +// An identifier can be pushed only once in this container. +class unique_identifiers + : private boost::contract::constructor_precondition +{ +public: + + // Create this container with all identifiers in range [from, to]. + unqiue_identifiers(int from, int to) : + boost::contract::constructor_precondition([&] { + BOOST_CONTRACT_ASSERT(from <= to); + }) + { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == (to - from)); + }) + ; + + // Constructor body. + for(id = from; id <= to; ++id) vect_.push_back(id); + } + + /* ... */ +//] + + //[unique_identifiers_destructor + // Destroy this container. + virtual ~unique_identifiers() { + auto c = boost::contract::destructor(this); // Check invariants. + // Destructor body here... + } + //] + + int size() const { + auto c = boost::contract::public_function(this); // Check invariants. + return vect_.size(); + } + + //[unique_identifiers_find + // Check if specified identifier is in container. + bool find(int id) const { + bool result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + if(size() == 0) BOOST_CONTRACT_ASSERT(!result); + }) + ; + + // Function body. + return result = std::find(vect_.begin(), vect_.end(), id) != + vect_.end(); + } + //] + + //[unique_identifiers_push_back + // Specified identifier must not already be in container. + virtual int push_back(int id, boost::contract::virtual_* v = 0) { + int result; + auto old_find = BOOST_CONTRACT_OLDOF(v, find(id)); + auto old_size = BOOST_CONTRACT_OLDOF(v, size()); + auto c = boost::contract::public_function(v, result, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!find(id)); // Already in, not allowed. + }) + .postcondition([&] (int result) { + if(!*old_find) { // Pushed in container. + BOOST_CONTRACT_ASSERT(find(id)); + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + } + BOOST_CONTRACT_ASSERT(result == id); + }) + ; + + // Function body. + vect_.push_back(id); + return result = id; + } + //] + + void invariant() const { + BOOST_CONTRACT_ASSERT(size() >= 0); + } + +private: + std::vector vect_; +}; + +//[identifiers_push_back +// Can push same identifier multiple times in container (but with no effect). +class identifiers + #define BASES public unique_identifiers + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { // Check in AND with bases. + BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); + } + + // Do nothing if specified identifier already in container. + int push_back(int id, boost::contract::virtual_* v = 0) /* override */ { + int result; + auto old_find = BOOST_CONTRACT_OLDOF(v, find(id)); + auto old_size = BOOST_CONTRACT_OLDOF(v, size()); + auto c = boost::contract::public_function( + v, result, &identifiers::push_back, this, id) + .precondition([&] { // Check in OR with bases. + BOOST_CONTRACT_ASSERT(find(id)); // Already in, now allowed. + }) + .postcondition([&] (int result) { // Check in AND with bases. + if(*old_find) { // Not added. + BOOST_CONTRACT_ASSERT(size() == *old_size); + } + }) + ; + + // Function body. + if(!find(id)) unique_identifiers::push_back(id); // Else, do nothing. + return result = id; + } + BOOST_CONTRACT_OVERRIDE(push_back); // Define `override_push_back`. + + /* ... */ +//] + + bool empty() const { + auto c = boost::contract::public_function(this); // Check invariants. + return size() == 0; + } +}; + +//[multi_identifiers +class multi_identifiers + #define BASES \ + private boost::contract::constructor_precondition, \ + public identifiers, public virtual pushable, \ + protected sizer, private capacitor + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + /* ... */ +//] +}; + diff --git a/example/features/inc.cpp b/example/features/inc.cpp new file mode 100644 index 0000000..1e69088 --- /dev/null +++ b/example/features/inc.cpp @@ -0,0 +1,21 @@ + +//[inc +#include + +int inc(int& x) { + int result; + boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF(x); + boost::contract::guard c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(x < std::numberic_limits::max()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(x == *old_x + 1); + BOOST_CONTRACT_ASSERT(result == *old_x); + }) + ; + + return result = x++; // Function body. +} +//] + diff --git a/example/features/inc_no_contract.cpp b/example/features/inc_no_contract.cpp new file mode 100644 index 0000000..26cf236 --- /dev/null +++ b/example/features/inc_no_contract.cpp @@ -0,0 +1,11 @@ + +//[inc_no_contract +int inc(int& x) + // Precondition: x < std::numeric_limits::max() + // Postcondition: x == oldof(x) + 1 + // result == oldof(x) +{ + return x++; +} +//] + diff --git a/example/features/old.cpp b/example/features/old.cpp new file mode 100644 index 0000000..43c6554 --- /dev/null +++ b/example/features/old.cpp @@ -0,0 +1,29 @@ + +#include +#include +#include + +//[old +char replace(std::string& s, std::size_t index, char c) { + char result; + boost::shared_ptr old_c; // But old values copied later... + auto c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(index < s.size()); + }) + .old([&] { // ...here, after preconditions (and invariants) checked. + old_c = BOOST_CONTRACT_OLDOF(s[index]); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(s[index] == c); + BOOST_CONTRACT_ASSERT(result == *old_c); + }) + ; + + // Function body. + result = s[index]; + s[index] = c; + return result; +} +//] + diff --git a/example/features/optional_result.cpp b/example/features/optional_result.cpp new file mode 100644 index 0000000..cf33065 --- /dev/null +++ b/example/features/optional_result.cpp @@ -0,0 +1,28 @@ + +#include +#include + +//[optional_result +struct surface { + // No default constructor. + explicit surface(int area) : area_(area) {} + int area() const { return area_; } +private: + int area_; +}; + +surface square_area(int edge) { + boost::optional result; // No default constructor so use optional. + auto c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(edge > 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result->area() == edge * edge); + }) + ; + + return *(result = surface(edge * edge)); // Function body. +} +//] + diff --git a/example/features/override_overload.cpp b/example/features/override_overload.cpp new file mode 100644 index 0000000..a2a90ba --- /dev/null +++ b/example/features/override_overload.cpp @@ -0,0 +1,27 @@ + +//[override_overload +class a + #define BASES public b + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void f(int x, boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function( + v, &a::f, this, x); + /* ... */ + } + + void f(double x, boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function( + v, &a::f, this, x); + /* ... */ + } + +private: + BOOST_CONTRACT_OVERRIDE(f) +}; +//] + diff --git a/example/features/override_trait.cpp b/example/features/override_trait.cpp new file mode 100644 index 0000000..57bfcf4 --- /dev/null +++ b/example/features/override_trait.cpp @@ -0,0 +1,19 @@ + +//[override_trait +class a + #define BASES public b + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void _f(boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function(v, &a::_f, this); + /* ... */ + } + BOOST_CONTRACT_OVERRIDE_TRAIT(override_f, _f) +}; +//] + + diff --git a/example/features/pure_virtual.cpp b/example/features/pure_virtual.cpp new file mode 100644 index 0000000..d648c8f --- /dev/null +++ b/example/features/pure_virtual.cpp @@ -0,0 +1,80 @@ + +#include +#include +#include + +class surface { +public: + explicit surface(int area) : area_(area) {} + int area() const { return area_; } +pirvate: + int area_; +}; + +//[pure_virtual +class shape { +public: + virtual surface area(boost::contract::virtual_* v = 0) const = 0; +}; + +// Pure-virtual function definitions (so also contracts) out-of-line in C++. +surface shape::area(boost::contract::virtual_* v) const { + boost::optional result; + auto c = boost::contract::public_function(v, result, this) + .postcondition([&] (boost::optional const& result) { + BOOST_CONTRACT_ASSERT(result->area() > 0); + }) + ; + + // Pure function body (will never be executed by this library). + assert(false); + return *result; +} + +class square + #define BASES private boost::contract::constructor_precondition, \ + public shape + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + surface area(boost::contract::virtual_* v = 0) const /* override */ { + boost::optional result; + auto c = boost::contract::public_function( + v, result, &square::area, this) + .postcondition([&] (boost::optional const& result) { + BOOST_CONTRACT_ASSERT(result->area() == edge() * edge()); + }) + ; + + return *(result = surface(edge() * edge())); // Function body. + } + BOOST_CONTRACT_OVERRIDE(area) + + /* ... */ +//] + + explicit square(int edge) : + boost::contract::constructor_precondition([&] { + BOOST_CONTRACT_ASSERT(edge > 0); + }), + edge_(edge) + { + auto c = boost::contract::constructor(this); // Check invariants. + } + + int edge() const { + auto c = boost::contract::public_function(this); // Check invariants. + return edge_; + } + + void invarinat() const { + BOOST_CONTRACT_ASSERT(edge() > 0); + } + +private: + int edge_; +}; + diff --git a/example/features/push_back.cpp b/example/features/push_back.cpp new file mode 100644 index 0000000..a27c84c --- /dev/null +++ b/example/features/push_back.cpp @@ -0,0 +1,89 @@ + +// Copyright (C) 2008-2015 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). +// Home at http://www.boost.org/libs/contract + +#include + +template +class pushable; + +//[push_back +#include +#include +#include + +template +class vector + #define BASES public pushable + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Subcontracting. + #undef BASES + + void invariant() const { // Checked in AND with base class invariants. + BOOST_CONTRACT_ASSERT(size() <= capacity()); + } + + virtual void push_back(T const& value, boost::contract::virtual_* v = 0) + /* override */ { + auto old_size = BOOST_CONTRACT_OLDOF(v, size()); // Old values. + auto c = boost::contract::public_function( + v, &vector::push_back, this, value) + .precondition([&] { // Checked in OR with base preconditions. + BOOST_CONTRACT_ASSERT(size() < max_size()); + }) + .postcondition([&] { // Checked in AND with base postconditions. + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + ; + + vect_.push_back(value); + } + BOOST_CONTRACT_OVERRIDE(push_back) + + std::size_t size() const { return vect_.size(); } + std::size_t max_size() const { return vect_.max_size(); } + std::size_t capacity() const { return vect_.capacity(); } + +private: + std::vector vect_; +}; +//] + +template +class pushable { +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(capacity() <= max_size()); + } + + virtual void push_back(T const& value, boost::contract::virtual_* v = 0) + = 0; + + virtual std::size_t max_size() const = 0; + virtual std::size_t capacity() const = 0; +}; + +template // Contract for pure virtual function. +void pushable::push_back(T const& value, boost::contract::virtual_* v) { + auto old_capacity = BOOST_CONTRACT_OLDOF(v, capacity()); + auto c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(capacity() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + }) + ; +} + +int main() { + vector vect; + vect.push_back(123); + BOOST_TEST_EQ(vect.size(), 1); + return boost::report_errors(); +} + diff --git a/example/features/separate_body.cpp b/example/features/separate_body.cpp new file mode 100644 index 0000000..031bcac --- /dev/null +++ b/example/features/separate_body.cpp @@ -0,0 +1,152 @@ + +// Vector of unique integer numbers. +//[unique_identifiers_constructor +// An identifier can be pushed only once in this container. +class unique_identifiers + : private boost::contract::constructor_precondition +{ +public: + + // Create this container with all identifiers in range [from, to]. + unqiue_identifiers(int from, int to) : + boost::contract::constructor_precondition([&] { + BOOST_CONTRACT_ASSERT(from <= to); + }) + { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == (to - from)); + }) + ; + + // Constructor body. + for(id = from; id <= to; ++id) vect_.push_back(id); + } + + /* ... */ +//] + + //[unique_identifiers_destructor + // Destroy this container. + virtual ~unique_identifiers() { + auto c = boost::contract::destructor(this); // Check invariants. + // Destructor body here... + } + //] + + int size() const { + auto c = boost::contract::public_function(this); // Check invariants. + return vect_.size(); + } + + //[unique_identifiers_find + // Check if specified identifier is in container. + bool find(int id) const { + bool result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + if(size() == 0) BOOST_CONTRACT_ASSERT(!result); + }) + ; + + // Function body. + return result = std::find(vect_.begin(), vect_.end(), id) != + vect_.end(); + } + //] + + //[unique_identifiers_push_back + // Specified identifier must not already be in container. + virtual int push_back(int id, boost::contract::virtual_* v = 0) { + int result; + auto old_find = BOOST_CONTRACT_OLDOF(v, find(id)); + auto old_size = BOOST_CONTRACT_OLDOF(v, size()); + auto c = boost::contract::public_function(v, result, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!find(id)); // Already in, not allowed. + }) + .postcondition([&] (int result) { + if(!*old_find) { // Pushed in container. + BOOST_CONTRACT_ASSERT(find(id)); + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + } + BOOST_CONTRACT_ASSERT(result == id); + }) + ; + + // Function body. + vect_.push_back(id); + return result = id; + } + //] + + void invariant() const { + BOOST_CONTRACT_ASSERT(size() >= 0); + } + +private: + std::vector vect_; +}; + +//[identifiers_push_back +// Can push same identifier multiple times in container (but with no effect). +class identifiers + #define BASES public unique_identifiers + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { // Check in AND with bases. + BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); + } + + // Do nothing if specified identifier already in container. + int push_back(int id, boost::contract::virtual_* v = 0) /* override */ { + int result; + auto old_find = BOOST_CONTRACT_OLDOF(v, find(id)); + auto old_size = BOOST_CONTRACT_OLDOF(v, size()); + auto c = boost::contract::public_function( + v, result, &identifiers::push_back, this, id) + .precondition([&] { // Check in OR with bases. + BOOST_CONTRACT_ASSERT(find(id)); // Already in, now allowed. + }) + .postcondition([&] (int result) { // Check in AND with bases. + if(*old_find) { // Not added. + BOOST_CONTRACT_ASSERT(size() == *old_size); + } + }) + ; + + // Function body. + if(!find(id)) unique_identifiers::push_back(id); // Else, do nothing. + return result = id; + } + BOOST_CONTRACT_OVERRIDE(push_back); // Define `override_push_back`. + + /* ... */ +//] + + bool empty() const { + auto c = boost::contract::public_function(this); // Check invariants. + return size() == 0; + } +}; + +//[multi_identifiers +class multi_identifiers + #define BASES \ + private boost::contract::constructor_precondition, \ + public identifiers, public virtual pushable, \ + protected sizer, private capacitor + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + /* ... */ +//] +}; + diff --git a/example/features/static.cpp b/example/features/static.cpp new file mode 100644 index 0000000..d7f4ac1 --- /dev/null +++ b/example/features/static.cpp @@ -0,0 +1,49 @@ + +#include + +//[static +template +class instance_counter { +public: + static void static_invariant() { // Static class invariants. + BOOST_CONTRACT_ASSERT(count() >= 0); + } + + static int count() { // Static public function (check static invariants). + auto c = boost::contract::public_function(); + return count_; // Function body. + } + + instance_counter() : obj_() { + auto old_count = BOOST_CONTRACT_OLDOF(count()); + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_OLDOF(count() == *old_count + 1); + }) + ; + + ++count_; + } + + ~instance_counter() { + auto old_count = BOOST_CONTRACT_OLDOF(count()); + auto c = boost::contract::destructor(this) + .postcondition([&] { // (An example of destructor postconditions.) + BOOST_CONTRACT_OLDOF(count() == *old_count - 1); + }) + ; + + --count_; + } + + /* ... */ + +private: + C obj_; + static int count_; +}; + +template +int instance_counter::count_ = 0; +//] + diff --git a/example/mitchell02/name_list.cpp b/example/mitchell02/name_list.cpp index c12344b..bbf2370 100644 --- a/example/mitchell02/name_list.cpp +++ b/example/mitchell02/name_list.cpp @@ -91,8 +91,8 @@ public: boost::contract::virtual_* v = 0) /* override */ { auto old_has_name = BOOST_CONTRACT_OLDOF(v, has(name)); auto old_count = BOOST_CONTRACT_OLDOF(v, count()); - auto c = boost::contract::public_function(v, - &relaxed_name_list::put, this, name) + auto c = boost::contract::public_function( + v, &relaxed_name_list::put, this, name) .precondition([&] { // Relax inherited preconditions. BOOST_CONTRACT_ASSERT(has(name)); // Already in list. }) diff --git a/example/n1962/circle.cpp b/example/n1962/circle.cpp new file mode 100644 index 0000000..2539edf --- /dev/null +++ b/example/n1962/circle.cpp @@ -0,0 +1,55 @@ + +#include +#include +#include + +class shape { +public: + virtual ~shape() {} + + virtual int compute_area(boost::contract::virtual_* v = 0) const = 0; +}; + +int shape::compute_area(boost::contract::virtual_* v) const { + int result; + auto c = boost::contract::public_function(v, result, this) + .postcondition([&] (int const& result) { + BOOST_CONTRACT_ASSERT(result > 0); + }) + ; + assert(false); return result = -1; // Never gets here. +} + +class circle + #define BASES public shape + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + int radius; // Make sure to set this... + static int const pi = 3; // Truncated to int from 3.14... + + virtual int compute_area(boost::contract::virtual_* v = 0) + const /* override */ { + int result; + auto c = boost::contract::public_function( + v, result, &circle::compute_area, this) + .postcondition([&] (int const& result) { + BOOST_CONTRACT_ASSERT(result == pi * radius * radius); + }) + ; + + return result = pi * radius * radius; + } + BOOST_CONTRACT_OVERRIDE(compute_area); +}; + +int main() { + circle c; + c.radius = 2; + BOOST_TEST_EQ(c.compute_area(), 12); + return boost::report_errors(); +} + diff --git a/example/n1962/equal.cpp b/example/n1962/equal.cpp new file mode 100644 index 0000000..cfa8ab6 --- /dev/null +++ b/example/n1962/equal.cpp @@ -0,0 +1,44 @@ + +#include +#include + +// Forward declaration because == and != contracts use one another's function. +template +bool operator==(T const& left, T const& right); + +template +bool operator!=(T const& left, T const& right) { + bool result; + auto c = boost::contract::function() + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result == !(left == right)); + }) + ; + + return result = (left.value != right.value); +} + +template +bool operator==(T const& left, T const& right) { + bool result; + auto c = boost::contract::function() + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result == !(left != right)); + }) + ; + + return result = (left.value == right.value); +} + +struct number { int value; }; + +int main() { + number n; + n.value = 123; + + BOOST_TEST_EQ(n == n, true); // Explicitly call operator==. + BOOST_TEST_EQ(n != n, false); // Explicitly call operator!=. + + return boost::report_errors(); +} + diff --git a/example/n1962/factorial.cpp b/example/n1962/factorial.cpp new file mode 100644 index 0000000..0c2f57b --- /dev/null +++ b/example/n1962/factorial.cpp @@ -0,0 +1,43 @@ + +#include +#include + +// Assertion complexity classified relative their function body complexity. +#define O_LESS_THAN_BODY 0 +#define O_SAME_AS_BODY 1 +#define O_GREATHER_THAN_BODY 2 +#define COMPLEXITY_MAX O_SAME_AS_BODY + +int factorial(int n ) { + int result; + auto c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(n >= 0); // Non-negative natural number. + BOOST_CONTRACT_ASSERT(n <= 12); // Max function input. + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result >= 1); + if(n < 2) { // Select assertion. + BOOST_CONTRACT_ASSERT(result == 1); + } else { + // 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) { + // Assertion automatically disable within other assertions. + // Therefore, this postcondition can recursively call the + // function without causing infinite recursion. + BOOST_CONTRACT_ASSERT(n * factorial(n - 1)); + } + } + }) + ; + + return n < 2 ? (result = 1) : (result = n * factorial(n - 1)); +} + +int main() { + BOOST_TEST_EQ(factorial(4), 24); + return boost::report_errors(); +} + diff --git a/example/n1962/sqrt.cpp b/example/n1962/sqrt.cpp new file mode 100644 index 0000000..e9ed204 --- /dev/null +++ b/example/n1962/sqrt.cpp @@ -0,0 +1,25 @@ + +#include +#include +#include + +double mysqrt(double x, double precision = 1e-6) { + double result; + auto c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(x >= 0.0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(fabs(result * result - x) <= precision); + }) + ; + + return result = sqrt(x); +} + +int main() { + double const precision = 1e-6; + BOOST_TEST(fabs(mysqrt(4.0, precision) - 2.0) <= precision); + return boost::report_errors(); +} + diff --git a/example/n1962/sqrt.d b/example/n1962/sqrt.d new file mode 100644 index 0000000..0dba6d5 --- /dev/null +++ b/example/n1962/sqrt.d @@ -0,0 +1,31 @@ + +// Copyright (C) 2008-2012 Lorenzo Caminiti +// Use, modification, and distribution is subject to 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). +// Documentation at http://contractpp.sourceforge.net. + +//[n1962_sqrt_d +// File: sqrt.d +// Extra spaces, newlines, etc used to align text with this library code. + + + + +real mysqrt ( real x ) // No default parameters in D. + in { assert(x >= 0); } + out(root) { + + assert(std.math.fabs(root * root - x) <= 1e6); + } +body { + return std.math.sqrt(x); +} + + + + + + +//] + diff --git a/example/n1962/sum.cpp b/example/n1962/sum.cpp new file mode 100644 index 0000000..3c71c90 --- /dev/null +++ b/example/n1962/sum.cpp @@ -0,0 +1,23 @@ + +#include +#include + +int sum(int count, int* array) { + int result; + auto c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(count % 4 == 0); + }) + ; + + result = 0; + for(int i = 0; i < count; ++i) result += array[i]; + return result; +} + +int main() { + int a[4] = {1, 2, 3, 4}; + BOOST_TEST_EQ(sum(4, a), 10); + return boost::report_errors(); +} + diff --git a/example/n1962/vector.cpp b/example/n1962/vector.cpp index 9da3c98..80283e3 100644 --- a/example/n1962/vector.cpp +++ b/example/n1962/vector.cpp @@ -1,10 +1,43 @@ #include -#include +#include #include +#include +#include +#include #include -#include +#include #include +#include + +// TODO: Is there any way around this? Probably not... +// This can be programmed directly at call site with C++14 generic lambdas. +struct all_of_equal { + typedef bool result_type; + + template + result_type operator()(InputIter first, InputIter last, T const& value) { + return boost::algorithm::all_of_equal(first, last, value); + } +}; + +// TODO: Try if this is still the case with MSVC 2013... +// This is required on MSVC (which cannot always deduce lambda result type). +template +struct always_call { + typedef T result_type; + + explicit always_call(T const& r) : r_(r) {} + + result_type operator()(...) const { return r_; } + +private: + T r_; +}; +template +always_call always(T const& r) { return always_call(r); } + +// TODO: Fix all code below to use helpers above... template > class vector { @@ -25,8 +58,8 @@ public: void invariant() const { BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); - BOOST_CONTRACT_ASSERT(std::distance(cbegin(), cend()) == int(size())); - BOOST_CONTRACT_ASSERT(std::distance(rcbegin(), rcend()) == int(size())); + BOOST_CONTRACT_ASSERT(std::distance(begin(), end()) == int(size())); + BOOST_CONTRACT_ASSERT(std::distance(rbegin(), rend()) == int(size())); BOOST_CONTRACT_ASSERT(size() <= capacity()); BOOST_CONTRACT_ASSERT(capacity() <= max_size()); } @@ -51,13 +84,12 @@ public: explicit vector(size_type count) : vect_(count) { auto c = boost::contract::constructor(this) .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == count); -// BOOST_CONTRACT_ASSERT( -// boost::contract::check_if >( -// boost::bind(&boost::algorithm::all_of_equal, cbegin(), -// cend(), boost::cref(T())) -// ) -// ); + BOOST_CONTRACT_ASSERT(this->size() == count); + BOOST_CONTRACT_ASSERT( + boost::contract::call_if >( + boost::bind(all_of_equal(), begin(), end(), T()) + ).else_(always(true)) + ); }) ; } @@ -67,10 +99,13 @@ public: .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == count); BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::bind(&boost::algorithm::all_of_equal, cbegin(), - cend(), boost::cref(value)) - ) + boost::contract::call_if >( + boost::bind( + &boost::algorithm::all_of_equal< + const_iterator, T>, + begin(), end(), boost::cref(value) + ) + ).else_([] { return true; }) ); }) ; @@ -78,7 +113,7 @@ public: template vector(InputIter first, InputIter last) : vect_(first, last) { - auto c = boost::contract::construcotr(this) + auto c = boost::contract::constructor(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(std::distance(first, last) == int(size())); @@ -89,7 +124,7 @@ public: template vector(InputIter first, InputIter last, Alloc const& allocator) : vect_(first, last, allocator) { - auto c = boost::contract::construcotr(this) + auto c = boost::contract::constructor(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(std::distance(first, last) == int(size())); @@ -102,10 +137,10 @@ public: auto c = boost::contract::constructor(this) .postcondition([&] { BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::bind(&std::equal_to, boost::cref(*this), - boost::cref(other)) - ) + boost::contract::call_if >( + boost::bind(std::equal_to >(), + boost::cref(*this), boost::cref(other)) + ).else_(always(true)) ); }) ; @@ -116,16 +151,18 @@ public: auto c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::bind(&std::equal_to, boost::cref(*this), - boost::cref(other)) - ) + boost::contract::call_if > >( + boost::bind(std::equal_to >(), + boost::cref(*this), boost::cref(other)) + ).else_([] { return true; }) ); BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::bind(&std::equal_to, boost::cref(*result), - boost::cref(*this)) - ) + boost::contract::call_if > >( + boost::bind(std::equal_to >(), + boost::cref(*result), boost::cref(*this)) + ).else_([] { return true; }) ); }) ; @@ -160,10 +197,10 @@ public: } iterator begin() { - itetator result; + iterator result; auto c = boost::contract::public_function(this) .postcondition([&] { - if(empty()) BOOST_CONTRACT_ASSERT(result == end()); + if(this->empty()) BOOST_CONTRACT_ASSERT(result == end()); }) ; @@ -171,10 +208,10 @@ public: } const_iterator begin() const { - const_itetator result; + const_iterator result; auto c = boost::contract::public_function(this) .postcondition([&] { - if(empty()) BOOST_CONTRACT_ASSERT(result == end()); + if(this->empty()) BOOST_CONTRACT_ASSERT(result == end()); }) ; @@ -192,7 +229,7 @@ public: } reverse_iterator rbegin() { - itetator result; + iterator result; auto c = boost::contract::public_function(this) .postcondition([&] { if(empty()) BOOST_CONTRACT_ASSERT(result == rend()); @@ -203,10 +240,10 @@ public: } const_reverse_iterator rbegin() const { - const_itetator result; + const_reverse_iterator result; auto c = boost::contract::public_function(this) .postcondition([&] { - if(empty()) BOOST_CONTRACT_ASSERT(result == rend()); + if(this->empty()) BOOST_CONTRACT_ASSERT(result == rend()); }) ; @@ -230,13 +267,15 @@ public: BOOST_CONTRACT_ASSERT(size() == count); if(count > *old_size) { BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::bind(&boost::algorithm::all_of_equal, + boost::contract::call_if >( + boost::bind( + &boost::algorithm::all_of_equal< + const_iterator, T>, begin() + *old_size, end(), boost::cref(value) ) - ) + ).else_([] { return true; }) ); } }) @@ -271,7 +310,7 @@ public: bool result; auto c = boost::contract::public_function(this) .postcondition([&] { - BOOST_CONTRACT_ASSERT(result == (size() == 0)); + BOOST_CONTRACT_ASSERT(result == (this->size() == 0)); }) ; @@ -360,17 +399,16 @@ public: auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); auto c = boost::contract::public_function(this) .precondition([&] { - BOOST_CONTRACT_ASSERT(size() < max_size()); + BOOST_CONTRACT_ASSERT(this->size() < max_size()); }) .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + BOOST_CONTRACT_ASSERT(this->size() == *old_size + 1); BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); - using namespace boost::contract; BOOST_CONTRACT_ASSERT( - call_if >( - boost::bind(callable(), - boost::cref(back()), boost::cref(value)) - ).else_(true) + boost::contract::call_if >( + boost::bind(std::equal_to(), boost::cref(back()), + boost::cref(value)) + ).else_([] { return true; }) ); }) ; @@ -412,10 +450,13 @@ public: }) .postcondition([&] { BOOST_CONTRACT_ASSERT( - boost::contract;:check_if >( - boost::bind(&boost::algorithm::all_of_equal, - begin(), end(), boost::cref(value)) - ) + boost::contract::call_if >( + boost::bind( + &boost::algorithm::all_of_equal< + const_iterator, T>, + begin(), end(), boost::cref(value) + ) + ).else_([] { return true; }) ); }) ; @@ -433,10 +474,10 @@ public: .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == *old_size + 1); BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::bind(&std::equal_to, boost::cref(*result), + boost::contract::call_if >( + boost::bind(std::equal_to(), boost::cref(*result), boost::cref(value)) - ) + ).else_([] { return true; }) // if(capacity() > oldof capacity()) // [begin(), end()) is invalid // else @@ -454,20 +495,20 @@ public: auto old_where = BOOST_CONTRACT_OLDOF(where); auto c = boost::contract::public_function(this) .precondition([&] { - BOOST_CONTRACT_ASSERT(size() + count < max_size()); + BOOST_CONTRACT_ASSERT(this->size() + count < max_size()); }) .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == *old_size + count); + BOOST_CONTRACT_ASSERT(this->size() == *old_size + count); BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); if(capacity() == *old_capacity) { BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::bind(&boost::algorithm::all_of_equal( + boost::contract::call_if >( + boost::bind(all_of_equal(), boost::prior(*old_where), boost::prior(*old_where) + count, boost::cref(value) ) - ) + ).else_(always(true)) ); } }) @@ -480,9 +521,9 @@ public: void insert(iterator where, InputIter first, InputIter last) { auto old_size = BOOST_CONTRACT_OLDOF(size()); auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); - auto c = boost::contract::public_functon(this) + auto c = boost::contract::public_function(this) .precondition([&] { - BOOST_CONTRACT_ASSERT(size() + std::distance(fist, last) < + BOOST_CONTRACT_ASSERT(size() + std::distance(first, last) < max_size()); // [first, last) not contained in [begin(), end()) }) @@ -516,7 +557,7 @@ public: iterator erase(iterator first, iterator last) { iterator result; - auto old_size = + auto old_size = BOOST_CONTRACT_OLDOF(size()); auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(size() >= std::distance(first, last)); @@ -542,22 +583,24 @@ public: vect_.clear(); } - void swap(vecotr& other) { + void swap(vector& other) { auto old_me = BOOST_CONTRACT_OLDOF(*this); auto old_other = BOOST_CONTRACT_OLDOF(other); auto c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::bind(&std::equal_to, boost::cref(*this), - boost::cref(*old_other)) - ) + boost::contract::call_if > >( + boost::bind(std::equal_to >(), + boost::cref(*this), boost::cref(*old_other)) + ).else_([] { return true; }) ); BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::bind(&std::equal_to, boost::cref(other), - boost::cref(*old_me)) - ) + boost::contract::call_if > >( + boost::bind(std::equal_to >(), + boost::cref(other), boost::cref(*old_me)) + ).else_([] { return true; }) ); }) ; @@ -573,28 +616,52 @@ private: std::vector vect_; }; +struct x {}; + +template +decltype(boost::declval()()) r(F f) { +// std::cout << typeid(t).name() << std::endl; + return "abc"; +} + int main() { + // Test vector of equality comparable type `char`. + vector v(3); BOOST_TEST_EQ(v.size(), 3); BOOST_TEST(boost::algorithm::all_of_equal(v, '\0')); vector const& cv = v; vector w(v); - BOOST_TEST_EQ(w, v); + BOOST_TEST(w == v); // Cannot use TEST_EQ here (because it'd print w and v). - vector::iterator b = v.begin(); - BOOST_TEST_EQ(*b, '\0'); + vector::iterator i = v.begin(); + BOOST_TEST_EQ(*i, '\0'); - vector::const_iterator cb = cv.begin(); - BOOST_TEST_EQ(*cb, '\0'); + vector::const_iterator ci = cv.begin(); + BOOST_TEST_EQ(*ci, '\0'); - v.insert(b, 2, 'a'); + v.insert(i, 2, 'a'); BOOST_TEST_EQ(v[0], 'a'); BOOST_TEST_EQ(v[1], 'a'); v.push_back('b'); BOOST_TEST_EQ(v.back(), 'b'); + // Test vector of non equality comparable type `x`. + + vector y(3); + BOOST_TEST_EQ(y.size(), 3); + vector const& cy = y; + + vector z(y); + + vector::iterator j = y.begin(); + + vector::const_iterator cj = cy.begin(); + + y.insert(j, 2, x()); + return boost::report_errors(); } diff --git a/example/n1962/vector_n1962.hpp b/example/n1962/vector_n1962.cpp similarity index 100% rename from example/n1962/vector_n1962.hpp rename to example/n1962/vector_n1962.cpp diff --git a/example/push_back.cpp b/example/push_back.cpp deleted file mode 100644 index 7687938..0000000 --- a/example/push_back.cpp +++ /dev/null @@ -1,77 +0,0 @@ - -#include -#include - -template -struct pusahble { - virtual void push_back(T const& value, - boost::contract::virtual_* v = 0) = 0 { - boost::contract::var c = boost::contract::public_member(v, this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(false); // Force check derived precond. - }) - .postcondition[&] { - BOOST_CONTRACT_ASSERT( - boost::contract::call_if >( - boost::bind(std::equal_to(), - boost::cref(this->back()), boost::cref(value)) - ).else_(boost::contract::always(true)) - ); - }) - ; - } -protected: - virtual T const& back() const = 0; -}; - -template -class vector - #define BASES public ushable - : BASES -{ -public: - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { - BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); - } - - virtual void push_back(T const& value, boost::contract::virtual_* v = 0) { - boost::shared_ptr old_size = - BOOST_CONTRACT_OLDOF(v, size()); - boost::contract::type contract = boost::contract::public_member< - introspect_push_back>(v, this, value) - .precondition([&]() { - BOOST_CONTRACT_ASSERT(this->size() < this->max_size()); - }) - .postcondition([&]() { - BOOST_CONTRACT_ASSERT(this->size() == old_size + 1); - }) - ; - vector_.push_back(value); - } - BOOST_CONTRACT_INTROSPECT(push_back) - - bool empty() const { return vector_.empty(); } - unsigned size() const { return vector_.size(); } - unsigned max_size() const { return vector_.max_size(); } - T const& back() const { return vector_.back(); } - -private: - std::vector vector_; -}; - -void my_sqrt(double& x) { // My square root (with contracts). - boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF(x); - boost::contract::scoped contract = boost::contract::free_function() - .precondition([&] { - BOOST_CONTRACT_ASSERT(x >= 0); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(x * x == old_x); - }) - ; - x = std::sqrt(x); // C++ square root (without contracts). -} - diff --git a/example/stroustrup97/string.cpp b/example/stroustrup97/string.cpp new file mode 100644 index 0000000..95570a2 --- /dev/null +++ b/example/stroustrup97/string.cpp @@ -0,0 +1,126 @@ + +#include +#include +#include +#include + +// Adapted from an example presented in the book "The C++ Programming Language" +// (Stroustrup, 1997) to illustrate importance of class invariants. Simple +// preconditions were added where it made sense. +// This should be compiled with postconditions checking turned off (define the +// `BOOST_CONTRACT_NO_POSTCONDITIONS` macro) because postconditions are +// deliberately not used here. +// See referenced book for a discussion on the importance of class invariants, +// and on pros and cons of using pre and post conditions. +class string + #define BASES private boost::contract::constructor_precondition + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + // Here contracts throw these exceptions instead of terminating on failure. + struct invariant_error {}; + struct range_error {}; + struct null_error {}; + struct too_large_error {}; + + enum { too_large = 16000 }; // Length limit. + + void invariant() const { + if(!chars_) throw invariant_error(); + if(size_ < 0) throw invariant_error(); + if(size_ > too_large) throw invariant_error(); + if(chars_[size_] != '\0') throw invariant_error(); + } + + static void string_precondition(char const* const chars) { + if(!chars) throw string::null_error(); + if(strlen(chars) > too_large) throw too_large_error(); + } + /* implicit */ string(char const* chars) : + boost::contract::constructor_precondition( + boost::bind(&string_precondition, chars)) + { + auto c = boost::contract::constructor(this); // Check invariants. + init(chars); + } + + /* implicit */ string(string const& other) { + auto c = boost::contract::constructor(this); // Check invariants. + init(other.chars_); + } + + ~string() { + auto c = boost::contract::destructor(this); // Check invariants. + delete[] chars_; + } + + char& operator[](int index) { + auto c = boost::contract::public_function(this) + .precondition([&] { + if(index < 0) throw string::range_error(); + if(index >= size_) throw string::range_error(); + }) + ; + + return chars_[index]; + } + + int size() const { + auto c = boost::contract::public_function(this); // Check invariants. + return size_; + } + +private: + void init(char const* chars) { // Non public so does not check invariants. + auto c = boost::contract::function() + .precondition([&] { + if(!chars) throw string::null_error(); + }) + ; + + size_ = strlen(chars); + chars_ = new char[size_ + 1]; + for(int i = 0; i < size_; ++i) chars_[i] = chars[i]; + chars_[size_] = '\0'; + } + + int size_; + char* chars_; +}; + +void throwing_handler(boost::contract::from context) { + if(context == boost::contract::from_destructor) { + // Ignore exception because destructors should never throw. + std::cerr << "destructor contract failed (ignored)" << std::endl; + } else { + throw; // Re-throw active exception throw by the contract. + } +} + +int main() { + boost::contract::set_precondition_failed(&throwing_handler); + boost::contract::set_postcondition_failed(&throwing_handler); + boost::contract::set_invariant_failed(&throwing_handler); + + string s("abc"); + BOOST_TEST_EQ(s[0], 'a'); + + bool pass = false; + try { + std::cout << "1" << std::endl; + s[3]; + std::cout << "2" << std::endl; + } // Out of range. + catch(string::range_error const&) { + std::cout << "3" << std::endl; + pass = true; + } + std::cout << "4" << std::endl; + BOOST_TEST(pass); + + return boost::report_errors(); +} + diff --git a/example/vector.cpp b/example/vector.cpp deleted file mode 100644 index 50d2fa0..0000000 --- a/example/vector.cpp +++ /dev/null @@ -1,512 +0,0 @@ - -#include -#include - -template > -class vector : - #define BASES private boost::contract::constructor_precondition - BASES -{ -public: - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { - BOOST_CONTRACT_ASSERT(emtpy() == (size() == 0)); - BOOST_CONTRACT_ASSERT(std::distance(begin(), end()) == int(size())); - BOOST_CONTRACT_ASSERT(std::distance(rbegin(), rend()) == int(size())); - BOOST_CONTRACT_ASSERT(size() <= capacity()); - BOOST_CONTRACT_ASSERT(capacity() <= max_size()); - } - - vector() : vector_() { - auto c = boost::contract::constructor(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(empty()); - }) - ; - } - - explicit vector(Allocator const& allocator) : vector_(allocator) { - auto c = boost::contract::constructor(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(empty()); - BOOST_CONTRACT_ASSERT(get_allocator() == allocator); - }) - ; - } - - explicit vector(size_type const count) : - boost::contract::constructor_precondition([&] { - BOOST_CONTRACT_ASSERT(count >= 0); - }), - vector_(count) - { - auto c = boost::contract::constructor(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == count); - BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - &boost::algorithm::all_of_equal, begin(), end(), value - ) - ); - }) - ; - } - - vector(size_type const count, T const& value) : - boost::contract::constructor_precondition([&] { - BOOST_CONTRACT_ASSERT(count >= 0); - }), - vector_(count, value) - { - auto c = boost::contract::constructor(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == count); - BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - &boost::algorithm::all_of_equal, begin(), end(), value - ) - ); - }) - ; - } - - template - vector(Iterator first, Iterator last) : vector_(first, last) { - auto c = boost::contract::constructor(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(std::distance(first, lat) == int(size())); - }) - ; - } - - vector(vector const& other) { - auto c = boost::contract::constructor(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - &std::equal_to, other, *this - ) - ); - }) - ; - } - - vector& operator=(vector const& other) { - vector& result = *this; - auto c = boost::contract::public_member(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - &std::equal_to, result, *this - ) - ); - BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - &std::equal_to, result, other - ) - ); - }) - ; - vector_ = right.vector_; - return result; - } - - virtual ~vector() { - // No pre/post, but still contract so to check invariants. - auto c = boost::contract::destructor(this); - } - - size_type capacity() const { - size_type result; - auto c = boost::contract::public_member(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(result >= size()); - }) - ; - return result = vector_.capacity(); - } - - iterator begin() { - iterator result; - auto c = boost::contract::public_member(this) - .postcondition([&] { - if(empty()) BOOST_CONTRACT_ASSERTION(result == end()); - }) - ; - return result = vector_.begin(); - } - - const_iterator begin() const { - const_iterator result; - auto c = boost::contract::public_member(this) - .postcondition([&] { - if(empty()) BOOST_CONTRACT_ASSERTION(result == end()); - }) - ; - return result = vector_.begin(); - } - - interator end() { - auto c = boost::contract::public_member(this); // To check invariants. - return vector_.end(); - } - - const_interator end() const { - auto c = boost::contract::public_member(this); - return vector_.end(); - } - - iterator rbegin() { - iterator result; - auto c = boost::contract::public_member(this) - .postcondition([&] { - if(empty()) BOOST_CONTRACT_ASSERTION(result == end()); - }) - ; - return result = vector_.rbegin(); - } - - const_iterator rbegin() const { - const_iterator result; - auto c = boost::contract::public_member(this) - .postcondition([&] { - if(empty()) BOOST_CONTRACT_ASSERTION(result == end()); - }) - ; - return result = vector_.rbegin(); - } - - interator rend() { - auto c = boost::contract::public_member(this); - return vector_.end(); - } - - const_interator rend() const { - auto c = boost::contract::public_member(this); - return vector_.end(); - } - - void resize(size_type const new_size) { - auto old_size = BOOST_CONTRACT_OLDOF(size()); - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(new_size >= 0); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == new_size); - if(new_size > old_size) BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::algorithm::all_of_equal, begin() + old_size, - end(), T() - ) - ); - }) - ; - vector_.resize(new_size); - } - - void resize(size_type const new_size, T const& value) { - auto old_size = BOOST_CONTRACT_OLDOF(size()); - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(new_size >= 0); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == new_size); - if(new_size > old_size) BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::algorithm::all_of_equal, begin() + old_size, - end(), value - ); - }) - ; - vector_.resize(new_size, value); - } - - size_type size() const { - size_type result; - auto c = boost::contract::public_member(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(result >= capacity()); - }) - ; - return result = vector_.size(); - } - - size_type max_size() const { - size_type result; - auto c = boost::contract::public_member(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(result >= capacity()); - }) - ; - return result = vector_.max_size(); - } - - bool empty() const { - bool result; - auto c = boost::contract::public_member(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(result == (size() == 0)); - }) - ; - return result = vector_.empty(); - } - - Allocator get_allocator() const { - auto c = boost::contract::public_member(this); - return vector_.get_allocator(); - } - - reference at(size_type const index) { - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(index < size()); - }) - ; - return vector_.at(index); - } - - const_reference at(size_type const index) const { - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(index < size()); - }) - ; - return vector_.at(index); - } - - reference operator[](size_type const index) { - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(index < size()); - }) - ; - return vector_.at(index); - } - - const_reference operator[](size_type const index) const { - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(index < size()); - }) - ; - return vector_.at(index); - } - - reference front() { - auto c = booost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(!emtpy()); - }) - ; - return vector_.front(); - } - - const_reference front() const { - auto c = booost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(!emtpy()); - } - ; - return vector_.front(); - } - - reference back() { - auto c = booost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(!emtpy()); - } - ; - return vector_.back(); - } - - const_reference back() const { - auto c = booost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(!emtpy()); - } - ; - return vector_.back(); - } - - void push_back(T const& value) { - auto old_size = BOOST_CONTRACT_OLDOF(size()); - auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(size() < max_size()); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == old_size + 1); - BOOST_CONTRACT_ASSERT(capacity() >= old_capacity); - BOOST_CONTRACT_ASSERT( - bost::contract::check_if >( - &std::equal_to, back(), value) - ); - }) - ; - vector_.push_back(value); - } - - void pop_back() { - auto old_size = BOOST_CONTRACT_OLDOF(size()); - auto = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(!empty()); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == old_size - 1); - }) - ; - vector_.pop_back(); - } - - template - void assign(Iterator const first, Iterator const last) { - auto c = boost::contract::public_member(this) - // precondition: [begin(), end()) does not contain [first, last) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(std::distance(first, last) == - int(size())); - }) - ; - vector_.assign(first, last); - } - - void assign(size_type const count, T const& value) { - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(count <= max_size()); - } - .postcondition([&] { - BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - &boost::algorithm::all_of_equal, begin(), end(), value - ) - ); - }) - ; - vector_.assign(count, value); - } - - iterator insert(iterator const where, T const& value) { - iterator result; - auto old_size = BOOST_CONTRACT_OLDOF(size()); - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(size() < max_size()); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == old_size + 1); - BOOST_CONTRACT_ASSERT(boost::contract::check_if >(&std::equal_to, result, value)); - // if(capacity() > oldof capacity()) - // [begin(), end()) is invalid - // else - // [where, end()) is invalid - }) - ; - return result = vector_.insert(where, value); - } - - void insert(iterator where, size_type const count, T const& value) { - auto old_size = BOOST_CONTRACT_OLDOF(size()); - auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); - auto old_where = BOOST_CONTRACT_OLDOF(where); - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(size() + count < max_size()); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == old_size + count); - BOOST_CONTRACT_ASSERT(capacity() >= old_capacity); - if(capacity() == old_capacity) - BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - boost::contract::algorithm::all_of_equal( - boost::prior(old_where), - boost::prior(old_where) + count, - value - ) - ) - ); - // [where, end()) is invalid - // else - // [begin() end()) is invalid - }) - ; - vector_.insert(where, count, value); - } - - template - void insert(Iterator where, Iterator first, Iterator last) { - auto old_size = BOOST_CONTRACT_OLDOF(size()); - auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); - auto c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(size() + std::distance(first, lat) < - max_size()); - // [first, last) is not contained in [begin(), end()) - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == old_size + std::distance(first, - last)); - BOOST_CONTRACT_ASSERT(capacity() >= old_capacity); - }) - ; - vector_.insert(where, first, last); - } - - iterator erase(iterator where) { - iterator result; - auto old_size = BOOST_CONTRACT_OLDOF(size()); - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] { - BOOST_CONTRACT_ASSERT(!empty()); - BOOST_CONTRACT_ASSERT(where != end()); - }) - .postcondition([&] { - BOOST_CONTRACT_ASSERT(size() == old_size - 1); - if(empty()) BOOST_CONTRACT_ASSERT(result == end()); - // [where, end()) is invalid - }) - ; - return result = vector_.erase(first, last); - } - - void clear() { - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] { BOOST_CONTRACT_ASSERT(empty()); }) - ; - vector_.clear(); - } - - void swap(vector& other) { - auto old_self = BOOST_CONTRACT_OLDOF(*this); - auto old_other = BOOST_CONTRACT_OLDOF(other); - auto = boost::contract::public_member(this) - .postcondition([&] { - BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - &std::equal_to, other, old_self) - ); - BOOST_CONTRACT_ASSERT( - boost::contract::check_if >( - &std::equal_to, old_other, *this) - ); - }) - ; - vector_.swap(other); - } - - friend bool operator==(vector const& left, vector const& right) { - return left.vector_ == right.vector_; - } - -private: - std::vector vector_; -}; - diff --git a/features.txt b/features.txt index 85b8507..9205941 100644 --- a/features.txt +++ b/features.txt @@ -46,4 +46,32 @@ x Old values with/without subcontracting * Derived public function override base protected virtual function (subst princ does not apply here because base protected virtual cannot be called by users so it cannot be "substituted")... what will this lib do? +* add a test to disable/ similar to n1962/factial.cpp, where the contract + recursively calls the function itself in the assertions +* add a test for throwing exception handlers (somewhat similar to + stroustrup97/string.cpp but but comprehensive) +* see if MSVC 2013 resolves issues with call_if::else_([] { return true; }) + result type deduction, and also using lambdas within + constructor_precondition +* Volatile class invariants... +* Check inv after C++11 move operations... documented pro/cons +* Compiler-error if public_function does not find any function + to actually override +* Config macro to disable no assertion during preconditions (to avoid passing + unchecked argument to function body) +* Look at Andrzej's discussion on preconditions: + https://akrzemi1.wordpress.com/2013/01/04/preconditions-part-i/ +* Can constructor/destructor body call a volatile member function? If so, + they should also check volatile class invariant (currently they don't...) +* If an overriding functions does not specify preconditions, make sure the + overridden preconditions are checked (and not that subcontracted + preconditions always pass just because the overriding function does not + specify them) +* Can I use unique_ptr instead of shared_ptr for old values, and maybe also + for contract variables internal to the library, etc... ? +* Test function and array argument types like + `void f(int x[2][3], int (*g)(int))` +* What shall I do with unions... can/shall I contract them? Check-out which + members C++11 unions can have (ctors, dtor, etc.) +* Make work the case a pure virtual uses boost::optional result but an overriding function uses just T result, and the other way around too. diff --git a/include/boost/contract/call_if.hpp b/include/boost/contract/call_if.hpp index f17f26a..4a87866 100644 --- a/include/boost/contract/call_if.hpp +++ b/include/boost/contract/call_if.hpp @@ -50,12 +50,12 @@ struct call_if_statement { // Copyable as *. R else_(Else const&) const { return *r_; } template - call_if_statement else_if_c(ElseIfThen const&) { + call_if_statement else_if_c(ElseIfThen const&) const { return *this; } template - call_if_statement else_if(ElseIfThen const&) { + call_if_statement else_if(ElseIfThen const&) const { return *this; } @@ -74,12 +74,12 @@ struct call_if_statement { void else_(Else const&) const {} template - call_if_statement else_if_c(ElseIfThen const&) { + call_if_statement else_if_c(ElseIfThen const&) const { return *this; } template - call_if_statement else_if(ElseIfThen const&) { + call_if_statement else_if(ElseIfThen const&) const { return *this; } }; @@ -101,12 +101,13 @@ struct call_if_statement { } template - call_if_statement else_if_c(ElseIfThen f) { + call_if_statement else_if_c(ElseIfThen f) const { return call_if_statement(f); } template - call_if_statement else_if(ElseIfThen f) { + call_if_statement else_if(ElseIfThen f) + const { return call_if_statement(f); } }; diff --git a/include/boost/contract/core/config.hpp b/include/boost/contract/core/config.hpp index 520f4bf..ece05e2 100644 --- a/include/boost/contract/core/config.hpp +++ b/include/boost/contract/core/config.hpp @@ -4,6 +4,18 @@ /** @file */ +#ifndef BOOST_CONTRACT_CONFIG_NO_PRECONDITIONS +# define BOOST_CONTRACT_CONFIG_NO_PRECONDITIONS 0 +#endif + +#ifndef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS +# define BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS 0 +#endif + +#ifndef BOOST_CONTRACT_CONFIG_NO_INVARIANTS +# define BOOST_CONTRACT_CONFIG_NO_INVARIANTS 0 +#endif + // TODO: base_types, invariant, and static_invariant must be public. Allow to // make them private (so to not alter user's public API) by declaring some // `friend class boost::contract::aux::access;` from the user's class (then diff --git a/include/boost/contract/core/exception.hpp b/include/boost/contract/core/exception.hpp index e75fbc0..c80d278 100644 --- a/include/boost/contract/core/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -81,18 +81,21 @@ namespace exception_ { s = "precondition "; break; case post_key: s = "postcondition "; break; + // NOTE: Following only needs to distinguish between entry and + // exit invariant (const, volatile, static, etc. can already be + // distinguished by code around assertion failure line number). case const_entry_inv_key: - s = "const entry invariant "; break; + s = "entry invariant "; break; case const_volatile_entry_inv_key: - s = "const volatile entry invariant "; break; + s = "entry invariant "; break; case static_entry_inv_key: - s = "static entry invariant "; break; + s = "entry invariant "; break; case const_exit_inv_key: - s= "const exit invariant "; break; + s= "exit invariant "; break; case const_volatile_exit_inv_key: - s= "const volatile exit invariant "; break; + s= "exit invariant "; break; case static_exit_inv_key: - s = "static exit invariant "; break; + s = "exit invariant "; break; // No default (so compiler warning/error on missing enum case). } try { @@ -296,6 +299,10 @@ void set_invariant_failed(assertion_failed_handler f) set_exit_invariant_failed(f); } +// TODO: Simplify the invariant failure handlers. I only need two, one for +// entry_inv and one for exit_inv (I do not need to distinguish volatile, +// const, static... they are all inv). + } } // namespace #endif // #include guard diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 538d962..a2d9bd9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -53,7 +53,7 @@ test-suite call_if : test-suite cxx14 : [ subdir-run call_if : equal_to_cxx14 : clang:-std=c++1y ] - [ subdir-run call_if : myadvance_cxx14 : + [ subdir-run call_if : advance_cxx14 : clang:-std=c++1y ] ; explicit cxx14 ; diff --git a/test/call_if/myadvance_cxx14.cpp b/test/call_if/advance_cxx14.cpp similarity index 100% rename from test/call_if/myadvance_cxx14.cpp rename to test/call_if/advance_cxx14.cpp diff --git a/test/call_if/false_.cpp b/test/call_if/false_.cpp index cb315d6..7aef3ad 100644 --- a/test/call_if/false_.cpp +++ b/test/call_if/false_.cpp @@ -10,7 +10,7 @@ boost::contract::aux::test::oteststream out; -struct equal { +struct eq { typedef bool result_type; // Test non-void result type. template @@ -28,7 +28,7 @@ int main() { out.str(""); out << boost::contract::call_if >( - boost::bind(equal(), x1, x1) // Compiler-error... but not called. + boost::bind(eq(), x1, x1) // Compiler-error... but not called. ).else_([] { return false; }) // Test else. << std::endl; ok.str(""); ok << false << std::endl; @@ -37,7 +37,7 @@ int main() { out.str(""); out << boost::contract::call_if >( - boost::bind(equal(), x1, x2) // Compiler-error... but not called. + boost::bind(eq(), x1, x2) // Compiler-error... but not called. ).else_([] { return true; }) << std::endl; ok.str(""); ok << true << std::endl; @@ -46,7 +46,7 @@ int main() { out.str(""); out << // Test "..._c". boost::contract::call_if_c::value>( - boost::bind(equal(), x1, x2) // Compiler-error...but not called. + boost::bind(eq(), x1, x2) // Compiler-error...but not called. ).else_([] { return true; }) << std::endl; ok.str(""); ok << true << std::endl; diff --git a/test/call_if/false_void.cpp b/test/call_if/false_void.cpp index a571c23..e682828 100644 --- a/test/call_if/false_void.cpp +++ b/test/call_if/false_void.cpp @@ -10,7 +10,7 @@ boost::contract::aux::test::oteststream out; -struct equal { +struct eq { typedef void result_type; // Test void result type. template @@ -27,7 +27,7 @@ int main() { out.str(""); boost::contract::call_if >( - boost::bind(equal(), x1, x2) // Compiler-error... but not called. + boost::bind(eq(), x1, x2) // Compiler-error... but not called. ); // Test no else. ok.str(""); BOOST_TEST(out.eq(ok.str())); @@ -35,7 +35,7 @@ int main() { out.str(""); // Test "..._c". boost::contract::call_if_c::value>( - boost::bind(equal(), x1, x2) // Compiler-error...but not called. + boost::bind(eq(), x1, x2) // Compiler-error...but not called. ).else_( [] { out << true << std::endl; } // Test else. ); diff --git a/test/call_if/true_.cpp b/test/call_if/true_.cpp index e860254..4000920 100644 --- a/test/call_if/true_.cpp +++ b/test/call_if/true_.cpp @@ -10,7 +10,7 @@ boost::contract::aux::test::oteststream out; -struct equal { +struct eq { typedef bool result_type; // Test non-void result type. template @@ -28,7 +28,7 @@ int main() { out.str(""); out << boost::contract::call_if >( - boost::bind(equal(), 123, 456) // False. + boost::bind(eq(), 123, 456) // False. ) // Test no else (not called). << std::endl; ok.str(""); ok << false << std::endl; @@ -37,7 +37,7 @@ int main() { out.str(""); out << boost::contract::call_if >( - boost::bind(equal(), 123, 123) // True. + boost::bind(eq(), 123, 123) // True. ).else_([] { return false; }) // Test else not called. << std::endl; ok.str(""); ok << true << std::endl; @@ -46,9 +46,9 @@ int main() { out.str(""); out << // Test "..._c". boost::contract::call_if_c::value>( - boost::bind(equal(), 123, 123) // True. + boost::bind(eq(), 123, 123) // True. ).else_( // Test else not called. - boost::bind(equal(), x1, x2) // Compiler-error... but not called. + boost::bind(eq(), x1, x2) // Compiler-error... but not called. ) << std::endl; ok.str(""); ok << true << std::endl; diff --git a/test/call_if/true_void.cpp b/test/call_if/true_void.cpp index d6b9a01..d0957d1 100644 --- a/test/call_if/true_void.cpp +++ b/test/call_if/true_void.cpp @@ -10,7 +10,7 @@ boost::contract::aux::test::oteststream out; -struct equal { +struct eq { typedef void result_type; // Test void result type. template @@ -27,14 +27,14 @@ int main() { out.str(""); boost::contract::call_if >( - boost::bind(equal(), 123, 456) // False. + boost::bind(eq(), 123, 456) // False. ); // Test no else (not called). ok.str(""); ok << false << std::endl; BOOST_TEST(out.eq(ok.str())); out.str(""); boost::contract::call_if >( - boost::bind(equal(), 123, 123) // True. + boost::bind(eq(), 123, 123) // True. ).else_( [] { return false; } ); // Test else (not called). @@ -44,9 +44,9 @@ int main() { out.str(""); // Test "..._c". boost::contract::call_if_c::value>( - boost::bind(equal(), 123, 123) // True. + boost::bind(eq(), 123, 123) // True. ).else_( // Test else (not called). - boost::bind(equal(), x1, x2) // Compiler-error... but not called. + boost::bind(eq(), x1, x2) // Compiler-error... but not called. ); ok.str(""); ok << true << std::endl; BOOST_TEST(out.eq(ok.str()));