diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt new file mode 100644 index 0000000..fe7981d --- /dev/null +++ b/COPYRIGHT.txt @@ -0,0 +1,4 @@ +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://sourceforge.net/projects/contractpp. diff --git a/LICENSE b/LICENSE_1_0.txt similarity index 100% rename from LICENSE rename to LICENSE_1_0.txt diff --git a/README.md b/README.txt similarity index 100% rename from README.md rename to README.txt diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..1605959 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,124 @@ + + +* Possible to remove public/protected/private (simplify syntax)? + --> This requires to be able to implement has_public_f meta-function... + --> Use CONTRACT_MEMBER/FUNCTION to differentiate function kind. + +* Possible to remove CONTRACT_CLASS_INVARIANT( void ) (simplify syntax)? + --> See related ticket. + +* Possible to remove _TPL in C++11 (simplify syntax)? + + + +* Assume C++11 variadic-macros (simplify impl). + --> No longer need to support sequence-syntax. + +* Assume C++11 auto/decltype or better Boost.Typeof (simplify impl). + --> No longer need to support `(type) ...` in syntax. + +* Maybe use lambdas instead of local functions... would this simplify impl of + const-blocks? + +* Remove `(f) ( void )` use just `(f) ( )` instead (assuming variadic-macros). + +* Make a note that older revs of the lib did not use any C++11 feature... + +* Remove concepts (simplify impl, plus C++11 decltype-expr-sfinae...). + +* Remove named params (simplify impl, plus C++11 version of Boost.Parameters + without macros...). + +* Remove loop-variants and block-invariants. + +* Remove virtual specifiers (simplify impl, plus now in C++11...). + + +* Allow unnamed parameters (template, function, etc)? + +* Support all C++11 decl features. + --> Move semantics (these should all "just work", but try them). + --> constexpr (for functions, constructors, operators, etc). + --> Default constructor syntax + T() = default; T() = delete; ... (use "as" instead of "=") + I don't need to support = delete because that's no decl and so has no + contracts. + However, I'd ideally support = default so I can add contracts for + default declarations. + --> `extern template class ...` do I need to do anything here given that + contracts will not be specified when template instantiation is forced + off or on (similar to `template class vector;`)... probably not, + but test it! + --> std::initializer_list I don't need to do anything special to support + initializer constructors but test them! + --> Support trailing-return-type using `return` instead of `->`: + template + auto add ( R r, L l ) -> decltype(r + l) ; + template( typename R, typename L ) + FUNC( auto (add) ( (R) r, (L) l ) return(decltype(r + l)) ); + Or: + FUNC( auto (f) ( ) return(int) ); + FUNC( auto (f) ( ) return int ); + --> Delegating constructors... Will these pose problems/bugs for contracts? + When shall class invariants be checked (i.e., when is an object + considered constructed full)? Can these be used to overcome Contract++ + CONSTRUCTOR_BODY limitations? + --> Support virtual specifiers override (func) and final (class and func). + --> Explicit conversion operators `explicit operator T() ...`. + --> Variadic (templates). + I should be able to support variadic templates and variadic functions + without changing the syntax: + template( typename... Args ) + void (f) ( (Args...) args ) + Because `... Args` will be parsed as one token for the template param + name then it'll be parsed again as a token `Args...` as the function + param type. Same for value- and template- template params. + Also I should be able to support C-style variadic functions: + void (f) ( int size, ... ) + Because `...` will be parsed as the parameter type (no name). + --> User-define literals `... operator "" ...` (only free or member too?). + --> Anything to do for threading... (probably not given that's all in STL). + --> Make sure `long long int` can be specified (ideally, the syntax will + support `{long}* int` etc so type qualifier can be repeated as many + times as the user wants and the compiler will just error if they used + incorrectly). + --> Double check that alignas(...) cannot be used in class/function decl + (but only in var decl). If so, no need to support it. + --> Support attributes [[...]] maybe as ((...) -- Or: + Support MSVC/GCC/CLang decl-spec (for DLLs, etc). + I can support verbatim(...) in the class and function declaration + positions used by MSVC, G++, and CLang (I won't support positions used + by other compilers). + Read more about C++11 attributes [[...]], where they can appear in + class/function decl, and the default attributes [[noreturn]] and + [[carries_dependency]] so to decide how to support C++11 attributes + + MSVC __declspec + GCC __attributes__ in the syntax. + --> Type deduction: + I should probably allow `auto` and `decltype(...)` (extra paren not + necessary) everywhere a type is expected as I do for `int` (`(int)` not + necessary), including func param types. + +* Using C++11 delegating constructors --> see if I can remove initialize() + (and their function-try-blocks) all together from this library macros + (as they belong with constructor definitions and not declarations). + +* C++14 + --> Function return type deduction: + auto f ( ) { return true; } + FUNC( auto (f) ( ) /* no return... here */ ) { return true; } + --> Check what "variable templates" are... (probably not in class/func decl + so OK, but check). + +* Support usual redundant C++ syntax: + --> `(f) ( )` and `(f) ( void )` (but only `template< >`, no void here) + --> `T const` and `const T` + --> `const volatile` and `volatile const` + --> Is this valid C++ `struct x : public virtual y` and + `struct x : virtual public y`? If so, support both (but I think only + the 1st one of these is valid...). + --> Optional (template, func, etc) param names. + +* Add all and only (not size_t!!) syntax highlight to both QuickBook and VIM. +* Make Boost.Preprocess macros highlighted in VIM in dark yellow. + + diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 new file mode 100644 index 0000000..04b2a5a --- /dev/null +++ b/doc/Jamfile.v2 @@ -0,0 +1,66 @@ + +# 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 + +import quickbook ; +using boostbook ; +using doxygen ; + +doxygen reference + : + ../include/contract/function.hpp + ../include/contract/constructor.hpp + ../include/contract/destructor.hpp + ../include/contract/class.hpp + ../include/contract/class_invariant.hpp + ../include/contract/body.hpp + ../include/contract/block_invariant.hpp + ../include/contract/loop_variant.hpp + ../include/contract/parameter.hpp + ../include/contract/oldof.hpp + ../include/contract/copy.hpp + ../include/contract/broken.hpp + ../include/contract/config.hpp + ../include/contract/limits.hpp + : + "Reference" + contract # Strip path prefix. + PREDEFINED="DOXYGEN" + QUIET=YES + WARN_IF_UNDOCUMENTED=NO + HIDE_UNDOC_MEMBERS=YES + HIDE_UNDOC_CLASSES=YES + SHORT_NAMES=NO + ALIASES=" Params=\"Parameters: \" Param{2}=\"\" EndParams=\"
\\1\\2
\" Returns=\"Returns:\" Note=\"Note:\" Warning=\"Warning:\" SeeAlso=\"See also:\" RefSect{2}=\"\\xmlonly\\2\\endxmlonly\" RefClass{1}=\"\\xmlonly\\1\\endxmlonly\" RefFunc{1}=\"\\xmlonly\\1\\endxmlonly\" RefMacro{1}=\"\\xmlonly\\1\\endxmlonly\" RefEnum{1}=\"\\xmlonly\\1\\endxmlonly\" " + ; + +xml contractpp : contractpp.qbk + : reference + ; + +boostbook bjampy : 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" + ; + +# explicit bjampy contractpp reference ; + +# echo """ +# Usage: python bjam.py [bjam-options-and-targets] +# Build documentation using Bjam via Python (to customize navbar, etc). +# +# NOTE: Use `python bjam.py pdf` to update PDF documentation. +# """ ; + diff --git a/doc/acknowledgments.qbk b/doc/acknowledgments.qbk new file mode 100644 index 0000000..20e5475 --- /dev/null +++ b/doc/acknowledgments.qbk @@ -0,0 +1,33 @@ + +[/ 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 Acknowledgments] + +This section aims to recognize the contributions of /all/ the different people that participated directly or indirectly to the design and development of this library. + +Sincere thanks to my parents for their support with my education and my studies in computer science. + +Sincere thanks to Marina for her kindness and continuous support. + +Many thanks to Bertrand Meyer for his pioneering and thorough work on Contract Programming in __Meyer97__. + +Many thanks to Thorsten Ottosen for his work with __N1962__ (and previous revisions) and for clarifying the __N1962__ requirements directly with the library authors when needed. + +Many thanks to Andrzej Krzemienski for reviewing earlier versions of this library providing valuable insights, for exchanging ideas on implementing assertion requirements, and for suggesting to support named parameters. + +Many thanks to Vicente J. Botet Escriba for reviewing earlier versions of this library providing valuable insights and for suggesting to use `contract::copy`. + +Thanks to Steven Watanabe for providing valuable insights on C++ and for hinting to use template meta-programming introspection to detect if a base class has a given member function (technique which turned out to be essential to fully automate subcontracting). + +Thanks to Dave Abrahams for providing valuable comments on the library syntax and especially on the syntax to support named parameters. + +Thanks to David Maley for having shared source code form his inspiring work in __Maley99__ on emulating Contract Programming in C++. + +Finally, many thanks to the entire __Boost__ community and [@http://lists.boost.org mailing list] for providing valuable comments about this library and great insights on the C++ programming language. + +[endsect] + diff --git a/doc/advanced_topics.qbk b/doc/advanced_topics.qbk new file mode 100644 index 0000000..6c08b22 --- /dev/null +++ b/doc/advanced_topics.qbk @@ -0,0 +1,835 @@ + +[/ 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. + +[section Commas and Leading Symbols in Macros] + +C++ macros cannot correctly parse a macro parameter if it contains a comma `,` that is not wrapped within round parenthesis `()` (because the preprocessor interprets such a comma as separation between two distinct macro parameters instead that as part of one single macro parameter, see also __Boost_Utility_IdentityType__). +Furthermore, syntactic elements specified to this library macros cannot start with a non-alphanumeric symbol (`-1`, `1.23`, `"abc"`, `::`, etc). +[footnote +Note that for the preprocessor a number with decimal period `1.23`, `0.12`, `.34` is considered a symbol (because its concatenation will not result in a valid macro identifier). +] +For example, the parameter type `::std::pair const&` cannot be passed to this library for two reasons: It starts with the non-alphanumeric symbol `::` and it contains the comma `OtherKey, OtherT` which is not wrapped by round parenthesis. + +The __Boost_Utility_IdentityType__ macro `BOOST_IDENTITY_TYPE` can be used as usual to overcome this issue. +However, using the `BOOST_IDENTITY_TYPE` macro presents two limitations: It makes the syntax of this library macros more cumbersome and, more importantly, it does not allow C++ to automatically deduce function template parameters (see __Boost_Utility_IdentityType__ for more information). +Therefore, the syntax of this library provides an alternative to `BOOST_IDENTITY_TYPE` to handle commas and leading symbols within macro parameters: + +# Commas and leading symbols can be used freely within elements of the syntax that already require wrapping parenthesis (e.g., non-fundamental parameter types `(::std::pair const&)`). +# Extra parenthesis can always be used to wrap elements of the syntax that might contain commas and leading symbols (e.g, the base class type `public (::sizeable)`). +# Extra parenthesis can always be used to wrap value expressions so they can contain commas and leading symbols (e.g., a class invariants assertion `(::sizeable::max_size >= size())`). + +For example (see also [file example/contracts macro_commas_symbols_integral_map.cpp]): + +[import ../example/contracts/macro_commas_symbols_integral_map.cpp] +[macro_commas_symbols_integral_map] + +(Concepts and other advanced constructs used in this example are explained in the rest of this section and in later sections of this documentation.) + +All these extra wrapping parenthesis are optional when there is no unwrapped comma and no leading symbol. +Programmers could chose to always program the extra parenthesis for consistency but it is the authors' opinion that the syntax is harder to read with the extra parenthesis so it is recommended to use them only when strictly necessary. + +It is also recommended to avoid using commas and leading symbols whenever possible so to limit the cases when it is necessary to use the extra wrapping parenthesis. +For example, in many cases the leading symbol `::` might not be necessary and leading symbols like `!` can be replaced by the alternative keywords like `not`. +Furthermore, in some cases `typedef` can be programmed just before class and function declarations to avoid passing types within multiple template parameters separated by commas. +Declarations of class templates and function templates are the most common cases were commas cannot be avoided and extra wrapping parenthesis are necessarily used. + +[warning +Preconditions, postconditions, and class invariants composed of one single assertion that needs to be wrapped within extra parenthesis need to use double parenthesis (this should be a relatively rare case). +[footnote +*Rationale.* +This limitation is introduced by the need to support also the sequence syntax for preprocessor without variadic macros (see the __No_Variadic_Macros__ section). +] +This is the case in the above example for `precondition( ((!full())) )` (but note that these extra parenthesis could have been avoided all together simply using `not` instead of `!` as in the more readable `precondition( not full() )`). +] + +[endsect] + +[section Static Assertions] + +This library allows to use [@http://en.wikipedia.org/wiki/C%2B%2B11#Static_assertions /static assertions/] to program preconditions, postconditions, class invariants, and block invariants so that they are checked at compile-time instead of at run-time. +The __CXX11__ syntax is used (but __Boost_MPL__ `BOOST_MPL_ASSERT_MSG` is used to implement static assertions so no __CXX11__ feature is required): + + static_assert(``/constant-boolean-condition/``, ``/constant-string-literal/``) + +For example (see also [file example/contracts static_assertion_memcopy.cpp]): + +[import ../example/contracts/static_assertion_memcopy.cpp] +[static_assertion_memcopy] + +Static assertions are always checked at compile-time (regardless of them appearing in preconditions, postconditions, etc). +However, static assertions can be selectively disabled depending on where they are specified using [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS], etc so it is still important to logically associate them with preconditions, postconditions, etc. + +The string message passed as the second parameter of `static_assert` is ignored by the current implementation of this library (but it could be used by future revisions of this library that take advantage of __CXX11__ features). +It is recommended to always specify meaningful messages for static assertions to increase the readability and documentation of contracts. +Similarly, it might be useful to put a short code comment following each assertions (`// pointer not null`, etc) to increase contract readability and documentation. +[footnote +*Rationale.* +__Eiffel__ supports /assertion labeling/ to further document assertions. +However, when designing this library for C++, the authors judged that it is sufficient to add a short code comment after each assertion to achieve a similar effect. +] + +In case of a static assertion failure, this library will generated a compile-time error containing text similar to the following: + +[pre +static_assertion_memcopy.cpp:18 ... ERROR_statically_checked_precondition_number_1_failed_at_line_18 ... +] + +This message is similar to the run-time assertion errors generated by this library, note how it contains all the information to uniquely identify the assertion that failed. + +[endsect] + +[section Constant Assertions] + +As explained in the __Constant_Correctness__ section, contract assertions shall not change the state of the program because contracts are only supposed to check (and not to alter) the state of the program. +This library automatically makes member functions, function parameters, function result, and old values constant so the compiler will correctly generate an error if assertions mistakenly try to change the object, the function parameters, the function result, or the old values (this should be sufficient in most cases when programming contracts). + +[important +This library cannot automatically make constant other variables that might be accessible by the contract assertions (e.g., global and static variables). +[footnote +*Rationale.* +The library needs to know at least the variable name in order to make it constant. +There is no way for this library to know the name of a global variable that is implicitly accessible from the contract assertion scope so such a variable cannot be automatically made constant. +Non-static data members are automatically made constant by making constant the member function that checks the contract, but that does not apply to static data members. +Not even __CXX11__ lambda implicit captures could be used in this context because they make variables constant only when captured by value and that introduces a __CopyConstructible__ requirement of the captured variable types. +] +] + +This library provides /constant assertions/ that can be used by programmers to explicitly make constant the variables used by the asserted boolean expression: + + const( ``/variable1/``, ``/variable2/``, ...) ``/boolean-expression-using-variable1-variable2-.../`` + +The following example calculates the next even and odd numbers that are stored (for some reason) in a global variable and static data member respectively (see also [file example/contracts const_assertion_number.cpp]): + +[import ../example/contracts/const_assertion_number.cpp] +[const_assertion_number] + +Note know the postconditions use constant assertions to force the `even` and `odd` variables to be constant within each boolean expression that evaluates the assertion. +If for example the assignment operator `=` were mistakenly used instead of the equality operator `==` in the above postconditions, the compiler would correctly generate an error. + +[endsect] + +[section Select Assertions] + +In the __Tutorial__ section we have used the ternary operator `:?` to program assertions that are guarded by a boolean condition: + + old_found ? true : std::find(begin(), end(), id) != end(), + old_found ? true : size() == old_size + 1 + +However, in cases like this one when the same boolean condition guards multiple assertions, it might be more efficient to evaluate the guard condition only once using one /select assertion/ instead of multiple ternary operators `:?`. +In addition, some programmers might find the select assertion syntax more readable than the ternary operator `:?`. +For example, the above guarded assertions could have been programmed using select assertions as: + + if(not old_found) ( // Guard condition evaluated only once. + std::find(begin(), end(), id) != end(), + size() == old_size + 1 + ) + +Select assertion allow to specify an optional else-block: + + if(``/boolean-condition/``) ( // Round parenthesis `()`. + ... // Comma-separated assertions. + ) else ( // Else optional as usual. + ... // Comma-separated assertions. + ) + +Note that round parenthesis `( ... )` are used to program the then-block and else-block instead of the usual C++ curly parenthesis `{ ... }`: +Select assertions can be nested into one another (the [macroref CONTRACT_LIMIT_NESTED_SELECT_ASSERTIONS] macro specifies the maximum nesting level for select assertions). + +For example, consider the postconditions of the following function which calculates the factorial of a natural number (see also [file example/contracts select_assertion_factorial.cpp]): + +[import ../example/contracts/select_assertion_factorial.cpp] +[select_assertion_factorial] + +Using the same syntax used for constant assertions, it is possible to force all variables (global, static, etc) used to evaluate the if-condition of the select assertion to be constant (see also [file example/contracts const_select_assertion_factorial.cpp]): + +[import ../example/contracts/const_select_assertion_factorial.cpp] +[const_select_assertion_factorial] + +[endsect] + +[section Assertion Statements] + +Only assertions can be programmed within the contracts while normal C++ statements are not allowed. +This is keeps contracts simple making programming errors within the contracts less likely and therefore increasing the probably that error-free contracts can properly check the correctness of the implementation. + +However, `using` directives, `namespace` aliases, and `typedef` statements are allowed within the contracts because they only affect compilation (not altering the state of the program at run-time) and they can be used to write more readable contracts (for example, shortening namespaces within contract assertions). +When used, these statements have effect only locally within the preconditions, postconditions, class invariants, etc where they appear. +[footnote +Assertion statements might be especially useful because contracts appear with the class and function declarations usually in header files where `using` directives and `namespace` aliases should only be used with extreme care and, for example, at local scope as assertion statements allow to do. +] + +For example (see also [file example/contracts assertion_statement_ialloc.cpp]): + +[import ../example/contracts/assertion_statement_ialloc.cpp] +[assertion_statement_ialloc] + +These statements follow their usual C++ syntax but they are terminated with a comma `,` instead of a semicolon `;`. +(The `BOOST_IDENTITY_TYPE` macro can be used to wrap eventual commas within the `typedef` statement.) + +[endsect] + +[section Assertion Requirements] + +In general, programming contract assertions can introduce a new set of requirements on the types used by the program. +Some of these type requirements might be necessary only to program the assertions and they might not be required by the implementation itself. +In such cases, if the code is compiled with contracts disabled ([macroref CONTRACT_CONFIG_NO_PRECONDITIONS], etc), the program might compile but it might no longer compile when contracts are enabled because some of the types do not provide all the operations necessary to check the contract assertions. + +# More in general, in some cases it might be acceptable or even desirable to cause a compile-time error when a program uses types that do not provide all the operations needed to check the contracts (because it is not possible to fully check the correctness of the program). +In these cases, programmers specify contract assertions as we have seen so far (and maybe even use concepts to explicitly specify the contract type requirements, see the __Concepts__ section). +# However, in other cases it might be desirable that adding contracts to a program does not change its type requirements and that assertions are simply not checked when the types do not provide all the operations necessary to evaluate the asserted conditions. +In these cases, programmers can use /assertion requirements/ to disable compilation and run-time checking of specific assertions: +[footnote +*Rationale.* +The assertion requirement syntax takes a constant boolean expression instead of a nullary boolean meta-function because the authors have found no reason to use a meta-function in this context. +Furthermore, constant boolean expressions can be manipulated via the usual operators `not`, `and`, etc, therefore more naturally than boolean meta-functions which need to use `boost::mpl::not_`, `boost::mpl::and_`, etc instead. +] + + ``/assertion/``, requires ``/constant-boolean-expression/`` + +(The constant boolean expression of an assertion requirement can be wrapped within round parenthesis `()` if it contains unwrapped commas.) + +Let's consider the STL `std::vector` class template. +This template normally does not require the value type `T` to be __EqualityComparable__ (i.e., to have an equality operator `==`), it only requires `T` to be __CopyConstructible__ (i.e., to have a copy constructor). +However, in order to check the following `std::vector::push_back` postcondition the type `T` must to be __EqualityComparable__: + + back() == value // Compiler error if not `EqualityComparable`. + +Therefore, the __EqualityComparable__ requirement on `T` is introduced only by the contract assertions and it is not required by the `std::vector` implementation. + +In some cases, programmers might want compilation to fail when `T` is not __EqualityComparable__ because in these cases it is not possible to fully check the `std::vector` contracts and therefore its correctness (in these cases programmers do not specify assertion requirements and let the compilation fail, or even better programmers can explicitly specify the assertion type requirements using concepts which will also fail compilation but hopefully with more informative error messages, see the __Concepts__ section). + +However, in other cases programmers might want to use the contracted version of `std::vector` exactly as they use the non-contracted version of the template and therefore without failing compilation if `T` is not __EqualityComparable__. +This can be achieved specifying assertion requirements for the `std::vector::push_back` postcondition: + + back() == value, requires boost::has_equal_to::value // No error if not `EqualityComparable`. + +This postcondition will be checked only when `T` is __EqualityComparable__, otherwise the postcondition will be ignored causing no compilation error. + +For example (see also [file example/contracts assertion_requirements_push_back.cpp]): +[footnote +Future revisions of this library might provide wrappers that program contracts for the STL in appropriate header files =contract/std/vector.hpp=, =contract/std/algorithm.hpp=, etc (see also [@http://www.sgi.com/tech/stl/ SGI STL] and [@http://sourceforge.net/apps/trac/contractpp/ticket/47 Ticket 47]). +However, given that STL implementations are usually considered to be ["correct], it is not clear if STL class invariants and postconditions would add any value, maybe programmers would only find STL preconditions useful. +] + +[import ../example/contracts/assertion_requirements_push_back.cpp] +[assertion_requirements_push_back] +[assertion_requirements_push_back_call] + +The `i.push_back(123)` call will check the postcondition `back() == value` because `int` is __EqualityComparable__ and the assertion requirement `boost::has_equal_to::value` is true. +However, the `n.push_back(num(123))` call will not check, and in fact not even compile, the postconditions `back() == value` because `num` is not __EqualityComparable__ and the assertion requirement `boost::has_equal_to::value` is false. +[footnote +Assertion requirements where first introduced by this library and they are not supported by __N1962__, __D__, or __Eiffel__ (even if they all allow to write contracts for templates). +Based on the authors' experience, assertion requirements are necessary for a language that make extensive use of templates like C++. +Furthermore, C++ does not automatically define equality operators `==` while it automatically defines copy constructors and that makes the use of the assertion requirements for __EqualityComparable__ a rather common practise (in __Eiffel__ instead types can be both copied and compared for equality by default). +It has been argued that it is not possible to check a program for correctness if types that are copyable cannot also be compared for equality and the authors experience with programming contracts confirms such an argument. +] + +The __Boost_TypeTraits__ library provides a set of meta-functions that are very useful to program assertion requirements. +[footnote +As of __Boost__ 1.50, `boost::has_equal_to` and similar traits always return true for an STL container even if the value type of the container does not have an operator `==`. +This is arguably a defect of the STL that always defines an operator `==` for its containers even when a container template is instantiated with a value type that has no operator `==`, in which case the container operator `==` will produce a compiler error (the STL should instead use __SFINAE__ to disable the declaration of the container operator `==` when the value type has no operator `==`). +Future versions of __Boost_TypeTraits__ will probably specialize `boost::has_equal_to` and similar traits to work around this behaviour of the STL. +In the meanwhile, programmers can specialize these traits themselves if needed: +`` +// Header: std_has_equal_to.hpp +#include +#include +#include +#include + +// STL defines `operator==` only between two identical containers (same value +// type, allocator, etc) and returning a type convertible to `bool`. + +namespace boost { + +// Specializations for `std::vector`. + +template< typename T, class Alloc > +struct has_equal_to < std::vector, std::vector > : + has_equal_to +{}; + +template< typename T, class Alloc, typename Ret > +struct has_equal_to < std::vector, std::vector, Ret > : + mpl::and_< + has_equal_to + , is_convertible + > +{}; + +// ... specialize `has_equal_to` for more STL containers. + +} // namespace +`` +] +However, C++ does not allow to inspect every trait of a type so there might be some assertion requirements that unfortunately cannot be programmed within the language. + +Another interesting use of assertion requirements is to model assertion computational complexity. +In some cases, checking assertions can be as computationally expensive as executing the function body or even more. +While preconditions, postconditions, etc can be disabled in groups at compile-time to improve performance (using [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS], etc), it is also useful to be able to disable only specific assertions that are very computationally expensive while keeping all other preconditions, postconditions, etc enabled. +For example (see also [file example/contracts assertion_complexity_factorial.cpp]): + +[import ../example/contracts/assertion_complexity_factorial.cpp] +[assertion_complexity_factorial] + +In this case the postcondition `result = n * factorial(n - 1)` has factorial computational complexity and it is compiled and checked at run-time only if the macro `COMPLEXITY_MAX` is defined to be `O_FACTN` or greater. +Similarly, macros like `O_SMALLER_BODY`, `O_BODY`, and `O_GREATER_BODY` could have been defined to express computational complexity in relative terms with respect to the body computational complexity (see the __Examples__ section). +[footnote +__N1866__, an earlier version of __N1962__, introduced the notion of /importance ordering/ that could be used to selectively disable assertions that where too expensive computationally. +Importance ordering was then dropped by __N1962__. +Among other things, assertion requirements can be used to achieve the importance ordering functionality. +] + +Assertion requirements can be used with assertions, constant assertions, and static assertions but they cannot be used with assertion statements and with the if-condition of select assertions (however, if select assertions are programmed using the ternary operator `:?` then assertion requirements will disable the entire ternary operator `:?` expression including its if-condition). + +[endsect] + +[section Old-Of Requirements] + +Assertion requirements can be specified also for postconditions that use old values. +However, old values have the additional requirement that the type of the expression passed to the [macroref CONTRACT_OLDOF] macro must be __ConstantCopyConstructible__. +If such a requirement is not met: + +# Either, programmers want the compiler to error because the postconditions using the old value cannot be evaluated (in which case programmers will not specify assertion requirements and they might explicitly specify type requirements using concepts so to get more informative error messages, see the __Concepts__ section). +# Or, programmers want the old value declaration that uses the [macroref CONTRACT_OLDOF] macro to have no effect (because the old value cannot be copied) and the postconditions using such an old value to not be evaluated. + +Unfortunately, C++ cannot automatically detect if a type has a copy constructor therefore a special trait [classref contract::has_oldof] has to be introduced to support this second case. +The `contract::has_oldof` trait is a unary boolean meta-function which is `boost::mpl::true_` by default for any type `T` and it must be specialized by programmers for types which old values cannot be copied. + +For example, consider the following increment function (see also [file example/contracts has_oldof_inc.cpp]): + +[import ../example/contracts/has_oldof_inc.cpp] +[has_oldof_inc] +[has_oldof_inc_call] + +In this example, the `num` type is non-copyable so the `contract::has_oldof` specialization inherits from `boost::mpl::false_`. +As a consequence, the call `inc(n, m)` will automatically skip the old value declaration: + + auto old_value = CONTRACT_OLDOF value + +The following postcondition will also be skipped because its assertion requirement lists `contract::has_oldof` (where `T` is indeed the type of `value` passed to the [macroref CONTRACT_OLDOF] macro): + + value == old_value + offset, requires contract::has_oldof::value and ... + +Note how this postcondition actually requires the type `T` to have an old value, a plus operator `+`, and an equality operator `==` thus all of these requirements are programmed in the assertion requirements. + +Finally, return value declarations are never skipped so there is no `has_result` trait. +[footnote +*Rationale.* +The result type needs to be copyable in order for the function itself to return a value so this library can always evaluate return value declarations. +] + +[endsect] + +[section Old and Result Value Copies] + +This library uses the class template [classref contract::copy] to copy old values and the result value for postconditions. + + namespace contract + { + template< typename T > + class copy + { + public: copy ( T const& object ) ; + public: T const& value ( void ) const ; + }; + } // namespace + +The default implementation of the [classref contract::copy] class template requires that the type of the old value expression passed to the [macroref CONTRACT_OLDOF] macro and the result type are __ConstantCopyConstructible__ (i.e., these types provide a copy constructor that copies the object from a constant reference, the reference has to be constant so to ensure the constant-correctness of the copy operations that are executed within the contracts, see also the __Constant_Correctness__ section): + + // `ConstantCopyConstructible` (which implies `CopyConstructible`): + T::T ( T const& source ) ; // OK: constant-correct copy constructor. + + // `CopyConstructible` (but not `ConstantCopyConstructible`): + T::T ( T& source ) ; // Error, copy constructor is not constant-correct. + +Programmers can specialize the [classref contract::copy] class template to allow old value and result value copies even for types that are not __ConstantCopyConstructible__ (in this case it is the programmers' responsibility to make sure that the copy operations that they define are constant-correct, otherwise the contracts will no longer be constant-correct). +[footnote +Currently, it is not possible to force constant-correctness of the expression passed to the [macroref CONTRACT_OLDOF] macro. +Future revisions of this library will support `CONTRACT_OLDOF const( ... ) ...` to allow to make constant all variables (including global, static, etc) used by old value expressions (see also [@http://sourceforge.net/apps/trac/contractpp/ticket/52 Ticket 52]). +] + +In the following example the old and result value declarations use the specialization `contract::copy` so it is possible to access the old and result value of variables of type `num` even if `num` is non-copyable (see also [file example/contracts copy_inc.cpp]): + +[import ../example/contracts/copy_inc.cpp] +[copy_inc] +[copy_inc_call] + +Both calls `inc(i, j)` and `inc(n, m)` check all postconditions. +The first call copies the old and result values using `int`'s default copy constructor, the second call copies the old and result values using the copy operation implemented by the `contract::copy` specialization. + +[endsect] + +[section Pure Virtual Functions] + +It is possible to program contracts for pure virtual functions. +Pure virtual functions are specified with the usual `= 0;` symbol replacing the function definition just after the contract macros, for example (see also [file example/contracts pushable.hpp]): + +[import ../example/contracts/pushable.hpp] +[pushable] + +Furthermore, using the [macroref CONTRACT_MEMBER_BODY] macro, a derived class can be programmed without using the [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] macros even when the base class has pure virtual functions (see also [file example/contracts default_subcontracting_base.cpp]): + +[import ../example/contracts/default_subcontracting_base.cpp] +[default_subcontracting_base] + +This use of the [macroref CONTRACT_MEMBER_BODY] macro does not force programmers of derived classes to use the library macros [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] which would otherwise introduce the unusual library syntax in the derived class declaration. +However, in this case the derived class is forced to inherit the base class invariants, preconditions, and postconditions exactly as they are without the possibility to truly subcontract the base class (which is instead possible when the [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] macros are used in declaring the derived class). +[footnote +*Rationale.* +Older revisions of this library defined the macro `CONTRACT_MEMBER_BODY(class_type, function_name)` taking two parameters so this macro could not be used in declaring derived classes and the [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] macros where required when programming a class inheriting from a base class with contracts. +However, the authors prefer to leave the choice of programming full contracts for derived classes to the derived class programmers because of the unusual declaration syntax introduced by this library might not be necessary when derived classes do not need to alter the base's class contract. +] +Correctly, the derived class can never avoid checking the base class contracts neither when declared using the [macroref CONTRACT_CLASS] and [macroref CONTRACT_FUNCTION] macros, nor when declared using the [macroref CONTRACT_MEMBER_BODY] macro. + +[endsect] + +[section Subcontracting Preconditions] + +While subcontracting is theoretically sound and justified by the __substitution_principle__, in practise subcontracted preconditions might be confusing for programmers because of the implications of evaluating overriding preconditions in __logic_or__ with overridden preconditions (this is not the case for subcontracted postconditions and class invariants which usually behave as programmers expect because they are evaluated in __logic_and__). + +For example, consider the following base class `integer` which holds an integral value and its derived class `natural` which holds a natural (i.e., non-negative integer) value (see also [file example/contracts subcontract_pre_natural_failure.cpp]): + +[import ../example/contracts/subcontract_pre_natural_failure.cpp] +[subcontract_pre_natural_failure] + +From reading the contracts we conclude that: + +* `integer::get` returns the latest value set (as specified by `integer::set` postconditions). +* There is no constraint on the integer value that is passed to `integer::set` (because `integer::set` has no precondition). +* `natural::get` always returns a non-negative value (as specified by the `natural` class invariants). +* Only non-negative values can be passed to `natural::set` (as specified by `natural::set` preconditions). + +This last conclusion is incorrect! +Negative values can be passed to `natural::set` because they can be passed to its base virtual function `integral::set` (preconditions cannot only be weakened). +The complete set of `natural::set` preconditions is given by its base virtual function `integer::set` preconditions (which are always `true` because they are not specified) evaluated in __logic_or__ with the preconditions explicitly specified by `natural::set` (i.e., `value >= 0`): + + (true) or (value >= 0) + +Obviously, this always evaluates to `true` regardless of `value` being non-negative. +This is correct in accordance with the __substitution_principle__ for which `natural::set` can be called in any context where `integer::set` is called because `natural` inherits from `integer`. +Given that `integer::set` can be called regardless of `value` being non-negative (because it has no precondition) there is no precondition that we can later specify for `natural::set` that will change that and in fact `natural::set` can also be called with negative values without failing its subcontracted preconditions. +For example, the call: + +[subcontract_pre_natural_failure_call] + +Fails the class invariants checked while exiting `natural::set`: + +[pre +class invariant (on exit) number 1 "get() >= 0" failed: file "natural_subcontractpre.cpp", line 30 +] + +Ideally, this call would have failed much earlier at `natural::set` preconditions (in fact, the `natural::set` body is executed with the logically invalid negative value `-123` which could in general lead to catastrophic errors and mysterious bugs). + +The issue here is in the design. +A natural number is not an integer number because while it is valid to use an integer number in a context where it is assigned to a negative number, it is not valid to use a natural number in such a context so a natural number should not inherit from an integer number. +Inheritance models the [@http://en.wikipedia.org/wiki/Is-a /is-a/] relationship which should not be used in this case as the contracts and the __substitution_principle__ are telling us. + +[note +Note that if a virtual member function has no preconditions, it means that it is always valid to call it, and (in accordance with the __substitution_principle__) this semantic cannot be changed by the contracts of any overriding function no matter what preconditions we specify for it. +Similarly, if an overriding member function has no preconditions, it means that is is always valid to call it regardless of possible preconditions specified by any function that it overrides. +] + +An overriding function can specify `precondition( false )` if it wants to keep the same preconditions of the functions that is overriding. +A pure virtual function can specify `precondition( false )` to indicate that overriding functions will specify preconditions (this only makes sense for pure virtual functions because a function with `precondition( false )` can never be called successfully unless it is overridden and its preconditions are weakened, that might be acceptable for pure virtual because they must always be overridden). + +If programmers find subcontracted preconditions confusing, this library allows to forbid them by defining the configuration macro [macroref CONTRACT_CONFIG_DO_NOT_SUBCONTRACT_PRECONDITIONS]. +When this macro is defined, the library will generate a compile-time error if a derived class tries to override preconditions of member functions of any of its base classes (this is also the subcontracting behaviour specified by __N1962__). +However, note that in case of multiple-inheritance preconditions from the overridden function from all bases classes will always be checked in __logic_or__ with each other so preconditions from a base class could still be weaken by the preconditions of another base class even when the [macroref CONTRACT_CONFIG_DO_NOT_SUBCONTRACT_PRECONDITIONS] macro is defined. +By default the [macroref CONTRACT_CONFIG_DO_NOT_SUBCONTRACT_PRECONDITIONS] macro is not defined and this library allows to override preconditions (as specified by for __Eiffel__ by __Meyer97__ and in accordance with the __substitution_principle__). + +Another difference between subcontracted preconditions and subcontracted postconditions or class invariants is that subcontracted preconditions will always report a failure of the overridden preconditions. +For example, consider a set of base classes [^b['N]] and a derived class `d`: + + CONTRACT_CLASS( + struct (a) + ) { + ... // No member function `f`. + }; + + CONTRACT_CLASS( + struct (b``/N/``) + ) { + CONTRACT_CLASS_INVARIANT( ... ) + + CONTRACT_FUNCTION( + public virtual void (f) ( void ) // Overridden function. + precondition( ... ) + postcondition( ... ) + ) {} + + ... + }; + + CONTRACT_CLASS( + struct (c) + ) { + ... // No member function `f`. + }; + + CONTRACT_CLASS( + struct (d) extends( b1, a, b2, c, b3 ) + ) { + CONTRACT_CLASS_INVARIANT( ... ) + + CONTRACT_FUNCTION( + public virtual void (f) ( void ) // Overriding function. + precondition( ... ) + postcondition( ... ) + ) {} + + ... + }; + +When `d::f` is called, its subcontracted class invariants, postconditions, and preconditions are evaluated using the following expressions (the base classes `a` and `c` do not declare a virtual function `f` so they are automatically excluded from `d::f` subcontracting): + + b1::``/class-invariants/`` and b2::``/class-invariants/`` and b3::``/class-invariants/`` and d::``/class-invariants/`` // `d::f` subcontracted class invariants. + b1::f::``/postconditions/`` and b2::f::``/postconditions/`` and b3::f::``/postconditions/`` and d::f::``/postconditions/`` // `d::f` subcontracted postconditions. + b1::f::``/preconditions/`` or b2::f::``/preconditions/`` or b3::f::``/preconditions/`` or d::f::``/preconditions/`` // `d::f` subcontracted preconditions. + +When subcontracted class invariants or subcontracted postconditions fail, this library reports the first failed condition which can in general be in the base class contracts because they are checked first in the __logic_and__ chain (this can report a failure from any subcontracted class invariants [^b['N]::/class-invariants/] or [^d::/class-invariants/], and subcontracted postconditions [^b['N]::f::/postconditions/] or [^d::f::/postconditions/]). +However, when subcontracted preconditions fail it means that all overridden preconditions as well as the overriding preconditions have failed (because subcontracted preconditions are evaluated in __logic_or__). +In this case, this library will report the last evaluated failure which will always be in the overriding preconditions (always report a failure from [^d::f::/preconditions/]). +If programmers want instead the library to report the failure from the first overridden precondition that failed, they can define the configuration macro [macroref CONTRACT_CONFIG_REPORT_BASE_PRECONDITION_FAILURE] (always report a failure from [^b1::f::/preconditions/]). + +[endsect] + +[section Static Member Functions] + +It is possible to program contracts for static member functions. +Static member functions cannot access the object therefore their preconditions and postconditions also cannot access the object and they can only access other static members. +This library allows to specify a subset of class invariants called /static class invariants/ which do not access the object and that are checked at entry and exit of every constructor, destructor, and member functions even if static. +(Non-static class invariants are instead not checked at constructor entry, at destructor exit, and at entry and exit of static member functions because they require accessing the object, see also the __Contract_Programming_Overview__ section.) + +Static class invariants are empty (`void`) by default unless they are explicitly specified within the [macroref CONTRACT_CLASS_INVARIANT] macro using the following syntax: +[footnote +Static class invariants are not part of __N1962__ and they were first introduced by this library. +] + + static class( ``/assertion1/``, ``/assertion2/``, ... ) + +For example (see also [file example/contracts static_contract_instance_counter.cpp]): + +[import ../example/contracts/static_contract_instance_counter.cpp] +[static_contract_instance_counter] + +In this example there is only one static class invariant assertion `count() >= 0` and it is checked at entry and exit of every constructor, destructor, and member function including the static member function `count`. +If the static member function `count` had preconditions or postconditions, they would not be able to access the object (i.e., preconditions and postconditions will also be executed in static context). + +[endsect] + +[section Volatile Member Functions] + +It is possible to program contracts for volatile member functions. +Volatile member functions access the object as volatile therefore their preconditions and postconditions also access the object as volatile and can only access other volatile members. +This library allows to specify a different set of class invariants called /volatile class invariants/ which can only access the object as volatile and that are checked at entry and exit of every volatile member function. +(Constructors and destructors never access the object as volatile so volatile class invariants are not checked by constructors and destructors, see also the __Contract_Programming_Overview__ section.) + +Volatile class invariants are assumed to be the same as non-volatile class invariants unless they are explicitly specified within the [macroref CONTRACT_CLASS_INVARIANT] macro using the following syntax: +[footnote +Volatile class invariants are not part of __N1962__ and they were first introduced by this library. +It is not clear if there are real applications for volatile class invariants mainly because real applications of `volatile` itself are not clear in C++. +One very interesting use of `volatile` has been to [@http://www.drdobbs.com/cpp/184403766 avoid race conditions] in concurrent programming (but contracts are not useful for such an application of `volatile`). +] + + + volatile class( ``/assertion1/``, ``/assertion2/``, ... ) + +In most cases, it will be necessary to explicitly specify volatile class invariants when using volatile member functions (unless volatile overloads are provided for every member function that is used by the non-volatile class invariants). + +For example (see also [file example/contracts volatile_contract_shared_instance.cpp]): + +[import ../example/contracts/volatile_contract_shared_instance.cpp] +[volatile_contract_shared_instance] + +As usual, contracts are checked in constant-correct context therefore only `const volatile` members can be accessed from volatile class invariants, preconditions, and postconditions. + +[endsect] + +[section Operators] + +It is possible to program contracts for operators (both member function operators and free function operators). +The operator name must be specified using the following syntax when passed to the [macroref CONTRACT_FUNCTION], [macroref CONTRACT_FREE_BODY], and [macroref CONTRACT_MEMBER_BODY] macros: + + operator(``/symbol/``)(``/arbitrary-alphanumeric-name/``) + +The first parameter is the usual operator symbol (`==`, `+`, etc) the second parameter is an arbitrary but alphanumeric name (`equal`, `plus`, etc). +The operator `new`, the operator `delete`, and implicit type conversion operators for fundamental types containing no symbol can also be specified simply as: + + operator new + operator delete + operator ``/fundamental-type-without-symbols/`` + +The comma operator must be specified as: +[footnote +*Rationale.* +The comma operator cannot be specified using the comma symbol as in `operator(,)(my_comma_operator)` because the preprocessor uses commas to separate macro parameters so it is not possible to distinguish that from an implicit type conversion operator like `operator(std::vector)(std_vector)` (note that the operator name is arbitrary so it also cannot be used to distinguish these two cases). +] + + operator comma + +For example (see also [file example/contracts member_operator_string.cpp]): + +[import ../example/contracts/member_operator_string.cpp] +[member_operator_string] + +The memory operators `new`, `delete`, `new[]`, and `delete[]` must always be specified `static` when they are programmed as member function operators. +[footnote +*Rationale.* +C++ automatically promotes memory member operators to static members so the `static` keyword is optional for these member operators. +However, this library cannot inspect the operator symbol using the preprocessor to check if the operator is a memory member operator or not because the symbol contains non-alphanumeric tokens (which cannot be concatenated by the preprocessor). +Therefore, this library always requires memory member operators to be explicitly declared as static member functions. +] + +Free function operators are programmed using the same syntax for the operator names. + +[endsect] + +[section Nested Classes] + +It is possible to program contracts for nested classes noting that: + +# The access level `public`, `protected`, or `private` must be specified for contracted members and therefore also for nested classes. +# The `_TPL` macros must be used within templates so the [macroref CONTRACT_CLASS_TPL] macro needs to be used when programming a class nested within a class template. + +For example (see also [file example/contracts nested_class_bitset.cpp] and the __Concepts__ section): + +[import ../example/contracts/nested_class_bitset.cpp] +[nested_class_bitset] + +[endsect] + +[section Friends] + +It is possible to program contracts for friend classes and friend functions. +Classes can be declared friends and later contracted using the [macroref CONTRACT_CLASS] macro as usual: + + CONTRACT_CLASS( // Not even necessary to contract this class. + class (x) + ) { + CONTRACT_CLASS_INVARIANT( void ) + + friend class y ; + + // ... + }; + + CONTRACT_CLASS( + class (y) + ) { + CONTRACT_CLASS_INVARIANT( void ) + + // ... + }; + +Friend functions that are declared and defined within the enclosing class use the `friend` keyword within the [macroref CONTRACT_FUNCTION] macro (note that the access level `public`, `protected`, or `private` is optional in this case because these friend functions are not member functions). +Friend functions that are either forward declared friends or that are defined friends within the enclosing class, must use the [macroref CONTRACT_FREE_BODY] macro. +For example (see also [file example/contracts friend_counter.cpp]): + +[import ../example/contracts/friend_counter.cpp] +[friend_counter] + +The class enclosing the friend declarations might or might not be contracted. + +[endsect] + +[section Template Specializations] + +It is possible to program contracts for class template specializations. +The generic class template might or might not be contracted (see also [file example/contracts template_specializations_vector.cpp]): + +[import ../example/contracts/template_specializations_vector.cpp] +[template_specializations_vector] + +The template specialization types follow the class name as usual but they are wrapped within round parenthesis `( bool, Allocator )` instead than angular parenthesis `< bool, Allocator >` as in the following partial specialization: + +[template_specializations_vector_bool_allocator] + +The syntax `template( void )` must be used instead of `template< >` to indicate explicit specializations: + +[template_specializations_vector_bool] + +[endsect] + +[section Exception Specifications and Function-Try Blocks] + +It is possible to program exception specifications and function-try blocks for constructors, destructors, member functions, and free functions with contracts. +Exception specifications are part of the function declarations therefore they are programmed within the contract macros but the special syntax `throw( void )` must be used instead of `throw( )` to specify that no exception is thrown: + + throw( ``/exception-type1/``, ``/exception-type2/``, ... ) // As usual. + throw( void ) // Instead of `throw( )`. + +Function-try blocks are part of the function definition so they are normally programmed outside the contract macros. +However, for constructors with member initializers, the member initializers must be programmed within the [macroref CONTRACT_CONSTRUCTOR] macro and therefore also the function-try blocks must be programmed within the macro using the following syntax: + + try initialize( ``/initializer1/``, ``/initializer2/``, ... ) + catch(``/exception-declaration1/``) ( ``/instruction1/``; ``/instruction2/``; ... ) + catch(``/exception-declaration2/``) ( ``/instruction1/``; ``/instruction2/``; ... ) + catch(...) ( ``/instruction1/``; ``/instruction2/``; ... ) + +As usual, only one catch statement must be specified and the other catch statements are optional plus `catch(...)` can be used to catch all exceptions. +Note however that round parenthesis `( ... )` are used instead of curly parenthesis `{ ... }` to wrap the catch statement instructions (then the catch instructions are programmed with the usual syntax and separated by semicolons `;`). +(The maximum number of catch statements that can be programmed for constructor-try blocks is specified by the [macroref CONTRACT_LIMIT_CONSTRUCTOR_TRY_BLOCK_CATCHES] macro.) + +In the following example the constructor uses a function-try block to throw only `out_of_memory` and `error` exceptions while the destructor uses exception specifications to throw no exception (see also [file example/contracts exception_array.cpp]): + +[import ../example/contracts/exception_array.cpp] +[exception_array] + +(The `BOOST_IDENTITY_TYPE` macro can be used to wrap the catch statement exception declaration types if they contain unwrapped commas.) + +Exception specifications and 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 this library macros. +[footnote +*Rationale.* +__N1962__ specifies that function-try blocks should only apply to the body code and not to the contract code. +No explicit requirement is stated in __N1962__ for exception specifications but the authors have decided to adopt the same requirement that applies to function-try blocks (because it seemed of little use for the contract to throw an exception just so it is handled by the exception specification). +] + +[endsect] + +[section Specifying Types (no Boost.Typeof)] + +This library uses __Boost_Typeof__ to automatically deduces postcondition old value types and constant assertion variable types. +If programmers do not want the library to use __Boost_Typeof__ they can explicitly specify these types. + +The types of postcondition old values are specified instead of using `auto` and they must be wrapped within round parenthesis unless they are fundamental types containing no symbol (these must match the type of the specified old-of expressions): + + (``/type/``) ``/variable/`` = CONTRACT_OLDOF ``/oldof-expression/`` + +The types of constant assertion variables are specified just before each variable name and they also must be wrapped within round parenthesis unless they are fundamental types containing no symbol: + + const( (``/type1/``) ``/variable1/``, (``/type2/``) ``/variable2/``, ... ) ``/boolean-expression/`` + +For example (see also [file example/contracts typed_counter.cpp]): + +[import ../example/contracts/typed_counter.cpp] +[typed_counter] + +Note that postcondition result values are always specified using `auto`: + + auto ``/result-variable/`` = return + +This is because the function return type is know by the library as specified in the function declaration within the [macroref CONTRACT_FUNCTION] macro. +Therefore, the postcondition result value type is never explicitly specified by programmers (but __Boost_Typeof__ is never used to deduce it). + +[note +It is recommended to not specify these types explicitly and let the library internally use __Boost_Typeof__ to deduce them because the library syntax is more readable without the explicit types. +However, all types must be properly registered with __Boost_Typeof__ as usual in order to use type-of emulation mode on __CXX03__ compilers that do not support native type-of (see __Boost_Typeof__ for more information). +] + +[endsect] + +[section Block Invariants and Loop Variants] + +/Block invariants/ can be used anywhere within the function body and they are used to assert correctness conditions of the implementation (very much like `assert`). +They are programmed specifying a list of assertions to the [macroref CONTRACT_BLOCK_INVARIANT] macro (including static, constant, and select assertions): + + CONTRACT_BLOCK_INVARIANT( ``/assertion1/``, ``/assertion2/``, ... ) + +When block invariants are used within a loop, they are also called /loop invariants/ (e.g., __Eiffel__ uses this terminology). + +Furthermore, this library allows to specify [@http://en.wikipedia.org/wiki/Loop_variant ['loop variants]]. +A loop variant is a non-negative monotonically decreasing number that is updated at each iteration of the loop. +The specified loop variant expression is calculated by this library at each iteration of the loop and it is automatically asserted to be non-negative (`>= 0`) and to decrease monotonically from the previous loop iteration. +Because the loop variant monotonically decreases and it cannot be smaller than zero, either the loop terminates or one of the two library assertions will eventually fail in which case the library will call the [funcref contract::loop_variant_broken] handler therefore detecting and stopping infinite loops. +Each given loop can only have one variant which is specified using the [macroref CONTRACT_LOOP_VARIANT] macro. +The enclosing loop (`while`, `for`, `do`, etc) must be declared using the [macroref CONTRACT_LOOP] macro: + + CONTRACT_LOOP( ``/loop-declaration/`` ) { + CONTRACT_LOOP_VARIANT( ``/non-negative-monotonically-decreasing-expression/`` ) + ... + } + +Note that the library cannot automatically make constant any of the variables within the function body therefore constant block invariant assertions and constant loop variant expressions should be used by programmers if they want to enforce constant-correctness for block invariants and loop variants. + +The following example uses a loop to calculate the [@http://en.wikipedia.org/wiki/Greatest_common_divisor Greatest Common Divisor (GCD)] of two integral numbers (see also [file example/contracts blockinv_loopvar_gcd.cpp]): + +[import ../example/contracts/blockinv_loopvar_gcd.cpp] +[blockinv_loopvar_gcd] + +__Eiffel__ supports loop variants but __N1962__ does not. +Loop variants might not be very useful especially if __Boost_Foreach__ or similar constructs are used to ensure loop termination. + +[endsect] + +[section Contract Broken Handlers (Throw on Failure)] + +When a contract assertion fails, this library prints a message on the standard error `std::cerr` and it terminates the program calling `std::terminate`. +Programmers can change this behavior customizing the actions that the library takes on contract assertion failure by setting the contract broken handler functions. +By default the library terminates the program because a contract failure indicates that the program is in an invalid state that programmers specified it should never happen (so the only sensible assumption is that the program execution should not continue). +However, in some cases programmers might need to handle even such catastrophic failures by executing some fail-safe code instead of terminating the program and that can be done customizing the contract broken handlers. + +The library functions [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] can be used to customize the action to taken in case of precondition, postcondition, class invariant, block invariant, and loop variant failure respectively. +Furthermore, class invariants are checked at entry, at normal exit, and at exit but when exceptions are thrown so more granular handlers can be set for each of these cases using [funcref contract::set_class_invariant_broken_on_entry], [funcref contract::set_class_invariant_broken_on_exit], and [funcref contract::set_class_invariant_broken_on_throw] (using [funcref contract::set_class_invariant_broken] is equivalent to setting all these class invariant broken handles to the same handler). +[footnote +__N1962__ does not allow to configure class invariant broken handlers differently for entry, exit, and throw. +] + +This library passes a parameter of type [enumref contract::from] to the contract broken handler functions indicating the context that failed the contract assertion (e.g., this parameter will be set to `contract::FROM_DESTRUCTOR` if the contract assertion failed from a destructor): +[footnote +The `contract::from` parameter was not part of __N1962__ contract broken handlers but the proposal hinted that it might be needed (need that was confirmed by the implementation of this library). +] + + void ``/contract-broken-handler/`` ( contract::from const& context ) + +[important +In order to comply with the STL exception safety requirements, destructors should never throw. +Therefore, even if programmers customize the contract broken handlers to throw exceptions instead of terminating, the handlers should never throw when contract assertions fail from a destructor (and the [enumref contract::from] parameter can be used to discriminate this case). +] + +The contract broken handlers are always invoked with an active exception that refers to the exception that failed the contract: +[footnote +*Rationale.* +Exceptions are used to signal a contract assertion failure because it is not possible to directly call the contract broken handler ([funcref contract::precondition_broken], etc) instead of throwing the exception in oder to properly implement subcontracting. +For example, if an overriding precondition fails but the overridden precondition is true then the library will not call the broken handler even if the overriding precondition threw an exception (as required by subcontracting). +Contract assertion failures are critical error conditions so it is actually natural that the library uses exceptions to signal them (note that the library will always handle the exceptions by calling the contract broken handlers which terminate the program by default so the fact that the library signals contract assertion failures using exceptions does not imply that an exception will be thrown if a contract assertion fails, that is entirely decided by the implementation of the broken handlers). +] + +# Either an exception that was explicitly thrown by the user from the contract (e.g. `not_a_number` in the example blow). +# Or, an exception that was thrown ["behind the scene] while evaluating a contract assertion (e.g., the assertion calls an STL algorithm and that throws `std::bad_alloc`). +# Or, an exception automatically thrown by this library in case a contract assertion is evaluated to be false (these exceptions are always [classref contract::broken] objects and they contained detailed information about the contract assertion that was evaluated to be false: file name, line number, assertion number, and assertion code). +[footnote +The assertion number is meaningful only within a specific handler. +For example, if assertion number `2` failed within the class invariant broken handler that mean that the class invariant number `2` failed. +Therefore, the assertion number is not useful if a single handler is programmed for all types of contracts because such an handler can no longer distinguish between class invariants, preconditions, postconditions, etc. +] + +In all these cases the contract assertion is considered failed because it was not evaluated to be true (and that is the case not only for assertions that are evaluated to be false but also for assertions that throw exceptions while being evaluated). +[footnote +*Rationale.* +Threating an exception thrown while evaluating an assertion as a failure of the contract assertion is a clear policy established by this library under the principle that a contract assertion fails unless it is evaluated to be true. +__N1962__ does not completely clarify this point. +] +The customized contract broken handlers can re-throw the active exception and catch it so to inspect it for logging or for any other customized behaviour that might need to be implemented by the programmers. + +The following example customizes the contract broken handlers to throw exceptions (both user-defined exceptions like `not_a_number` and the [classref contract::broken] exception that the library automatically throws in case of a contract assertion failure). +However, the customized handlers never throw from within a destructor to comply with STL exception safety requirements (see also [file example/contracts broken_handler_sqrt.cpp]): +[footnote +In this example, contract failures from destructors are logged and then simply ignored. +That might be acceptable in this simple example but it is probably a very bad idea in general. +] + +[import ../example/contracts/broken_handler_sqrt.cpp] +[broken_handler_sqrt] + +Note how the ternary operator `:?` can be used to program assertions that throw exceptions on failure: + + x >= 0.0 ? true : throw not_a_number + +Then the contract broken handlers are customized to propagate the exceptions instead of handling them by calling `std::terminate` (default behaviour). + +See also [file example/contracts contract_failure.cpp] for a more complex example that redefines the contract broken handlers to throw exceptions in order to automatically check that the correct contract broken handlers are called when assertions fail in accordance with the call semantics explained in the __Contract_Programming_Overview__ section. + +[endsect] + +[endsect] + diff --git a/doc/bibliography.qbk b/doc/bibliography.qbk new file mode 100644 index 0000000..cedb89a --- /dev/null +++ b/doc/bibliography.qbk @@ -0,0 +1,77 @@ + +[/ 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 Bibliography] + +[#Bright04_anchor] [Bright04] W. Bright. [@http://www.digitalmars.com/d/2.0/dbc.html /Contract Programming for the D Programming Language/]. 2004. + +[#Bright04b_anchor] [Bright04b] W. Bright. [@http://www.digitalmars.com/ctg/contract.html /Contract Programming for the Digital Mars C++ Compiler/]. 2004. + +[#C2_anchor] [C2] Aechmea. [@http://www.programmersheaven.com/app/news/DisplayNews.aspx?NewsID=3843 /C^2 Contract Programming add-on for C++/]. 2005. + +[#Chrome02_anchor] [Chrome02] RemObjects. [@http://blogs.remobjects.com/blogs/mh/2008/05/01/p216 /Chrome: Contract Programming for Object Pascal in .NET/]. 2002. + +[#Clarke06_anchor] [Clarke06] L. A. Clarke and D. S. Rosenblum. [@http://discovery.ucl.ac.uk/4991/1/4991.pdf /A Historical Perspective on Runtime Assertion Checking in Software Development/]. Newsletter ACM SIGSOFT Software Engineering Notes, 2006. + +[#Cline90_anchor] [Cline90] M. Cline and D. Lea. /The Behaviour of C++ Classes/ and [@http://surface.syr.edu/cgi/viewcontent.cgi?article=1116&context=eecs /Using Annotated C++/]. Proc. of the Symposium on Object Oriented Programming Emphasizing Practical Applications, Maris College, 1990. + +[#Ellis90_anchor] [Ellis90] M. A. Ellis and B. Stroustrup. /The Annotated C++ Reference Manual/. ANSI Base Document, Addison Wesley, 1990. + +[#Gautron92_anchor] [Gautron92] P. Gautron. /An Assertion Mechanism Based on Exceptions/. Fourth C++ Technical Conference, 1992. + +[#Hoare73_anchor] [Hoare73] C. A. R. Hoare. /Hints on Programming Language Design/. Stanford University Artificial Intelligence memo AIM-224/STAN-CS-73-403, pages 193-216, 1973. + +[#CodeContracts_anchor] [CodeContracts] Microsoft Research. [@http://research.microsoft.com/en-us/projects/contracts/ /Code Contracts: Design-By-Contract Programming for All .NET Programming Languages/]. 2012. + +[#iContract_anchor] [iContract] O. Enseling. [@http://www.javaworld.com/javaworld/jw-02-2001/jw-0216-cooltools.html /iContract: Contract Programming for Java/]. 2001. + +[#Jcontract_anchor] [Jcontract] Parasoft. [@http://www.parasoft.com/jsp/products/article.jsp?label=product_info_Jcontract /Jcontract: Contract Programming for Java/]. + +[#Lindrud04_anchor] [Lindrud04] J. Lindrud. [@http://www.codeproject.com/Articles/8293/Design-by-Contract-in-C /Design by Contract in C++/]. 2004. + +[#Maley99_anchor] [Maley99] D. Maley and I. Spence. [@http://www.computer.org/portal/web/csdl/doi/10.1109/TOOLS.1999.779000 /Emulating Design by Contract in C++/]. Proceedings of TOOLS, IEEE Computer Society, 1999. + +[#Meyer97_anchor] [Meyer97] B. Meyer. /Object Oriented Software Construction/. Prentice-Hall, 2nd edition, 1997. + +[#Mitchell02_anchor] [Mitchell02] R. Mitchell and J. McKim. /Design by Contract, by Example/. Addison-Wesley, 2002. + +[#N1613_anchor] [N1613] T. Ottosen. [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1613.pdf /Proposal to add Design by Contract to C++/]. The C++ Standards Committee, N1613, 2004. + +[#N1653_anchor] [N1653] C. Nelson. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm /Working draft changes for C99 preprocessor synchronization/]. C++ Standards Committee, N1653, 2004. + +[#N1669_anchor] [N1669] T. Ottosen. [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1669.html /Proposal to add Contract Programming to C++ (revision 1)/]. The C++ Standards Committee, N1669, 2004. + +[#N1773_anchor] [N1773] D. Abrahams, L. Crowl, T. Ottosen, and J. Widman. [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1773.html /Proposal to add Contract Programming to C++ (revision 2)/]. The C++ Standards Committee, N1773, 2005. + +[#N1866_anchor] [N1866] L. Crowl and T. Ottosen. [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1866.html /Proposal to add Contract Programming to C++ (revision 3)/]. The C++ Standards Committee, N1866, 2005. + +[#N1895_anchor] [N1895] H. Sutter and F. Glassborow. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1895.pdf /Delegating Constructors (revision 2)/]. C++ Standards Committee, N1895, 2005. + +[#N1962_anchor] [N1962] L. Crowl and T. Ottosen. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html /Proposal to add Contract Programming to C++ (revision 4)/]. The C++ Standards Committee, N1962, 2006. + +[#N2081_anchor] [N2081] D. Gregor, B. Stroustrup. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdf /Concepts (revision 1)/]. The C++ Standards Committee, N2081, 2006. + +[#N2914_anchor] [N2914] P. Becker. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2914.pdf /Working Draft, Standard for Programming Language C++/]. The C++ Standards Committee, N2914, 2009. + +[#N2906_anchor] [N2906] B. Stroustrup. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2906.pdf /Simplifying the sue of concepts/]. The C++ Standards Committee, N2906, 2009. + +[#Rosenblum95_anchor] [Rosenblum95] D. S. Rosenblum. [@http://www.cs.toronto.edu/~chechik/courses06/csc410/rosenblum_assert95.pdf /A practical Approach to Programming With Assertions/]. IEEE Transactions on Software Engineering, 1995. + +[#SPARKAda_anchor] [SPARKAda] Praxis. [@http://www.praxis-his.com/sparkada/language.asp /SPARKAda (Ada-like Language with Contract Programming)/]. + +[#SpecSharp_anchor] [SpecSharp] Microsoft. [@http:://research.microsoft.com/en-us/projects/specsharp/ /Spec# (C# Extension)/]. + +[#Stroustrup94_anchor] [Stroustrup94] B. Stroustrup. /The Design and Evolution of C++/. Addison Wesley, 1994. + +[#Stroustrup97_anchor] [Stroustrup97] B. Stroustrup. /The C++ Programming Language/. Prentice-Hall, 2nd Edition, 1997. + +[#Tandin04_anchor] [Tandin04] A. Tandin. [@http://www.codeproject.com/KB/macros/DbC_and_Doxygen.aspx /Design by Contract macros for C++ and link to Doxygen/]. 2004. + +[#Wilson06_anchor] [Wilson06] M. Wilson. [@http://www.artima.com/cppsource/deepspace.html /Contract Programming 101 - The Nuclear Reactor and the Deep Space Probe/]. The C++ Source, 2006. + +[endsect] + diff --git a/doc/concepts.qbk b/doc/concepts.qbk new file mode 100644 index 0000000..dbd880c --- /dev/null +++ b/doc/concepts.qbk @@ -0,0 +1,219 @@ + +[/ 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 Concepts] + +This section explains how to use this library to check concepts. +Concepts are part of the program specifications because they enforce requirements on generic types at compile-time and therefore they are within the scope of this library. + +Concepts were proposed for addition to __CXX11__ but they were unfortunately never adopted (see __N2081__). +The concepts that are checked using this library need to be defined using the __Boost_ConceptCheck__ library. +This library does not add any extra functionality with respect to the concept checking features already provided by __Boost_ConceptCheck__ but it allows to specify both concepts and contracts together within a unified syntax. + +[section Class Templates] + +It is possible to list the concepts to check for class templates using `requires` within the [macroref CONTRACT_CLASS] macro, after the template parameter declarations (see also the __Grammar__ section): + + template( ``/template-parameter1/``, ``/template-parameter2/``, ... ) requires( ``/concept1/``, ``/concept2/``, ... ) + +The following example requires that the generic type `T` specified for the class template `vector` is always __CopyConstructible__ and it uses the `boost::CopyConstructible` concept defined by __Boost_ConceptCheck__ (see also [file example/concepts class_member_concept_vector.hpp], [file example/concepts class_member_concept_vector_error.cpp], and [file example/concepts class_member_concept_vector.cpp]): + +[import ../example/concepts/class_member_concept_vector.hpp] +[class_member_concept_vector_class] + +If the class template `vector` is instantiated on a type `T` that is not __CopyConstructible__, the compiler will generate an error (with the usual format of __Boost_ConceptCheck__ errors). + +[endsect] + +[section Function Templates] + +It is possible to list concepts to check for function templates using `requires` within the [macroref CONTRACT_FUNCTION] macro, after the template parameter declarations (see also the __Grammar__ section). + +For example, for a constructor function template (see also [file example/concepts class_member_concept_vector.hpp], [file example/concepts class_member_concept_vector_constructor_error.cpp], and [file example/concepts class_member_concept_vector.cpp]): + +[class_member_concept_vector_constructor] + +And, for a member function template (see also [file example/concepts class_member_concept_vector.hpp], [file example/concepts class_member_concept_vector_member_error.cpp], and [file example/concepts class_member_concept_vector.cpp]): + +[class_member_concept_vector_member] + +If the `vector` constructor template or the `vector::insert` member function template are instantiated on a type `Iterator` that is not an __InputIterator__, the compiler will generate an error (with the usual format of __Boost_ConceptCheck__ errors). + +So far we have used concepts that are predefined by __Boost_ConceptCheck__ but it is also possible to check user-defined concepts as long as they are defined using __Boost_ConceptCheck__. +For example, consider the following user-defined `Addable` concept (see also [file example/concepts free_concept_operator_preinc.hpp], [file example/concepts free_concept_operator_preinc_error.cpp], and [file example/concepts free_concept_operator_preinc.cpp]): + +[import ../example/concepts/free_concept_operator_preinc.hpp] +[free_concept_operator_preinc] + +If this templated operator `++` is instantiated on a type `T` that is not __Assignable__ or not `Addable`, the compiler will generate an error (with the usual format of __Boost_ConceptCheck__ error). + +Note that concepts can also be specified for free function templates, for free operator templates, and for member operator templates (as illustrated in some of the above examples). + +[endsect] + +[section Concept Definitions (Not Implemented)] + +Using the preprocessor parsing techniques introduced by the library, it should be possible to implement the following syntax to define [@http://en.wikipedia.org/wiki/Concepts_(C%2B%2B) concepts]. +Note how this syntax resembles the syntax proposed by __N2081__ for adding concepts to __CXX11__ (__N2081__ and concepts were unfortunately not adopted by the standard committee). + + CONTRACT_CONCEPT( // A concept definition. + auto concept (LessThanComparable) ( typename T ) + ( + bool operator(<)(less) ( T , T ) + ) + ) + + CONTRACT_CONCEPT( // Concepts with multiple parameters. + auto concept (Convertible) ( typename T, typename U ) + ( + operator(U)(U_type) ( T const& ) + ) + ) + + CONTRACT_CONCEPT( // Concept composition. + concept (InputIterator) ( typename Iterator, typename Value ) + ( + requires Regular, + + (Value) operator(*)(deref) ( Iterator const& ), + (Iterator&) operator(++)(preinc) ( Iterator& ), + (Iterator) operator(++)(postinc) ( Iterator&, int ) + ) + ) + + CONTRACT_CONCEPT( // Derived concepts. + concept (ForwardIterator) ( typename Iterator, typename Value ) + extends( InputIterator ) + ( + // Other requirements here... + ) + ) + + CONTRACT_CONCEPT( // Typenames within concepts. + concept (InputIterator) ( typename Iterator ) + ( + typename value_type, + typename reference, + typename pointer, + typename difference_type, + + requires Regular, + requires (Convertible), + + (reference) operator(*)(deref) ( const Iterator& ), + (Iterator&) operator(++)(preinc) ( Iterator& ), + (Iterator) operator(++)(postinc) ( Iterator&, int ) + ) + ) + + CONTRACT_CONCEPT( // Concept maps. + concept_map (InputIterator) + ( + typedef char value_type, + typedef (char&) reference, + typedef (char*) pointer, + typedef ptrdiff_t difference_type + ) + ) + + CONTRACT_CONCEPT( // Concept maps can be templated. + template( typename T ) + concept_map (InputIterator) ( T* ) + ( + typedef (T&) value_type, + typedef (T&) reference, + typedef (T*) pointer, + typedef ptrdiff_t difference_type + ) + ) + + CONTRACT_CONCEPT( // Concept maps as mini-types. + concept (Stack) ( typename X ) + ( + typename value_type, + + void (push) ( X&, value_type const& ), + void (pop) ( X& ), + (value_type) (top) ( X const& ), + bool (empty) ( X const& ) + ) + ) + + CONTRACT_CONCEPT( // Concept maps as mini-types (specializations). + template( typename T ) + concept_map (Stack) ( std::vector ) + ( + typedef (T) value_type, + + void (push) ( (std::vector&) v, (T const&) x ) + ( + v.push_back(x); + ), + + void (pop) ( (std::vector&) v ) + ( + v.pop_back(); + ), + + (T) (top) ( (std::vector const&) v ) + ( + return v.back(); + ), + + bool (empty) ( (std::vector const&) v ) + ( + return v.emtpy(); + ) + ) + ) + + CONTRACT_CONCEPT( // Axioms. + concept (Semigroup) ( typename Op, typename T ) + extends( CopyConstructible ) + ( + (T) operator(())(call) ( Op, T, T ), + + axiom (Associativity) ( (Op) op, (T) x, (T) y, (T) z ) + ( + op(x, op(y, z)) == op(op(x, y), z); + ) + ) + ) + +Note that: + +# Parenthesis around function parameter types can be always allowed but they should be required only when the parameter name is also specified. +# The function bodies need to be specified within the macros and that will make compiler errors very hard to use (because the errors will all refer to the same line number, the line number on which the `CONTRACT_CONCEPT` macro expanded). +However, concept definitions, including possible function bodies, might be simple enough for this not to be a major issue at least in the most common cases (the authors do not have enough experience with programming concept definitions to truly assess this). + +The authors /think/ this syntax can be implemented and parsed using the preprocessor however the authors have not tried to implement this yet. +If this syntax can indeed be implemented, it should then be investigated if the actual concept definitions can be programmed from the parsed concept traits using C++ (this seems possible at least for __CXX11__ based on some work done for the [@http://zao.se/~zao/boostcon/11/slides/Boost.Generic.pdf Generic] library). + +The authors recognize that implementing concept definitions would be a nice addition to this library (again, concepts are parts of the program specifications, they are contracts on the type system that are checked at compile-time, so both concept checking and concept definition are within the scope of this library). +However, at the moment there are no concrete plans for extending this library with the concept definitions (see also [@https://sourceforge.net/apps/trac/contractpp/ticket/49 Ticket 49]). + +The following is a side-by-side comparison of this possible concept definition syntax with the syntax proposed by __N2081__: + +[import ../example/concepts/concept_def.cpp] +[import ../example/concepts/concept_def_npaper.cpp] +[table +[ [Possible Extension of This Library (not implemented)] [\[N2081\] Proposal (not part of C++)] ] +[ [[concept_def]] [[concept_def_npaper]] ] +] + +Note that: + +# Extra wrapping parenthesis are used when expressions contain unwrapped commas `,` or leading symbols. +# The specifiers `constructor`, `destructor`, and `member` follow the same syntax as the [macroref CONTRACT_CONSTRUCTOR_BODY] and [macroref CONTRACT_DESTRUCTOR_BODY], and they serve a purpose similar to these macros in naming the constructors, destructors, and member functions outside class declarations. + +If concept definitions were added to this library, concepts would still be checked using the `requires` specifier in class and function declarations as we have seen so far (it might even be possible for concepts defines using __Boost_ConceptCheck__ to be still specified using some type tagging of this library concept types to internally distinguish between __Boost_ConceptCheck__ concepts and concepts define using this library). +Furthermore, this library could provide all the standard concepts defined in __N2914__ in an header file =contract/std/concept.hpp=. + +[endsect] + +[endsect] + diff --git a/doc/contract_programming_overview.qbk b/doc/contract_programming_overview.qbk new file mode 100644 index 0000000..6c5ed4a --- /dev/null +++ b/doc/contract_programming_overview.qbk @@ -0,0 +1,528 @@ + +[/ 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). + +[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. +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. + +[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. +[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 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. +] ] +] + +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). + +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): + +# `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. +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. + +[endsect] + +[section 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__. + +[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. +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] [ +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. +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] [ +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. +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] [ +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] [ +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] [ +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] [ +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] + +[section Costs] + +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 the following: + +# 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 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]). + +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. + +[endsect] + +[section Free 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: + +# Check the function preconditions. +# Execute the function body. +# Check the function postconditions. + +[endsect] + +[section Member Function Calls] + +A member function call executes the following steps: + +# 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. + +[#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: + +* `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. + +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 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. + +Note that: + +* 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. + +[endsect] + +[section Constructor Calls] + +A constructor call executes the following steps: + +# 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). +# 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. + +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. + +Note that: + +* 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. + +[endsect] + +[section Destructor Calls] + +A destructor call executes the following steps: + +# 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). +[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. +] +# Check the non-static class invariants, but only if the body threw an exception. + +C++ object destruction mechanism will automatically check base class contracts when subcontracting. + +Note that: + +* 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]). +] +* 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. + +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). + +[endsect] + +[section Specification vs. 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. +] + +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). +[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. +] + +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] + +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. + +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. + +[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__. + +[table +[ + [Feature] + [This Library (C++03)] + [\[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=] +][ + [['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] +][ + [['Result value in postconditions]] + [Yes, `auto `[^['result-variable-name]]` = return`.] + [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]].] + [No.] +][ + [['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.] + [Yes.] +][ + [['Contracts for pure virtual functions]] + [Yes.] + [Yes.] + [Yes (contracts for abstract functions).] + [No (but planned).] +][ + [['Arbitrary code in contracts]] + [No, assertions only.] + [No, assertions only.] + [No, assertions only plus preconditions can only access public members.] + [Yes.] +][ + [['Constant-correct]] + [Yes.] + [Yes.] + [Yes.] + [No.] +][ + [['Function code ordering]] + [Preconditions, postconditions, 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]] + [ + 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 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.] + [Disable all checks.] + [Disable nothing.] +][ + [['Non-static class invariants 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 Programming is also provided by the following references. + +[table +[ [Reference] [Language] [Notes] ] +[ [__Bright04b__] [C++] [ +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). +] ] +[ [__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. +] +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). +] ] +[ [__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.) +] ] +[ [__C2__] [C++] [ +This uses an external preprocessing tool (the authors could no longer find this project code-base to evaluate it). +] ] +[ [__iContract__] [Java] [ +This uses an external preprocessing tool. +] ] +[ [__Jcontract__] [Java] [ +This uses an external preprocessing tool. +] ] +[ [__CodeContracts__] [.NET] [ +Microsoft Contract Programming for .NET programming languages. +] ] +[ [__SpecSharp__] [C#] [ +This is a C# extension with Contract Programming language support. +] ] +[ [__Chrome02__] [Object Pascal] [ +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. +] ] +] + +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). + +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). + +[endsect] + +[endsect] + diff --git a/doc/contractpp.qbk b/doc/contractpp.qbk new file mode 100644 index 0000000..80197c6 --- /dev/null +++ b/doc/contractpp.qbk @@ -0,0 +1,137 @@ + +[/ 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++ + [quickbook 1.5] + [version 0.4.1] + [authors [Caminiti lorcaminiti@gmail.com, Lorenzo]] + [copyright 2008-2012 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] +] + +[template file[dir name] ''''''[^[name]]''''''] + +[def __CXX03__ [@http://en.wikipedia.org/wiki/C%2B%2B C++03]] +[def __CXX11__ [@http://en.wikipedia.org/wiki/C%2B%2B11 C++11]] +[def __C99__ [@http://en.wikipedia.org/wiki/C99 C99]] +[def __Java__ [@http://en.wikipedia.org/wiki/Java_(programming_language) Java]] +[def __Ada__ [@http://en.wikipedia.org/wiki/Ada_(programming_language) Ada]] +[def __Python__ [@http://www.python.org/ Python]] +[def __Eiffel__ [@http://en.wikipedia.org/wiki/Eiffel_(programming_language) Eiffel]] +[def __D__ [@http://dlang.org D]] +[def __substitution_principle__ [@http://en.wikipedia.org/wiki/Liskov_substitution_principle substitution principle]] +[def __Doxygen__ [@http://www.doxygen.org Doxygen]] +[def __SFINAE__ [@http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error SFINAE]] + +[def __Boost__ [@http://www.boost.org Boost]] +[def __Boost_ConceptCheck__ [@http://www.boost.org/doc/libs/release/libs/concept_check Boost.ConceptCheck]] +[def __Boost_Config__ [@http://www.boost.org/doc/libs/release/libs/config Boost.Config]] +[def __Boost_Foreach__ [@http://www.boost.org/doc/libs/release/libs/foreach Boost.Foreach]] +[def __Boost_Function__ [@http://www.boost.org/doc/libs/release/libs/function Boost.Function]] +[def __Boost_Graph__ [@http://www.boost.org/doc/libs/release/libs/graph Boost.Graph]] +[def __Boost_Jam__ [@http://www.boost.org/doc/libs/release/doc/html/jam.html Boost.Jam]] +[def __Boost_LocalFunction__ [@http://www.boost.org/doc/libs/release/libs/local_function Boost.LocalFunction]] +[def __Boost_MPL__ [@http://www.boost.org/doc/libs/release/libs/mpl Boost.MPL]] +[def __Boost_Parameter__ [@http://www.boost.org/doc/libs/release/libs/parameter Boost.Parameter]] +[def __Boost_Phoenix__ [@http://www.boost.org/doc/libs/release/libs/phoenix Boost.Phoenix]] +[def __Boost_Preprocessor__ [@http://www.boost.org/doc/libs/release/libs/preprocessor Boost.Preprocessor]] +[def __Boost_Python__ [@http://www.boost.org/doc/libs/release/libs/python Boost.Python]] +[def __Boost_Typeof__ [@http://www.boost.org/doc/libs/release/libs/typeof Boost.Typeof]] +[def __Boost_TypeTraits__ [@http://www.boost.org/doc/libs/release/libs/type_traits Boost.TypeTraits]] +[def __Boost_Utility_IdentityType__ [@http://www.boost.org/doc/libs/release/libs/utility/identity_type Boost.Utility/IdentityType]] + +[def __Bright04__ [link Bright04_anchor \[Bright04\]]] +[def __Bright04b__ [link Bright04b_anchor \[Bright04b\]]] +[def __C2__ [link C2_anchor \[C2\]]] +[def __Chrome02__ [link Chrome02_anchor \[Chrome02\]]] +[def __Cline90__ [link Cline90_anchor \[Cline90\]]] +[def __CodeContracts__ [link CodeContracts_anchor \[CodeContracts\]]] +[def __iContract__ [link iContract_anchor \[iContract\]]] +[def __Hoare73__ [link Hoare73_anchor \[Hoare73\]]] +[def __Jcontract__ [link Jcontract_anchor \[Jcontract\]]] +[def __Lindrud04__ [link Lindrud04_anchor \[Lindrud04\]]] +[def __Maley99__ [link Maley99_anchor \[Maley99\]]] +[def __Meyer97__ [link Meyer97_anchor \[Meyer97\]]] +[def __Mitchell02__ [link Mitchell02_anchor \[Mitchell02\]]] +[def __N1613__ [link N1613_anchor \[N1613\]]] +[def __N1866__ [link N1866_anchor \[N1866\]]] +[def __N1962__ [link N1962_anchor \[N1962\]]] +[def __N2081__ [link N2081_anchor \[N2081\]]] +[def __N2914__ [link N2914_anchor \[N2914\]]] +[def __SPARKAda__ [link SPARKAda_anchor \[SPARKAda\]]] +[def __SpecSharp__ [link SpecSharp_anchor \[SpecSharp\]]] +[def __Stroustrup97__ [link Stroustrup97_anchor \[Stroustrup97\]]] +[def __Stroustrup94__ [link Stroustrup94_anchor \[Stroustrup94\]]] +[def __Tandin04__ [link Tandin04_anchor \[Tandin04\]]] + +[def __Introduction__ [link contract__.introduction Introduction]] +[def __Full_Table_of_Contents__ [link contract__.full_table_of_contents Full Table of Contents]] +[def __Getting_Started__ [link contract__.getting_started Getting Started]] +[def __Contract_Programming_Overview__ [link contract__.contract_programming_overview Contract Programming Overview]] +[def __Costs__ [link contract__.contract_programming_overview.costs Costs]] +[def __Free_Function_Calls__ [link contract__.contract_programming_overview.free_function_calls Free Function Calls]] +[def __Member_Function_Calls__ [link contract__.contract_programming_overview.member_function_calls Member Function Calls]] +[def __Constructor_Calls__ [link contract__.contract_programming_overview.constructor_calls Constructor Calls]] +[def __Destructor_Calls__ [link contract__.contract_programming_overview.destructor_calls Destructor Calls]] +[def __Constant_Correctness__ [link contract__.contract_programming_overview.constant_correctness Constant-Correctness]] +[def __Specification_vs__Implementation__ [link contract__.contract_programming_overview.specification_vs__implementation Specification vs. Implementation]] +[def __Broken_Contracts__ [link contract__.contract_programming_overview.broken_contracts Broken Contracts]] +[def __Features__ [link contract__.contract_programming_overview.features Features]] +[def __Tutorial__ [link contract__.tutorial Tutorial]] +[def __Forward_Declarations_and_Body_Definitions__ [link contract__.tutorial.forward_declarations_and_body_definitions Forward Declarations and Body Definitions]] +[def __Advanced_Topics__ [link contract__.advanced_topics Advanced Topics]] +[def __Assertion_Requirements__ [link contract__.advanced_topics.assertion_requirements Assertion Requirements]] +[def __Contract_Broken_Handlers__ [link contract__.advanced_topics.contract_broken_handlers__throw_on_failure_ Contract Broken Handlers]] +[def __Virtual_Specifiers__ [link contract__.virtual_specifiers Virtual Specifiers]] +[def __Concepts__ [link contract__.concepts Concepts]] +[def __Named_Parameters__ [link contract__.named_parameters Named Parameters]] +[def __Parameter_Identifiers__ [link contract__.named_parameters.parameter_identifiers Parameter Identifiers]] +[def __Examples__ [link contract__.examples Examples]] +[def __Grammar__ [link contract__.grammar Grammar]] +[def __Differences_with_CXX_Syntax__ [link contract__.grammar.differences_with_c___syntax Differences with C++ Syntax]] +[def __No_Variadic_Macros__ [link contract__.no_variadic_macros No Variadic Macros]] +[def __Reference__ [link contract__.reference Reference]] +[def __Bibliography__ [link contract__.bibliography Bibliography]] +[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 __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]]] +[def __DefaultConstructible__ [@http://www.sgi.com/tech/stl/DefaultConstructible.html [^DefaultConstructible]]] +[def __EqualityComparable__ [@http://www.sgi.com/tech/stl/EqualityComparable.html [^EqualityComparable]]] +[def __InputIterator__ [@http://www.sgi.com/tech/stl/InputIterator.html [^InputIterator]]] + +[:['["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. + +Consult this documentation in [@index.html HTML] or [@contractpp.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 grammar.qbk] +[include no_variadic_macros.qbk] +[xinclude reference.xml] +[include release_notes.qbk] +[include bibliography.qbk] +[include acknowledgments.qbk] + diff --git a/doc/examples.qbk b/doc/examples.qbk new file mode 100644 index 0000000..ac55374 --- /dev/null +++ b/doc/examples.qbk @@ -0,0 +1,318 @@ + +[/ 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 Examples] + +This section lists non-trivial examples programmed using this library. +The listed examples are taken from the foloowing sources (which are referenced in the title of each example). + +[table +[ [Sources] [Notes] ] +[ [__N1962__] [ +Examples from the proposal to add Contract Programming to __CXX11__ submitted to the standard committee (unfortunately, this proposal was never accepted into the standard). +] ] +[ [__N2081__] [ +Examples from the proposal to add concepts to __CXX11__ submitted to the standard committee (unfortunately, this proposal was never accepted into the standard). +These examples have been extended to specify both concepts and contracts. +] ] +[ [__Meyer97__ __Mitchell02__] [ +Examples using the __Eiffel__ programming language and reprogrammed using this library for C++. +] ] +[ [__Cline90__] [ +Examples from a very early proposal called Annotated C++ (A++) to add Contract Programming to C++ (A++ was never implemented or proposed for addition to the standard). +] ] +[ [__Stroustrup97__] [ +One example that shows the importance of class invariants and how to configure this library to throw exceptions instead of terminating the program when contracts are broken. +] ] +] + +The followings are among the most interesting examples: + +[table +[ [Key Example] [Topic] ] +[ [[link contract__.examples.__n1962___vector__comparison_with_c___proposed_syntax \[N1962\] Vector]] [ +A comparison between this library syntax and the syntax for contract and concept checking proposed by __N1962__ and __N2081__ respectively. +] ] +[ [[link contract__.examples.__n2081___add__generic_addition_algorithm \[N2081\] Add]] [ +Contracts and user-defined concepts. +] ] +[ [[link contract__.examples.__mitchell02___counter__subcontracting_and_virtual_specifiers__final__override__new__and_pure_virtual_ \[Mitchell02\] Counter]] [ +Subcontracting and __CXX11__-like virtual specifiers `final`, `override`, `new`, and pure virtual. +] ] +[ [[link contract__.examples.__meyer97___stack4__comparison_with_eiffel_syntax \[Meyer97\] Stack4]] [ +A comparison between this library and __Eiffel__ syntax for preconditions, postconditions, and class invariants. +] ] +[ [[link contract__.examples.__meyer97___gcd__loop_variants_and_invariants_plus_comparison_with_eiffel_syntax \[Meyer97\] GCD]] [ +A comparison between this library and __Eiffel__ syntax for loop variants and block invariants. +] ] +[ [[link contract__.examples.__cline90___vector__comparison_with_a___proposed_syntax \[Cline90\] Vector]] [ +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] +[table + [ [This Library (C++03)] [\[N1962\] and \[N2081\] Proposals (not part of C++)] ] + [ [[n1962_vector]] [[n1962_vector_npaper]] ] + [ [[n1962_vector_main]] [] ] +] +[endsect] + +[section \[N1962\] Circle: Subcontracting] +[import ../example/n1962/circle.cpp] +[n1962_circle] +[endsect] + +[section \[N1962\] Factorial: Recursion and assertion computational complexity] +[import ../example/n1962/factorial.cpp] +[n1962_factorial] +[endsect] + +[section \[N1962\] Equal: Operators] +[import ../example/n1962/equal.hpp] +[n1962_equal_header] +[import ../example/n1962/equal_not.hpp] +[n1962_equal_not_header] +[import ../example/n1962/equal_main.cpp] +[n1962_equal_main] +[endsect] + +[section \[N1962\] Sum: Separated body definitions] +[import ../example/n1962/sum.hpp] +[n1962_sum_header] +[import ../example/n1962/sum.cpp] +[n1962_sum] +[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] +[table + [ [This Library (C++03)] [The D Programming Language] ] + [ [[n1962_sqrt]] [[n1962_sqrt_d]] ] +] +[endsect] + +[section \[N1962\] Block: Block invariants] +[import ../example/n1962/block_invariant.cpp] +[n1962_block_invariant] +[endsect] + +[section \[N2081\] Add: Generic addition algorithm] +[import ../example/n2081/add.hpp] +[n2081_add_header] +[import ../example/n2081/add.cpp] +[n2081_add] +[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] +[n2081_advance] +[endsect] + +[section \[N2081\] Find: Generic find algorithm] +[import ../example/n2081/find.hpp] +[n2081_find_header] +[import ../example/n2081/find.cpp] +[n2081_find] +[import ../example/n2081/find_error.cpp] +[n2081_find_error] +[endsect] + +[section \[N2081\] Apply: Overloaded invocation of functors] +[import ../example/n2081/apply.cpp] +[n2081_apply] +[endsect] + +[section \[N2081\] For Each: Generic for-each algorithm] +[import ../example/n2081/for_each.cpp] +[n2081_for_each] +[endsect] + +[section \[N2081\] Transform: Generic binary transformation algorithm] +[import ../example/n2081/transform.cpp] +[n2081_transform] +[endsect] + +[section \[N2081\] Count: Generic counting algorithm] +[import ../example/n2081/count.cpp] +[n2081_count] +[endsect] + +[section \[N2081\] Convert: Conversion between two types] +[import ../example/n2081/convert.hpp] +[n2081_convert_header] +[import ../example/n2081/convert.cpp] +[n2081_convert] +[import ../example/n2081/convert_error.cpp] +[n2081_convert_error] +[endsect] + +[section \[N2081\] Equal: Generic equality comparison] +[import ../example/n2081/equal.hpp] +[n2081_equal_header] +[import ../example/n2081/equal.cpp] +[n2081_equal] +[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] +[n2081_less_eq] +[endsect] + +[section \[N2081\] De-Ref: Generic iterator dereferencing] +[import ../example/n2081/deref.cpp] +[n2081_deref] +[endsect] + +[section \[N2081\] Min: Generic minimum algorithm] +[import ../example/n2081/min.hpp] +[n2081_min_header] +[import ../example/n2081/min.cpp] +[n2081_min] +[import ../example/n2081/min_error.cpp] +[n2081_min_error] +[endsect] + +[section \[Meyer97\] Stack4: Comparison with Eiffel syntax] +[import ../example/meyer97/stack4.hpp] +[import ../example/meyer97/stack4_main.cpp] +[import ../example/meyer97/stack4.e] +[table + [ [This Library (C++03)] [The Eiffel Programming Language] ] + [ [[meyer97_stack4_header]] [[meyer97_stack4_e]] ] + [ [[meyer97_stack4_main]] [] ] +] +[endsect] + +[section \[Meyer97\] Stack3: Error codes instead of preconditions] +[import ../example/meyer97/stack3.cpp] +[meyer97_stack3] +[endsect] + +[section \[Meyer97\] GCD: Loop variants and invariants plus comparison with Eiffel syntax] +[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++]] ] +] +[endsect] + +[section \[Meyer97\] Max-Array: Nested loop variants and invariants] +[import ../example/meyer97/maxarray.cpp] +[meyer97_maxarray] +[endsect] + +[section \[Mitchell02\] Name List: Relaxed subcontracts] +[import ../example/mitchell02/name_list.hpp] +[mitchell02_name_list_header] +[import ../example/mitchell02/name_list.cpp] +[mitchell02_name_list] +[import ../example/mitchell02/name_list_main.cpp] +[mitchell02_name_list_main] +[endsect] + +[section \[Mitchell02\] Dictionary: Simple key-value map] +[import ../example/mitchell02/dictionary.cpp] +[mitchell02_dictionary] +[endsect] + +[section \[Mitchell02\] Courier: Subcontracting and static class invariants] +[import ../example/mitchell02/courier.hpp] +[mitchell02_courier_header] +[import ../example/mitchell02/courier.cpp] +[mitchell02_courier] +[import ../example/mitchell02/courier_main.cpp] +[mitchell02_courier_main] +[endsect] + +[section \[Mitchell02\] Stack: Simple stack dispenser] +[import ../example/mitchell02/stack.cpp] +[mitchell02_stack] +[endsect] + +[section \[Mitchell02\] Simple Queue: Simple queue dispenser] +[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] +[mitchell02_customer_manager_header] +[import ../example/mitchell02/customer_manager.cpp] +[mitchell02_customer_manager] +[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] +[mitchell02_observer_header] +[import ../example/mitchell02/observer/subject.hpp] +[mitchell02_subject_header] +[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] +[mitchell02_push_button_header] +[import ../example/mitchell02/counter/decrement_button.hpp] +[mitchell02_decrement_button_header] +[import ../example/mitchell02/counter/counter.hpp] +[mitchell02_counter_header] +[import ../example/mitchell02/counter_main.cpp] +[mitchell02_counter_main] +[endsect] + +[section \[Stroustrup97\] String: Throw when contract is broken] +[import ../example/stroustrup97/string.hpp] +[stroustrup97_string_header] +[import ../example/stroustrup97/string.cpp] +[stroustrup97_string] +[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] +[table + [ [This Library (C++03)] [A++ Proposal (not part of C++)] ] + [ [[cline90_vector_header]] [[cline90_vector_app_header]] ] + [ [[cline90_vector_main]] [] ] +] +[endsect] + +[section \[Cline90\] Stack: Function-Try blocks and exception specifications] +[import ../example/cline90/stack.cpp] +[cline90_stack] +[endsect] + +[section \[Cline90\] Vector-Stack: Subcontracting from Abstract Data Type (ADT)] +[import ../example/cline90/vstack.cpp] +[cline90_vstack] +[endsect] + +[section \[Cline90\] Calendar: A very simple calendar] +[import ../example/cline90/calendar.cpp] +[cline90_calendar] +[endsect] + +[endsect] + diff --git a/doc/full_table_of_contents.qbk b/doc/full_table_of_contents.qbk new file mode 100644 index 0000000..4188126 --- /dev/null +++ b/doc/full_table_of_contents.qbk @@ -0,0 +1,248 @@ + +[/ 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/getting_started.qbk b/doc/getting_started.qbk new file mode 100644 index 0000000..b9436bf --- /dev/null +++ b/doc/getting_started.qbk @@ -0,0 +1,131 @@ + +[/ 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 Getting Started] + +This section explains how to setup a system to use 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. + +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. +[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. +] + +[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: + +# 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. +] + +# Microsoft Visual C++ (MSVC) 8.0 on Windows XP and Windows 7. + +At present, the library has not been tested on other compilers or platforms. + +[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. + +[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: + +* 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. + +[endsect] + +[endsect] + diff --git a/doc/grammar.qbk b/doc/grammar.qbk new file mode 100644 index 0000000..fd0d8e4 --- /dev/null +++ b/doc/grammar.qbk @@ -0,0 +1,780 @@ + +[/ 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 ] + +[def __assertion__ [link assertion_anchor [^['assertion]]]] +[def __assertion_condition__ [link assertion_condition_anchor [^['assertion-condition]]]] +[def __assertion_expression__ [link assertion_expression_anchor [^['assertion-expression]]]] +[def __preconditions__ [link preconditions_anchor [^['preconditions]]]] +[def __base_classes__ [link base_classes_anchor [^['base-classes]]]] +[def __boolean_condition__ [link boolean_condition_anchor [^['boolean-condition]]]] +[def __class_declaration__ [link class_declaration_anchor [^['class-declaration]]]] +[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_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]]]] +[def __fundamental_type__ [link fundamental_type_anchor [^['fundamental-type]]]] +[def __inscope_variables__ [link inscope_variables_anchor [^['inscope-variables]]]] +[def __loop_variant__ [link loop_variant_anchor [^['loop-variant]]]] +[def __member_initializers__ [link member_initializers_anchor [^['member-initializers]]]] +[def __named_function_parameter__ [link named_function_parameter_anchor [^['named-function-parameter]]]] +[def __named_function_parameters__ [link named_function_parameters_anchor [^['named-function-parameters]]]] +[def __named_parameter_declaration__ [link named_parameter_declaration_anchor [^['named-parameter-declaration]]]] +[def __named_template_parameter__ [link named_template_parameter_anchor [^['named-template-parameter]]]] +[def __named_template_parameters__ [link named_template_parameters_anchor [^['named-template-parameters]]]] +[def __named_template_template_parameter__ [link named_template_template_parameter_anchor [^['named-template-template-parameter]]]] +[def __named_type_template_parameter__ [link named_type_template_parameter_anchor [^['named-type-template-parameter]]]] +[def __named_value_template_parameter__ [link named_value_template_parameter_anchor [^['named-value-template-parameter]]]] +[def __oldof_declaration__ [link oldof_declaration_anchor [^['oldof-declaration]]]] +[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 __postconditions__ [link postconditions_anchor [^['postconditions]]]] +[def __return_type__ [link return_type_anchor [^['result-type]]]] +[def __cv_qualifier__ [link cv_qualifier_anchor [^['cv-qualifier]]]] +[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 __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 __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 __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]]]] +[def __class_name__ [link class_name_anchor [^[*class-name]]]] +[def __class_type__ [link class_type_anchor [^[*class-type]]]] +[def __constant_boolean_expression__ [link constant_boolean_expression_anchor [^[*constant-boolean-expression]]]] +[def __constant_string_literal__ [link constant_string_literal_anchor [^[*constant-string-literal]]]] +[def __exception_type__ [link exception_type_anchor [^[*exception-type]]]] +[def __function_identifier__ [link function_identifier_anchor [^[*function-identifier]]]] +[def __inscope_variable__ [link inscope_variable_anchor [^[*inscope-variable]]]] +[def __loop_declaration__ [link loop_declaration_anchor [^[*loop-declaration]]]] +[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_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 __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] + +[:['["Almost every macro demonstrates a flaw in the programming language, in the program, or in the programmer.]]] +[:['-- Bjarne Stroustrup (see __Stroustrup97__ page 160)]] + +This library uses macros to overcome a limitation of C++, namely the fact that the core language does not support preconditions, postconditions, class invariants, old values, and subcontracting. +This section lists the complete grammar of the syntax used by this library macros. + +[#syntax_error_warning_anchor] +[warning +In general, an error in programming this library syntax will generate cryptic compiler errors (often exposing internal code from this library and from __Boost_Preprocessor__). +[footnote +Usually, the complexity of C++ definitions is greater than the complexity of C++ declaration and the fact that this library macros only affect declarations would help by preserving the usefulness of the compiler error messages for the definition code. +However, this library aims to make declarations more complex by adding program specifications to them (preconditions, postconditions, etc). +Therefore, it can no longer be argued that declarations are significantly simpler than definitions and it would be rather helpful to have sensible compiler error messages at least for the declarations with contracts. +] + +There are intrinsic limitations on the amount of error checking that can be implemented by this library because it uses the preprocessor to parse its syntax (e.g., there is no way the preprocessor can gracefully detect and report unbalanced round parenthesis `( ... /* missing closing parenthesis here */` or an invalid concatenation symbol `BOOST_PP_CAT(xyz, ::std::vector)`). +In addition, for a given macro all compiler error messages report the same line number (because macros always expand on a single line) so line numbers are not very useful in identifying syntactic errors. + +While the preprocessor imposes limits on the error checking that can be implemented, the current version of this library does not focus on providing the best possible syntax error messages (this will be the focus of future releases, see also [@https://sourceforge.net/apps/trac/contractpp/ticket/44 Ticket 44]). +] + +The best way to resolve syntactic errors is for programmers to inspect the code ["by eye] instead of trying to make sense of the compiler errors. +This section is very useful for programmers to make sure that they are using the syntax correctly. + +[section Preprocessor DSEL] + +The syntax used by this library macros effectively defies a new language within C++. +More precisely, this library macros define a [@http://en.wikipedia.org/wiki/Domain-specific_language Domain-Specific Embedded Language (DSEL)] that replaces the usual C++ syntax for class and function declarations. +This is the ['Language of Contract++] (or ['LC++] for short). + +In contrast with other DSEL hosted by C++ which are parsed using template meta-programming (e.g., __Boost_Phoenix__), this library DSEL is parsed ["one meta-programming level higher] using preprocessor meta-programming. +Using both processor meta-programming and template meta-programming allows this library to implement rules like this: + + ``/if a member function is not public then it does not check the class invariants/`` + +This rule cannot be implemented using only template meta-programming because it is not possible to check if a function is public using template meta-programming introspection techniques. +For example, it is not possible to implement a boolean meta-function like the following: +[footnote +Using __CXX11__, it /might/ be possible to implement the `is_public` template because __SFINAE__ was extended to support access level (but to the authors' knowledge such a meta-function has not been implemented yet so the authors cannot be sure that `is_public` can be properly implemented even using __CXX11__ __SFINAE__). +Even if that were possible in __CXX11__, this library still needs declaration traits other than `public` in oder to properly implement Contract Programming (e.g., if a function is `virtual` or not in order to implement subcontracting, and there are examples like that). +Therefore, the arguments made here for the need to use a preprocessor DSEL in oder to properly implement Contract Programming in C++ hold even if `is_public` could be implemented in __CXX11__. +] + + template< ... > + struct is_public { ... }; // Unfortunately, this cannot be implemented. + +Instead a macro can be programmed to parse the following function declarations and expand to `1` if and only if the function is public: + + #define IS_PUBLIC(function_declaration) ... // This can be implemented. + + IS_PUBLIC( public void (f) ( int x ) ) // Expand to 1. + IS_PUBLIC( private void (g) ( int y ) ) // Expand to 0. + IS_PUBLIC( void (h) ( int z ) ) // Expand to 0. + +There are more examples of class and function declaration traits (`virtual`, etc) that need to be known to correctly implement Contract Programming but that cannot be inspected using template meta-programming. +This library macros can instead parse the specified class and function declarations extracting /any/ declaration trait (if a constructor is `explicit`, if a member function is `virtual`, if a base class is `protected`, if a parameter has a default value, etc). + +It should be noted that while the syntax of the DSEL defined by this library macros is rather extensive and complex, macros always define a DSEL that is intrinsically different from the core C++ language. +For example, consider the following function-like macro: + + #define F(x, y) (int(x) - int(y)) + + template< typename X, typename Y > + int f ( X const& x, Y const& y ) { return (int(x) - int(y)); } + + int main ( void ) + { + std::cout << F( , 2) << std::endl; // OK, no syntax error, it prints `-2`. + std::cout << f( , 2) << std::endl; // Compiler generates a syntax error. + return 0; + } + +Note how it is valid to invoke the macro with an empty parameter `F( , 2)` while it is syntactically invalid to invoke a function with an empty parameter `f( , 2)`. +This very simple macro already shows fundamental differences between the syntax of macros and the syntax of the core language. + +[endsect] + +[section Differences with C++ 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] ] +[ [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. +] ] +[ [3] [Class and Function Names, and Operators] [ +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. +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. +] ] +[ [6] [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). +] ] +[ [7] [Member Initializers] [ +Use `initialize( `[^['member-initializers]]` )` instead of the column symbol `: `[^['member-initializers]] to specify a constructor's 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.). +] ] +] + +[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). +] + +[endsect] + +[section Macro Interface] + +This library uses the following macros. + + ``[macroref CONTRACT_CLASS]``(__class_declaration__) + ``[macroref CONTRACT_CLASS_TPL]``(__class_declaration__) + + ``[macroref CONTRACT_CONSTRUCTOR]``(__function_declaration__) + ``[macroref CONTRACT_CONSTRUCTOR_TPL]``(__function_declaration__) + ``[macroref CONTRACT_CONSTRUCTOR_BODY]``(__class_type__, __class_name__) + + ``[macroref CONTRACT_DESTRUCTOR]``(__function_declaration__) + ``[macroref CONTRACT_DESTRUCTOR_TPL]``(__function_declaration__) + ``[macroref CONTRACT_DESTRUCTOR_BODY]``(__class_type__, ~__class_name__) + + ``[macroref CONTRACT_MEMBER]``(__function_declaration__) + ``[macroref CONTRACT_MEMBER_TPL]``(__function_declaration__) + ``[macroref CONTRACT_MEMBER_BODY]``(__function_name__) + + ``[macroref CONTRACT_FUNCTION]``(__function_declaration__) + ``[macroref CONTRACT_FUNCTION_TPL]``(__function_declaration__) + ``[macroref 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] + +[section Lexical Conventions] + +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. +] ] +[ [[^['{]expression['}]]] [ +The result of the enclosed expression `expression` (evaluation order). ] [ +Curly brackets in italic font. +] ] +[ [[^symbol1 ['|] symbol2]] [ +Either `symbol1` or `symbol2` (["or] operation). ] [ +Vertical bar in italic font. +] ] +[ [[^symbol['*]]] [ +`symbol` repeated zero or more times (repetition starting from zero). ] [ +Asterisk in italic font. +] ] +[ [[^symbol['+]]] [ +`symbol` repeated one or more times (repetition starting from one). ] [ +Plus in italic front. +] ] +[ [[^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. +] ] +[ [[^[*symbol]]] [ +Terminal symbol (defined outside this grammar). ] [ +Dash separated words in bold font. +] ] +[ [[^['symbols]]] [ +Non-terminal symbol (defined within this grammar). ] [ +Dash separated words in italic font. +] ] +] + +[endsect] + +[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__ )``/]/`` + ``/[/``invariant(__class_invariants__)``/]/`` + ``/[/``static invariant(__class_invariants__)``/]/`` + ``/[/``invariant volatile(__class_invariants__)``/]/`` + +[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__``/, .../`` + +[endsect] + +[section Base Classes] + + __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). + +[endsect] + +[section Types] + + __wrapped_type__``/:/ [#wrapped_type_anchor]`` + (__type__``/[/``...``/]/``) ``/|/`` __fundamental_type__ ``/|/`` decltype(__expression__) + + __fundamental_type__``/:/ [#fundamental_type_anchor]`` + ``/{/``const ``/|/`` volatile ``/|/`` long ``/|/`` short ``/|/`` signed ``/|/`` unsigned ``/|/`` + void ``/|/`` bool ``/|/`` char ``/|/`` char16_t ``/|/`` char32_t ``/|/`` double ``/|/`` float ``/|/`` int ``/|/`` wchar_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...)`). + +[endsect] + +[section Function Declarations] + + __function_declaration__``/:/ [#function_declaration_anchor]`` + ``/[/``verbatim(__attributes__)``/]/`` + ``/[/````/[/``export``/]/`` ``/[/``template( ``/[/``__template_parameters__``/]/`` )``/]/`` + __classifiers__ ``/[/``__return_type__``/]/`` __function_name__ ( __function_parameters__ ) __qualifiers__ + ``/[/``__exception_specifications__``/]/`` ``/[/``return __wrapped_type__``/]/`` + ``/[/``precondition( __preconditions__ )``/]/`` + ``/[/``postcondition( __postconditions__ )``/]/`` + +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__). + +In __CXX11__ the object `this` of a member functions case be specified as lvalue using `ref` (instead of the usual __CXX11__ `&`) or as a rvalue using `ref ref` (instead of the usual CXX11 `&&`) after the function parameters and the optional cv-qualifier. + +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 +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. +] + +[endsect] + +[section Function Return Type] + + __return_type__``/:/ [#return_type_anchor]`` + __wrapped_type__ ``/|/`` auto + +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(x), 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`. + +[endsect] + +[section Function and Operator Names] + + __function_name__``/:/ [#function_name_anchor]`` + (__function_identifier__) ``/|/`` (__class_name__) ``/|/`` (~__class_name__) ``/|/`` __operator_name__ + + __operator_name__``/:/ [#operator_name_anchor]`` + operator(__operator_symbol__)(__operator_identifier__) ``/|/`` operator __fundamental_type__ ``/|/`` + operator new ``/|/`` operator delete + +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(+)(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: + + 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: + + operator const int // OK. + operator(const int)(const_int) // Also allowed (but less readable). + +Similarly, the parenthesis and alphanumeric identifier are optional for the `new` and `delete` operators: + + operator new // OK. + operator(new)(new_ptr) // Also allowed (but less readable). + + operator delete // OK. + operator(delete)(delete_ptr) // Also allowed (but less readable). + +[endsect] + +[section Function Parameters] + + __function_parameters__``/:/ [#function_parameters_anchor]`` + ``/[/``__function_parameter__``/, .../````/]/`` ``/[/``...``/]/`` ``/|/`` void + + __function_parameter__``/:/ [#function_parameter_anchor]`` + ``/{/````/[/``__storage_classifier__``/]/`` __wrapped_type__ ``/[/``__parameter_name__``/]/````/|/`` + __type__``/}/`` + ``/[/``, default __default_argument__``/]/`` + + __storage_classifier__``/:/`` + auto ``/|/`` register + +Note how this syntax allows to specify variadic functions as usual in C++ using ellipses `...` at the end of the parameter list. + +Note that 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__). + +Note that when the parameter name is not specified, the parenthesis wrapping the parameter type are optional. + +If present, default parameters must be specified at the end of the parameter list as usual in C++. + +[endsect] + +[section Function Classifiers (`static`, etc.)] + + __classifiers__``/:/`` + ``/[/``explicit``/]/`` ``/[/``inline``/]/`` ``/[/``extern``/]/`` ``/[/``static``/]/`` ``/[/``virtual``/]/`` ``/[/``friend``/]/`` + +[endsect] + +[section Function Qualifiers (`const`, etc.)] + + __qualifiers__``/:/`` + ``/[/``const ``/|/`` volatile ``/|/`` const volatile ``/|/`` volatile const``/]/`` ``/[/``ref ``/[/``ref``/]/````/]/`` ``/[/``override``/]/`` ``/[/``final``/]/`` + +Note that member functions are lvalue reference qualified using `ref` (instead of C++11 usual `&`) and rvalue reference qualified using `ref ref` (instead of C++11 usual `&&`). + +[endsect] + +[section Exception Specifications] + + __exception_specifications__``/:/`` + ``/[/``throw( ``/[/``__exception_type__``/, .../````/]/`` ) ``/|/`` noexcept ``/|/`` noexcept(__boolean_constant_expression__)``/]/`` + +[endsect] + +[section Preconditions] + + __preconditions__``/:/ [#preconditions_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. + +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. +Programmers can use the ternary operator `?:` instead of a select assertion if they need to specify a guarded assertion with a condition that is also disabled by the assertion requirements: + + ``/boolean-guard/`` ? __boolean_expression__ : true, requires __constant_boolean_expression__ + +Constant expressions `const( ... ) `[^['expression]] can be used to assert conditions and to check the select assertion if-condition so to fully enforce the assertion constant-correctness requirement. +However, function arguments, result value, old-of values, and the object `this` are automatically made constant by this library so constant expressions only need to be used to assert conditions on global variables, static variables, etc. +The type of the in-scope variable __inscope_variable__ is optional and it is automatically deduced using __Boost_Typeof__ when it is not specified. + +[endsect] + +[section Postconditions] + + __postconditions__``/:/ [#postconditions_anchor]`` + ``/[/``__aliasing__``/, .../````/]/`` + ``/[/``auto __variable_name__ = return,``/]/`` + ``/{/``auto __variable_name__ = ``[macroref CONTRACT_OLDOF]`` __oldof_expression__,``/}*/`` + __assertion__``/, .../`` + +If present, result and old value declarations should appear before any assertion because they will always be visible to all assertions, plus these declarations cannot be nested (within select-assertions, etc). + +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). + +[endsect] + +[section Class Invariants] + + __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. + +[endsect] + +[section Terminals] + +[table +[ +[Terminal] +[Description] +[If terminal contains unwrapped commas or leading symbols] +] [ +[__boolean_expression__[#boolean_expression_anchor]] +[A boolean expression: `x == 1`.] +[Wrap value within parenthesis: `(vey_sizeof::value)`.] +] [ +[__boolean_expression_of_inscope_variables__[#boolean_expression_of_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)`.] +] [ +[__boost_concept__[#boost_concept_anchor]] +[A concept class defined using __Boost_ConceptCheck__: `boost::CopyConstructible`.] +[Wrap type within parenthesis: `(boost::Convertible)`.] +] [ +[__catch_declaration__[#catch_declaration_anchor]] +[The declaration of an exception for a `catch` statement: `std::runtime_error& error`.] +[Wrap type using __Boost_Utility_IdentityType__: `BOOST_IDENTITY_TYPE((map::exception&)) error`.] +] [ +[__catch_instructions__[#catch_instructions_anchor]] +[The instructions of a `catch` statement terminated by semicolons `;`: `std::cout << "error" << std::endl; exit(255);`.] +[Wrap types using __Boost_Utility_IdentityType__ and values within parenthesis: `typedef BOOST_UTILITY_TYPE(std::map) mtype; (mtype m, m['a'] = 1);`.] +] [ +[__class_name__[#class_name_anchor]] +[The class name: `myclass`. For class templates this must not include the template instantiation parameters: `vector`. (For non-template classes, the class type and name are the same.)] +[Never the case.] +] [ +[__class_type__[#class_type_anchor]] +[The class type, for class templates this must include the template instantiation parameters: `vector`.] +[Wrap type within parenthesis: `(map)`.] +] [ +[__constant_boolean_expression__[#constant_boolean_expression_anchor]] +[A compile-time constant boolean expression: `sizeof(T) >= sizeof(int)`.] +[Wrap value within parenthesis: `(boost::is_convertible::value)`.] +] [ +[__constant_string_literal__[#constant_string_literal_anchor]] +[A compile-time constant string literal: `"abc"`.] +[Do nothing: `"abc"`.] +] [ +[__exception_type__[#exception_type_anchor]] +[A type: `std::exception`, `int`, `mytype`.] +[Wrap type within parenthesis: `(map::exception)`.] +] [ +[__function_identifier__[#function_identifier_anchor]] +[A valid function name identifier (C++ requires it to be alphanumeric): `f`, `push_back`, `myfunc`.] +[Never the case.] +] [ +[__inscope_variable__[#inscope_variable_anchor]] +[A variable in-scope.] +[Never the case.] +] [ +[__loop_declaration__[#loop_declaration_anchor]] +[A loop declaration: `for(int i = 0; i < 10; ++i)`, `while(i < 10)`.] +[Never the case.] +] [ +[__member_initializer__[#member_initializer_anchor]] +[A member initialization expression: `vector_(count)`.] +[Wrap object initializations within parenthesis: `(base_map())`.] +] [ +[__named_argument_identifier_name__[#named_argument_identifier_anchor]] +[The argument name to use at the calling site to pass named and deduced parameter values: `value_arg`, `NumberArg`.] +[Never the case.] +] [ +[__named_parameter_identifier_namespace__[#named_parameter_identifier_namespace_anchor]] +[The internal namespace for named and deduced parameter identifiers: `params`.] +[Never the case.] +] [ +[__namespace_alias__[#namespace_alias_anchor]] +[The argument to pass to namespace aliasing: `mpl = boost::mpl`.] +[Never the case.] +] [ +[__natural_expression__[#natural_expression_anchor]] +[A natural (i.e., non-negative integral) expression: `2 - 1`.] +[Wrap value within parenthesis: `(key_sizeof::value)`.] +] [ +[__natural_expression_using_inscope_variables__[#natural_expression_using_inscope_variables_anchor]] +[A natural (i.e., non-negative integral) expression that only uses in-scope variables captured as constant by a constant-expression: `x + 10`.] +[Wrap value within parenthesis: `(key_sizeof::value + x)`.] +] [ +[__new_type_name__[#new_type_name_anchor]] +[A new type name for `typedef` statement: `myint`.] +[Never the case.] +] [ +[__oldof_expression__[#oldof_expression_anchor]] +[A expression of type __ConstantCopyConstructible__ to pass to the [macroref CONTRACT_OLDOF] macro: `value`, `size()`.] +[Wrap value within parenthesis: `(x, y)`.] +] [ +[__operator_identifier__[#operator_identifier_anchor]] +[An arbitrary but alphanumeric identifier: `equal`, `less`, `call`.] +[Never the case.] +] [ +[__operator_symbol__[#operator_symbol_anchor]] +[The usual operator symbols: `==`, `<=`, `()`.] +[Do nothing: `std::map`.] +] [ +[__parameter_default__[#parameter_default_anchor]] +[A function or template parameter default value (either a value, a type, or a template depending on the kind of parameter): `123`.] +[Wrap value within parenthesis: `("abc")`, `('a')`, `(-123)`, `(1.23)`.] +] [ +[__parameter_name__[#parameter_name_anchor]] +[A function or template parameter name: `value`, `T`.] +[Never the case.] +] [ +[__cxx_template_parameter__[#cxx_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]] +[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)`.] +] [ +[__type__[#type_anchor]] +[A type: `int`, `int const&`, `mytype`.] +[Do nothing: `std::map`.] +] [ +[__typedef_type__[#typedef_type_anchor]] +[A type: `int`, `mytype`.] +[Wrap type using __Boost_Utility_IdentityType__: `BOOST_IDENTITY_TYPE((std::map))`.] +] [ +[__unary_boolean_metafunction__[#unary_boolean_metafunction_anchor]] +[A boolean meta-function that takes one parameter: `boost::is_class`.] +[Do nothing: `boost:is_convertible`.] +] [ +[__using_directive__[#using_directive_anchor]] +[The argument to pass to a using directive: `namespace std`, `std::vector`.] +[Never the case.] +] [ +[__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.] +] +] + +If terminals contain commas not already wrapped by round parenthesis or if they start with a non-alphanumeric symbol (including tokens like `'a'`, `"abc"`, `-123`, and `1.23`), +[footnote +The C++ preprocessor cannot concatenate `1.23` because it contains the `.` symbol (even if that symbol is technically not the leading symbol). +The precise preprocessor requirement is that the concatenated symbol must be a valid macro identifier and concatenating `1.23` with any token will never give a valid macro identifier because of the presence of the dot symbol `.` (e.g., `BOOST_PP_CAT(XYZ, 1.23)` gives `XYZ1.23` which is not a valid macro identifier). +] +they need to be wrapped by extra round parenthesis `(...)` or by the __Boost_Utility_IdentityType__ `BOOST_IDENTITY_TYPE((...))` macro. +Value expressions can always be wrapped within extra around parenthesis in C++. +Type expressions can always be wrapped using __Boost_Utility_IdentityType__ but that will make the syntax less readable (and it prevents C++ from automatically deducing function template parameters) so this syntax allows to wrap type expressions within extra round parenthesis `(...)` for most terminals, including types, as indicated by the table above. + +[endsect] + +[section Alternative Assertion Syntax (Not Implemented)] + +The following alternative syntax could have been implemented to program the contract assertions: + +[table +[ [This Library Syntax] [Alternative Syntax (not implemented)] ] +[ [`` +CONTRACT_CLASS( + template( typename T ) + class (vector) +) { +public: + CONTRACT_MEMBER_TPL( + (iterator) (erase) ( (iterator) where ) + precondition( + not empty(), + where != end() + ) + postcondition( + auto result = return, + auto old_size = CONTRACT_OLDOF size(), + size() == old_size - 1, + if(const( this ) this->empty()) ( + result == end() + ) + ) + ) ; + + ... +}; +`` ] [`` +CONTRACT_CLASS( + template( typename T ) + class (vector) +) { +public: + CONTRACT_MEMBER_TPL( + (iterator) (erase) ( (iterator) where ) + precondition( + assert(not empty()) + assert(where != end()) + ) + postcondition( + const(auto result = return) + const(auto old_size = CONTRACT_OLDOF size()) + assert(size() == old_size - 1) + if(const(this, this->empty())) ( + assert(result == end()) + ) + ) + ) ; + + ... +}; +``] ] +] + +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). +Therefore, the authors opted for implementing the syntax on the left hand side. + +[endsect] + +[endsect] + diff --git a/doc/introduction.qbk b/doc/introduction.qbk new file mode 100644 index 0000000..6837d0f --- /dev/null +++ b/doc/introduction.qbk @@ -0,0 +1,100 @@ + +[/ 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 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. +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): + +# 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). + +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__. + +[heading An Example] + +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: + +[pre + precondition number 1 "size() < max_size()" failed: file "push_back.cpp", line 26 +] + +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: + +[pre + postcondition number 1 "size() == old_size + 1" failed: file "push_back.cpp", line 26 +] + +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.) + +[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). + +[endsect] + diff --git a/doc/named_parameters.qbk b/doc/named_parameters.qbk new file mode 100644 index 0000000..e48df60 --- /dev/null +++ b/doc/named_parameters.qbk @@ -0,0 +1,426 @@ + +[/ 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 Named Parameters] + +This section explains how to use this library to program named parameters and deduced named parameters which are used instead of C++ usual positional parameters to specify arguments to function calls. +Parameter names are part of the program specifications and therefore named parameters are within the scope of this library. + +This library internally uses __Boost_Parameter__ to implement named parameters. +This library only offers an easier syntax for constructor and class template named parameters with respect the functionality already provided by __Boost_Parameter__, but this library allows to specify named parameters, concepts, and contracts all together within a unified syntax. + +[section Overview] + +In C++, parameters are identified with respect to their declaration position within the parameter list: The first call /argument/ (i.e., the specific value assigned to the formal parameter at the call site) maps to the first declared parameter, the second call argument maps to the second declared parameter, etc. +For example: + + window* make_window ( + char const& name, + size_t width = 10, + bool moveable = true, + bool visible = true + ) + ; + +This protocol is sufficient when there is at most one parameter with a useful default value but when there are even a few useful default parameters the positional interface becomes difficult to use at the calling site. +For example, in the following call we need to repeat the default parameter value `10`: + + bool const unmoveable = false; + make_window("warning", 10, unmoveable); // Positional (usual). + +Furthermore, it would be easier to understand the meaning of the arguments at the calling site if the parameters could be referred by their names. +For example, in order to understand if the following window is moveable and invisible, or unmoveable and visible, programmers at the calling site need to remember the order of the parameter declarations: + + make_window("note", 10, true, false); // Positional (usual). + +These issues would be solved if the parameter names could be referred at the calling site and that is what [@http://en.wikipedia.org/wiki/Named_parameter ['named parameters]] allow to do: + + make_window("warning", moveable = false); // Named. + make_widnow("note", visible = false); + +Named parameters were proposed for addition to early versions of C++ but the proposal was never accepted (see ["keyword arguments] in __Stroustrup94__). +Other programming languages support named parameters (__Ada__, __Python__, etc). + +Furthermore, /deduced named parameters/ are named parameters that can be passed in any position and without supplying their names. +These are useful when functions have parameters that can be uniquely identified (or /deduced/) based on the argument types of the function call. +For example, the `name` parameter is such a parameter, it can be deduced because no other argument, if valid, can be reasonably converted into a `char const*`. +Therefore, with a deduced parameter interface, we could pass the window name in any position without causing any ambiguity (with an appropriately designed deduced parameter interface, the caller might not even have to remember the actual parameter names): + + make_window(moveable = false, "warning"); // Deduced. + make_window("note", visible = false); + +The same reasoning applies to named template parameters and deduced named template parameters: + + template< typename ValueType, bool Shared = true > + class smart_ptr ; + + smart_ptr p1; // Positional (usual). + smart_ptr p2; // Deduced. + smart_ptr p3; // Named. + +[endsect] + +[section Named Function Parameters] + +To show how to program named parameters, we will program a named parameter interface for the [@http://www.boost.org/doc/libs/1_49_0/libs/graph/doc/depth_first_search.html Depth First Search (DFS)] algorithm of the __Boost_Graph__ library: + + template< + class Graph, + class Visitor, + class IndexMap, + class ColorMap + > requires + is_incidence_and_vertex_list_graph, + is_integral_property_map_of_key >, + is_property_map_of_key > + void depth_first_search ( + Graph const& graph, + Visitor const& visitor = dfs_visitor<>(), + vertex_descriptor const& root_vertex = + *vertices(graph).first, + IndexMap const& index_map = get(vertex_index, graph), + ColorMap& color_map = + default_color_map(num_vertices(graph), index_map) + ) + ; + +This is non-valid C++ code but it can be considered pseudo-code to illustrate the function interface that we need to program. +The concept syntax `requires` was ["borrowed] here to express parameter type requirements but a failure to satisfy such requirements is intended to fail the function call resolution and not to cause a concept error as usual. + +[variablelist +[ [=graph=] [ +This is an input parameter (`const&`), its type must match a model of both `IndicenceGraph` and `VertexListGraph`, and it has no default value (required parameter). +] ] +[ [=visitor=] [ +This is an input parameter (`const&`), its type has no requirement, and its value defaults to a DFS visitor (optional parameter). +] ] +[ [=root_vertex=] [ +This is an input parameter (`const&`), its type must be `vertex_descriptor`, and its value defaults to the first vertex of the specified graph (optional parameter). +] ] +[ [=index_map=] [ +This is an input parameter (`const&`), its type must match a model of `IntegralPropertyMap` with key type `vertex_descriptor`, its value defaults to the vertex index of the specified graph (optional parameter). +] ] +[ [=color_map=] [ +This is an input and output parameter (non-constant reference `&`), its type must match a model of `PropertyMap` with key type `vertex_descriptor`, its value defaults to a map with size equal to the number of vertices of the specified graph and created from the specified `index_map` (optional parameter). +] ] +] + +[*Parameter Identifiers] + +First of all, it is necessary to declare special elements that will serve as the parameter and argument identifiers (see also [file example/named_parameters named_params_dfs.cpp]): + +[import ../example/named_parameters/named_params_dfs.cpp] +[named_params_dfs_keywords] + +For example, the first [macroref CONTRACT_PARAMETER] macro declares an identifier `graph` that is used as the parameter name in the function declaration and also an identifier `graph_` (note the trailing underscore `_`) that is used to name the argument at the call site. + +[note +By default, argument identifiers are differentiated from parameter identifiers using a trailing underscore `_` to avoid name clashes (see also the __Parameter_Identifiers__ section). +Furthermore, it is recommended to always declare these identifiers within a namespace to avoid name clashes (because different functions in different sections of the code might very well use the same parameter names so namespaces can be used to control overlapping names). +] + +For example, for a library named Graphs, all named parameter identifiers could be declared under the `graphs` namespace and maybe in a single header =graphs_params.hpp=. +Many different functions within `graphs` (for example `graphs::depth_first_search` and `graphs::breadth_first_search`) will share a number of common parameter names (for example a parameter named `graph` with parameter identifier `graphs::graph` and argument identifier `graphs::graph_`). +All these named parameters will be defined in one places in =graphs_params.hpp= and within the `graphs` namespace so programmers can conveniently control and avoid named clashes. + +[*Function Declaration] + +The function is declared using the following syntax (see also [file example/named_parameters named_params_dfs.cpp]): + +[named_params_dfs_decl] + +This example required no preconditions and no postconditions. + +[*In, In Out, and Out Parameters] + +Input parameters (i.e., constant references `const&`) are prefixed by the specifier `in` (see also the __Grammar__ section): + + in ... graph // Input parameter. + +Input and output parameters (i.e., non-constant reference `&`) are prefixed by both specifiers `in out` (in this order, see also the __Grammar__ section): + + in out ... color_map // Input-output parameter. + +Output parameters can be prefixed just by the specifier `out` but their implementation is equivalent to using the specifiers `in out` (i.e., non-constant reference `&`). +[footnote +*Rationale.* +C++ cannot express the semantics that an output parameter should be written and never read within a function because references can always be both written and read. +] +Note that a named parameter must always be specified either `in`, `in out`, or `out` (and that is what distinguish syntactically a named parameter from a positional parameter; this use of `in`, `in out`, and `out` resembles __Ada__'s syntax). +Named and positional parameters cannot be used together in the same function declaration. + +[*Parameter Types] + +Exact parameter types are specified just before the parameter name and within parenthesis (unless they are fundamental types containing no symbol, see also the __Grammar__ section): + + in (vertex_descriptor) root_vertex // Exact parameter type requirement. + +Generic parameter types (i.e., parameter types with no requirement, same as usual type template parameters) are specified using `auto` instead of the parameter type (see also the __Grammar__ section): + + in auto visitor // No parameter type requirement. + +Predicate parameter type requirements are specified using `requires(`[^['unary-boolean-metafunction]]`)` instead of the parameter type, the type of the argument specified by the function call will be required to match the specified unary boolean meta-function in order for the call to be resolved (see also the __Grammar__ section): + + in requires(is_incidence_and_vertex_list_graph) graph // Predicate parameter type requirement. + +The placeholder `boost::mpl::_` makes this expression a unary meta-function (see __Boost_MPL__) and the library will substitute such a placeholder with the argument type specified at the call site when resolving the function call. + +[*Default Parameter Values] + +Default parameter values are specified using `, default `[^['default-parameter-value]] right after the parameter declaration (see also the __Grammar__ section): + + in auto visitor, default boost::dfs_visitor<>() + +Default parameter values are not evaluated and their types are not even instantiated if an actual argument is specified by the function call. + +[note +The type and value of a parameters can be used within the declaration of other parameters. +The type of a named parameter can be accessed using the [macroref CONTRACT_PARAMETER_TYPEOF] macro (this is especially useful for generic parameter types and for parameter types with predicate requirements because these types are not known until the function call is resolved). +] + +[*Function Call] + +The `graphs::depth_first_search` function can be called using argument identifiers to name its parameters (see also [file example/named_parameters named_params_dfs.cpp]): + +[named_params_dfs_call] + +[endsect] + +[section Deduced Function Parameters] + +To show how to program deduced named parameters, we program the parameter interface for the [@http://www.boost.org/doc/libs/1_49_0/libs/python/doc/v2/def.html#def-spec `def`] function of the __Boost_Python__ library (see also [file example/named_parameters deduced_params_pydef.cpp]): + +[import ../example/named_parameters/deduced_params_pydef.cpp] +[deduced_params_pydef_decl] + +Also a precondition was specified in this example. +(Concepts for named parameters are explained later in this section.) + +Deduced parameters are named parameter that are prefixed by the `deduce` specifier (see also the __Grammar__ section): + + deduce in (char const*) docstring // Deduced input parameter. + +When calling the function `py::def` only two arguments are required `name` and `func`. +The association between any addition argument and its parameter can be deduced based on the types of the arguments specified by the function call (so the caller is neither required to remember the parameter positions nor to explicitly specify the parameter names for these arguments). + +For example, the first two calls below are equivalent and if programmers need to pass a `policy` argument that is also, for some reason, convertible to `char const*`, they can always specify the parameter name as in the third call below (see also [file example/named_parameters deduced_params_pydef.cpp]): + +[deduced_params_pydef_calls] + +[endsect] + +[section Member Function Parameters] + +The same syntax is used to specify named and deduced parameters for member functions (see also [file example/named_parameters member_named_params_callable2.cpp]): + +[import ../example/named_parameters/member_named_params_callable2.cpp] +[member_named_params_callable2] + +No contracts were specified in this example. + +[note +When the body definition of a function with named parameters is deferred from the function declaration, the body must be declared as a template function when it is defined and the special macro [macroref CONTRACT_PARAMETER_BODY] must be used to name the function. +] + +The same macro is used to name both free and member body functions because the class type is specified outside this macro. +The constructor body definition cannot be deferred from the constructor declaration (because of the lack of delegating constructors in __CXX03__). +Destructors have no named parameters (because they have no parameter). +Named parameters are not supported for operators (because of a __Boost_Parameter__ bug). +[footnote +*Rationale.* +This library syntax supports named and deduced parameters for operators. +However, __Boost_Parameter__ does not compile when used with operators because of a bug (__Boost_Parameter__ documentation claims support for operators but later revisions of __Boost_Parameter__ no longer compile when operators are used). +If __Boost_Parameter__ were to be fixed to work with operators then this library named and deduced parameters should also work with operators. +] +Therefore the [macroref CONTRACT_PARAMETER_BODY] macro is used only with free and member functions that are not operators. +[footnote +*Rationale.* +A macro [macroref CONTRACT_PARAMETER_BODY] different from [macroref CONTRACT_MEMBER_BODY] and [macroref CONTRACT_FREE_BODY] is necessary because named parameters will still be enabled even when contracts are turned off using [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], etc. +] + +In this example, named parameters were specified for all `callable2::call` overloads and for the `static` member function `callable2:static_call`: + +[member_named_params_callable2_calls] + +[endsect] + +[section Constructor Parameters] + +The same syntax is used to specify named and deduced parameters for constructors (see also [file example/named_parameters constructor_named_params_family.cpp]): +[footnote +Arguably, this library offers a better syntax than __Boost_Parameter__ for constructor named and deduced parameters (because __Boost_Parameter__ requires boiler-plate code and an extra base class in order to handle constructors). +] + +[import ../example/named_parameters/constructor_named_params_family.cpp] +[constructor_named_params_family] + +Both preconditions and postconditions were specified for the constructor. + +[important +Member initializers must access named and deduced parameters using the special macro [macroref CONTRACT_CONSTRUCTOR_ARG] (otherwise the compiler will generate an error). +[footnote +*Rationale.* +This limitation comes from the lacks of delegating constructors in __CXX03__ (as with all other limitations of this library related to member initializers). +] +] + +Named and deduced parameters can be used to specify the arguments when constructing the object: + +[constructor_named_params_family_call] + +[endsect] + +[section Class Template Parameters] + +Only class templates are discussed in this section because function templates are effectively always declared when a function uses named or deduced parameters. +In fact, a function with named or deduced parameters is always a function template (possibly with fully generic templated types when the named and deduced parameters types are specified `auto`). + +To show how to program named and deduced template parameters, we will program a named parameter interface for the [@http://www.boost.org/doc/libs/1_49_0/libs/python/doc/v2/class.html#class_-spec `class_`] class template of the __Boost_Python__ library: + + template< + class ClassType, + class Bases = bases<>, + typename HeldType = not_sepcified, + typename Copyable = not_specified + > requires + is_class + class class_ ; + +[variablelist +[ [ClassType] [ +This type parameter must be a class and it has no default value (required parameter). +] ] +[ [Bases] [ +This type parameter must be a specialization of `boost::python::bases` specifying base classes if any (see `boost::python::detail::specifies_bases`) and its value defaults to `boost::python::bases<>`. +] ] +[ [HeldType] [ +This type parameter has no constraint and it is not specified by default (see `boost::python::detail::not_specified`). +] ] +[ [Copyable] [ +This type parameter must be `boost::noncopyable` if specified and it is not specified by default (see `boost::python::detail::not_specified`). +] ] +] + +[important +Unfortunately, named and deduced template parameters can only handle type template parameters (i.e., value template parameters and template template parameters are not supported). +[footnote +*Rationale.* +This library only supports named and deduced type template parameter because it internally uses __Boost_Parameter__ and __Boost_Parameter__ does not support non-type template parameters. +However, this library syntax would support named and deduced value template parameters and template template parameters if these were ever supported by __Boost_Parameter__ (see template parameters within the __Grammar__ section). +Named and deduced value template parameters can be emulated by wrapping their values into types (using `boost::mpl::int_`, `boos::mpl::bool_`, etc) at the cost of a somewhat cumbersome syntax. +] +] + +First of all, it is necessary to declare elements that will serve as template parameter and argument identifiers (see also [file example/named_parameters named_template_params_pyclass.cpp]): + +[import ../example/named_parameters/named_template_params_pyclass.cpp] +[named_template_params_pyclass_keywords] + +For example, the first [macroref CONTRACT_TEMPLATE_PARAMETER] macro declares a specifier `ClassType` that can be used as the parameter name in the class template declaration and a specifier `ClassType_` (note the trailing underscore `_`) that can be used for the template argument at the template instantiation site. + +[note +By default, template argument identifiers are differentiated from template parameter identifiers using a trailing underscore `_` to avoid name clashes (see also the __Parameter_Identifiers__ section). +Furthermore, it is recommended to always declare these identifiers within a namespace to avoid name clashes (because different class templates in different sections of the code might very well use the same template parameter names so namespaces can be used to control overlapping names). +] + +The class template is declared using a syntax similar to the one we have seen so far for named and deduced function parameters (see also [file example/named_parameters named_template_params_pyclass.cpp]): +[footnote +Arguably, this library offers a better syntax than __Boost_Parameter__ for named and deduced template parameters (because __Boost_Parameter__ requires boiler-plate code and the additional argument packing types to be programmed manually). +] + +[named_template_params_pyclass] + +Note that template parameters are always specified using `in` because they are always input parameters (they are static types). +Furthermore, `typename` or `class` must always follow the `in` specifier for type template parameters. +[footnote +*Rationale.* +This syntax was designed so it can support non-type template parameters if this library and __Boost_Parameter__ were ever extended to support value template parameters and template template parameters (see template parameters in the __Grammar__ section). +] +Predicate type requirements `requires(`[^['unary-boolean-metafunction]]`)` are optional and they are specified right after `typename` or `class` if present. +Default template parameter values are specified using `, default `[^['default-parameter-value]] as usual. +(See also the __Grammar__ section.) + +The class template `py::class_` can be instantiated using the template parameter identifiers to name the arguments (see also [file example/named_parameters named_template_params_pyclass.cpp]): +[footnote +This named and deduced parameter syntax is not entirely ideal because it uses angular parenthesis `py::ClassType_` instead of the more readable assignment operator `py::ClassType_ = bx` to name the arguments (but that is how __Boost_Parameter__ is implemented and also this library authors see no way to implement the assignment operator syntax for named and deduced template parameters). +] + +[named_template_params_pyclass_calls] + +[endsect] + +[section Concepts] + +As shown in the `py::class_` example above, it is possible to specify concepts for named and deduced template parameters. +Concepts are specified using `requires` after the class template parameter declaration: + + template( ... ) requires( ``[^['concept1]]``, ``[^['concept2]]``, ... ) + class (class_) ... + +As shown in the `py::def` example earlier in this section, it is also possible to specify concepts for named and deduced function parameters (because named and deduced function parameter can be generic, as function template parameters are, when their types are specified `auto` or via a predicate type requirement). +However, in this case concepts are specified using `requires` after the function parameter list (because there is not `template` declaration for functions with named and deduced parameters): + + void (def) ( ... ) requires( ``[^['concept1]]``, ``[^['concept2]]``, ... ) + +Note the following differences between specifying predicate type requirements and concepts for named and deduced parameters: + +* If predicate type requirements are not met, the function or class template will be taken out from the set of possible function overloads or template specializations in the function call or template instantiation resolution (this might ultimately generate a compiler error but only if there is no other function overload or template specialization that can be used). +* If a concept check fails, the compiler will always generate a compiler error. + +[endsect] + +[section Parameter Identifiers] + +When using the [macroref CONTRACT_PARAMETER] and [macroref CONTRACT_TEMPLATE_PARAMETER] macros (see also the __Grammar__ section): + +# It is possible to specify a namespace that will contain the parameter identifiers using `namespace(`[^['parameter-identifier-namespace]]`)`. +# It is also possible to specify the name of the argument identifier instead of using the automatic underscore `_` postfix using `(`[^['argument-identifier]]`)`. + +The following example generates parameter identifiers within the `params` namespace, and argument identifiers `NumberArg` and `value_arg` instead of the default `Number_` and `value_` for the `Number` and `value` parameters respectively (see also [file example/named_parameters named_param_identifiers_positive.cpp]): + +[import ../example/named_parameters/named_param_identifiers_positive.cpp] +[named_param_identifiers_positive_keywords] + +When the parameter identifier namespace is specified, it must be repeated in the named and deduced parameter declaration list (see also the __Grammar__ section): + + using namespace ``/paraemeter-identifier-namespace/``, ... // named and deduced parameters follow + +The authors find this syntax confusing so they recommend to never specify the parameter identifier namespace when using the [macroref CONTRACT_PARAMETER] and [macroref CONTRACT_TEMPLATE_PARAMETER] macros. +[footnote +*Rationale.* +The ability to specify the parameter identifier (or tag) namespace is offered because it is offered by __Boost_Parameter__ and it gives programmers greater control. +However, it should be rarely if ever needed because this library provides the [macro CONTRACT_PARAMETER_TYPEOF] macro. +] +Instead programmers are encouraged to use these macros within an enclosing namespace as done by the rest of the examples in this documentation. + +For example (see also [file example/named_parameters named_param_identifiers_positive.cpp]): + +[named_param_identifiers_positive] + +Class invariants, preconditions, and postconditions were also specified in this example. + +At the template instantiation and function call site, the specified argument identifiers `NumberArg` and `value_arg` can be used instead of the usual trailing underscore (see also [file example/named_parameters named_param_identifiers_positive.cpp]): + +[named_param_identifiers_positive_call] + +It is not necessary to specify both the parameter identifier namespace and the argument identifier as they are both and independently optional (see also the __Grammar__ section): + + CONTRACT_TEMPLATE_PARAMETER( (NumberArg) Number ) // Specify only argument identifier. + CONTRACT_PARAMETER( namespace(params) value ) // Specify only parameter identifier namespace. + +It is recommended to never specify the argument identifiers to have the same names as the parameter identifiers in order to avoid the following usually silent bug (see also [file example/named_parameters named_param_identifiers_failure.cpp]): + +[import ../example/named_parameters/named_param_identifiers_failure.cpp] +[named_param_identifiers_failure] + +The call `print(age = 3);` will assign `3` to `f`'s parameter `age` instead than passing `3` as the argument of `print`'s parameter `age`. +The trailing underscore `_` convention and enclosing the named parameter declaration macros [macroref CONTRACT_PARAMETER] and [macroref CONTRACT_TEMPLATE_PARAMETER] within a namespace make this type of name clashes unlikely. + +[endsect] + +[endsect] + diff --git a/doc/no_variadic_macros.qbk b/doc/no_variadic_macros.qbk new file mode 100644 index 0000000..a2a50d3 --- /dev/null +++ b/doc/no_variadic_macros.qbk @@ -0,0 +1,81 @@ + +[/ 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 No Variadic Macros] + +This section illustrates an alternative syntax, the /sequence syntax/, that can be used on compilers that do not support variadic macros. +Most modern compilers support [@http://en.wikipedia.org/wiki/Variadic_macro variadic macros] (notably, these include GCC, MSVC, and all __CXX11__ compilers). + +[warning +The sequence syntax presented in this section has not been fully tested yet. +Future revisions of the library are expected to test and support the sequence syntax more thoroughly (see also [@https://sourceforge.net/apps/trac/contractpp/ticket/58 Ticket 58]). +] + +The sequence syntax uses many extra parenthesis and it is significantly less readable than the comma-separated syntax that we have seen so far. +Therefore, it is strongly recommended to not use the sequence syntax unless it is absolutely necessary to program contracts that are portable to compilers that do not support variadic macros. + +[section Sequence Syntax] + +In the rare case that programmers need to use this library on compliers without variadic macros, this library also allows to specify its macro parameters using a __Boost_Preprocessor__ sequence in which tokens are separated using round parenthesis `()`: + + (token1) (token2) ... // All compilers. + +Instead of the comma-separated lists that we have seen so far which require variadic macros: + + token1, token2, ... // Only compilers with variadic macros (preferred). + +This library detects preprocessor support for variadic macros using the __Boost_Config__ macro `BOOST_NO_VARIADIC_MACROS`. +__Boost_Config__ defines the `BOOST_NO_VARIADIC_MACROS` only on compilers that do not support variadic macros furthermore programmers can forcefully define this macro also on compilers that support variadic macros. +When this macro is not defined, this library macros support both the camma-separated and sequence syntax, otherwise only the sequence syntax is supported. + +[note +The same macros accept both syntaxes on compilers with variadic macros and only the sequence syntax on compilers without variadic macros. +] + +For example, the syntax on the left hand side works on all compilers with and without variaidic macros (see also [file example/contracts class_template_vector_seq.cpp], [file example/contracts pushable_seq.hpp], [file example/contracts class_template_vector.cpp], and [file example/contracts pushable.hpp]): + +[import ../example/contracts/pushable_seq.hpp] +[import ../example/contracts/class_template_vector_seq.cpp] +[table +[ [Sequence Syntax (all compilers)] [Comma-Separated Syntax (variadic macros only, preferred)] ] +[ [[pushable_seq]] [[pushable]] ] +[ [[class_template_vector_seq]] [[class_template_vector]] ] +] + +Note the many extra parenthesis around all tokens within the lists: template parameters `(typename T)`, base classes `(public pushable)`, function parameters `(size_type) count`, all assertions, etc. +Furthermore, empty lists need to be specified using `(void)` instead of just `void`. + +When using the sequence syntax, the macro [macroref CONTRACT_LIMIT_OLDOFS] specifies the maximum number of postconditions sequence elements (instead of the maximum possible number of old value declarations as for variadic macros). + +[endsect] + +[section Commas and Leading Symbols in Macros] + +As we have seen in the __Advanced_Topics__ section, syntactic elements containing unwrapped commas and leading symbols need to be wrapped within extra round parenthesis: + + (::std::map >) // With variadic macros. + +However, without variadic macros this is no longer sufficient and the number of commas needs to be explicitly specified using the following syntax: +[footnote +*Rationale.* +Using variadic macros, the preprocessor can automatically determine the number of commas within a tuple but without variadic macros that is no longer possible so programmers must manually specify the number of commas. +] + + comma(2)(::std::map >) // Without variadic macros. + +For example (see also [file example/contracts macro_commas_symbols_integral_map_seq.cpp] and [file example/contracts macro_commas_symbols_integral_map.cpp]): + +[import ../example/contracts/macro_commas_symbols_integral_map_seq.cpp] +[table +[ [Sequence Syntax (all compilers)] [Comma-Separated Syntax (variadic macros only, preferred)] ] +[ [[macro_commas_symbols_integral_map_seq]] [[macro_commas_symbols_integral_map]] ] +] + +[endsect] + +[endsect] + diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk new file mode 100644 index 0000000..b9402ea --- /dev/null +++ b/doc/release_notes.qbk @@ -0,0 +1,124 @@ + +[/ 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 Release Notes] + +This section contains notes on the current and on all previous library releases (in chronological order). + +[heading Release 0.4.1] + +August 20, 2012 + +Notes: + +# Using non-fix-spaced font in Full Table of Contents section. +# Added a couple of notes to the documentation. +# Changed `CONTRACT_MEMBER_BODY(class_type, function_name)` to `class_type::CONTRACT_MEMBER_BODY(function_name)` so the macro can also be used to declare derived classes avoiding using the library syntax even when the base class has contracts. + +Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1/doc/html/index.html documentation]. + +[heading Release 0.4.0] + +June 4, 2012 + +Notes: + +# Simplified syntax by reducing extra parenthesis to the bare necessary minimum (using some of the preprocessor parsing techniques originally introduced by Boost.LocalFunction). +# Postcondition old values only copy the old-of expression (e.g., copy just vector size instead of entire vector). +This improves performance and introduces the `ConstantCopyConstructible` requirement just for the old value expression type (e.g., a vector might not be copyable while its size always is because it is an integral type). +Removed the `copyable` tag. +# Body defined outside the macros (so compiler-errors for definitions retain their usual meaning). +# Added `CONTRACT_CLASS` macro and removed the need to duplicate declaration elements (do not repeat function declaration, do not repeat class name in function declaration, etc). +# Using `_TPL` macros so to reduce compile-time (instead of internally making all templates contract functions so to use `typename` freely). +# Overloading no longer requires unique parameter names. +# Added C++11-like virtual specifiers. +# Added constant assertions plus constant-expressions for select assertion if-conditions and for loop variants. +# Added named and deduced parameters. +# Added concept checking. +# Removed the interface to use the library without the macro (programmers were required to write too much boiler-plate code for the non-macro interface to be actually usable, plus supporting both the macro and non-macro interfaces limited what the macros could do). + +Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_0 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_0/doc/html/index.html documentation]. + +[heading Release 0.3.490] + +March 7, 2010 + +Notes: + +# Added support and examples for `volatile`, `auto`, `explicit`, `export`, `extern`, `friend`, `inline`, `struct`, and `throw` (for exception specifications). +# Documented that `union` cannot be contracted. + +Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_490 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_490/doc/html/index.html documentation]. + +[heading Release 0.3.469] + +February 21, 2010 + +Notes: + +# Removed use of `self`, `variable.now`, and `variable.old` in writing contracts. +Object `this` and variables are now accessed as usual in member functions. +`CONTRACT_OLDOF(variable)` is used to access old values in postconditions. +# Added `(precondition)`, `(postcondition)`, and `(body)` to specify contracts within the function signature sequence. +If no preconditions then `(precondition) ({...})` is simply omitted from the sequence (same for postconditions, body is mandatory instead). +For non-void functions, users can name the result argument with `(postcondition) (result-name) ({...})`. +# Changed contract class template to use same syntax as Boost.Function (i.e., `F` function type). +# Added support for free functions and static member functions. +# Added support for subcontracting with multiple inheritance. +# Added static class invariants which are always checked (also at constructors entry, destructor exit, and by static member functions). +# Added block invariants and Eiffel-like loop variants. +# Added handlers to customize action on contract failure (default to `std::terminate()`). +# Removed feature for automatic contract documentation using Doxygen (this is not compatible with added `(precondition)`, `(postcondition)`, and `(body)` because Doxygen preprocessor is not capable to handle Boost.Preprocessor sequences). +# Rewritten entire documentation (now using Boost.QuickBook instead of Doxygen). + +Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_469 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_3_469/doc/html/index.html documentation]. + +[heading Release 0.2.190] + +November 21, 2009 + +Notes: + +# Compiled using both GCC (Linux and Cygwin) and MSVC (Windows XP). +# Required to use void to specify empty function argument list. +This is to comply with C++03 standard that does not allow to pass empty macro parameters so it does not support empty preprocessor sequences `()`. + +Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_2_190 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_2_190/doc/html/index.html documentation]. + +[heading Release 0.1.126] + +June 17, 2009 + +Notes: + +# Completed first documentation draft. + +Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_126 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_126/doc/html/index.html documentation]. + +[heading Release 0.1.55] + +April 19, 2009 + +Notes: + +# Reorganized files to cleanup root directory. +# Added installation program. + +Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_55 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_55/doc/DBC_Documentation.txt documentation]. + +[heading Release 0.1.50] + +April 19, 2009 + +Notes: + +# First public release. + +Release [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_50 files] and [@http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_1_50/README.txt documentation]. + +[endsect] + diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk new file mode 100644 index 0000000..de272d8 --- /dev/null +++ b/doc/tutorial.qbk @@ -0,0 +1,491 @@ + +[/ 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. + +[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]): + +[import ../example/contracts/no_contract_postinc.cpp] +[no_contract_postinc] + +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]): + +[import ../example/contracts/no_pre_post_postinc.cpp] +[no_pre_post_postinc] + +All necessary header files for this library are included by `#include ` (see also the __Getting_Started__ section). + +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. + +The function name `(postinc)` must always be wrapped within parenthesis so it can be passed to this library macros. + +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. +] +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] + +[section Preconditions] + +Let's program the preconditions of `postinc` (see also [file example/contracts pre_only_postinc.cpp]): + +[import ../example/contracts/pre_only_postinc.cpp] +[pre_only_postinc] + +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. + +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`. + +[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. +] +] + +[endsect] + +[section Classes and Class Invariants] + +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]): + +[import ../example/contracts/no_contract_ivector.cpp] +[no_contract_ivector] + +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]): + +[import ../example/contracts/class_ivector.cpp] +[class_ivector_classinv] + +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`: + + CONTRACT_CLASS( + class (ivector) + ) { + CONTRACT_CLASS_INVARIANT( void ) // No class invariant. + + // ... + +Using the same macro, this library also allows to specify contracts for `struct`: +[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. +] + + CONTRACT_CLASS( + struct (ivector) // Structs with contracts. + ) { + // ... + +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`). + +[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 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]): + +[class_ivector_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.) + +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). +[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. +] +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. + +[endsect] + +[section Destructors] + +Let's program the `ivector` class destructor using the [macroref CONTRACT_DESTRUCTOR] macro (see also [file example/contracts class_ivector.cpp]): + +[class_ivector_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). + +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. + +[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). +] + +In general, there is no need to use this library macros to declare free functions, constructors, destructors, and member function only when: + +# 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. + +[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. + +[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). +] + +[endsect] + +[section Inheritance and Subcontracting] + +Consider the following class `unique_identifiers` which is a collection of unique integral identifiers (see also [file example/contracts subcontract_identifiers.cpp]): + +[import ../example/contracts/subcontract_identifiers.cpp] +[subcontract_identifiers_unique] + +Reading the contracts we can understand the semantics of the class operation (even if we do not consult the class implementation): + +# 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). + +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]): + +[subcontract_identifiers_duplicate] + +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). + +[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]). +] + +[endsect] + +[section Class Templates] + +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]): + +[import ../example/contracts/class_template_vector.cpp] +[class_template_vector] + +(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.) + +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`). + +[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. +[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.) +] + +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). + +[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. +] + +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. + +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. +] + +[import ../example/contracts/body_natural_impl.hpp] +[body_natural_impl] + +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. +[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. +] +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). + +In this example, it was possible to separate the constructor body definition because the constructor did not specify member initializers. + +[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]). +] +] + +[endsect] + +[endsect] + diff --git a/doc/virtual_specifiers.qbk b/doc/virtual_specifiers.qbk new file mode 100644 index 0000000..fe3862d --- /dev/null +++ b/doc/virtual_specifiers.qbk @@ -0,0 +1,138 @@ + +[/ 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 Virtual Specifiers] + +This section explains how to use this library to program virtual specifiers `final`, `override`, and `new`. +Virtual specifiers are part of the program specifications because they enforce inheritance constraints at compile-time and therefore they are within the scope of this library. + +[important +This library implements virtual specifiers for __CXX03__ and without using any __CXX11__ feature. +[footnote +This library declares special member functions to ["tag] virtual traits of a given member function in a base class (if it is `virtual`, `final`, etc). +Then template meta-programming introspection is used by the derived class to inspect virtual trait in its base classes and generate compiler errors if the virtual specifiers are not satisfied. +These techniques do not use any __CXX11__ feature however, future revisions of this library might use __CXX11__ native support for virtual specifiers so to eliminate the extra compilation time required by template meta-programming introspection and correct a number of bugs associated with the current implementation of virtual specifiers in this library (see also [@http://sourceforge.net/apps/trac/contractpp/ticket/53 Ticket 53], [@http://sourceforge.net/apps/trac/contractpp/ticket/53 Ticket 55], and [@http://sourceforge.net/apps/trac/contractpp/ticket/53 Ticket 56]). +] +Obviously, virtual specifiers are supported only if both the base and derived classes and member functions in question are declared using this library macros (otherwise this library has no control over usual C++ declarations). +] + +The examples presented in this section are rather simple (and they do not define virtual destructors for brevity). +These examples only aim to illustrate the syntax of this library virtual specifiers and not to make a case about the utility of these specifiers. +Virtual specifiers were adopted by __CXX11__ and in some form are part of other languages like __Java__, programmers can refer to the web and to the __Examples__ section for more interesting examples. + +[section Final Classes] + +Final classes cannot be derived, otherwise the compiler will generated an error. +This library allows to declare a class final by specifying `final` within the [macroref CONTRACT_CLASS] macro after the class name, after template specialization types but before base classes if present (see also the __Grammar__ section). + +For example (see also [file example/virtual_specifiers final_class.hpp] and [file example/virtual_specifiers final_class.cpp]): + +[import ../example/virtual_specifiers/final_class.hpp] +[final_class] + +If a derived class declared using [macroref CONTRACT_CLASS] attempts to inherit from a final base class, the compiler will generate a compile-time error (this is true only if both the base and derived classes are declared using this library macro [macroref CONTRACT_CLASS]). +For example, consider the following derived class (see also [file example/virtual_specifiers final_class_error.cpp]): + +[import ../example/virtual_specifiers/final_class_error.cpp] +[final_class_error] + +This will generate a compile-time error similar to the following because `x` is final (note that the number of the base class that violates the `final` specifier is reported so it is clear which base class is causing the error also in case of multiple-inheritance): + +[pre +final_class_error.cpp:8 ... ERROR_cannot_extend_final_base_class_number_1 ... +] + +Final class checks are performed at compile-time even when contracts are disabled (using [macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS], [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS], etc). + +[endsect] + +[section Final Member Functions] + +Final member functions cannot be overridden by derived classes, otherwise the compiler will generate an error. +This library allows to declare a member function final by specifying `final` within the [macroref CONTRACT_FUNCTION] macro, after the cv-qualifier but before exception specifications if present (see also the __Grammar__ section). + +For example (see also [file example/virtual_specifiers final_member.hpp] and [file example/virtual_specifiers final_member.cpp]): + +[import ../example/virtual_specifiers/final_member.hpp] +[final_member] + +If a member function of a derived class is declared using [macroref CONTRACT_FUNCTION] and attempts to override a final member function from one of the base classes, the compiler will generate a compile-time error (this is true only if both the overriding and overridden functions are declared using this library macro [macroref CONTRACT_FUNCTION]). +For example, consider the following derived class (see also [file example/virtual_specifiers final_member_error.cpp]): + +[import ../example/virtual_specifiers/final_member_error.cpp] +[final_member_error] + +This will generate a compile-time error similar to the following because `y::f` is final (note that the number of the base class that violates the `final` specifier is reported so it is clear which overridden member function is causing the error also in case of multiple-inheritance): + +[pre +final_member_error.cpp:13 ... ERROR_cannot_override_final_function_from_base_class_number_1 ... +] + +In order to correctly handle overloaded functions, the overriding function and the final function must have the same name, parameter types, and cv-qualifier to generate this error. + +Final member function checks are performed at compile-time but only when class invariants are enabled ([macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS] is left not defined). + +[endsect] + +[section Overriding Member Functions] + +Overriding member functions must override a virtual member function from one or more of the base classes, otherwise the compiler will generate an error. +This library allows to declare an overriding member function by specifying `override` within the [macroref CONTRACT_FUNCTION] macro, after the cv-qualifier but before the `final` specifier if present (`override` and `final` can be used together, see also the __Grammar__ section). + +For example (see also [file example/virtual_specifiers override_member.hpp] and [file example/virtual_specifiers override_member.cpp]): + +[import ../example/virtual_specifiers/override_member.hpp] +[override_member] + +If a member function of a derived class is declared using [macroref CONTRACT_FUNCTION] and attempts to override an non-virtual or non-existing member function from one of the base classes, the compiler will generate a compile-time error (this is true only if both the overriding and overridden functions are declared using this library macro [macroref CONTRACT_FUNCTION]). +For example, consider the following derived class (see also [file example/virtual_specifiers override_member_error.cpp]): + +[import ../example/virtual_specifiers/override_member_error.cpp] +[override_member_error] + +This will generate a compile-time error similar to the following because `x::g` is not virtual: + +[pre +override_member_error.cpp:12 ... ERROR_no_base_class_declares_matching_virtual_function_to_override_at_line_12 ... +] + +In order to correctly handle overloaded functions, the overriding function and the overridden virtual function must have the same name, parameter types, and cv-qualifier to /not/ generate this error. + +Overriding member function checks are performed at compile-time but only if at least one between preconditions, postconditions, and class invariants is enabled ([macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS] and [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS] are not all defined at the same time). + +[endsect] + +[section New Member Functions] + +New member functions shall not override member functions from any of the base classes, otherwise the compiler will generate an error. +This library allows to declare a new member function by specifying `new` within the [macroref CONTRACT_FUNCTION] macro, after the cv-qualifier but before the `final` specifier if present (`new` and `final` can be used together, see also the __Grammar__ section). + +For example (see also [file example/virtual_specifiers new_member.hpp] and [file example/virtual_specifiers new_member.cpp]): + +[import ../example/virtual_specifiers/new_member.hpp] +[new_member] + +If a new member function of a derived class is declared using [macroref CONTRACT_FUNCTION] but it overrides an existing member function from one of the base classes, the compiler will generate a compile-time error (this is true only if both the overriding and overridden functions are declared using this library macro [macroref CONTRACT_FUNCTION]). +For example, consider the following derived class (see also [file example/virtual_specifiers new_member_error.cpp]): + +[import ../example/virtual_specifiers/new_member_error.cpp] +[new_member_error] + +This will generate a compile-time error similar to the following because `f` was already declared in `x` (note that the number of the base class that violates the `new` specifier is reported so it is clear which overridden member function is causing the error also in case of multiple-inheritance): + +[pre +new_member_error.cpp:12 ... ERROR_matching_virtual_function_already_declared_by_base_class_number_1 ... +] + +In order to correctly handle overloaded functions, the new function and the overridden function must have the same name, parameter types, and cv-qualifier to generate this error. + +New member function checks are performed at compile-time but only if at least one between preconditions, postconditions, and class invariants is enabled ([macroref CONTRACT_CONFIG_NO_PRECONDITIONS], [macroref CONTRACT_CONFIG_NO_POSTCONDITIONS] and [macroref CONTRACT_CONFIG_NO_CLASS_INVARIANTS] are not all defined at the same time). + +[endsect] + +[endsect] + diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 new file mode 100644 index 0000000..410b3df --- /dev/null +++ b/example/Jamfile.v2 @@ -0,0 +1,422 @@ + +# 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 + +import testing ; +import python ; +import type ; +import generators ; + +echo """ +Usage: bjam [TARGET]... [BJAM_OPTION]... +By default, build examples from all directories and with all contract on/off +combinations (this takes a long time). Targets `all_on` and `all_off` build +examples from all directories but only with contracts on and off respectively. +Target `dirname` build examples only in the given directory but with all +contracts on. See TARGET below for a complete list of targets. +Other Bjam options (`-q`, `--clean`, etc) are specified as usual. + +TARGET + [noflags][_dirname][_filename] | dirname_onoff | all_on | all_off +noflags + Turn off specific contract combinations using `no[e][o][i][b][l]`: + noe | noo | noi | nob | nol | noeo | noei | nooi | nobl | noeoi | noeoibl + Where: + e = prEconditions o = pOstconditions i = class Invariants + b = Block invariants l = Loop variants + Turn off no contract when `noflags` is not specified. (Longer flag names + would have caused too long build file names on some OS.) +dirname + Build the specified directory (contracts on if `noflags` not specified). +filename + Build the specified file (contracts on if `noflags` not specified). +dirname_onoff + Build in specified directory name with all contract on/off combinations. +all_on + Build all directories but with all contracts on. +all_off + Build all directories but with all contracts off. + +EXAMPLES + bjam contracts_push_back # only contracts/push_back, contracts on + bjam noeo_contracts_push_back # contract/push_back, pre and post off + bjam contracts # all in contracts/, contracts on + bjam noeo_contracts # all in contracts/, pre and post off + bjam contracts_onoff # all in contracts/, all on/off combinations + bjam all_on # all directories, contracts on + bjam # all directories, all on/off combinations +""" ; + +# Directory Builds # + +# Build from the "contracts" directory. +rule dir-contracts ( name : defines * ) +{ + test-suite $(name) : + [ dir-run contracts : assertion_complexity_factorial + : $(name) : $(defines) ] + [ dir-run contracts : assertion_requirements_push_back + : $(name) : $(defines) ] + [ dir-run contracts : assertion_statement_ialloc + : $(name) : $(defines) ] + [ dir-run contracts : blockinv_loopvar_gcd : $(name) : $(defines) ] + [ dir-run contracts : body_natural : $(name) : $(defines) ] + [ dir-run contracts : broken_handler_sqrt : $(name) : $(defines) ] + [ dir-run contracts : class_ivector : $(name) : $(defines) ] + [ dir-run contracts : class_template_vector : $(name) : $(defines) ] + [ dir-run contracts : class_template_vector_seq + : $(name) : $(defines) ] + [ dir-run contracts : class_template_vector_seq_nova + : $(name) : $(defines) ] + [ dir-run contracts : const_assertion_number : $(name) : $(defines) ] + [ dir-run contracts : contract_failure : $(name) : $(defines) ] + [ dir-err contracts : const_assertion_number_global_error + : $(name) : $(defines) ] + [ dir-err contracts : const_assertion_number_static_error + : $(name) : $(defines) ] + [ dir-run contracts : const_select_assertion_factorial + : $(name) : $(defines) ] + [ dir-err contracts : const_select_assertion_factorial_error + : $(name) : $(defines) ] + [ dir-run contracts : copy_inc : $(name) : $(defines) ] + [ dir-run contracts : default_subcontracting_base + : $(name) : $(defines) ] + [ dir-run contracts : exception_array : $(name) : $(defines) ] + [ dir-run contracts : friend_counter : $(name) : $(defines) ] + [ dir-run contracts : function_template_postinc : $(name) : $(defines) ] + [ dir-run contracts : has_oldof_inc : $(name) : $(defines) ] + [ dir-run contracts : macro_commas_symbols_integral_map + : $(name) : $(defines) ] + [ dir-run contracts : macro_commas_symbols_integral_map_seq + : $(name) : $(defines) ] + [ dir-run contracts : macro_commas_symbols_integral_map_seq_nova + : $(name) : $(defines) ] + [ dir-run contracts : member_operator_string : $(name) : $(defines) ] + [ dir-run contracts : nested_class_bitset : $(name) : $(defines) ] + [ dir-run contracts : no_contract_ivector : $(name) : $(defines) ] + [ dir-run contracts : no_contract_postinc : $(name) : $(defines) ] + [ dir-run contracts : no_pre_post_postinc : $(name) : $(defines) ] + [ dir-run contracts : params_funcptr_array_apply + : $(name) : $(defines) ] + [ dir-run contracts : params_postinc : $(name) : $(defines) ] + [ dir-run contracts : post_also_postinc : $(name) : $(defines) ] + [ dir-run contracts : pre_only_postinc : $(name) : $(defines) ] + [ dir-run contracts : push_back : $(name) : $(defines) ] + [ dir-run contracts : select_assertion_factorial + : $(name) : $(defines) ] + [ dir-run contracts : static_assertion_memcopy : $(name) : $(defines) ] + [ dir-run contracts : static_contract_instance_counter + : $(name) : $(defines) ] + [ dir-run contracts : subcontract_identifiers : $(name) : $(defines) ] + [ dir-run contracts : subcontract_pre_natural_failure + : $(name) : $(defines) ] + [ dir-run contracts : template_params : $(name) : $(defines) ] + [ dir-run contracts : template_specializations_vector + : $(name) : $(defines) ] + [ dir-run contracts : typed_counter : $(name) : $(defines) ] + [ dir-run contracts : volatile_contract_shared_instance + : $(name) : $(defines) ] + ; +} + +# Build from the "virtual_specifiers" directory. +rule dir-virtual_specifiers ( name : defines * ) +{ + test-suite $(name) : + [ dir-run virtual_specifiers : final_class : $(name) : $(defines) ] + [ dir-err virtual_specifiers : final_class_error + : $(name) : $(defines) ] + [ dir-run virtual_specifiers : final_member : $(name) : $(defines) ] + [ dir-err virtual_specifiers : final_member_error + : $(name) : $(defines) ] + [ dir-run virtual_specifiers : new_member : $(name) : $(defines) ] + [ dir-err virtual_specifiers : new_member_error : $(name) : $(defines) ] + [ dir-run virtual_specifiers : override_member + : $(name) : $(defines) ] + [ dir-err virtual_specifiers : override_member_error + : $(name) : $(defines) ] + ; +} + +# Build from the "concepts" directory. +rule dir-concepts ( name : defines * ) +{ + test-suite $(name) : + [ dir-run concepts : class_member_concept_vector + : $(name) : $(defines) ] + [ dir-err concepts : class_member_concept_vector_error + : $(name) : $(defines) ] + [ dir-err concepts : class_member_concept_vector_constructor_error + : $(name) : $(defines) ] + [ dir-err concepts : class_member_concept_vector_member_error + : $(name) : $(defines) ] + [ dir-run concepts : free_concept_operator_preinc + : $(name) : $(defines) ] + [ dir-err concepts : free_concept_operator_preinc_error + : $(name) : $(defines) ] + ; +} + +# Build from the "named_parameters" directory. +rule dir-named_parameters ( name : defines * ) +{ + test-suite $(name) : + [ dir-run named_parameters : constructor_named_params_family + : $(name) : $(defines) ] + [ dir-run named_parameters : member_named_params_callable2 + : $(name) : $(defines) ] + [ dir-run named_parameters : named_param_identifiers_failure + : $(name) : $(defines) ] + [ dir-run named_parameters : named_param_identifiers_positive + : $(name) : $(defines) ] + [ dir-run named_parameters : named_params_dfs + : $(name) : $(defines) ] + [ dir-pymodule named_parameters : deduced_params_pydef + : $(name) : $(defines) ] + [ dir-pymodule named_parameters : named_template_params_pyclass + : $(name) : $(defines) ] + ; +} + +# Build from the "n1962" directory. +rule dir-n1962 ( name : defines * ) +{ + test-suite $(name) : + [ dir-run n1962 : block_invariant : $(name) : $(defines) ] + [ dir-run n1962 : circle : $(name) : $(defines) ] + [ run n1962/equal_main.cpp : : : $(defines) : $(name)_equal ] + [ dir-run n1962 : factorial : $(name) : $(defines) ] + [ dir-run n1962 : sqrt : $(name) : $(defines) ] + [ run n1962/sum.cpp n1962/sum_main.cpp : : : $(defines) : $(name)_sum ] + [ dir-run n1962 : vector : $(name) : $(defines) ] + ; +} + +# Build from the "n2081" directory. +rule dir-n2081 ( name : defines * ) +{ + test-suite $(name) : + [ dir-run n2081 : add : $(name) : $(defines) ] + [ dir-err n2081 : add_error : $(name) : $(defines) ] + [ dir-run n2081 : advance : $(name) : $(defines) ] + [ dir-run n2081 : apply : $(name) : $(defines) ] + [ dir-run n2081 : convert : $(name) : $(defines) ] + [ dir-err n2081 : convert_error : $(name) : $(defines) ] + [ dir-run n2081 : count : $(name) : $(defines) ] + [ dir-run n2081 : deref : $(name) : $(defines) ] + [ dir-run n2081 : equal : $(name) : $(defines) ] + [ dir-err n2081 : equal_error : $(name) : $(defines) ] + [ dir-run n2081 : find : $(name) : $(defines) ] + [ dir-err n2081 : find_error : $(name) : $(defines) ] + [ dir-run n2081 : for_each : $(name) : $(defines) ] + [ dir-run n2081 : less_eq : $(name) : $(defines) ] + [ dir-run n2081 : min : $(name) : $(defines) ] + [ dir-err n2081 : min_error : $(name) : $(defines) ] + [ dir-run n2081 : transform : $(name) : $(defines) ] + ; +} + +# Build from the "meyer97" directory. +rule dir-meyer97 ( name : defines * ) +{ + test-suite $(name) : + [ dir-run meyer97 : gcd : $(name) : $(defines) ] + [ dir-run meyer97 : maxarray : $(name) : $(defines) ] + [ dir-run meyer97 : stack3 : $(name) : $(defines) ] + [ run meyer97/stack4_main.cpp : : : $(defines) : $(name)_stack4 ] + ; +} + +# Build from the "mitchell02" directory. +rule dir-mitchell02 ( name : defines * ) +{ + test-suite $(name) : + [ run mitchell02/counter_main.cpp : : : $(defines) : $(name)_counter ] + [ run mitchell02/courier_main.cpp mitchell02/courier.cpp : : + : $(defines) : $(name)_courier ] + [ run mitchell02/customer_manager_main.cpp + mitchell02/customer_manager.cpp : : : $(defines) + : $(name)_customer_manager ] + [ dir-run mitchell02 : dictionary : $(name) : $(defines) ] + [ run mitchell02/name_list_main.cpp mitchell02/name_list.cpp : : + : $(defines) : $(name)_name_list ] + [ run mitchell02/observer_main.cpp : : : $(defines) : $(name)_observer ] + [ dir-run mitchell02 : simple_queue : $(name) : $(defines) ] + [ dir-run mitchell02 : stack : $(name) : $(defines) ] + ; +} + +# Build from the "stroustrup97" directory. +rule dir-stroustrup97 ( name : defines * ) +{ + test-suite $(name) : + [ run stroustrup97/string_main.cpp stroustrup97/string.cpp : : + : $(defines) : $(name)_string ] + ; +} + +# Build from the "cline90" directory. +rule dir-cline90 ( name : defines * ) +{ + test-suite $(name) : + [ dir-run cline90 : calendar : $(name) : $(defines) ] + [ dir-run cline90 : stack : $(name) : $(defines) ] + [ run cline90/vector_main.cpp : : : $(defines) : $(name)_vector ] + [ dir-run cline90 : vstack : $(name) : $(defines) ] + ; +} + +# Convenience Rules # + +# Compile a file in a directory and run it. +rule dir-run ( dir : cppfile : name : defines * ) +{ + run $(dir)/$(cppfile).cpp : : : $(defines) : $(name)_$(cppfile) ; +} + +# Check compiler-error for a file in a directory. +rule dir-err ( dir : cppfile : name : defines * ) +{ + compile-fail $(dir)/$(cppfile).cpp : $(defines) : $(name)_$(cppfile) ; +} + +type.register UNIT_TEST_RAW : UNIT_TEST ; +generators.register-standard testing.unit-test : : UNIT_TEST_RAW ; +if ! [ python.configured ] +{ + exit "error: python is not configured" ; +} + +# Use Python script to run a test. +rule py-test ( name : pyscript : commandline ) +{ + # Unfortunately, unit-test does not stop compilation when `-q` is used but + # it will signal the failure and build again the test in next runs. + unit-test-raw $(name) : $(pyscript) : + "python "$(pyscript)" "$(commandline) ; + always $(name) ; +} + +# Assume Boost.Python cppfile defines module named `$(name)_$(cppfile)_module`. +# Assume Python test script to run is named "$(cppfile).py". +rule dir-pymodule ( dir : cppfile : name : defines * ) +{ + python-extension $(name)_$(cppfile)_module : + # Need this complex file name because file name is always target of + # this rule so it must be unique across all on/off combinations. + $(dir)/$(cppfile)_module/$(name)_$(cppfile)_module.cpp : + /boost/python//boost_python + /boost/regex//boost_regex + shared:BOOST_REGEX_DYN_LINK=1 + $(defines) + ; + install $(name)_$(cppfile)_install1 : + $(name)_$(cppfile)_module : + on + SHARED_LIB + PYTHON_EXTENSION + $(dir) + ; + install $(name)_$(cppfile)_install2 : + $(name)_$(cppfile)_module : + on + SHARED_LIB + PYTHON_EXTENSION + . + ; + # On Linux, need to install on both `$(dir)` and `.`. + alias $(name)_$(cppfile)_install : + $(name)_$(cppfile)_install1 $(name)_$(cppfile)_install2 ; + py-test $(name)_$(cppfile)_run + : $(dir)/$(cppfile).py + : $(name)_$(cppfile)_module + ; + alias $(name)_$(cppfile) : + $(name)_$(cppfile)_install + $(name)_$(cppfile)_run + ; +} + +# Build all files with all sensible combinations of contract-off config macros. +rule config-combinations ( name ) +{ + # Pre, post, and class-inv are combined with each other but not with + # block-inv and loop-var (unless for all off) because they do not influence + # each other and in the interest to limit the target combinations. + # All on. + dir-$(name) $(name) ; + # 1 off. + dir-$(name) noe_$(name) : + CONTRACT_CONFIG_NO_PRECONDITIONS + ; + dir-$(name) noo_$(name) : + CONTRACT_CONFIG_NO_POSTCONDITIONS + ; + dir-$(name) noi_$(name) : + CONTRACT_CONFIG_NO_CLASS_INVARIANTS + ; + dir-$(name) nob_$(name) : + CONTRACT_CONFIG_NO_BLOCK_INVARIANTS + ; + dir-$(name) nol_$(name) : + CONTRACT_CONFIG_NO_LOOP_VARIANTS + ; + # 2 off. + dir-$(name) noeo_$(name) : + CONTRACT_CONFIG_NO_PRECONDITIONS + CONTRACT_CONFIG_NO_POSTCONDITIONS + ; + dir-$(name) noei_$(name) : + CONTRACT_CONFIG_NO_PRECONDITIONS + CONTRACT_CONFIG_NO_CLASS_INVARIANTS + ; + dir-$(name) nooi_$(name) : + CONTRACT_CONFIG_NO_POSTCONDITIONS + CONTRACT_CONFIG_NO_CLASS_INVARIANTS + ; + dir-$(name) nobl_$(name) : + CONTRACT_CONFIG_NO_BLOCK_INVARIANTS + CONTRACT_CONFIG_NO_LOOP_VARIANTS + ; + # 3 off. + dir-$(name) noeoi_$(name) : + CONTRACT_CONFIG_NO_PRECONDITIONS + CONTRACT_CONFIG_NO_POSTCONDITIONS + CONTRACT_CONFIG_NO_CLASS_INVARIANTS + ; + # All off. + dir-$(name) noeoibl_$(name) : + CONTRACT_CONFIG_NO_PRECONDITIONS + CONTRACT_CONFIG_NO_POSTCONDITIONS + CONTRACT_CONFIG_NO_CLASS_INVARIANTS + CONTRACT_CONFIG_NO_BLOCK_INVARIANTS + CONTRACT_CONFIG_NO_LOOP_VARIANTS + ; + # Target for all contract on/off combinations for a given directory. + alias $(name)_onoff : $(name) noe_$(name) noo_$(name) noi_$(name) + nob_$(name) nol_$(name) noeo_$(name) noei_$(name) nooi_$(name) + nobl_$(name) noeoi_$(name) noeoibl_$(name) ; +} + +# Target Definitions # + +# Define targets for all directories and all contract on/off combinations. +config-combinations contracts ; +config-combinations virtual_specifiers ; +config-combinations concepts ; +config-combinations named_parameters ; +config-combinations n1962 ; +config-combinations n2081 ; +config-combinations meyer97 ; +config-combinations mitchell02 ; +config-combinations stroustrup97 ; +config-combinations cline90 ; +alias all_on : contracts virtual_specifiers concepts named_parameters n1962 + n2081 meyer97 mitchell02 stroustrup97 cline90 ; +alias all_off : noeoibl_contracts noeoibl_virtual_specifiers noeoibl_concepts + noeoibl_named_parameters noeoibl_n1962 noeoibl_n2081 noeoibl_meyer97 + noeoibl_mitchell02 noeoibl_stroustrup97 noeoibl_cline90 ; + diff --git a/example/cline90/calendar.cpp b/example/cline90/calendar.cpp new file mode 100644 index 0000000..1280f27 --- /dev/null +++ b/example/cline90/calendar.cpp @@ -0,0 +1,74 @@ + +// 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 + +//[cline90_calendar +// File: calendar.cpp +#include +#include + +CONTRACT_CLASS( + class (calendar) +) { + CONTRACT_CLASS_INVARIANT( + month() >= 1, + month() <= 12, + date() >= 1, + date() <= days_in(month()) + ) + + CONTRACT_CONSTRUCTOR( + public (calendar) ( void ) + postcondition( month() == 1, date() == 31 ) + initialize( month_(1), date_(31) ) + ) {} + + CONTRACT_DESTRUCTOR( + public virtual (~calendar) ( void ) + ) {} + + CONTRACT_FUNCTION( + public int (month) ( void ) const + ) { + return month_; + } + + CONTRACT_FUNCTION( + public int (date) ( void ) const + ) { + return date_; + } + + CONTRACT_FUNCTION( + public void (reset) ( int new_month ) + precondition( new_month >= 1, new_month <= 12 ) + postcondition( month() == new_month ) + ) { + month_ = new_month; + } + + CONTRACT_FUNCTION( + private static int (days_in) ( int month ) + precondition( month >= 1, month <= 12 ) + postcondition( auto result = return, result >= 1, result <= 31 ) + ) { + return 31; // For simplicity, assume all months have 31 days. + } + + private: int month_, date_; +}; + +int main ( void ) +{ + calendar c; + BOOST_TEST(c.date() == 31); + BOOST_TEST(c.month() == 1); + c.reset(8); // Set month to August. + BOOST_TEST(c.month() == 8); + return boost::report_errors(); +} +//] + diff --git a/example/cline90/stack.cpp b/example/cline90/stack.cpp new file mode 100644 index 0000000..b980ebb --- /dev/null +++ b/example/cline90/stack.cpp @@ -0,0 +1,139 @@ + +// 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 + +//[cline90_stack +// File: stack.cpp +#include +#include +#include +#include +#include +#include +#include +#include + +CONTRACT_CLASS( + template( typename T ) + class (stack) +) { + // NOTE: Incomplete set of assertions addressing only `empty` and `full`. + + CONTRACT_CLASS_INVARIANT( void ) + + public: struct out_of_memory {}; + public: struct error {}; + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (stack) ( int capacity ) + precondition( capacity >= 0 ) + postcondition( + empty(), + full() == (capacity == 0) + ) + // Function-Try blocks are programmed within the macros only for + // constructors with member initializers otherwise they are + // programmed with the body definition and outside the macros. + try initialize( // Try-block for constructor initializers and body. + data_(new T[capacity]), + capacity_(capacity), + size_(0) + ) catch(std::bad_alloc& e) ( + std::cerr << "out of memory for " << capacity << "-stack: " << + e.what() << std::endl; + throw out_of_memory(); + // Unfortunately, cannot wrap exception type commas with extra + // parenthesis (because symbol `...` used to catch-all) but + // `BOOST_IDENTITY_TYPE` can be used. + ) catch(BOOST_IDENTITY_TYPE((std::pair&)) e) ( + std::cerr << "error number " << e.first << " for " << + capacity << "-stack: " << e.second << std::endl; + throw error(); + ) catch(...) ( + std::cerr << "unknown error for " << capacity << "-stack" << + std::endl; + throw; // Re-throw exception. + ) + ) { + for(int i = 0; i < capacity_; ++i) data_[i] = T(); + } + + CONTRACT_DESTRUCTOR_TPL( + public virtual (~stack) ( void ) + ) +#if !defined(BOOST_MSVC) // MSVC supports only constructor-try blocks. + try { // Function-try block (outside the macro). + delete[] data_; + } catch(...) { + std::cerr << "error for stack destruction, terminating" << std::endl; + std::terminate(); // Destructor should never throw. + } +#else // MSVC + { + delete[] data_; + } +#endif // MSVC + + CONTRACT_FUNCTION_TPL( + public bool (empty) ( void ) const + ) { + return size_ == 0; + } + + CONTRACT_FUNCTION_TPL( + public bool (full) ( void ) const + ) { + return size_ == capacity_; + } + + CONTRACT_FUNCTION_TPL( + public void (push) ( (T) value ) +#if !defined(BOOST_MSVC) // MSVC only supports throw( void ) exception spec. + throw( std::exception, error ) // Ex spec. +#endif // MSVC + precondition( not full() ) + postcondition( not empty() ) + ) +#if !defined(BOOST_MSVC) // MSVC supports only constructor-try blocks. + try +#endif // MSVC + { // Function-Try block (outside the macro). + data_[size_++] = value; + } +#if !defined(BOOST_MSVC) // MSVC supports only constructor-try blocks. + catch(std::exception& e) { + std::cerr << "error for " << capacity_ << "-stack: " << e.what() << + std::endl; + throw; // Re-throw STL exception. + } catch(...) { + std::cerr << "unknown error for " << capacity_ << "-stack" << + std::endl; + throw error(); + } +#endif // MSVC + + CONTRACT_FUNCTION_TPL( + public (T) (pop) ( void ) + precondition( not empty() ) + postcondition( not full() ) + ) { + return data_[--size_]; + } + + private: T* data_; + private: int capacity_; + private: int size_; +}; + +int main ( void ) +{ + stack s(3); + s.push(123); + BOOST_TEST(s.pop() == 123); + return boost::report_errors(); +} +//] + diff --git a/example/cline90/vector.hpp b/example/cline90/vector.hpp new file mode 100644 index 0000000..6e3e0ea --- /dev/null +++ b/example/cline90/vector.hpp @@ -0,0 +1,73 @@ + +// 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 + +//[cline90_vector_header +// File: vector.hpp +#ifndef VECTOR_HPP_ +#define VECTOR_HPP_ + +#include + +CONTRACT_CLASS( + template( typename T ) + class (vector) +) { + // NOTE: Incomplete set of assertions addressing only `size`. + + CONTRACT_CLASS_INVARIANT_TPL( size() >= 0 ) + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (vector) ( int count, default 10 ) + precondition( count >= 0 ) + postcondition( size() == count ) + initialize( data_(new T[count]), size_(count) ) + ) { + for(int i = 0; i < size_; ++i) data_[i] = T(); + } + + CONTRACT_DESTRUCTOR_TPL( + public virtual (~vector) ( void ) + ) { + delete[] data_; + } + + CONTRACT_FUNCTION_TPL( + public int (size) ( void ) const + // postcondition: Result non-negative checked by class invariant + ) { + return size_; + } + + CONTRACT_FUNCTION_TPL( + public void (resize) ( int count ) + precondition( count >= 0 ) + postcondition( size() == count ) + ) { + T* slice = new T[count]; + for(int i = 0; i < count && i < size_; ++i) slice[i] = data_[i]; + delete[] data_; + data_ = slice; + size_ = count; + } + + CONTRACT_FUNCTION_TPL( + public (T&) operator([])(at) ( int index ) + precondition( + index >= 0, + index < size() + ) + ) { + return data_[index]; + } + + private: T* data_; + private: int size_; +}; + +#endif // #include guard +//] + diff --git a/example/cline90/vector_app.hpp b/example/cline90/vector_app.hpp new file mode 100644 index 0000000..2a0207d --- /dev/null +++ b/example/cline90/vector_app.hpp @@ -0,0 +1,73 @@ + +// 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 + +//[cline90_vector_app_header +// File: vector_app.hpp +// Extra spaces, newlines, etc used to align text with this library code. + + + + + +template< typename T> +class vector +{ + legal: size() >= 0; // Class invariants (legal). + + public: explicit vector ( int count = 10 ) + : data_(new T[count]), size_(count) + { + for(int i = 0; i < size_; ++i) data_[i] = T(); + } + + public: virtual ~vector ( void ) + { + delete[] data_; + } + + public: int size ( void ) const + { + return size_; + } + + public: void resize ( int count ) + { + T* slice = new T[count]; + for(int i = 0; i < count && i < size_; ++i) slice[i] = data_[i]; + delete[] data_; + data_ = slice; + size_ = count; + } + + public: T& operator[] ( int index ) + { + return data_[index]; + } + + // Preconditions (require) and postconditions (promise) for each function. + axioms: [ int count; require count >= 0; promise size() == count ] + vector(count); + axioms: [ int count; require count >= 0; promise size() == count ] + resize(count); + axioms: [ int index; require index >= 0 && index < size() ] + (*this)[x]; + + private: T* data_; + private: int size_; +}; + + + + + + + + + + +//] + diff --git a/example/cline90/vector_main.cpp b/example/cline90/vector_main.cpp new file mode 100644 index 0000000..0f1e892 --- /dev/null +++ b/example/cline90/vector_main.cpp @@ -0,0 +1,24 @@ + +// 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 + +//[cline90_vector_main +// File: vector_main.cpp +#include "vector.hpp" +#include + +int main ( void ) +{ + vector v(3); // Also set all elements to 0.0. + BOOST_TEST(v.size() == 3); + v[0] = 123; + v.resize(2); + BOOST_TEST(v[0] == 123); + BOOST_TEST(v.size() == 2); + return boost::report_errors(); +} +//] + diff --git a/example/cline90/vstack.cpp b/example/cline90/vstack.cpp new file mode 100644 index 0000000..4557b16 --- /dev/null +++ b/example/cline90/vstack.cpp @@ -0,0 +1,144 @@ + +// 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 + +//[cline90_vstack +// File: vstack.cpp +#include "vector.hpp" +#include +#include + +CONTRACT_CLASS( // Stack Abstract Data Type (ADT). + template( typename T ) + class (stack_adt) +) { + // NOTE: Incomplete set of assertions addressing only empty/full issues. + + CONTRACT_CLASS_INVARIANT_TPL( void ) // no invariants + + CONTRACT_CONSTRUCTOR_TPL( + public (stack_adt) ( void ) + // postcondition: + // empty (cannot be checked because empty's postcondition uses + // length which is pure virtual during construction) + ) {} + + CONTRACT_DESTRUCTOR_TPL( + public (~stack_adt) ( void ) + ) {} + + CONTRACT_FUNCTION_TPL( + public bool (full) ( void ) const + postcondition( + auto result = return, + result == (length() == capacity()) + ) + ) { + return length() == capacity(); + } + + CONTRACT_FUNCTION_TPL( + public bool (empty) ( void ) const + postcondition( auto result = return, result == (length() == 0) ) + ) { + return length() == 0; + } + + CONTRACT_FUNCTION_TPL( + public virtual int (length) ( void ) const + postcondition( auto result = return, result >= 0 ) + ) = 0; + + CONTRACT_FUNCTION_TPL( + public virtual int (capacity) ( void ) const + postcondition( auto result = return, result >= 0 ) + ) = 0; + + CONTRACT_FUNCTION_TPL( + public virtual void (push) ( (T) value ) + precondition( not full() ) + postcondition( not empty() ) + ) = 0; // Contract for pure virtual function. + + CONTRACT_FUNCTION_TPL( + public virtual (T) (pop) ( void ) + precondition( not empty() ) + postcondition( not full() ) + ) = 0; + + CONTRACT_FUNCTION_TPL( + public virtual void (clear) ( void ) + postcondition( empty() ) + ) = 0; +}; + +CONTRACT_CLASS( // Vector-based stack. + template( typename T ) + class (vstack) extends( public stack_adt ) +) { + CONTRACT_CLASS_INVARIANT_TPL( + length() >= 0, + length() < capacity() + ) + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (vstack) ( int count, default 10 ) + precondition( count >= 0 ) + postcondition( length() == 0, capacity() == count ) + initialize( vect_(count), length_(0) ) // OK, after preconditions. + ) {} + + CONTRACT_DESTRUCTOR_TPL( + public virtual (~vstack) ( void ) + ) {} + + // NOTE: All following inherit contracts from `stack_adt`. + + CONTRACT_FUNCTION_TPL( + public int (length) ( void ) const override final + ) { + return length_; + } + + CONTRACT_FUNCTION_TPL( + public int (capacity) ( void ) const + ) { + return vect_.size(); + } + + CONTRACT_FUNCTION_TPL( + public void (push) ( (T) value ) override final + ) { + vect_[length_++] = value; + } + + CONTRACT_FUNCTION_TPL( + public (T) (pop) ( void ) override final + ) { + return vect_[--length_]; + } + + CONTRACT_FUNCTION_TPL( + public void (clear) ( void ) override final + ) { + length_ = 0; + } + + private: vector vect_; + private: int length_; +}; + +int main ( void ) +{ + vstack s(3); + BOOST_TEST(s.capacity() == 3); + s.push(123); + BOOST_TEST(s.length() == 1); + BOOST_TEST(s.pop() == 123); + return boost::report_errors(); +} +//] + diff --git a/example/contracts/assertion_complexity_factorial.cpp b/example/contracts/assertion_complexity_factorial.cpp new file mode 100644 index 0000000..e98cf78 --- /dev/null +++ b/example/contracts/assertion_complexity_factorial.cpp @@ -0,0 +1,47 @@ + +// 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 + +#include +#include + +//[assertion_complexity_factorial +// Assertion requirements used to model assertion computational complexity. +#define O_1 0 // O(1) constant (default). +#define O_N 1 // O(n) linear. +#define O_NN 2 // O(n * n) quadratic. +#define O_NX 3 // O(n^x) polynomial. +#define O_FACTN 4 // O(n!) factorial. +#define O_EXPN 5 // O(e^n) exponential. +#define O_ALL 10 +#define COMPLEXITY_MAX O_ALL + +CONTRACT_FUNCTION( + int (factorial) ( int n ) + precondition( n >= 0 ) + postcondition( + auto result = return, + result >= 1, + if(n < 2) ( + result == 1 + ) else ( + // Assertion compiled and checked only if within complexity. + result == n * factorial(n - 1), + requires O_FACTN <= COMPLEXITY_MAX + ) + ) +) { + if(n < 2) return 1; + else return n * factorial(n - 1); +} +//] + +int main ( void ) +{ + BOOST_TEST(factorial(4) == 24); + return boost::report_errors(); +} + diff --git a/example/contracts/assertion_requirements_push_back.cpp b/example/contracts/assertion_requirements_push_back.cpp new file mode 100644 index 0000000..86769d5 --- /dev/null +++ b/example/contracts/assertion_requirements_push_back.cpp @@ -0,0 +1,77 @@ + +// 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 + +#include +#include +#include + +//[assertion_requirements_push_back +#include + +CONTRACT_CLASS( + template( typename T ) + class (vector) +) { + CONTRACT_CLASS_INVARIANT_TPL( + size() <= capacity(), + capacity() <= max_size() + // ... + ) + + CONTRACT_FUNCTION_TPL( + public void (push_back) ( (T const&) value ) + precondition( size() < max_size() ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + auto old_capacity = CONTRACT_OLDOF capacity(), + size() == old_size + 1, + capacity() >= old_capacity, + // Requirements disable assertion if `T` has no `operator==`. + back() == value, requires boost::has_equal_to::value + ) + ) { + vector_.push_back(value); + } + + // ... +//] + + public: typedef typename std::vector::size_type size_type; + public: typedef typename std::vector::const_reference const_reference; + + public: size_type size ( void ) const { return vector_.size(); } + public: size_type max_size ( void ) const { return vector_.max_size(); } + public: size_type capacity ( void ) const { return vector_.capacity(); } + public: const_reference back ( void ) const { return vector_.back(); } + + private: std::vector vector_; +}; + +//[assertion_requirements_push_back_call +struct num // Not equality comparable. +{ + int value; + explicit num ( int a_value ) : value(a_value) {} +}; + +int main ( void ) +{ + vector i; + i.push_back(123); + + vector n; + n.push_back(num(123)); + BOOST_TEST(not boost::has_equal_to::value); + + // ... +//] + + BOOST_TEST(i.size() == 1); + BOOST_TEST(n.size() == 1); + return boost::report_errors(); +} + diff --git a/example/contracts/assertion_statement_ialloc.cpp b/example/contracts/assertion_statement_ialloc.cpp new file mode 100644 index 0000000..6d4180d --- /dev/null +++ b/example/contracts/assertion_statement_ialloc.cpp @@ -0,0 +1,42 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +//[assertion_statement_ialloc +CONTRACT_FUNCTION( + template( typename T ) + (T*) (ialloc) ( void ) + precondition( + namespace mpl = boost::mpl, // Namespace aliasing. + using namespace std, // Using directive. + typedef typename allocator::pointer ptr, // Type definition. + static_assert( + (mpl::or_< + mpl::bool_ + , mpl::bool_ + >::value) + , "within max size" + ) + ) +) { + return static_cast(malloc(sizeof(T))); +} +//] + +int main ( void ) +{ + char* p = ialloc(); + BOOST_TEST(p); + return boost::report_errors(); +} + diff --git a/example/contracts/blockinv_loopvar_gcd.cpp b/example/contracts/blockinv_loopvar_gcd.cpp new file mode 100644 index 0000000..476b90c --- /dev/null +++ b/example/contracts/blockinv_loopvar_gcd.cpp @@ -0,0 +1,51 @@ + +// 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 + +#include +#include +#include + +//[blockinv_loopvar_gcd +CONTRACT_FUNCTION( + template( typename T ) + (T) (gcd) ( (T const&) a, (T const&) b ) + precondition( + static_assert(boost::is_integral::value, "integral type"), + a != 0, + b != 0 + ) + postcondition( + auto result = return, + result <= a, + result <= b + ) +) { + T x = a, y = b; + // Block invariant assert conditions within body, + CONTRACT_BLOCK_INVARIANT_TPL( const( x, a ) x == a, const( y, b ) y == b ) + + CONTRACT_LOOP( while(x != y) ) { // Define a loop with variants (below). + // Block invariant for loops (i.e., loop invariants). + CONTRACT_BLOCK_INVARIANT_TPL( const( x ) x > 0, const( y ) y > 0 ) + // Loop variant checked to be non-negative and monotonically decreasing. + CONTRACT_LOOP_VARIANT_TPL( const( x, y ) std::max(x, y) ) + + if(x > y) x = x - y; + else y = y - x; + } + + return x; +} +//] + +int main ( void ) +{ + BOOST_TEST(gcd(12, 28) == 4); + BOOST_TEST(gcd(4, 14) == 2); + return boost::report_errors(); +} + diff --git a/example/contracts/body_natural.cpp b/example/contracts/body_natural.cpp new file mode 100644 index 0000000..8e24ca2 --- /dev/null +++ b/example/contracts/body_natural.cpp @@ -0,0 +1,19 @@ + +// 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 + +#include +#include "body_natural.hpp" + +int main ( void ) +{ + natural n, m(123); + BOOST_TEST(n.equal(natural())); + BOOST_TEST(less(n, m)); + BOOST_TEST(greater(m, n)); + return boost::report_errors(); +} + diff --git a/example/contracts/body_natural.hpp b/example/contracts/body_natural.hpp new file mode 100644 index 0000000..cd94dd6 --- /dev/null +++ b/example/contracts/body_natural.hpp @@ -0,0 +1,78 @@ + +// 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 + +#ifndef BODY_NATURAL_HPP_ +#define BODY_NATURAL_HPP_ + +#include + +//[body_natural +template< typename T, T Default = T() > // Class forward declaration. +class natural ; + +template< typename T > // Function forward declaration. +bool less ( natural const& left, natural const& right ) ; + +CONTRACT_FUNCTION( + template( typename T ) + bool (greater) ( (natural const&) left, (natural const&) right ) + postcondition( + auto result = return, + result ? not less(left, right) : true + ) +) ; // Deferred free function body definition, use `;`. + +CONTRACT_CLASS( // Class declaration (with contracts). + template( typename T, (T) Default ) + class (natural) +) { + CONTRACT_CLASS_INVARIANT_TPL( get() >= 0 ) + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (natural) ( (T const&) value, default Default ) + precondition( value >= 0 ) + postcondition( get() == value ) + // Unfortunately, no member initializers when body deferred. + ) ; // Deferred constructor body definition, use `;`. + + CONTRACT_DESTRUCTOR_TPL( + public (~natural) ( void ) + ) ; // Deferred destructor body definition, use `;`. + + CONTRACT_FUNCTION_TPL( + public bool (equal) ( (natural const&) right ) const + postcondition( + auto result = return, + result == not less(*this, right) && not greater(*this, right) + ) + ) ; // Deferred member function body definition, use `;`. + + CONTRACT_FUNCTION_TPL( + public (T) (get) ( void ) const + ) { + return value_; + } + + private: T value_; +}; + +CONTRACT_FUNCTION( // Function declaration (with contracts). + template( typename T ) + bool (less) ( (natural const&) left, (natural const&) right ) + postcondition( + auto result = return, + result ? not greater(left, right) : true + ) +) { + return left.get() < right.get(); +} +//] + +#include "body_natural_impl.hpp" + +#endif // #include guard + diff --git a/example/contracts/body_natural_impl.hpp b/example/contracts/body_natural_impl.hpp new file mode 100644 index 0000000..a135e2d --- /dev/null +++ b/example/contracts/body_natural_impl.hpp @@ -0,0 +1,39 @@ + +// 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 + +#include "body_natural.hpp" + +//[body_natural_impl +// Deferred body definitions, separated from their declarations and contracts. + +template< typename T > +bool CONTRACT_FREE_BODY(greater) ( + natural const& left, natural const& right ) +{ + return left.get() > right.get(); +} + +template< typename T, T Default > +CONTRACT_CONSTRUCTOR_BODY((natural), natural) ( T const& value ) +{ + value_ = value; +} + +template< typename T, T Default > +CONTRACT_DESTRUCTOR_BODY((natural), ~natural) ( void ) +{ + // Do nothing. +} + +template< typename T, T Default > +bool natural::CONTRACT_MEMBER_BODY(equal) ( natural const& right ) + const +{ + return not less(*this, right) && not greater(*this, right); +} +//] + diff --git a/example/contracts/broken_handler_sqrt.cpp b/example/contracts/broken_handler_sqrt.cpp new file mode 100644 index 0000000..10ed041 --- /dev/null +++ b/example/contracts/broken_handler_sqrt.cpp @@ -0,0 +1,92 @@ + +// 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 + +#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) +# warning "ignored known failure on G++ with C++0x" +# warning "note: maybe a compiler bug catching re-throws" + int main ( void ) { return 0; } // Trivial success. +#else + +#include +#include +#include + +//[broken_handler_sqrt +struct not_a_number {}; // User defined exception. + +CONTRACT_FUNCTION( + double (sqrt) ( double x ) + precondition( + x >= 0.0 ? true : throw not_a_number() // Throw user exception. + ) + postcondition( + auto root = return, + root * root == x // Failure throws `contract::broken` exception. + ) +) { + return 0.0; // Intentionally incorrect to fail postcondition. +} + +void throwing_handler ( contract::from const& context ) +{ + // Failure handlers always called with active exception that failed the + // contract, so re-throw it to catch it below for logging. + try { + throw; + } catch(contract::broken& failure) { + std::cerr << failure.file_name() << "(" << failure.line_number() << + "): contract assertion \"" << failure.assertion_code() << + "\" failed " << std::endl; + } catch(std::exception& failure) { + std::cerr << "contract failed: " << failure.what() << std::endl; + } catch(...) { + std::cerr << "contract failed with unknown error" << std::endl; + } + + // Cannot throw from destructors to comply with STL exception safety, + // otherwise re-throw active exception that failed the contract. + if(context == contract::FROM_DESTRUCTOR) + std::cerr << "Ignoring destructor contract failure (probably " + << "something bad has happened)" << std::endl; + else throw; // Never terminates. +} + +int main ( void ) +{ + // Customize contract broken handlers to throw exceptions instead of + // terminating the program (default). + contract::set_precondition_broken(&throwing_handler); + contract::set_postcondition_broken(&throwing_handler); + +#ifndef CONTRACT_CONFIG_NO_PRECONDITIONS + bool pre = false; + try { + sqrt(-1.0); // Fails precondition. + } catch(not_a_number&) { + pre = true; + std::clog << "Ignoring not-a-number exception" << std::endl; + } + BOOST_TEST(pre); +#endif + +#ifndef CONTRACT_CONFIG_NO_POSTCONDITIONS + bool post = false; + try { + sqrt(4.0); // Fails postcondition. + } catch(...) { + post = true; + std::clog << "Unable to calculate square root" << std::endl; + } + BOOST_TEST(post); +#endif + + return boost::report_errors(); +} +//] + +#endif // known failures + diff --git a/example/contracts/class_ivector.cpp b/example/contracts/class_ivector.cpp new file mode 100644 index 0000000..221d152 --- /dev/null +++ b/example/contracts/class_ivector.cpp @@ -0,0 +1,89 @@ + +// 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 + +#include +#include +#include +#include +#include + +//[class_ivector_classinv +CONTRACT_CLASS( // Declare the class. + class (ivector) +) { + CONTRACT_CLASS_INVARIANT( // Specify the class invariants. + empty() == (size() == 0), + size() <= capacity(), + capacity() <= max_size(), + std::distance(begin(), end()) == int(size()) + ) + + public: typedef std::vector::size_type size_type; + // ... +//] + public: typedef std::vector::const_reference const_reference; + public: typedef std::vector::const_iterator const_iterator; + + + //[class_ivector_constructor + CONTRACT_CONSTRUCTOR( // Declare the constructor and its contract. + public explicit (ivector) ( (size_type) count ) + precondition( count >= 0 ) + postcondition( + size() == count, + boost::algorithm::all_of_equal(begin(), end(), 0) + ) + initialize( vector_(count) ) + ) {} + //] + + //[class_ivector_destructor + CONTRACT_DESTRUCTOR( // Declare the destructor (so it checks invariants). + public virtual (~ivector) ( void ) + ) {} + //] + + //[class_ivector_member + CONTRACT_FUNCTION( // Declare the member function with its contract. + public void (push_back) ( int const value ) + precondition( size() < max_size() ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + auto old_capacity = CONTRACT_OLDOF capacity(), + size() == old_size + 1, + capacity() >= old_capacity, + back() == value + ) + ) { + vector_.push_back(value); + } + //] + + public: bool empty ( void ) const { return vector_.empty(); } + public: size_type size ( void ) const { return vector_.size(); } + public: size_type max_size ( void ) const { return vector_.max_size(); } + public: size_type capacity ( void ) const { return vector_.capacity(); } + public: const_reference back ( void ) const { return vector_.back(); } + public: const_iterator begin ( void ) const { return vector_.begin(); } + public: const_iterator end ( void ) const { return vector_.end(); } + + private: std::vector vector_; +}; + +int main ( void ) +{ + ivector v(1); + BOOST_TEST(v.size() == 1); + BOOST_TEST(v.back() == 0); + + v.push_back(123); + BOOST_TEST(v.size() == 2); + BOOST_TEST(v.back() == 123); + + return boost::report_errors(); +} + diff --git a/example/contracts/class_template_vector.cpp b/example/contracts/class_template_vector.cpp new file mode 100644 index 0000000..53b0bc1 --- /dev/null +++ b/example/contracts/class_template_vector.cpp @@ -0,0 +1,88 @@ + +// 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 + +#include +#include +#include +#include +#include + +//[class_template_vector +#include "pushable.hpp" + +CONTRACT_CLASS( + template( typename T ) + class (vector) extends( public pushable ) // Subcontract. +) { + // Within templates, use contract macros postfixed by `_TPL`. + + CONTRACT_CLASS_INVARIANT_TPL( + empty() == (size() == 0), + size() <= capacity(), + capacity() <= max_size(), + std::distance(begin(), end()) == int(size()) + ) + + public: typedef typename std::vector::size_type size_type; + public: typedef typename std::vector::const_reference const_reference; + public: typedef typename std::vector::const_iterator const_iterator; + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (vector) ( (size_type) count ) + precondition( count >= 0 ) + postcondition( + size() == count, + boost::algorithm::all_of_equal(begin(), end(), T()) + ) + initialize( vector_(count) ) + ) {} + + CONTRACT_DESTRUCTOR_TPL( + public virtual (~vector) ( void ) + ) {} + + CONTRACT_FUNCTION_TPL( + public void (push_back) ( (T const&) value ) + precondition( size() < max_size() ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + auto old_capacity = CONTRACT_OLDOF capacity(), + size() == old_size + 1, + capacity() >= old_capacity + // Overridden postconditions also check `back() == value`. + ) + ) { + vector_.push_back(value); + } + + // ... +//] + + public: bool empty ( void ) const { return vector_.empty(); } + public: size_type size ( void ) const { return vector_.size(); } + public: size_type max_size ( void ) const { return vector_.max_size(); } + public: size_type capacity ( void ) const { return vector_.capacity(); } + public: const_reference back ( void ) const { return vector_.back(); } + public: const_iterator begin ( void ) const { return vector_.begin(); } + public: const_iterator end ( void ) const { return vector_.end(); } + + private: std::vector vector_; +}; + +int main ( void ) +{ + vector v(1); + BOOST_TEST(v.size() == 1); + BOOST_TEST(v.back() == 0); + + v.push_back(123); + BOOST_TEST(v.size() == 2); + BOOST_TEST(v.back() == 123); + + return boost::report_errors(); +} + diff --git a/example/contracts/class_template_vector_seq.cpp b/example/contracts/class_template_vector_seq.cpp new file mode 100644 index 0000000..d53542c --- /dev/null +++ b/example/contracts/class_template_vector_seq.cpp @@ -0,0 +1,88 @@ + +// 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 + +#include +#include +#include +#include +#include + +//[class_template_vector_seq +#include "pushable_seq.hpp" + +CONTRACT_CLASS( + template( (typename T) ) + class (vector) extends( (public pushable) ) +) { + // Use preprocessor sequences instead of variadic comma-separated lists. + + CONTRACT_CLASS_INVARIANT_TPL( + (empty() == (size() == 0)) + (size() <= capacity()) + (capacity() <= max_size()) + (std::distance(begin(), end()) == int(size())) + ) + + public: typedef typename std::vector::size_type size_type; + public: typedef typename std::vector::const_reference const_reference; + public: typedef typename std::vector::const_iterator const_iterator; + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (vector) ( ((size_type) count) ) + precondition( (count >= 0) ) + postcondition( + (size() == count) + (boost::algorithm::all_of_equal(begin(), end(), T())) + ) + initialize( (vector_(count)) ) + ) {} + + CONTRACT_DESTRUCTOR_TPL( + public virtual (~vector) ( void ) + ) {} + + CONTRACT_FUNCTION_TPL( + public void (push_back) ( ((T const&) value) ) + precondition( (size() < max_size()) ) + postcondition( + (auto old_size = CONTRACT_OLDOF size()) + (auto old_capacity = CONTRACT_OLDOF capacity()) + (size() == old_size + 1) + (capacity() >= old_capacity) + // Overridden postconditions also check `back() == value`. + ) + ) { + vector_.push_back(value); + } + + // ... +//] + + public: bool empty ( void ) const { return vector_.empty(); } + public: size_type size ( void ) const { return vector_.size(); } + public: size_type max_size ( void ) const { return vector_.max_size(); } + public: size_type capacity ( void ) const { return vector_.capacity(); } + public: const_reference back ( void ) const { return vector_.back(); } + public: const_iterator begin ( void ) const { return vector_.begin(); } + public: const_iterator end ( void ) const { return vector_.end(); } + + private: std::vector vector_; +}; + +int main ( void ) +{ + vector v(1); + BOOST_TEST(v.size() == 1); + BOOST_TEST(v.back() == 0); + + v.push_back(123); + BOOST_TEST(v.size() == 2); + BOOST_TEST(v.back() == 123); + + return boost::report_errors(); +} + diff --git a/example/contracts/class_template_vector_seq_nova.cpp b/example/contracts/class_template_vector_seq_nova.cpp new file mode 100644 index 0000000..5569113 --- /dev/null +++ b/example/contracts/class_template_vector_seq_nova.cpp @@ -0,0 +1,10 @@ + +// 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 + +#include "nova.hpp" +#include "class_template_vector_seq.cpp" + diff --git a/example/contracts/const_assertion_number.cpp b/example/contracts/const_assertion_number.cpp new file mode 100644 index 0000000..42f5576 --- /dev/null +++ b/example/contracts/const_assertion_number.cpp @@ -0,0 +1,47 @@ + +// 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 + +#include +#include + +//[const_assertion_number +unsigned even = 0; + +CONTRACT_CLASS( + class (number) +) { + CONTRACT_CLASS_INVARIANT( void ) + + public: static unsigned odd; + + CONTRACT_FUNCTION( + public void (next) ( void ) + postcondition( + auto old_even = CONTRACT_OLDOF even, + auto old_odd = CONTRACT_OLDOF odd, + // `[old_]even` and `[old_]odd` all `const&` within assertions. + const( even, old_even ) even == old_even + 2, + const( odd, old_odd ) odd == old_odd + 2 + ) + ) { + even += 2; + odd += 2; + } +}; + +unsigned number::odd = 1; +//] + +int main ( void ) +{ + number n; + n.next(); + BOOST_TEST(even == 2); + BOOST_TEST(number::odd == 3); + return boost::report_errors(); +} + diff --git a/example/contracts/const_assertion_number_global_error.cpp b/example/contracts/const_assertion_number_global_error.cpp new file mode 100644 index 0000000..d2497be --- /dev/null +++ b/example/contracts/const_assertion_number_global_error.cpp @@ -0,0 +1,50 @@ + +// 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 + +#include +#include + +#ifdef CONTRACT_CONFIG_NO_POSTCONDITIONS +# error "constant assertion failure requires postconditions" +#endif + +//[const_assertion_number +unsigned even = 0; + +CONTRACT_CLASS( + class (number) +) { + CONTRACT_CLASS_INVARIANT( void ) + + public: static unsigned odd; + + CONTRACT_FUNCTION( + public void (next) ( void ) + postcondition( + auto old_even = CONTRACT_OLDOF even, + auto old_odd = CONTRACT_OLDOF odd, + const( even, old_even ) even = old_even + 2, // Correctly error. + const( odd, old_odd ) odd == old_odd + 2 + ) + ) { + even += 2; + odd += 2; + } +}; + +unsigned number::odd = 1; +//] + +int main ( void ) +{ + number n; + n.next(); + BOOST_TEST(even == 2); + BOOST_TEST(number::odd == 3); + return boost::report_errors(); +} + diff --git a/example/contracts/const_assertion_number_static_error.cpp b/example/contracts/const_assertion_number_static_error.cpp new file mode 100644 index 0000000..20e7c63 --- /dev/null +++ b/example/contracts/const_assertion_number_static_error.cpp @@ -0,0 +1,50 @@ + +// 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 + +#include +#include + +#ifdef CONTRACT_CONFIG_NO_POSTCONDITIONS +# error "constant assertion failure requires postconditions" +#endif + +//[const_assertion_number +unsigned even = 0; + +CONTRACT_CLASS( + class (number) +) { + CONTRACT_CLASS_INVARIANT( void ) + + public: static unsigned odd; + + CONTRACT_FUNCTION( + public void (next) ( void ) + postcondition( + auto old_even = CONTRACT_OLDOF even, + auto old_odd = CONTRACT_OLDOF odd, + const( even, old_even ) even == old_even + 2, + const( odd, old_odd ) odd = old_odd + 2 // Correctly error. + ) + ) { + even += 2; + odd += 2; + } +}; + +unsigned number::odd = 1; +//] + +int main ( void ) +{ + number n; + n.next(); + BOOST_TEST(even == 2); + BOOST_TEST(number::odd == 3); + return boost::report_errors(); +} + diff --git a/example/contracts/const_select_assertion_factorial.cpp b/example/contracts/const_select_assertion_factorial.cpp new file mode 100644 index 0000000..2f8469d --- /dev/null +++ b/example/contracts/const_select_assertion_factorial.cpp @@ -0,0 +1,42 @@ + +// 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 + +#include +#include + +//[const_select_assertion_factorial +int n = 0; + +CONTRACT_FUNCTION( + int (factorial) ( void ) + precondition( const( n ) n >= 0 ) + postcondition( + auto result = return, + if(const( n ) n == -1 or n == 0) ( // Constant-correct if-condition. + result == 1 + ) else ( + result >= 1 + ) + ) +) { + int m = n; + if(m == 0 or m == 1) { + return 1; + } else { + --n; + return m * factorial(); + } +} +//] + +int main ( void ) +{ + n = 4; + BOOST_TEST(factorial() == 24); + return boost::report_errors(); +} + diff --git a/example/contracts/const_select_assertion_factorial_error.cpp b/example/contracts/const_select_assertion_factorial_error.cpp new file mode 100644 index 0000000..df76e58 --- /dev/null +++ b/example/contracts/const_select_assertion_factorial_error.cpp @@ -0,0 +1,46 @@ + +// 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 + +#include +#include + +#ifdef CONTRACT_CONFIG_NO_POSTCONDITIONS +# error "constant select assertion failure requires postconditions" +#endif + +//[const_select_assertion_factorial +int n = 0; + +CONTRACT_FUNCTION( + int (factorial) ( void ) + precondition( const( n ) n >= 0 ) + postcondition( + auto result = return, + if(const( n ) n = 0 or n == 1) ( // n is const& within if-condition. + result == 1 + ) else ( + result >= 1 + ) + ) +) { + int m = n; + if(m == 0 or m == 1) { + return 1; + } else { + --n; + return m * factorial(); + } +} +//] + +int main ( void ) +{ + n = 4; + BOOST_TEST(factorial() == 24); + return boost::report_errors(); +} + diff --git a/example/contracts/contract_failure.cpp b/example/contracts/contract_failure.cpp new file mode 100644 index 0000000..0db6dcc --- /dev/null +++ b/example/contracts/contract_failure.cpp @@ -0,0 +1,474 @@ + +// 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 + +#include +#include +#include +#include + +bool // Fail the asserted conditions. + class_inv = true + , static_class_inv = true + , volatile_class_inv = true + , pre = true + , post = true +; + +struct check_pre // Check pre asserted before member initializers. +{ + check_pre ( void ) { BOOST_TEST(pre); } +}; + +struct forced_exception {}; + +CONTRACT_CLASS( + struct (failer) extends( check_pre ) +) { + CONTRACT_CLASS_INVARIANT( + class_inv, + static class( static_class_inv ), + volatile class( volatile_class_inv ) + ) + + CONTRACT_CONSTRUCTOR( + public (failer) ( + (bool*) inv, default 0, + bool const throwing, default false + ) + precondition( pre ) + postcondition( post ) + initialize( + check_pre(), + destructor_inv(0), + destructor_throwing(false) + ) + ) { + if(inv) *inv = false; + if(throwing) throw forced_exception(); + } + + bool* destructor_inv; // Destructor has not parameter, + bool destructor_throwing; // use data members instead. + + CONTRACT_DESTRUCTOR( + public virtual (~failer) ( void ) + ) { + if(destructor_inv) *destructor_inv = false; + // STL says destrcutors shall not throw, throwing here just for testing. + if(destructor_throwing) throw forced_exception(); + } + + CONTRACT_FUNCTION( + public void (fail) ( + (bool*) inv, default 0, + bool const throwing, default false + ) + precondition( pre ) + postcondition( post ) + ) { + if(inv) *inv = false; + if(throwing) throw forced_exception(); + } + + CONTRACT_FUNCTION( + public void (fail) ( + (bool*) inv, default 0, + bool const throwing, default false + ) volatile + precondition( pre ) + postcondition( post ) + ) { + if(inv) *inv = false; + if(throwing) throw forced_exception(); + } + + CONTRACT_FUNCTION( + public static void (static_failure) ( + (bool*) inv, default 0, + bool const throwing, default false + ) + precondition( pre ) + postcondition( post ) + ) { + if(inv) *inv = false; + if(throwing) throw forced_exception(); + } +}; + +CONTRACT_FUNCTION( + void (free_failure) ( bool const throwing, default false ) + precondition( pre ) + postcondition( post ) +) { + if(throwing) throw forced_exception(); +} + +std::string str ( contract::from const& context ) +{ + switch(context) { + case contract::FROM_CONSTRUCTOR: return "constructor"; + case contract::FROM_DESTRUCTOR: return "destructor"; + case contract::FROM_NONSTATIC_MEMBER_FUNCTION: + return "non-static member function"; + case contract::FROM_STATIC_MEMBER_FUNCTION: return "static member function"; + case contract::FROM_FREE_FUNCTION: return "free function"; + case contract::FROM_BODY: return "body"; + } + return ""; +} + +#define THROWING_HANDLER(name) \ + struct name \ + { \ + contract::from context; \ + contract::broken error; \ + name ( contract::from const& a_context, \ + contract::broken const& an_error ) \ + : context(a_context), error(an_error) {} \ + }; \ + void BOOST_PP_CAT(name, _handler) ( contract::from const& context ) \ + { \ + try { \ + throw; \ + } catch(contract::broken& error) { \ + std::cerr << "checking " << BOOST_PP_STRINGIZE(name) << \ + " from " << str(context) << ":" << std::endl; \ + std::cerr << " " << error.what() << std::endl; \ + throw name(context, error); \ + } \ + } + +#define CHECK(assertion, exception, from_context, body) \ + pass = false; \ + try { \ + body \ + } catch(exception& ex) { \ + assertion = true; \ + BOOST_TEST(ex.context == from_context); \ + BOOST_TEST(std::string(ex.error.assertion_code()) == \ + BOOST_PP_STRINGIZE(assertion)); \ + BOOST_TEST(ex.error.assertion_number() == 1); \ + pass = true; \ + } \ + assertion = true; \ + BOOST_TEST(pass); \ + +#define CHECK_THROW(body) \ + pass = false; \ + try { \ + body \ + } catch(forced_exception) { \ + std::cerr << "checking throw with no contract failure:" << std::endl; \ + std::cerr << " no broken contract: file \"" << __FILE__ << \ + "\", line " << __LINE__ << std::endl; \ + pass = true; \ + } \ + BOOST_TEST(pass); + +THROWING_HANDLER(class_inv_broken_on_entry) +THROWING_HANDLER(class_inv_broken_on_exit) +THROWING_HANDLER(class_inv_broken_on_throw) +THROWING_HANDLER(pre_broken) +THROWING_HANDLER(post_broken) +THROWING_HANDLER(block_inv_broken) +THROWING_HANDLER(loop_var_broken) + +int main ( void ) +{ + contract::set_class_invariant_broken_on_entry( + &class_inv_broken_on_entry_handler); + contract::set_class_invariant_broken_on_exit( + &class_inv_broken_on_exit_handler); + contract::set_class_invariant_broken_on_throw( + &class_inv_broken_on_throw_handler); + contract::set_precondition_broken(&pre_broken_handler); + contract::set_postcondition_broken(&post_broken_handler); + contract::set_block_invariant_broken(&block_inv_broken_handler); + contract::set_loop_variant_broken(&loop_var_broken_handler); + + bool const throwing = true; + bool* const no_broken_inv = 0; + contract::from context; + bool pass = false; + + // Check constructor contract failures. + context = contract::FROM_CONSTRUCTOR; +#ifndef CONTRACT_CONFIG_NO_CLASS_INVARIANTS + // Fail static class invariants on entry. + CHECK(static_class_inv, class_inv_broken_on_entry, context, + static_class_inv = false; + failer failure; + ) + // Fail static class invariants on exit. + CHECK(static_class_inv, class_inv_broken_on_exit, context, + failer failure(&static_class_inv); + ) + // Fail static class invariants on throw. + CHECK(static_class_inv, class_inv_broken_on_throw, context, + failer failure(&static_class_inv, throwing); + ) + // Class invariants on entry do not apply. + // Fail class invariants on exit. + CHECK(class_inv, class_inv_broken_on_exit, context, + failer failure(&class_inv); + ) + // Class invariants on throw do not apply. + // Volatile class invariants on entry do not apply. + // Volatile class invariants on exit do not apply. + // Volatile class invariants on throw do not apply. +#endif +#ifndef CONTRACT_CONFIG_NO_PRECONDITIONS + // Fail preconditions on entry (before member initializers). + CHECK(pre, pre_broken, context, + pre = false; + failer failure; + ) +#endif +#ifndef CONTRACT_CONFIG_NO_POSTCONDITIONS + // Fail postconditions on exit (when no throw). + CHECK(post, post_broken, context, + post = false; + failer failure; + ) +#endif + // Throw with no contract failure. + CHECK_THROW( + failer failure(no_broken_inv, throwing); + ) + std::cerr << std::endl; + + // Check destructor contract failures. + context = contract::FROM_DESTRUCTOR; +#ifndef CONTRACT_CONFIG_NO_CLASS_INVARIANTS + // Fail static class invariants on entry. + CHECK(static_class_inv, class_inv_broken_on_entry, context, + failer failure; + static_class_inv = false; + ) + // Fail static class invariants on exit. + CHECK(static_class_inv, class_inv_broken_on_exit, context, + failer failure; + failure.destructor_inv = &static_class_inv; + ) + // Fail static class invariants on throw. + CHECK(static_class_inv, class_inv_broken_on_throw, context, + failer failure; + failure.destructor_inv = &static_class_inv; + failure.destructor_throwing = true; + ) + // Fail class invariants on entry. + CHECK(class_inv, class_inv_broken_on_entry, context, + failer failure; + class_inv = false; + ) + // Class invariants on exit do not apply. + // Fail class invariants on throw. + CHECK(class_inv, class_inv_broken_on_throw, context, + failer failure; + failure.destructor_inv = &class_inv; + failure.destructor_throwing = true; + ) + // Volatile class invariants on entry do not apply. + // Volatile class invariants on exit do not apply. + // Volatile class invariants on throw do not apply. +#endif + // Preconditions on entry do not apply. + // Postconditions on exit (when no throw) do not apply. + // Throw with no contract failure. + CHECK_THROW( + failer failure; + failure.destructor_throwing = true; + ) + std::cerr << std::endl; + + // Failure objects declared here to they are not destructed within the + // code checking member function contracts (otherwise, that code would also + // re-check constructor and destructor contracts all the times). + failer failure; + failer volatile volatile_failure; + + // Check non-static member function contract failures. + context = contract::FROM_NONSTATIC_MEMBER_FUNCTION; +#ifndef CONTRACT_CONFIG_NO_CLASS_INVARIANTS + // Fail static class invariants on entry. + CHECK(static_class_inv, class_inv_broken_on_entry, context, + static_class_inv = false; + failure.fail(); + ) + // Fail static class invariants on exit. + CHECK(static_class_inv, class_inv_broken_on_exit, context, + failure.fail(&static_class_inv); + ) + // Fail static class invariants on throw. + CHECK(static_class_inv, class_inv_broken_on_throw, context, + failure.fail(&static_class_inv, throwing); + ) + // Fail class invariants on entry. + CHECK(class_inv, class_inv_broken_on_entry, context, + class_inv = false; + failure.fail(); + ) + // Fail class invariants on exit. + CHECK(class_inv, class_inv_broken_on_exit, context, + failure.fail(&class_inv); + ) + // Fail class invariants on throw. + CHECK(class_inv, class_inv_broken_on_throw, context, + failure.fail(&class_inv, throwing); + ) + // Fail volatile class invariants on entry. + CHECK(volatile_class_inv, class_inv_broken_on_entry, context, + volatile_class_inv = false; + volatile_failure.fail(); + ) + // Fail volatile class invariants on exit. + CHECK(volatile_class_inv, class_inv_broken_on_exit, context, + volatile_failure.fail(&volatile_class_inv); + ) + // Fail volatile class invariants on throw. + CHECK(volatile_class_inv, class_inv_broken_on_throw, context, + volatile_failure.fail(&volatile_class_inv, throwing); + ) +#endif +#ifndef CONTRACT_CONFIG_NO_PRECONDITIONS + // Fail preconditions on entry. + CHECK(pre, pre_broken, context, + pre = false; + failure.fail(); + ) +#endif +#ifndef CONTRACT_CONFIG_NO_POSTCONDITIONS + // Fail postconditions on exit (when no throw). + CHECK(post, post_broken, context, + post = false; + failure.fail(); + ) +#endif + // Throw with no contract failure. + CHECK_THROW( + failure.fail(no_broken_inv, throwing); + ) + std::cerr << std::endl; + + // Check static member function contract failures. + context = contract::FROM_STATIC_MEMBER_FUNCTION; +#ifndef CONTRACT_CONFIG_NO_CLASS_INVARIANTS + // Fail static class invariants on entry. + CHECK(static_class_inv, class_inv_broken_on_entry, context, + static_class_inv = false; + failer::static_failure(); + ) + // Fail static class invariants on exit. + CHECK(static_class_inv, class_inv_broken_on_exit, context, + failer::static_failure(&static_class_inv); + ) + // Fail static class invariants on throw. + CHECK(static_class_inv, class_inv_broken_on_throw, context, + failer::static_failure(&static_class_inv, throwing); + ) + // Class invariants on entry do not apply. + // Class invariants on exit do not apply. + // Class invariants on throw do not apply. + // Volatile class invariants on entry do not apply. + // Volatile class invariants on exit do not apply. + // Volatile class invariants on throw do not apply. +#endif +#ifndef CONTRACT_CONFIG_NO_PRECONDITIONS + // Fail preconditions on entry. + CHECK(pre, pre_broken, context, + pre = false; + failer::static_failure(); + ) +#endif +#ifndef CONTRACT_CONFIG_NO_POSTCONDITIONS + // Fail postconditions on exit (when no throw). + CHECK(post, post_broken, context, + post = false; + failer::static_failure(); + ) +#endif + // Throw with no contract failure. + CHECK_THROW( + failer::static_failure(no_broken_inv, throwing); + ) + std::cerr << std::endl; + + // Check free function contract failures. + context = contract::FROM_FREE_FUNCTION; + // Static class invariants on entry do not apply. + // Static class invariants on exit do not apply. + // Static class invariants on throw do not apply. + // Class invariants on entry do not apply. + // Class invariants on exit do not apply. + // Class invariants on throw do not apply. + // Volatile class invariants on entry do not apply. + // Volatile class invariants on exit do not apply. + // Volatile class invariants on throw do not apply. +#ifndef CONTRACT_CONFIG_NO_PRECONDITIONS + // Fail preconditions on entry. + CHECK(pre, pre_broken, context, + pre = false; + free_failure(); + ) +#endif +#ifndef CONTRACT_CONFIG_NO_POSTCONDITIONS + // Fail postconditions on exit (when no throw). + CHECK(post, post_broken, context, + post = false; + free_failure(); + ) +#endif + // Throw with no contract failure. + CHECK_THROW( + free_failure(throwing); + ) + std::cerr << std::endl; + + // Check block invariant contract failure. +#ifndef CONTRACT_CONFIG_NO_BLOCK_INVARIANTS + pass = false; + try { + CONTRACT_BLOCK_INVARIANT(false) + } catch(block_inv_broken) { + pass = true; + } + BOOST_TEST(pass); + std::cerr << std::endl; +#endif + + // Check loop variant contract failures. +#ifndef CONTRACT_CONFIG_NO_LOOP_VARIANTS + // OK, decreasing to 0. + CONTRACT_LOOP( for(int i = 0; i < 10; ++i) ) { + CONTRACT_LOOP_VARIANT( 9 - i ) + } + // Failure, decreasing to negative. + pass = false; + try { + CONTRACT_LOOP( for(int i = 0; i < 10; ++i) ) { + CONTRACT_LOOP_VARIANT( 8 - i ) + } + } catch(loop_var_broken) { + pass = true; + } + BOOST_TEST(pass); + // Failure, not decreasing. + pass = false; + try { + CONTRACT_LOOP( for(int i = 0; i < 10; ++i) ) { + CONTRACT_LOOP_VARIANT( 10 ) + } + } catch(loop_var_broken) { + pass = true; + } + BOOST_TEST(pass); + std::cerr << std::endl; +#endif + + return boost::report_errors(); +} + diff --git a/example/contracts/copy_inc.cpp b/example/contracts/copy_inc.cpp new file mode 100644 index 0000000..facbd7a --- /dev/null +++ b/example/contracts/copy_inc.cpp @@ -0,0 +1,76 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +//[copy_inc +CONTRACT_FUNCTION( + template( typename T ) + (T&) (inc) ( (T&) value, (T const&) offset ) + postcondition( + auto old_value = CONTRACT_OLDOF value, // Use `copy`. + auto result = return, // Would use `copy` but reference so no copy. + value == old_value + offset, requires + boost::has_plus::value and + boost::has_equal_to::value, + result == value, requires + boost::has_equal_to::value + ) +) { + return value += offset; +} + +class num : boost::noncopyable // Non-copyable (for some reason...). +{ + friend class contract::copy; // Contract copy is friend. + + public: explicit num ( int value ) : ptr_(new int(value)) {} + private: num ( num const& other ) : ptr_(other.ptr_) {} + public: ~num ( void ) { delete ptr_; } + + public: num operator+ ( num const& right ) const + { return num(*ptr_ + *right.ptr_); } + public: num& operator+= ( num const& right ) + { *ptr_ += *right.ptr_; return *this; } + public: bool operator== ( num const& right ) const + { return *ptr_ == *right.ptr_; } + + private: int* ptr_; +}; + +// Specialization disables old-of for non-copyable `num` (no C++ type trait can +// automatically detect copy constructors). +namespace contract +{ + template< > + class copy < num > + { + public: explicit copy ( num const& n ) : num_(*n.ptr_) {} + public: num const& value ( void ) const { return num_; } + + private: num num_; + }; +} // namespace +//] + +int main ( void ) +{ + //[copy_inc_call + int i = 1, j = 2; + BOOST_TEST(inc(i, j) == 3); + + num n(1), m(2); + BOOST_TEST(inc(n, m) == num(3)); + //] + return boost::report_errors(); +} + diff --git a/example/contracts/default_subcontracting_base.cpp b/example/contracts/default_subcontracting_base.cpp new file mode 100644 index 0000000..1030b3a --- /dev/null +++ b/example/contracts/default_subcontracting_base.cpp @@ -0,0 +1,34 @@ + +#include +#include + +//[default_subcontracting_base +CONTRACT_CLASS( + class (base) // Declared with contract macros. +) { + CONTRACT_CLASS_INVARIANT( std::clog << "base::inv" << std::endl ) + + CONTRACT_FUNCTION( + public virtual void (f) ( void ) + precondition( std::clog << "base::f::pre" << std::endl ) + postcondition( std::clog << "base::f::post" << std::endl ) + ) = 0; +}; + +class deriv : public base // Declared without contract macros... +{ + // ...but using `BODY` instead of `CLASS` and `FUNCTION` macros, overriding + // functions have exact same contracts as base (not real subcontracting). + public: virtual void CONTRACT_MEMBER_BODY(f) ( void ) + { + std::clog << "deriv::f::body" << std::endl; + } +}; +//] + +int main ( void ) +{ + deriv().f(); // Check `base::f` contract but execute `deriv::f` body. + return 0; +} + diff --git a/example/contracts/exception_array.cpp b/example/contracts/exception_array.cpp new file mode 100644 index 0000000..9bcb8c8 --- /dev/null +++ b/example/contracts/exception_array.cpp @@ -0,0 +1,75 @@ + +// 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 + +#include +#include + +//[exception_array +CONTRACT_CLASS( + template( typename T ) + class (array) +) { + CONTRACT_CLASS_INVARIANT_TPL( size() >= 0 ) + + public: struct out_of_memory {}; + public: struct error {}; + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (array) ( size_t count ) + precondition( count >= 0 ) + postcondition( size() == count ) + // Function try-blocks are programmed within the macros only for + // constructors with member initializers otherwise they are + // programmed with the body definitions and outside the macros. + try initialize( // Try block for constructor initializers and body. + data_(new T[count]), + size_(count) + // Use `BOOST_IDENTITY_TYPE` if the exception type has unwrapped + // commas or leading symbols. + ) catch(std::bad_alloc&) ( + throw out_of_memory(); + ) catch(...) ( + throw error(); + ) + ) {} + + CONTRACT_DESTRUCTOR_TPL( + public virtual (~array) ( void ) throw( void ) // Throw nothing. + ) { + delete[] data_; + } + + // ... +//] + + CONTRACT_FUNCTION_TPL( + public size_t (size) ( void ) const + ) { + return size_; + } + + CONTRACT_FUNCTION_TPL( + public (T&) operator([])(at) ( size_t index ) + precondition( index >= 0, index < size() ) + ) { + return data_[index]; + } + + private: T* data_; + private: size_t size_; +}; + +int main ( void ) +{ + array a(3); + BOOST_TEST(a.size() == 3); + a[0] = 1; BOOST_TEST(a[0] == 1); + a[1] = 2; BOOST_TEST(a[1] == 2); + a[2] = 3; BOOST_TEST(a[2] == 3); + return boost::report_errors(); +} + diff --git a/example/contracts/friend_counter.cpp b/example/contracts/friend_counter.cpp new file mode 100644 index 0000000..35009d6 --- /dev/null +++ b/example/contracts/friend_counter.cpp @@ -0,0 +1,106 @@ + +// 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 + +#include +#include +#include + +//[friend_counter +CONTRACT_CLASS( // Not even necessary to contract this class. + template( typename T ) requires( boost::CopyConstructible ) + class (counter) +) { + CONTRACT_CLASS_INVARIANT_TPL( value() >= 0 ); + + CONTRACT_FUNCTION_TPL( // Friend (contracted declaration and definition). + public friend (counter) operator(/)(div) ( (counter const&) left, + (T const&) right ) + precondition( right > 0 ) // Strictly positive, cannot be zero. + postcondition( + auto result = return, + result.value() * right == left.value() + ) + ) { + return counter(left.value() / right); + } + + // Friend forward declaration (contracted declaration and definition below). + public: template< typename U > + friend bool CONTRACT_FREE_BODY(operator(==)(equal)) ( // Use BODY. + counter const& left, U const& right ) ; + +// NOTE: Forward friend template instantiations give internal MSVC error. +#if defined(BOOST_MSVC) && !defined(CONTRACT_CONFIG_NO_POSTCONDITIONS) + // Friend definition (contracted declaration below). + public: friend counter CONTRACT_FREE_BODY(operator(*)(mult)) ( // Use BODY. + counter const& left, T const& right ) + { + return counter(left.value() * right); // Contract checked `right >=0` . + } +#endif + + CONTRACT_CONSTRUCTOR_TPL( // Public constructor gets next counter value. + public explicit (counter) ( void ) + initialize( value_(next_value_++) ) + ) {} + + CONTRACT_CONSTRUCTOR_TPL( // Private constructor. + private explicit (counter) ( (T const&) a_value ) + precondition( a_value >= 0 ) + postcondition( value() == a_value ) + initialize( value_(a_value) ) + ) {} + + CONTRACT_FUNCTION_TPL( + public (T) (value) ( void ) const + postcondition( auto result = return, result >= 0 ) + ) { + return value_; + } + + private: T value_; + private: static T next_value_; +}; + +template +T counter::next_value_ = T(); + +CONTRACT_FUNCTION( + template( typename U ) + bool operator(==)(equal) ( (counter const&) left, (U const&) right ) + precondition( right >= 0 ) + postcondition( + auto result = return, + result == (left.value() == right) + ) +) { + return left.value() == right; +} + +#if defined(BOOST_MSVC) && !defined(CONTRACT_CONFIG_NO_POSTCONDITIONS) +CONTRACT_FUNCTION( + (counter) operator(*)(mult) ( (counter const&) left, + (int const&) right ) + precondition( right >= 0 ) + postcondition( + auto result = return, + result.value() == left.value() * right + ) +) ; +#endif +//] + +int main ( void ) +{ + counter i0, i1, i2, i3, i4; + BOOST_TEST(i4 / 2 == 2); +#if defined(BOOST_MSVC) && !defined(CONTRACT_CONFIG_NO_POSTCONDITIONS) + BOOST_TEST(i3 * 2 == 6); +#endif + return boost::report_errors(); +} + diff --git a/example/contracts/function_template_postinc.cpp b/example/contracts/function_template_postinc.cpp new file mode 100644 index 0000000..85b4e02 --- /dev/null +++ b/example/contracts/function_template_postinc.cpp @@ -0,0 +1,35 @@ + +// 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 + +#include +#include +#include + +//[function_template_postinc +CONTRACT_FUNCTION( + template( typename T ) // Template parameter(s). + (T const) (postinc) ( (T&) value ) + precondition( value < std::numeric_limits::max() ) + postcondition( + auto result = return, + auto old_value = CONTRACT_OLDOF value, + value == old_value + 1, + result == old_value + ) +) { + return value++; +} +//] + +int main ( void ) +{ + int value = 1; + BOOST_TEST(postinc(value) == 1); + BOOST_TEST(value == 2); + return boost::report_errors(); +} + diff --git a/example/contracts/has_oldof_inc.cpp b/example/contracts/has_oldof_inc.cpp new file mode 100644 index 0000000..029cafb --- /dev/null +++ b/example/contracts/has_oldof_inc.cpp @@ -0,0 +1,68 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +//[has_oldof_inc +CONTRACT_FUNCTION( + template( typename T ) + (T&) (inc) ( (T&) value, (T const&) offset ) + postcondition( + auto old_value = CONTRACT_OLDOF value, // Skip if no old-of. + auto result = return, // Never skipped. + value == old_value + offset, requires + contract::has_oldof::value and // Requires old-of. + boost::has_plus::value and + boost::has_equal_to::value, + result == value, requires + boost::has_equal_to::value + ) +) { + return value += offset; +} + +class num : boost::noncopyable // Non-copyable (for some reason...). +{ + public: explicit num ( int value ) : ptr_(new int(value)) {} + private: num ( num const& other ) : ptr_(other.ptr_) {} // Private copy. + public: ~num ( void ) { delete ptr_; } + + public: num operator+ ( num const& right ) const + { return num(*ptr_ + *right.ptr_); } + public: num& operator+= ( num const& right ) + { *ptr_ += *right.ptr_; return *this; } + public: bool operator== ( num const& right ) const + { return *ptr_ == *right.ptr_; } + + private: int* ptr_; +}; + +// Specialization disables old-of for non-copyable `num` (no C++ type trait can +// automatically detect copy constructors). +namespace contract +{ + template< > struct has_oldof < num > : boost::mpl::false_ {}; +} // namespace +//] + +int main ( void ) +{ + //[has_oldof_inc_call + int i = 1, j = 2; + BOOST_TEST(inc(i, j) == 3); + + num n(1), m(2); + BOOST_TEST(inc(n, m) == num(3)); + //] + return boost::report_errors(); +} + diff --git a/example/contracts/macro_commas_symbols_integral_map.cpp b/example/contracts/macro_commas_symbols_integral_map.cpp new file mode 100644 index 0000000..72ffd87 --- /dev/null +++ b/example/contracts/macro_commas_symbols_integral_map.cpp @@ -0,0 +1,103 @@ + +// 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 + +#include +#include +#include +#include +#include + +template< typename Key, typename T > +struct sizeable +{ + public: typedef typename std::map::size_type size_type; + public: static size_type const max_size = 100; + public: virtual size_type size( void ) const = 0; +}; + +//[macro_commas_symbols_integral_map +CONTRACT_CLASS( + template( + typename Key, + typename T, // Commas in following template params. + class Allocator, + default (::std::allocator >), + (typename ::std::map::key_type) default_key, + default (-1) + ) requires( (boost::Convertible) ) // Commas in concepts. + class (integral_map) + extends( public (::sizeable) ) // Commas in bases. +) { + CONTRACT_CLASS_INVARIANT_TPL( // Commas in class invariants. + (::sizeable::max_size) >= size() + ) + + public: typedef typename std::map, Allocator>:: + iterator iterator; + + CONTRACT_FUNCTION_TPL( + public template( typename OtherKey, typename OtherT ) + requires( + (::boost::Convertible), + (::boost::Convertible) + ) + (::std::pair) (insert) ( // Commas in result and params. + (::std::pair const&) other_value, + default (::std::pair(default_key, T())) + ) throw( (::std::pair) ) // Commas in exception specs. + precondition( // Leading symbols in preconditions (same for commas). + ((!full())) // LIMITATION: Two sets `((...))` (otherwise seq.). + ) + postcondition( // Commas in postconditions. + auto result = return, + (typename sizeable::size_type) + old_other_size = CONTRACT_OLDOF + (size()), + (::sizeable::max_size) >= size(), + size() == old_other_size + (result.second ? 1 : 0) + ) + ) { + // ... +//] + std::pair value(other_value.first, other_value.second); + std::pair result = map_.insert(value); + if(size() > sizeable::max_size) throw value; + return result; + } + + public: bool full ( void ) const + { return size() == sizeable::max_size; } + + public: typename sizeable::size_type size ( void ) const + { return map_.size(); } + + public: template< typename OtherKey, typename OtherT > + typename sizeable::size_type size ( void ) const + { return map_.size(); } + + public: T& operator[] ( Key const& key ) { return map_[key]; } + + private: std::map, Allocator> map_; +}; + +int main ( void ) +{ + integral_map m; + m.insert(std::make_pair(123, 'a')); + BOOST_TEST(m[char(123)] == int('a')); + m.insert(); + BOOST_TEST(m[char(-1)] == int()); + + // Test an implementation detail. + BOOST_TEST(CONTRACT_DETAIL_PP_IS_VARIADIC( (std::pair) ) == 1); + BOOST_TEST(CONTRACT_DETAIL_PP_IS_VARIADIC( (std::pair) p) == 1); + BOOST_TEST(CONTRACT_DETAIL_PP_IS_VARIADIC( false ) == 1); + BOOST_TEST(CONTRACT_DETAIL_PP_IS_VARIADIC( (!false) ) == 0); // Sequence. + + return boost::report_errors(); +} + diff --git a/example/contracts/macro_commas_symbols_integral_map_seq.cpp b/example/contracts/macro_commas_symbols_integral_map_seq.cpp new file mode 100644 index 0000000..8160eda --- /dev/null +++ b/example/contracts/macro_commas_symbols_integral_map_seq.cpp @@ -0,0 +1,96 @@ + +// 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 + +#include +#include +#include +#include +#include + +template< typename Key, typename T > +struct sizeable +{ + public: typedef typename std::map::size_type size_type; + public: static size_type const max_size = 100; + public: virtual size_type size( void ) const = 0; +}; + +//[macro_commas_symbols_integral_map_seq +CONTRACT_CLASS( + template( + (typename Key) + (typename T) + (class Allocator) + (default comma(1)(::std::allocator >)) + (comma(1)(typename ::std::map::key_type) default_key) + (default (-1)) + ) requires( (comma(1)(boost::Convertible)) ) + class (integral_map) + extends( (public comma(1)(::sizeable)) ) +) { + CONTRACT_CLASS_INVARIANT_TPL( + (((::sizeable::max_size)) >= size()) + ) + + public: typedef typename std::map, Allocator>:: + iterator iterator; + + CONTRACT_FUNCTION_TPL( + public template( (typename OtherKey) (typename OtherT) ) + requires( + (comma(1)(::boost::Convertible)) + (comma(1)(::boost::Convertible)) + ) + comma(1)(::std::pair) (insert) ( + (comma(1)(::std::pair const&) other_value) + (default comma(1)(::std::pair(default_key, T()))) + ) throw( (comma(1)(::std::pair)) ) + precondition( + ((!full())) + ) + postcondition( + (auto result = return) + (comma(1)(typename sizeable::size_type) + old_other_size = CONTRACT_OLDOF + (size())) + (((::sizeable::max_size)) >= size()) + (size() == old_other_size + (result.second ? 1 : 0)) + ) + ) { + // ... +//] + std::pair value(other_value.first, other_value.second); + std::pair result = map_.insert(value); + if(size() > sizeable::max_size) throw value; + return result; + } + + public: bool full ( void ) const + { return size() == sizeable::max_size; } + + public: typename sizeable::size_type size ( void ) const + { return map_.size(); } + + public: template< typename OtherKey, typename OtherT > + typename sizeable::size_type size ( void ) const + { return map_.size(); } + + public: T& operator[] ( Key const& key ) { return map_[key]; } + + private: std::map, Allocator> map_; +}; + +int main ( void ) +{ + integral_map m; + m.insert(std::make_pair(123, 'a')); + BOOST_TEST(m[char(123)] == int('a')); + m.insert(); + BOOST_TEST(m[char(-1)] == int()); + return boost::report_errors(); +} + diff --git a/example/contracts/macro_commas_symbols_integral_map_seq_nova.cpp b/example/contracts/macro_commas_symbols_integral_map_seq_nova.cpp new file mode 100644 index 0000000..a0c49ae --- /dev/null +++ b/example/contracts/macro_commas_symbols_integral_map_seq_nova.cpp @@ -0,0 +1,10 @@ + +// 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 + +#include "nova.hpp" +#include "macro_commas_symbols_integral_map_seq.cpp" + diff --git a/example/contracts/member_operator_string.cpp b/example/contracts/member_operator_string.cpp new file mode 100644 index 0000000..ef0b356 --- /dev/null +++ b/example/contracts/member_operator_string.cpp @@ -0,0 +1,136 @@ + +// 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 + +#include +#include +#include +#include +#include + +//[member_operator_string +CONTRACT_CLASS( + class (string) +) { + CONTRACT_CLASS_INVARIANT( + static class( pointers >= 0, arrays >= 0 ) + ) + + public: static int pointers; + public: static int arrays; + + CONTRACT_CONSTRUCTOR( + public explicit (string) ( (char const*) c_str, default("") ) + initialize( string_(c_str) ) + ) {} + + CONTRACT_DESTRUCTOR( + public (~string) ( void ) + ) {} + + CONTRACT_FUNCTION( // Symbolic operators: `(==)(equal)`, `(())(call)`, etc. + public bool operator(==)(equal) ( (string const&) right ) const + ) { + return string_ == right.string_; + } + + CONTRACT_FUNCTION( // Implicit type conversion operator (keyword type). + public operator char const ( void ) const + ) { + return string_[0]; + } + + CONTRACT_FUNCTION( // Implicit type conversion operator (symbolic type). + public operator(char const*)(char_const_ptr) ( void ) const + ) { + return string_.c_str(); + } + + CONTRACT_FUNCTION( // Implicit type conversion operator (type with commas). + public template( typename T, class Allocator ) + operator(std::vector)(std_vector) ( void ) const + ) { + std::vector v(string_.size()); + for(size_t i = 0; i < string_.size(); ++i) v[i] = string_[i]; + return v; + } + + CONTRACT_FUNCTION( // Comma operator (use `comma` to diff. from above). + public (string&) operator comma ( (string const&) right ) + ) { + string_ += right.string_; + return *this; + } + + // All memory operators (new, delete, new[], and delete[]) must be + // explicitly `static` (because pp can't inspect new[] and delete[] that + // could be any symbolic operator like ==, +, etc). + + CONTRACT_FUNCTION( + public static (void*) operator new ( size_t size ) + ) { + void* p = malloc(size); + if(p == 0) throw std::bad_alloc(); + pointers++; + return p; + } + + CONTRACT_FUNCTION( + public static void operator delete ( (void*) pointer ) + ) { + if(pointer) { + free(pointer); + pointers--; + } + } + + CONTRACT_FUNCTION( + public static (void*) operator(new[])(new_array) ( size_t size ) + ) { + void* a = malloc(size); + if(a == 0) throw std::bad_alloc(); + arrays++; + return a; + } + + CONTRACT_FUNCTION( + public static void operator(delete[])(delete_array) ( (void*) array ) + ) { + if(array) { + free(array); + arrays--; + } + } + + private: std::string string_; +}; + +int string::pointers = 0; +int string::arrays = 0; +//] + +int main ( void ) +{ + string const xyz("xyz"); + + string s("abc"); BOOST_TEST(s == string("abc")); + BOOST_TEST((s, xyz) == string("abcxyz")); + + char x = xyz; BOOST_TEST(x == 'x'); + char const* c_xyz = xyz; BOOST_TEST(string(c_xyz) == xyz); + + std::vector > v = xyz; + BOOST_TEST(v[0] == 'x' && v[1] == 'y' && v[2] == 'z'); + + string* p = new string; BOOST_TEST(string::pointers == 1); + delete p; BOOST_TEST(string::pointers == 0); + + string* a = new string[5]; BOOST_TEST(string::arrays == 1); + delete[] a; BOOST_TEST(string::arrays == 0); + + return boost::report_errors(); +} + diff --git a/example/contracts/nested_class_bitset.cpp b/example/contracts/nested_class_bitset.cpp new file mode 100644 index 0000000..df1ba2c --- /dev/null +++ b/example/contracts/nested_class_bitset.cpp @@ -0,0 +1,112 @@ + +// 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 + +#include +#include +#include +#include + +//[nested_class_bitset +CONTRACT_CLASS( // Enclosing class. + template( size_t N ) + class (bitset) +) { + CONTRACT_CLASS_INVARIANT_TPL( + static class( size() == N ) + ) + + CONTRACT_CLASS_TPL( // Nested class. + public class (reference) + ) { + CONTRACT_CLASS_INVARIANT_TPL( bitptr_ ) + + friend class bitset; + + CONTRACT_CLASS_TPL( // Nested (twice) class template with concepts. + private template( typename T ) + requires( boost::DefaultConstructible ) + class (bit) + ) { + CONTRACT_CLASS_INVARIANT_TPL( void ) + + CONTRACT_CONSTRUCTOR_TPL( + public (bit) ( void ) + initialize( value_() ) + ) {} + + CONTRACT_FUNCTION_TPL( + public void (from_bool) ( bool value ) + postcondition( to_bool() == value ) + ) { + value_ = value; + } + + CONTRACT_FUNCTION_TPL( + public bool (to_bool) ( void ) const + ) { + return value_; + } + + private: T value_; + }; + + CONTRACT_CONSTRUCTOR_TPL( + private (reference) ( void ) + postcondition( bitptr_->to_bool() == int() ) + initialize( + bitptr_(boost::shared_ptr >(new bit())) + ) + ) {} + + CONTRACT_DESTRUCTOR_TPL( + public (~reference) ( void ) + ) {} + + CONTRACT_FUNCTION_TPL( + public operator bool ( void ) const + ) { + return bitptr_->to_bool(); + } + + CONTRACT_FUNCTION_TPL( + public (reference&) operator(=)(assign) ( bool const bit_value ) + postcondition( auto result = return, result == *this ) + ) { + bitptr_->from_bool(bit_value); + return *this; + } + + private: boost::shared_ptr > bitptr_; + }; + + CONTRACT_FUNCTION_TPL( + public (reference) operator([])(at) ( size_t index ) + precondition( index < N ) + ) { + return bitset_[index]; + } + + CONTRACT_FUNCTION_TPL( + public static size_t (size) ( void ) + ) { + return N; + } + + private: reference bitset_[N]; +}; +//] + +int main ( void ) +{ + bitset<2> b; + b[0] = true; + BOOST_TEST(b[0]); + b[1] = false; + BOOST_TEST(not b[1]); + return boost::report_errors(); +} + diff --git a/example/contracts/no_contract_ivector.cpp b/example/contracts/no_contract_ivector.cpp new file mode 100644 index 0000000..b01c1aa --- /dev/null +++ b/example/contracts/no_contract_ivector.cpp @@ -0,0 +1,48 @@ + +// 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 + +#include + +//[no_contract_ivector +class ivector +{ + // invariant: empty() == (size() == 0) + // size() <= capacity() + // capacity() <= max_size() + // std::distance(begin(), end()) == int(size()) + + public: typedef std::vector::size_type size_type; + + public: explicit ivector ( size_type count ) + // precondition: count >= 0 + // postcondition: size() == count + // boost::algorithm::all_of_equal(begin(), end(), 0) + : vector_(count) + {} + + public: virtual ~ivector ( void ) {} + + public: void push_back ( int const value ) + // precondition: size() < max_size() + // postcondition: size() == oldof size() + 1 + // capacity() >= oldof capacity() + // back() == value + { + vector_.push_back(value); + } + + private: std::vector vector_; +}; +//] + +int main ( void ) +{ + ivector v(1); + v.push_back(123); + return 0; +} + diff --git a/example/contracts/no_contract_postinc.cpp b/example/contracts/no_contract_postinc.cpp new file mode 100644 index 0000000..2eaa89d --- /dev/null +++ b/example/contracts/no_contract_postinc.cpp @@ -0,0 +1,27 @@ + +// 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 + +#include + +//[no_contract_postinc +int const postinc ( int& value ) + // precondition: value < std::numeric_limits::max() + // postcondition: value == oldof value + 1 + // result == oldof valule +{ + return value++; +} +//] + +int main ( void ) +{ + int value = 1; + BOOST_TEST(postinc(value) == 1); + BOOST_TEST(value == 2); + return boost::report_errors(); +} + diff --git a/example/contracts/no_pre_post_postinc.cpp b/example/contracts/no_pre_post_postinc.cpp new file mode 100644 index 0000000..a345996 --- /dev/null +++ b/example/contracts/no_pre_post_postinc.cpp @@ -0,0 +1,30 @@ + +// 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 + +#include + +//[no_pre_post_postinc +#include + +CONTRACT_FUNCTION( // Declare free function (for programming contracts). + int const (postinc) ( (int&) value ) // Non-fundamental types in `()`. + // precondition: value < std::numeric_limits::max() + // postcondition: value == oldof value + 1 + // result == oldof value +) { + return value++; +} +//] + +int main ( void ) +{ + int value = 1; + BOOST_TEST(postinc(value) == 1); + BOOST_TEST(value == 2); + return boost::report_errors(); +} + diff --git a/example/contracts/nova.hpp b/example/contracts/nova.hpp new file mode 100644 index 0000000..4414741 --- /dev/null +++ b/example/contracts/nova.hpp @@ -0,0 +1,21 @@ + +// 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 + +#ifndef NOVA_HPP_ +#define NOVA_HPP_ + +// WARNING: This file must be included first in each compilation unit. + +#include + +// Force no variadic macros but avoiding macro redefinition warnings/errors. +#ifndef BOOST_NO_VARIADIC_MACROS +# define BOOST_NO_VARIADIC_MACROS +#endif + +#endif // #include guard + diff --git a/example/contracts/params_funcptr_array_apply.cpp b/example/contracts/params_funcptr_array_apply.cpp new file mode 100644 index 0000000..7db456d --- /dev/null +++ b/example/contracts/params_funcptr_array_apply.cpp @@ -0,0 +1,50 @@ + +// 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 + +#include +#include +#include + +//[params_funcptr_array_apply +// Contracts cannot directly use array type syntax, use via `typedef` instead. +typedef int array_2x3[2][3]; +typedef int (*func_ptr) ( int ); + +CONTRACT_FUNCTION( + void (apply) ( (func_ptr) f, (array_2x3) m ) + // precondition: f != NULL + // m != NULL +) { + for ( size_t i = 0; i < 2; ++i) + for ( size_t j = 0; j < 3; ++j) + m[i][j] = f(m[i][j]); +} + +int offset ( int i ) { return i + 10; } +//] + +int main ( void ) +{ + //[params_funcptr_array_apply_call + int x[2][3] = { + {1, 2, 3}, + {4, 5, 6} + }; + apply(offset, x); + //] + + BOOST_TEST(x[0][0] == 11); + BOOST_TEST(x[0][1] == 12); + BOOST_TEST(x[0][2] == 13); + + BOOST_TEST(x[1][0] == 14); + BOOST_TEST(x[1][1] == 15); + BOOST_TEST(x[1][2] == 16); + + return boost::report_errors(); +} + diff --git a/example/contracts/params_postinc.cpp b/example/contracts/params_postinc.cpp new file mode 100644 index 0000000..4c97e9d --- /dev/null +++ b/example/contracts/params_postinc.cpp @@ -0,0 +1,37 @@ + +// 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 + +#include +#include + +//[params_postinc +CONTRACT_FUNCTION( // Overload, storage classifiers, and default parameters. + long const (postinc) ( (long&) value, register unsigned offset, default 1 ) + // precondition: value < std::numeric_limits::max() + // postcondition: value == oldof value + offset + // result == oldof value +) { + long result = value; + if(offset > 0) { + value += 1; + postinc(value, offset - 1); // Recursive calls. + } + return result; +} +//] + +int main ( void ) +{ + //[params_postinc_call + long value = 1; + BOOST_TEST(postinc(value) == 1); // Increment of 1 (it is 1). + BOOST_TEST(postinc(value, 4) == 2); // Increment of 4 (it is 2). + BOOST_TEST(value == 6); // Incremented of 4 (it was 2). + //] + return boost::report_errors(); +} + diff --git a/example/contracts/post_also_postinc.cpp b/example/contracts/post_also_postinc.cpp new file mode 100644 index 0000000..3c25e0a --- /dev/null +++ b/example/contracts/post_also_postinc.cpp @@ -0,0 +1,34 @@ + +// 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 + +#include +#include +#include + +//[post_also_postinc +CONTRACT_FUNCTION( + int const (postinc) ( (int&) value ) + precondition( value < std::numeric_limits::max() ) + postcondition( // Postconditions. + auto result = return, // Result value. + auto old_value = CONTRACT_OLDOF value, // Old value(s). + value == old_value + 1, // Assertion(s)... + result == old_value + ) +) { + return value++; +} +//] + +int main ( void ) +{ + int value = 1; + BOOST_TEST(postinc(value) == 1); + BOOST_TEST(value == 2); + return boost::report_errors(); +} + diff --git a/example/contracts/pre_only_postinc.cpp b/example/contracts/pre_only_postinc.cpp new file mode 100644 index 0000000..131ae50 --- /dev/null +++ b/example/contracts/pre_only_postinc.cpp @@ -0,0 +1,30 @@ + +// 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 + +#include +#include +#include + +//[pre_only_postinc +CONTRACT_FUNCTION( + int const (postinc) ( (int&) value ) + precondition( value < std::numeric_limits::max() ) // Precondition. + // postcondition: value == oldof value + 1 + // result == oldof value +) { + return value++; +} +//] + +int main ( void ) +{ + int value = 1; + BOOST_TEST(postinc(value) == 1); + BOOST_TEST(value == 2); + return boost::report_errors(); +} + diff --git a/example/contracts/push_back.cpp b/example/contracts/push_back.cpp new file mode 100644 index 0000000..bab4efc --- /dev/null +++ b/example/contracts/push_back.cpp @@ -0,0 +1,56 @@ + +// 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 + +#include + +//[push_back +#include // This library. +#include +#include "pushable.hpp" // Some base class. + +BOOST_CONTRACT_CLASS( + template( typename T ) + class (vector) extends( public pushable ) // Subcontracting. + invariant( + empty() == (size() == 0) // More class invariants here... + ) +) { +public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::const_reference const_reference; + + BOOST_CONTRACT_FUNCTION_TPL( + void (push_back) ( (T const&) value ) + precondition( + size() < max_size() // More preconditions here... + ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), // Old-of values. + size() == old_size + 1 // More postconditions here... + ) + ) { + vector_.push_back(value); // Original function body. + } + + // Rest of class here (possibly with more contracts)... + bool empty ( ) const { return vector_.empty(); } + size_type size ( ) const { return vector_.size(); } + size_type max_size ( ) const { return vector_.max_size(); } + const_reference back ( ) const { return vector_.back(); } + +private: + std::vector vector_; +}; +//] + +int main ( ) { + vector v; + v.push_back(123); + BOOST_TEST(v.size() == 1); + return boost::report_errors(); +} + diff --git a/example/contracts/push_back_lines.cpp b/example/contracts/push_back_lines.cpp new file mode 100644 index 0000000..e1bcaa1 --- /dev/null +++ b/example/contracts/push_back_lines.cpp @@ -0,0 +1,47 @@ + +// 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 + +//[push_back_lines + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +//] + diff --git a/example/contracts/push_back_npaper.cpp b/example/contracts/push_back_npaper.cpp new file mode 100644 index 0000000..1c38998 --- /dev/null +++ b/example/contracts/push_back_npaper.cpp @@ -0,0 +1,47 @@ + +// 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 + +//[push_back_npaper +// Extra spaces, newlines, etc used to align text with this library code. +#include +#include +#include "pushable.hpp" // Some base class. + + +template< typename T > requires CopyConstructible // Concepts. +class vector : public pushable // Subcontracting. +{ + invariant { + empty() == (size() == 0); // More class invariants here... + } + + public: typedef typename std::vector::size_type size_type; + public: typedef typename std::vector::const_reference const_reference; + + + public: void push_back ( T const& value ) override + precondition { + size() < max_size(); // More preconditions here... + } + postcondition { + // Old-of values use `oldof` operator. + size() == oldof size() + 1; // More postconditions here... + } + { + vector_.push_back(value); // Original function body. + } + + // Rest of class here (with possibly more contracts)... + public: bool empty ( void ) const { return vector_.empty(); } + public: size_type size ( void ) const { return vector_.size(); } + public: size_type max_size ( void ) const { return vector_.max_size(); } + public: const_reference back ( void ) const { return vector_.back(); } + + private: std::vector vector_; +}; +//] + diff --git a/example/contracts/pushable.hpp b/example/contracts/pushable.hpp new file mode 100644 index 0000000..e6f243b --- /dev/null +++ b/example/contracts/pushable.hpp @@ -0,0 +1,40 @@ + +// 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 + +#ifndef PUSHABLE_HPP_ +#define PUSHABLE_HPP_ + +#include +#include +#include + +//[pushable +CONTRACT_CLASS( + template( typename T ) + class (pushable) +) { + // Subcontracting: In `and` with derived class invariants. + CONTRACT_CLASS_INVARIANT_TPL( void ) + + public: typedef typename std::vector::const_reference const_reference; + + CONTRACT_FUNCTION_TPL( + public virtual void (push_back) ( (T const&) value ) new + // Subcontracting: In `or` with overriding function preconditions. + precondition( false ) // Force check to overriding preconditions. + // Subcontracting: In `and` with overriding function postconditions. + postcondition( + back() == value, requires boost::has_equal_to::value + ) + ) = 0; // Contract for pure virtual function. + + public: virtual const_reference back ( void ) const = 0; +}; +//] + +#endif // #include guard + diff --git a/example/contracts/pushable_seq.hpp b/example/contracts/pushable_seq.hpp new file mode 100644 index 0000000..75d0ae6 --- /dev/null +++ b/example/contracts/pushable_seq.hpp @@ -0,0 +1,40 @@ + +// 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 + +#ifndef PUSHABLE_HPP_ +#define PUSHABLE_HPP_ + +#include +#include +#include + +//[pushable_seq +CONTRACT_CLASS( + template( (typename T) ) + class (pushable) +) { + // Subcontracting: In `and` with derived class invariants. + CONTRACT_CLASS_INVARIANT_TPL( (void) ) + + public: typedef typename std::vector::const_reference const_reference; + + CONTRACT_FUNCTION_TPL( + public virtual void (push_back) ( ((T const&) value) ) new + // Subcontracting: In `or` with overriding function preconditions. + precondition( (false) ) // Force check to overriding preconditions. + // Subcontracting: In `and` with overriding function postconditions. + postcondition( + (back() == value)(requires boost::has_equal_to::value) + ) + ) = 0; // Contract for pure virtual function. + + public: virtual const_reference back ( void ) const = 0; +}; +//] + +#endif // #include guard + diff --git a/example/contracts/select_assertion_factorial.cpp b/example/contracts/select_assertion_factorial.cpp new file mode 100644 index 0000000..734dcbb --- /dev/null +++ b/example/contracts/select_assertion_factorial.cpp @@ -0,0 +1,37 @@ + +// 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 + +#include +#include + +//[select_assertion_factorial +CONTRACT_FUNCTION( + int (factorial) ( int n ) + precondition( n >= 0 ) + postcondition( + auto result = return, + result >= 1, + if(n == 0 or n == 1) ( // Select assertion, if-then statement. + result == 1 + ) else ( // Select assertion, else statement (optional). + // Assertions disabled within assertion so recursion OK. + result == n * factorial(n - 1) + ) + ) +) { + if(n == 0 or n == 1) return 1; + else return n * factorial(n - 1); +} +//] + +int main ( void ) +{ + BOOST_TEST(factorial(4) == 24); + return boost::report_errors(); +} + + diff --git a/example/contracts/static_assertion_memcopy.cpp b/example/contracts/static_assertion_memcopy.cpp new file mode 100644 index 0000000..1fb9fe1 --- /dev/null +++ b/example/contracts/static_assertion_memcopy.cpp @@ -0,0 +1,43 @@ + +// 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 + +#include +#include +#include +#include + +//[static_assertion_memcopy +CONTRACT_FUNCTION( + template( typename To, typename From ) + (To*) (memcopy) ( (To*) to, (From*) from ) + precondition( // Static assertions. + static_assert(sizeof(To) >= sizeof(From), "destination too small"), + // Wrapping parenthesis for asserted condition with commas. + static_assert((boost::is_convertible::value), + "incompatible types"), + to, // pointer not null + from // pointer not null + ) +) ; +//] + +template< typename To, typename From > +To* CONTRACT_FREE_BODY(memcopy)( To* to, From* from ) +{ + memcpy(to, from, sizeof(From)); + return to; +} + +int main ( void ) +{ + int x = 0, y = 123; + memcopy(&x, &y); + BOOST_TEST(x == 123); + BOOST_TEST(y == 123); + return boost::report_errors(); +} + diff --git a/example/contracts/static_contract_instance_counter.cpp b/example/contracts/static_contract_instance_counter.cpp new file mode 100644 index 0000000..49289eb --- /dev/null +++ b/example/contracts/static_contract_instance_counter.cpp @@ -0,0 +1,77 @@ + +// 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 + +#include +#include + +//[static_contract_instance_counter +CONTRACT_CLASS( + template( typename T ) + class (instance_counter) +) { + CONTRACT_CLASS_INVARIANT_TPL( + object(), // Non-static class invariants. + static class( // Static class invariants. + count() >= 0 + // ... + ) + ) + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (instance_counter) ( (T*) the_object ) + precondition( the_object ) + postcondition( + auto old_count = CONTRACT_OLDOF count(), + count() == old_count + 1, + object() == the_object + ) + initialize( object_(the_object) ) + ) { + count_++; + } + + CONTRACT_DESTRUCTOR_TPL( + public virtual (~instance_counter) ( void ) + // FUTURE: Destructors could have static postconditions. + // postcondition: count() = oldof count() - 1 + ) { + delete object_; + count_--; + } + + CONTRACT_FUNCTION_TPL( + public (T const* const) (object) ( void ) const + ) { + return object_; + } + + CONTRACT_FUNCTION_TPL( // Contract static member function. + public static int (count) ( void ) + // No preconditions nor postconditions for this example but when + // present no object can be accessed by assertions (i.e., `static`). + ) { + return count_; + } + + private: static int count_; + private: T* object_; +}; + +template< typename T > +int instance_counter::count_ = 0; +//] + +int main ( void ) +{ + instance_counter i(new int(123)), j(new int(456)); + BOOST_TEST(i.count() == 2); + BOOST_TEST(j.count() == 2); + BOOST_TEST(*(i.object()) == 123); + BOOST_TEST(*(j.object()) == 456); + return boost::report_errors(); +} + diff --git a/example/contracts/subcontract_identifiers.cpp b/example/contracts/subcontract_identifiers.cpp new file mode 100644 index 0000000..8447495 --- /dev/null +++ b/example/contracts/subcontract_identifiers.cpp @@ -0,0 +1,115 @@ + +// 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 + +#include +#include +#include +#include + +//[subcontract_identifiers_unique +CONTRACT_CLASS( + class (unique_identifiers) +) { + CONTRACT_CLASS_INVARIANT( size() >= 0 ) + + CONTRACT_CONSTRUCTOR( + public (unique_identifiers) ( void ) + postcondition( size() == 0 ) + ) {} + + CONTRACT_DESTRUCTOR( + public virtual (~unique_identifiers) ( void ) + ) {} + + CONTRACT_FUNCTION( + public virtual void (add) ( int id ) + precondition( + // Id not already present. + std::find(begin(), end(), id) == end() + ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + auto old_found = CONTRACT_OLDOF + std::find(begin(), end(), id) != end(), + // If id was not already present, it was added now... + old_found ? true : std::find(begin(), end(), id) != end(), + // ...and size was increased of 1. + old_found ? true : size() == old_size + 1 + ) + ) { + identifiers_.push_back(id); + } + + // ... +//] + + public: typedef std::vector::const_iterator const_iterator; + + // Should contract these members too... + public: int size ( void ) const { return identifiers_.size(); } + public: const_iterator begin ( void ) const { return identifiers_.begin(); } + public: const_iterator end ( void ) const { return identifiers_.end(); } + + protected: std::vector identifiers_; +}; + +//[subcontract_identifiers_duplicate +CONTRACT_CLASS( + class (duplicate_identifiers) + extends( public unique_identifiers ) // Automatically subcontract. +) { + CONTRACT_CLASS_INVARIANT( + size() >= 1 // Strengthened inherited class invariants (in `and`). + ) + + CONTRACT_CONSTRUCTOR( + public (duplicate_identifiers) ( int id ) + postcondition( size() == 1 ) + ) { + // As usual, constructor should not call virtual member `add`. + identifiers_.push_back(id); + } + + CONTRACT_DESTRUCTOR( + public virtual (~duplicate_identifiers) ( void ) + ) {} + + CONTRACT_FUNCTION( + public virtual void (add) ( int id ) + precondition( // Wakened inherited preconditions (in `or`). + // OK even if id is already present. + std::find(begin(), end(), id) != end() + ) + postcondition( // Strengthened inherited postconditions (in `and`). + auto old_size = CONTRACT_OLDOF size(), + auto old_found = CONTRACT_OLDOF + std::find(begin(), end(), id) != end(), + // Inherited postconditions not checked because of + // select assertions, plus size unchanged if already present. + old_found ? size() == old_size : true + ) + ) { + if(std::find(begin(), end(), id) == end()) { // Not already present. + // Unfortunately, must invoke base function via `BODY` macro. + unique_identifiers::CONTRACT_MEMBER_BODY(add)(id); + } + } +}; +//] + +int main ( void ) +{ + //[subcontract_identifiers_duplicate_add + duplicate_identifiers ids(123); + ids.add(123); + //] + BOOST_TEST(ids.size() == 1); // Not 2 because `add(123)` has no effect. + ids.add(456); + BOOST_TEST(ids.size() == 2); + return boost::report_errors(); +} + diff --git a/example/contracts/subcontract_pre_natural_failure.cpp b/example/contracts/subcontract_pre_natural_failure.cpp new file mode 100644 index 0000000..a0f5834 --- /dev/null +++ b/example/contracts/subcontract_pre_natural_failure.cpp @@ -0,0 +1,69 @@ + +// 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 + +#include +#include +#include + +//[subcontract_pre_natural_failure +CONTRACT_CLASS( + class (integer) +) { + CONTRACT_CLASS_INVARIANT( void ) + + CONTRACT_FUNCTION( + public virtual void (set) ( int value ) + // No preconditions so this and all overrides can always be called. + postcondition( get() == value ) + ) { + value_ = value; + } + + CONTRACT_FUNCTION( + public virtual int (get) ( void ) const + ) { + return value_; + } + + private: int value_; +}; + +CONTRACT_CLASS( + class (natural) extends( public integer ) // Subcontract. +) { + CONTRACT_CLASS_INVARIANT( get() >= 0 ) + + CONTRACT_FUNCTION( + public virtual void (set) ( int value ) + precondition( value >= 0 ) // NOTE: Will not fail because of base. + ) { + integer::CONTRACT_MEMBER_BODY(set)(value); + } +}; +//] + +void throwing_handler ( contract::from const& context ) { throw; } + +int main ( void ) +{ + contract::set_class_invariant_broken(&throwing_handler); + bool pass = false; + try { + //[subcontract_pre_natural_failure_call + natural n; + n.set(-123); // Error: Fails call invariants instead of preconditions. + //] + } catch(contract::broken& ex) { + if(std::string(ex.assertion_code()) == std::string("get() >= 0")) + pass = true; + } +#ifndef CONTRACT_CONFIG_NO_CLASS_INVARIANTS + BOOST_TEST(pass); +#endif + return boost::report_errors(); +} + diff --git a/example/contracts/template_params.cpp b/example/contracts/template_params.cpp new file mode 100644 index 0000000..2de5ef4 --- /dev/null +++ b/example/contracts/template_params.cpp @@ -0,0 +1,64 @@ + +// 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 + +#include + +template< + typename X + , template< typename S, typename T = S > class Y + , class Z = int + , Z V = 0 +> struct x {}; + +//[template_params_class +CONTRACT_CLASS( // Class template parameters. + template( + typename A // Type template parameter. + , int B // Value template parameter. + , class C, default A // Optional type template parameter. + , (A) D, default B // Optional value template parameter. + , template( // Template template parameter: Outer template + typename X // uses `()` but rest uses usual syntax. + , template< typename S, typename T = S > class Y + , class Z = int + , Z V = 0 + ) class E, default x // Optional template template parameter. + ) + struct (a) +) { + // ... +//] + CONTRACT_CLASS_INVARIANT_TPL( void ) +}; + +//[template_params_function +CONTRACT_FUNCTION( // Function template parameters. + template( // As usual, no default template parameters allowed in functions. + typename A // Type template parameter. + , int B // Value template parameter. + , class C // Type template parameter. + , (A) D // Value template parameter. + , template( // Template template parameter: Outer template + typename X // uses `()` but rest uses usual syntax. + , template< typename S, typename T = S > class Y + , class Z = int + , Z V = 0 + ) class E + ) + void (f) ( void ) +) { + // ... +//] +} + +int main ( void ) +{ + a aa; + f(); + return 0; +}; + diff --git a/example/contracts/template_specializations_vector.cpp b/example/contracts/template_specializations_vector.cpp new file mode 100644 index 0000000..01a3a81 --- /dev/null +++ b/example/contracts/template_specializations_vector.cpp @@ -0,0 +1,128 @@ + +// 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 + +#include "pushable.hpp" +#include +#include + +//[template_specializations_vector +CONTRACT_CLASS( // Not even necessary to contract this template. + template( typename T, class Allocator, default std::allocator ) + class (vector) extends( public pushable ) +) { + // ... +//] + CONTRACT_CLASS_INVARIANT_TPL( empty() == (size() == 0) ) + + public: typedef typename std::vector::size_type size_type; + public: typedef typename std::vector::const_reference + const_reference; + + CONTRACT_FUNCTION_TPL( + public void (push_back) ( (T const&) value ) + precondition( size() < max_size() ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + size() == old_size + 1 + ) + ) { + std::cout << "T, Allocator" << std::endl; + vector_.push_back(value); + } + + public: bool empty ( void ) const { return vector_.empty(); } + public: size_type size ( void ) const { return vector_.size(); } + public: size_type max_size ( void ) const { return vector_.max_size(); } + public: const_reference back ( void ) const { return vector_.back(); } + + private: std::vector vector_; +}; + +//[template_specializations_vector_bool +CONTRACT_CLASS( // Template specialization (no template parameter). + template( void ) + class (vector) ( bool ) extends( public pushable ) +) { + // ... +//] + CONTRACT_CLASS_INVARIANT( empty() == (size() == 0) ) + + public: typedef std::vector::size_type size_type; + public: typedef std::vector::const_reference + const_reference; + + CONTRACT_FUNCTION( + public void (push_back) ( (bool const&) value ) + precondition( size() < max_size() ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + size() == old_size + 1 + ) + ) { + std::cout << "bool" << std::endl; + vector_.push_back(value); + } + + public: bool empty ( void ) const { return vector_.empty(); } + public: size_type size ( void ) const { return vector_.size(); } + public: size_type max_size ( void ) const { return vector_.max_size(); } + public: const_reference back ( void ) const { return vector_.back(); } + + private: std::vector vector_; +}; + +//[template_specializations_vector_bool_allocator +CONTRACT_CLASS( // Template specialization (one template parameter). + template( class Allocator ) + class (vector) ( bool, Allocator ) extends( public pushable ) +) { + // ... +//] + CONTRACT_CLASS_INVARIANT_TPL( empty() == (size() == 0) ) + + public: typedef typename std::vector::size_type size_type; + public: typedef typename std::vector::const_reference + const_reference; + + CONTRACT_FUNCTION_TPL( + public void (push_back) ( (bool const&) value ) + precondition( size() < max_size() ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + size() == old_size + 1 + ) + ) { + std::cout << "bool, Allocator" << std::endl; + vector_.push_back(value); + } + + public: bool empty ( void ) const { return vector_.empty(); } + public: size_type size ( void ) const { return vector_.size(); } + public: size_type max_size ( void ) const { return vector_.max_size(); } + public: const_reference back ( void ) const { return vector_.back(); } + + private: std::vector vector_; +}; + +int main ( void ) +{ + vector v; + v.push_back(123); + std::cout << v.size() << std::endl; + + vector b; + b.push_back(true); + std::cout << b.size() << std::endl; + + vector > bc; + bc.push_back(true); + std::cout << bc.size() << std::endl; + + return 0; +} + + diff --git a/example/contracts/typed_counter.cpp b/example/contracts/typed_counter.cpp new file mode 100644 index 0000000..8bde0e0 --- /dev/null +++ b/example/contracts/typed_counter.cpp @@ -0,0 +1,41 @@ + +// 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 + +#include +#include + +//[typed_counter +CONTRACT_CLASS( + class (counter) +) { + CONTRACT_CLASS_INVARIANT( void ) + + public: static unsigned value; + + CONTRACT_FUNCTION( + public static int (next) ( void ) + postcondition( // Explicit types so no Boost.Typeof. + auto result = return, + unsigned const old_value = CONTRACT_OLDOF value, + const( unsigned value, unsigned const old_value ) + value == old_value + 1, + result == int(value) + ) + ) { + return ++value; + } +}; + +unsigned counter::value = 0; +//] + +int main ( void ) +{ + BOOST_TEST(counter::next() == 1); + return boost::report_errors(); +} + diff --git a/example/contracts/volatile_contract_shared_instance.cpp b/example/contracts/volatile_contract_shared_instance.cpp new file mode 100644 index 0000000..632bd65 --- /dev/null +++ b/example/contracts/volatile_contract_shared_instance.cpp @@ -0,0 +1,63 @@ + +// 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 + +#include +#include + +//[volatile_contract_shared_instance +CONTRACT_CLASS( + template( typename T ) + class (shared_instance) +) { + CONTRACT_CLASS_INVARIANT_TPL( + queries() >= 0, // Non-volatile class invariants. + volatile class( // Volatile class invariants. + object() + // ... + ) + ) + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (shared_instance) ( (T*) the_object ) + precondition( the_object ) + postcondition( object() == the_object ) + initialize( object_(the_object), queries_(0) ) + ) {} + + CONTRACT_DESTRUCTOR_TPL( + public virtual (~shared_instance) ( void ) + ) { + delete object_; + } + + CONTRACT_FUNCTION_TPL( // Contracts for volatile member function. + public (T const volatile* const) (object) ( void ) const volatile + // No preconditions nor postconditions for this example but when + // present object is `const volatile` within assertions. + ) { + queries_++; + return object_; + } + + CONTRACT_FUNCTION_TPL( + public int (queries) ( void ) const + ) { + return queries_; + } + + private: T volatile* object_; + private: mutable int queries_; +}; +//] + +int main ( void ) +{ + shared_instance volatile i(new int(123)); + BOOST_TEST(*(i.object()) == 123); + return boost::report_errors(); +} + diff --git a/example/meyer97/gcd.cpp b/example/meyer97/gcd.cpp new file mode 100644 index 0000000..6ad5a0c --- /dev/null +++ b/example/meyer97/gcd.cpp @@ -0,0 +1,42 @@ + +// 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 + +//[meyer97_gcd +// File: gcd.cpp +#include +#include +#include + +CONTRACT_FUNCTION( // Great common divisor of given positive integers. + int (gcd) ( int a, int b ) + precondition( + a > 0, b > 0 + ) +) { + int x = a, y = b; + + CONTRACT_LOOP( while(x != y) ) { // Loop contracted with a variant. + // Block invariant assert loop invariant. + CONTRACT_BLOCK_INVARIANT( const( x ) x > 0, const( y ) y > 0 ) + // Loop variant is non-negative and monotonically decreasing. + CONTRACT_LOOP_VARIANT( const( x, y ) std::max(x, y) ) + + // `x` and `y` have the same GCD as `a` and `b`. + + if(x > y) x = x - y; else y = y - x; + } + return x; +} + +int main ( void ) +{ + BOOST_TEST(gcd(12, 18) == 6); + BOOST_TEST(gcd(4, 14) == 2); + return boost::report_errors(); +} +//] + diff --git a/example/meyer97/gcd.e b/example/meyer97/gcd.e new file mode 100644 index 0000000..53f3c79 --- /dev/null +++ b/example/meyer97/gcd.e @@ -0,0 +1,42 @@ + +-- 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. + +//[meyer97_gcd_e +-- File: gcd.e +-- Extra spaces, newlines, etc used to align text with this library code. + + + +-- Greatest common divisor of a and b. +gcd ( a, b : INTEGER ) : INTEGER is + require + a > 0; b > 0 + local + x, y : INTEGER + do + from + x := a; y := b + invariant + x > 0; y > 0 + variant + x.max(y) + until + x = y + loop + if x > y then x := x - y else y := y - x end + end + Result := x + end + + + + + + + +//] + diff --git a/example/meyer97/maxarray.cpp b/example/meyer97/maxarray.cpp new file mode 100644 index 0000000..f1e43bb --- /dev/null +++ b/example/meyer97/maxarray.cpp @@ -0,0 +1,44 @@ + +// 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 + +//[meyer97_maxarray +// File: maxarray.cpp +#include +#include +#include + +CONTRACT_FUNCTION( + int (maxarray) ( (int const* const) array, (size_t const&) size ) + precondition( + array, // array allocated + size >= 1 // size in range + ) +) { + int maxnow = array[0]; + CONTRACT_LOOP( for(size_t i = 0; i < (size - 1); ++i) ) { + // Nested loop (with variant) used to assert enclosing loop invariants. + CONTRACT_LOOP( for(size_t j = 0; j < i; ++j) ) { + CONTRACT_LOOP_VARIANT( const( i, j ) i - j ) + CONTRACT_BLOCK_INVARIANT( const( maxnow, array, j ) + maxnow >= array[j] ) + } + // -2 because starts from 0 (not 1) and already done element at 0. + CONTRACT_LOOP_VARIANT( const( size, i ) size - i - 2 ) + + maxnow = std::max(maxnow, array[i]); + } + return maxnow; +} + +int main ( void ) +{ + int a[] = {1, 5, 3}; + BOOST_TEST(maxarray(a, 3) == 5); + return boost::report_errors(); +} +//] + diff --git a/example/meyer97/stack3.cpp b/example/meyer97/stack3.cpp new file mode 100644 index 0000000..59d3ee6 --- /dev/null +++ b/example/meyer97/stack3.cpp @@ -0,0 +1,164 @@ + +// 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 + +//[meyer97_stack3 +// File: stack3.cpp +#include "stack4.hpp" +#include +#include + +CONTRACT_CLASS( // Dispenser LIFO and max capacity using error codes. + template( typename T ) + class (stack3) +) { + CONTRACT_CLASS_INVARIANT_TPL( void ) // no class invariant + + public: enum Error { // Error codes. + NO_ERROR = 0, + OVERFLOW_ERROR, + UNDERFLOW_ERROR, + SIZE_ERROR + }; + + // Initialization. + + // Create stack for max of n elements, if n < 0 set error (no precondition). + CONTRACT_CONSTRUCTOR_TPL( + public (stack3) ( (const int&) n, (const T&) none, default T() ) + postcondition( + bool(n < 0) == (error() == SIZE_ERROR), // error if impossible + bool(n >= 0) == !error(), // no error if possible + if(bool(!error())) ( capacity() == n ) // created if no error + ) + initialize( none_(none), representation_(0), error_(NO_ERROR) ) + ) { + if(n >= 0) representation_ = stack4(n); + else error_ = SIZE_ERROR; + } + + CONTRACT_DESTRUCTOR_TPL( // Destroy stack. + public virtual (~stack3) ( void ) + ) {} + + // Access. + + CONTRACT_FUNCTION_TPL( // Max number of stack elements. + public int (capacity) ( void ) const + ) { + return representation_.capacity(); + } + + CONTRACT_FUNCTION_TPL( // Number of stack elements. + public int (count) ( void ) const + ) { + return representation_.count(); + } + + // Top element if present, otherwise set error (no precondition). + CONTRACT_FUNCTION_TPL( + public (const T&) (item) ( void ) const + postcondition( + empty() == (error() == UNDERFLOW_ERROR), // error if impossible + bool(!empty() == !error()) // no error if possible + ) + ) { + if(!empty()) { + error_ = NO_ERROR; + return representation_.item(); + } else { + error_ = UNDERFLOW_ERROR; + return none_; + } + } + + // Status report. + + CONTRACT_FUNCTION_TPL( // Error indicator set by various operations. + public (Error) (error) ( void ) const + ) { + return error_; + } + + CONTRACT_FUNCTION_TPL( // Is stack empty? + public bool (empty) ( void ) const + ) { + return representation_.empty(); + } + + CONTRACT_FUNCTION_TPL( // Is stack full? + public bool (full) ( void ) const + ) { + return representation_.full(); + } + + // Element change. + + // Add x to top if capacity left, otherwise set error (no precondition). + CONTRACT_FUNCTION_TPL( + public void (put) ( (const T&) x ) + postcondition( + auto old_full = CONTRACT_OLDOF full(), + auto old_count = CONTRACT_OLDOF count(), + old_full == (error() == OVERFLOW_ERROR), // error if impossible + not old_full == not error(), // no error if possible + if(not error()) ( + not empty(), // not empty if no error + item() == x, // added to top is no error + count() == old_count + 1 // one more item if no error + ) + ) + ) { + if(full()) { + error_ = OVERFLOW_ERROR; + } else { + representation_.put(x); + error_ = NO_ERROR; + } + } + + // Remove top item if possible, otherwise set error to (no precondition). + CONTRACT_FUNCTION_TPL( + public void (remove) ( void ) + postcondition( + auto old_empty = CONTRACT_OLDOF empty(), + auto old_count = CONTRACT_OLDOF count(), + old_empty == (error() == UNDERFLOW_ERROR), // if impossible + not old_empty == not error(), // no error if possible + if(not error()) ( + not full(), // not full is no error + count() == old_count - 1 // one fewer item if no error + ) + ) + ) { + if(empty()) { + error_ = UNDERFLOW_ERROR; + } else { + representation_.remove(); + error_ = NO_ERROR; + } + } + + private: const T none_; + private: stack4 representation_; + private: mutable Error error_; // Mutable for logic constantness. +}; + +int main ( void ) +{ + stack3 s(3); + BOOST_TEST(s.capacity() == 3); + BOOST_TEST(s.count() == 0); + BOOST_TEST(s.empty()); + BOOST_TEST(not s.full()); + s.put(123); + BOOST_TEST(s.item() == 123); + s.remove(); + BOOST_TEST(s.empty()); + return boost::report_errors(); +} +//] + diff --git a/example/meyer97/stack4.e b/example/meyer97/stack4.e new file mode 100644 index 0000000..0ad23f7 --- /dev/null +++ b/example/meyer97/stack4.e @@ -0,0 +1,211 @@ + +-- 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. + +//[meyer97_stack4_e +-- File: stack4.e +-- Extra spaces, newlines, etc used to align text with this library code. + + + + + + +indexing + destription: "Dispenser with LIFO access policy and a fixed max capacity." +class interface STACK4[G] creation make + +invariant + count_non_negative: count >= 0 + count_bounded: count <= capacity + empty_if_no_elements: empty = (count = 0) + + +feature -- Initialization. + + -- Allocate stack for a maximum of n elements. + make ( n : INTEGER ) is + require + non_negative_capacity: n >= 0 + + ensure + capacity_set: capacity = n + + end + + + + + + + + + + + + + + + + + + + + + + + +feature -- Access. + + -- Max number of stack elements. + capacity : INTEGER + + + -- Number of stack elements. + count : INTEGER + + + -- Top element + item : G is + require + not_empty: not empty -- i.e., count > 0 + + end + +feature -- Status report. + + -- Is stack empty? + empty : BOOLEAN is + ensure + + empty_definition: result = (count = 0) + + end + + -- Is stack full? + full : BOOLEAN is + ensure + + full_definition: result = (count = capacity) + + end + +feature -- Element change. + + -- Add x on top. + put ( x : G ) is + require + not_full: not full + + ensure + + not_empty: not empty + added_to_top: item = x + one_more_item: count = old count + 1 + + end + + -- Remove top element. + remove is + require + not_empty: not empty -- i.e., count > 0 + + ensure + + not_full: not full + one_fewer_item: count = old count - 1 + + end + + + + +end -- class interface STACK4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +//] + diff --git a/example/meyer97/stack4.hpp b/example/meyer97/stack4.hpp new file mode 100644 index 0000000..af0e022 --- /dev/null +++ b/example/meyer97/stack4.hpp @@ -0,0 +1,212 @@ + +// 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 + +//[meyer97_stack4_header +// File: stack4.hpp +#ifndef STACK4_HPP_ +#define STACK4_HPP_ + +#include + +// Specification. + +CONTRACT_CLASS( // Dispenser with LIFO access policy and a fixed max capacity. + template( typename T ) + class (stack4) +) { + CONTRACT_CLASS_INVARIANT_TPL( + count() >= 0, // count non negative + count() <= capacity(), // count bounded + empty() == (count() == 0) // empty if no elements + ) + + // Initialization. + + CONTRACT_CONSTRUCTOR_TPL( // Allocate stack for a maximum of n elements. + public explicit (stack4) ( (const int&) n ) + precondition( + n >= 0 // non negative capacity + ) + postcondition( + capacity() == n // capacity set + ) + ) ; // Deferred body definition (see bottom). + + CONTRACT_CONSTRUCTOR_TPL( // Deep copy. + public (stack4) ( (const stack4&) right ) + postcondition( + capacity() == right.capacity(), + count() == right.count() + // all items equal right's items one by one + ) + ) ; + + CONTRACT_FUNCTION_TPL( // Deep assignment. + public (stack4&) operator(=)(assign) ( (const stack4&) right ) + postcondition( + capacity() == right.capacity(), + count() == right.count() + // all items equal right's items one by one + ) + ) ; + + CONTRACT_DESTRUCTOR_TPL( // Destroy this stack. + public virtual (~stack4) ( void ) + ) ; + + // Access. + + CONTRACT_FUNCTION_TPL( // Max number of stack elements. + public int (capacity) ( void ) const + ) ; + + CONTRACT_FUNCTION_TPL( // Number of stack elements. + public int (count) ( void ) const + ) ; + + CONTRACT_FUNCTION_TPL( // Top element. + public (const T&) (item) ( void ) const + precondition( + not empty() // not empty (i.e., count > 0) + ) + ) ; + + // Status report. + + CONTRACT_FUNCTION_TPL( // Is stack empty? + public bool (empty) ( void ) const + postcondition( + auto result = return, + result == (count() == 0) // empty definition + ) + ) ; + + CONTRACT_FUNCTION_TPL( // Is stack full? + public bool (full) ( void ) const + postcondition( + auto result = return, + result == (count() == capacity()) // full definition + ) + ) ; + + // Element change. + + CONTRACT_FUNCTION_TPL( // Add x on top. + public void (put) ( (const T&) x ) + precondition( + not full() // not full + ) + postcondition( + auto old_count = CONTRACT_OLDOF count(), + not empty(), // not empty + item() == x, // added to top + count() == old_count + 1 // one more item + ) + ) ; + + CONTRACT_FUNCTION_TPL( // Remove top item. + public void (remove) ( void ) + precondition( + not empty() // not empty (i.e., count > 0) + ) + postcondition( + auto old_count = CONTRACT_OLDOF count(), + not full(), // not full + count() == old_count - 1 // one fewer item + ) + ) ; + + private: int capacity_; + private: int count_; + private: T* representation_; // Using C-style array. +}; + +// Implementation. + +template< typename T > +CONTRACT_CONSTRUCTOR_BODY(stack4, stack4) ( const int& n ) +{ + capacity_ = n; + count_ = 0; + representation_ = new T[n]; +} + +template< typename T > +CONTRACT_CONSTRUCTOR_BODY(stack4, stack4) ( const stack4& right ) +{ + capacity_ = right.capacity_; + count_ = right.count_; + representation_ = new T[right.capacity_]; + for(int i = 0; i < right.count_; ++i) + representation_[i] = right.representation_[i]; +} + +template< typename T > +stack4& stack4::CONTRACT_MEMBER_BODY(operator(=)(assign)) ( + const stack4& right ) +{ + delete[] representation_; + capacity_ = right.capacity_; + count_ = right.count_; + representation_ = new T[right.capacity_]; + for(int i = 0; i < right.count_; ++i) + representation_[i] = right.representation_[i]; + return *this; +} + +template< typename T > +CONTRACT_DESTRUCTOR_BODY(stack4, ~stack4) ( void ) +{ + delete[] representation_; +} + +template< typename T > +int stack4::CONTRACT_MEMBER_BODY(capacity) ( void ) const +{ + return capacity_; +} + +template< typename T > +int stack4::CONTRACT_MEMBER_BODY(count) ( void ) const +{ + return count_; +} + +template< typename T > +const T& stack4::CONTRACT_MEMBER_BODY(item) ( void ) const +{ + return representation_[count() - 1]; +} + +template< typename T > +bool stack4::CONTRACT_MEMBER_BODY(empty) ( void ) const +{ + return count() == 0; +} + +template< typename T > +bool stack4::CONTRACT_MEMBER_BODY(full) ( void ) const +{ + return count() == capacity(); +} + +template< typename T > +void stack4::CONTRACT_MEMBER_BODY(put) ( const T& x ) +{ + representation_[count_++] = x; +} + +template< typename T > +void stack4::CONTRACT_MEMBER_BODY(remove) ( void ) +{ + --count_; +} + +#endif // #include guard +//] + + diff --git a/example/meyer97/stack4_main.cpp b/example/meyer97/stack4_main.cpp new file mode 100644 index 0000000..3b2b0ac --- /dev/null +++ b/example/meyer97/stack4_main.cpp @@ -0,0 +1,27 @@ + +// 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 + +//[meyer97_stack4_main +// File: stack4_main.cpp +#include "stack4.hpp" +#include + +int main ( void ) +{ + stack4 s(3); + BOOST_TEST(s.capacity() == 3); + BOOST_TEST(s.count() == 0); + s.put(123); + BOOST_TEST(not s.empty()); + BOOST_TEST(not s.full()); + BOOST_TEST(s.item() == 123); + s.remove(); + BOOST_TEST(s.empty()); + return boost::report_errors(); +} +//] + diff --git a/example/mitchell02/counter/counter.hpp b/example/mitchell02/counter/counter.hpp new file mode 100644 index 0000000..55e3b7c --- /dev/null +++ b/example/mitchell02/counter/counter.hpp @@ -0,0 +1,59 @@ + +// 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 + +//[mitchell02_counter_header +// File: counter/counter.hpp +#ifndef COUNTER_HPP_ +#define COUNTER_HPP_ + +#include "../observer/subject.hpp" +#include + +CONTRACT_CLASS( // Positive integer counter. + class (counter) extends( public subject ) +) { + CONTRACT_CLASS_INVARIANT( void ) // no invariants + + // Creation. + + CONTRACT_CONSTRUCTOR( // Construct counter with specified value. + public explicit (counter) ( int const a_value, default 10 ) + postcondition( value() == a_value ) // value set + initialize( value_(a_value) ) + ) {} + + CONTRACT_DESTRUCTOR( // Destroy counter. + public virtual (~counter) ( void ) + ) {} + + // Queries. + + CONTRACT_FUNCTION( // Current counter value. + public int (value) ( void ) const + ) { + return value_; + } + + // Commands. + + CONTRACT_FUNCTION( // Decrement counter value. + public void (decrement) ( void ) + postcondition( + auto old_value = CONTRACT_OLDOF value(), + value() == old_value - 1 // decremented + ) + ) { + --value_; + notify(); // Notifies all attached observers. + } + + private: int value_; +}; + +#endif // #include guard +//] + diff --git a/example/mitchell02/counter/decrement_button.hpp b/example/mitchell02/counter/decrement_button.hpp new file mode 100644 index 0000000..e4cd073 --- /dev/null +++ b/example/mitchell02/counter/decrement_button.hpp @@ -0,0 +1,76 @@ + +// 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 + +//[mitchell02_decrement_button_header +// File: counter/decrement_button.hpp +#ifndef DECREMENT_BUTTON_HPP_ +#define DECREMENT_BUTTON_HPP_ + +#include "push_button.hpp" +#include "counter.hpp" +#include "../observer/observer.hpp" +#include +#include + +CONTRACT_CLASS( // Button that decrements counter. + class (decrement_button) final // Contract for final class. + extends( public push_button, protected observer, boost::noncopyable ) +) { + CONTRACT_CLASS_INVARIANT( void ) // no invariant + + // Creation. + + CONTRACT_CONSTRUCTOR( // Create button associated with given counter. + public explicit (decrement_button) ( (counter&) the_counter ) + postcondition( + // enabled iff positive value + enabled() == (the_counter.value() > 0) + ) + initialize( counter_ref_(the_counter) ) + ) { + counter_ref_.attach(this); + } + + CONTRACT_DESTRUCTOR( // Destroy button. + public (~decrement_button) ( void ) + ) {} + + // Commands. + + CONTRACT_FUNCTION( + public void (on_bn_clicked) ( void ) override + postcondition( + old_value = CONTRACT_OLDOF counter_ref_.value(), + counter_ref_.value() == old_value - 1 // counter decremented + ) + ) { + counter_ref_.decrement(); + } + + CONTRACT_FUNCTION( + private bool (up_to_date_with_subject) ( void ) const override + ) { + return true; // For simplicity, always up-to-date. + } + + CONTRACT_FUNCTION( + private void (update) ( void ) override + postcondition( + // enabled if positive value + enabled() == (counter_ref_.value() > 0) + ) + ) { + if(counter_ref_.value() == 0) disable(); + else enable(); + } + + private: counter& counter_ref_; +}; + +#endif // #include guard +//] + diff --git a/example/mitchell02/counter/push_button.hpp b/example/mitchell02/counter/push_button.hpp new file mode 100644 index 0000000..b3e9265 --- /dev/null +++ b/example/mitchell02/counter/push_button.hpp @@ -0,0 +1,66 @@ + +// 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 + +//[mitchell02_push_button_header +// File: counter/push_button.hpp +#ifndef PUSH_BUTTON_HPP_ +#define PUSH_BUTTON_HPP_ + +#include + +CONTRACT_CLASS( // Basic button. + class (push_button) +) { + CONTRACT_CLASS_INVARIANT( void ) // no invariant + + // Creation. + + CONTRACT_CONSTRUCTOR( // Create an enabled button. + public (push_button) ( void ) + postcondition( enabled() ) // enabled + initialize( enabled_(true) ) + ) {} + + CONTRACT_DESTRUCTOR( // Destroy button. + public virtual (~push_button) ( void ) + ) {} + + // Queries. + + CONTRACT_FUNCTION( // If button enabled. + public bool (enabled) ( void ) const + ) { + return enabled_; + } + + // Commands. + + CONTRACT_FUNCTION( // Enable this button. + public void (enable) ( void ) + postcondition( enabled() ) // enabled + ) { + enabled_ = true; + } + + CONTRACT_FUNCTION( // Disable this button. + public void (disable) ( void ) + postcondition( not enabled() ) // disabled + ) { + enabled_ = false; + } + + CONTRACT_FUNCTION( // Invoked externally when this button is clicked. + public virtual void (on_bn_clicked) ( void ) new + precondition( enabled() ) // enabled + ) = 0; // Contract for pure virtual function. + + private: bool enabled_; +}; + +#endif // #include guard +//] + diff --git a/example/mitchell02/counter_main.cpp b/example/mitchell02/counter_main.cpp new file mode 100644 index 0000000..1742ba2 --- /dev/null +++ b/example/mitchell02/counter_main.cpp @@ -0,0 +1,64 @@ + +// 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 + +//[mitchell02_counter_main +// File: counter_main.cpp +#include "counter/counter.hpp" +#include "counter/decrement_button.hpp" +#include "observer/observer.hpp" +#include + +int counter_check; + +CONTRACT_CLASS( // Show current value of associated counter. + class (view_of_counter) extends( private observer ) +) { + CONTRACT_CLASS_INVARIANT( void ) // no invariant + + // Creation. + + CONTRACT_CONSTRUCTOR( // Create viewer associated with given counter. + public explicit (view_of_counter) ( (counter&) the_counter ) + initialize( counter_ref_(the_counter) ) + ) { + counter_ref_.attach(this); + BOOST_TEST(counter_ref_.value() == counter_check); + } + + CONTRACT_DESTRUCTOR( // Destroy viewer. + public virtual (~view_of_counter) ( void ) + ) {} + + CONTRACT_FUNCTION( + private bool (up_to_date_with_subject) ( void ) const override final + ) { + return true; // For simplicity, always up-to-date. + } + + CONTRACT_FUNCTION( + private void (update) ( void ) override final // Contract final func. + ) { + BOOST_TEST(counter_ref_.value() == counter_check); + } + + private: counter& counter_ref_; +}; + +int main ( void ) +{ + counter count(counter_check = 1); + view_of_counter view(count); + decrement_button decrement(count); + BOOST_TEST(decrement.enabled()); + + counter_check--; + decrement.on_bn_clicked(); + BOOST_TEST(not decrement.enabled()); + return boost::report_errors(); +} +//] + diff --git a/example/mitchell02/courier.cpp b/example/mitchell02/courier.cpp new file mode 100644 index 0000000..d61ced4 --- /dev/null +++ b/example/mitchell02/courier.cpp @@ -0,0 +1,49 @@ + +// 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 + +//[mitchell02_courier +// File: courier.cpp +#include "courier.hpp" + +// Courier. + +double courier::min_insurance_dollar = 10.0e+6; + +CONTRACT_CONSTRUCTOR_BODY(courier, courier) ( + double const an_insurance_cover_dollar ) +{ + insurance_cover_dollar_ = an_insurance_cover_dollar; +} + +CONTRACT_DESTRUCTOR_BODY(courier, ~courier) ( void ) {} + +double courier::CONTRACT_MEMBER_BODY(insurance_cover_dollar) ( void ) const + { return insurance_cover_dollar_; } + +void courier::CONTRACT_MEMBER_BODY(deliver) ( package& the_package, + std::string const destination ) +{ + the_package.location = destination; + // Delivery takes 2.5 hours. + the_package.delivered_hour = the_package.accepted_hour + 2.5; +} + +// Different courier. + +double different_courier::different_insurance_dollar = 20.0e+6; + +CONTRACT_DESTRUCTOR_BODY(different_courier, ~different_courier) ( void ) {} + +void different_courier::CONTRACT_MEMBER_BODY(deliver) ( package& the_package, + std::string const destination ) +{ + the_package.location = destination; + // Delivery takes only 0.5 hours. + the_package.delivered_hour = the_package.accepted_hour + 0.5; +} +//] + diff --git a/example/mitchell02/courier.hpp b/example/mitchell02/courier.hpp new file mode 100644 index 0000000..f138cb8 --- /dev/null +++ b/example/mitchell02/courier.hpp @@ -0,0 +1,133 @@ + +// 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 + +//[mitchell02_courier_header +// File: courier.hpp +#ifndef COURIER_HPP_ +#define COURIER_HPP_ + +#include +#include + +struct package // Basic package information. +{ + public: double weight_kg; // Weight in kilograms. + public: std::string location; // Current location. + public: double accepted_hour; // Hour when it was accepted for delivery. + public: double delivered_hour; // Hour when it was delivered. + + public: explicit package ( + double const a_weight_kg, + std::string const a_location = "", + double const an_accepted_hour = 0.0, + double const a_delivered_hour = 0.0 + ) + : weight_kg(a_weight_kg), + location(a_location), + accepted_hour(an_accepted_hour), + delivered_hour(a_delivered_hour) + {} +}; + +CONTRACT_CLASS( // Basic courier for package delivery. + class (courier) +) { + CONTRACT_CLASS_INVARIANT( + insurance_cover_dollar() >= min_insurance_dollar, // above min insur. + static class( // Static class invariants. + min_insurance_dollar > 0.0 // positive min insurance + ) + ) + + public: static double min_insurance_dollar; + + // Creation. + + CONTRACT_CONSTRUCTOR( // Create courier with specified insurance value. + public explicit (courier) ( + double const an_insurance_cover_dollar, + default min_insurance_dollar + ) + precondition( an_insurance_cover_dollar > 0.0 ) // positive insur. + ) ; // Deferred body definition. + + CONTRACT_DESTRUCTOR( // Destroy courier. + public virtual (~courier) ( void ) + ) ; + + // Queries. + + CONTRACT_FUNCTION( // Return insurance cover. + public double (insurance_cover_dollar) ( void ) const + ) ; + + // Commands. + + CONTRACT_FUNCTION( // Deliver package to destination. + public virtual void (deliver) ( (package&) the_package, + (std::string const) destination ) + precondition( + the_package.weight_kg < 5.0 // within max wight + ) + postcondition( + double(the_package.delivered_hour - the_package.accepted_hour) + <= 3.0, // within max delivery time + the_package.location == destination // delivered at destination + ) + ) ; + + private: double insurance_cover_dollar_; +}; + +CONTRACT_CLASS( // Different courier for package delivery. + class (different_courier) extends( public courier ) +) { + CONTRACT_CLASS_INVARIANT( + insurance_cover_dollar() >= different_insurance_dollar, + static class( + different_insurance_dollar >= courier::min_insurance_dollar + ) + ) + + public: static double different_insurance_dollar; + + // Creation. + + CONTRACT_CONSTRUCTOR( // Create currier with specified insurance value. + public explicit (different_courier) ( + double const insurance_cover_dollar, + default different_insurance_dollar + ) + precondition( insurance_cover_dollar > 0.0 ) + initialize( courier(insurance_cover_dollar) ) + ) {} // Cannot separated body definition because has member initializers. + + CONTRACT_DESTRUCTOR( // Destroy courier. + public virtual (~different_courier) ( void ) + ) ; + + // Commands. + + CONTRACT_FUNCTION( + public virtual void (deliver) ( (package&) the_package, + (std::string const) destination ) override final + precondition( + // Weaker precondition on weight (it can weight more). + the_package.weight_kg <= 8.0 + ) + postcondition( + // Stronger postcondition on delivery time (faster delivery). + double(the_package.delivered_hour - the_package.accepted_hour) + <= 2.0 + // Inherits "delivered at destination" postcondition. + ) + ) ; +}; + +#endif // #include guard +//] + diff --git a/example/mitchell02/courier_main.cpp b/example/mitchell02/courier_main.cpp new file mode 100644 index 0000000..d4a84e9 --- /dev/null +++ b/example/mitchell02/courier_main.cpp @@ -0,0 +1,23 @@ + +// 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 + +//[mitchell02_courier_main +// File: courier_main.cpp +#include "courier.hpp" + +int main ( void ) +{ + courier c; + different_courier dc; + package cups(3.6, "store"); + package desk(7.2, "store"); + c.deliver(cups, "home"); + dc.deliver(desk, "office"); + return 0; +} +//] + diff --git a/example/mitchell02/customer_manager.cpp b/example/mitchell02/customer_manager.cpp new file mode 100644 index 0000000..e96277c --- /dev/null +++ b/example/mitchell02/customer_manager.cpp @@ -0,0 +1,45 @@ + +// 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 + +//[mitchell02_customer_manager +// File: customer_manager.cpp +#include "customer_manager.hpp" +#include + +CONTRACT_CONSTRUCTOR_BODY(customer_manager, customer_manager) ( void ) {} + +CONTRACT_DESTRUCTOR_BODY(customer_manager, ~customer_manager) ( void ) {} + +int customer_manager::CONTRACT_MEMBER_BODY(count) ( void ) const + { return customers_.size(); } + +bool customer_manager::CONTRACT_MEMBER_BODY(id_active) ( + basic_customer_details::identifier const& id) const +{ + return customers_.find(id) != customers_.end(); +} + +std::string const& customer_manager::CONTRACT_MEMBER_BODY(name_for) ( + basic_customer_details::identifier const& id) const +{ + // Find != end because of `id_active()` pre so no defensive programming. + return customers_.find(id)->second.name; +} + +void customer_manager::CONTRACT_MEMBER_BODY(add) ( + basic_customer_details const& details ) + { customers_.insert(std::make_pair(details.id, customer(details))); } + +void customer_manager::CONTRACT_MEMBER_BODY(set_name) ( + basic_customer_details::identifier const& id, + std::string const& name ) +{ + // Find != end because of `id_active()` pre so no defensive programming. + customers_.find(id)->second.name = name; +} +//] + diff --git a/example/mitchell02/customer_manager.hpp b/example/mitchell02/customer_manager.hpp new file mode 100644 index 0000000..cd865a7 --- /dev/null +++ b/example/mitchell02/customer_manager.hpp @@ -0,0 +1,109 @@ + +// 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 + +//[mitchell02_customer_manager_header +// File: customer_manager.hpp +#ifndef CUSTOMER_MANAGER_HPP_ +#define CUSTOMER_MANAGER_HPP_ + +#include +#include +#include + +class basic_customer_details // Basic customer information. +{ + friend class customer_manager; + + public: typedef std::string identifier; + + public: explicit basic_customer_details ( identifier const& an_id ) + : id(an_id), name(), address(), birthday() + {} + + protected: identifier id; // Customer identifier. + protected: std::string name; // Customer name. + protected: std::string address; // Customer address. + protected: std::string birthday; // Customer date of birth. +}; + +CONTRACT_CLASS( // Manage customers. + class (customer_manager) +) { + CONTRACT_CLASS_INVARIANT( count() >= 0 ) // non-negative count + + // Creation. + + CONTRACT_CONSTRUCTOR( + public (customer_manager) ( void ) + // LIMITATION: Cannot use member initializes because deferring + // body definition. + ) ; // Deferred body definition. + + CONTRACT_DESTRUCTOR( + public virtual (~customer_manager) ( void ) + ) ; + + // Basic queries. + + CONTRACT_FUNCTION( + public int (count) ( void ) const + // postcondition: non-negative count asserted by class invariants + ) ; + + CONTRACT_FUNCTION( // There is a customer with given identifier. + public bool (id_active) ( + (basic_customer_details::identifier const&) id ) const + ) ; + + // Derived queries. + + CONTRACT_FUNCTION( // Name of customer with given identifier. + public (std::string const&) (name_for) ( + (basic_customer_details::identifier const&) id ) const + precondition( id_active(id) ) // id active + ) ; + + // Commands. + + CONTRACT_FUNCTION( // Add given customer. + public void (add) ( (basic_customer_details const&) details ) + precondition( not id_active(details.id) ) // id not active + postcondition( + auto old_count = CONTRACT_OLDOF count(), + count() == old_count + 1, // count increased + id_active(details.id) // id active + ) + ) ; + + CONTRACT_FUNCTION( // Set name of customer with given identifier. + public void (set_name) ( + (basic_customer_details::identifier const&) id, + (std::string const&) name + ) + precondition( id_active(id) ) // id active + postcondition( name_for(id) == name ) // name set + ) ; + + private: class agent {}; // Customer agent. + + private: struct customer : basic_customer_details // Basic customer. + { + public: agent managing_agent; // Customer agent. + public: std::string last_contact; // Customer last contacted. + + public: explicit customer ( basic_customer_details const& details ) + : basic_customer_details(details), managing_agent(), + last_contact() + {} + }; + + private: std::map customers_; +}; + +#endif // #include guard +//] + diff --git a/example/mitchell02/customer_manager_main.cpp b/example/mitchell02/customer_manager_main.cpp new file mode 100644 index 0000000..64d8b3d --- /dev/null +++ b/example/mitchell02/customer_manager_main.cpp @@ -0,0 +1,26 @@ + +// 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 + +//[mitchell02_customer_manager_main +// File: customer_manager_main.cpp +#include "customer_manager.hpp" +#include + +int main ( void ) +{ + customer_manager mgr; + basic_customer_details d("id1"); + + mgr.add(d); + mgr.set_name("id1", "abc"); + BOOST_TEST(mgr.name_for("id1") == "abc"); + BOOST_TEST(mgr.count() == 1); + BOOST_TEST(mgr.id_active("id1")); + return boost::report_errors(); +} +//] + diff --git a/example/mitchell02/dictionary.cpp b/example/mitchell02/dictionary.cpp new file mode 100644 index 0000000..bf990a2 --- /dev/null +++ b/example/mitchell02/dictionary.cpp @@ -0,0 +1,98 @@ + +// 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 + +//[mitchell02_dictionary +// File: dictionary.cpp +#include +#include +#include +#include + +CONTRACT_CLASS( // Simple dictionary. + template( typename Key, typename Value ) + class (dictionary) +) { + CONTRACT_CLASS_INVARIANT_TPL( count() >= 0 ) // non-negative count + + // Creation. + + CONTRACT_CONSTRUCTOR_TPL( // Create empty dictionary. + public (dictionary) ( void ) + postcondition( count() == 0 ) // empty + ) {} + + CONTRACT_DESTRUCTOR_TPL( // Destroy dictionary. + public virtual (~dictionary) ( void ) + ) {} + + // Basic queries. + + CONTRACT_FUNCTION_TPL( // Number of key entires. + public int (count) ( void ) const + // postcondition: non-negative count asserted by class invariants + ) { + return items_.size(); + } + + CONTRACT_FUNCTION_TPL( // Has entry for key? + public bool (has) ( (Key const&) key ) const + postcondition( + auto result = return, + if(count() == 0) ( not result ) // empty has no key + ) + ) { + return items_.find(key) != items_.end(); + } + + CONTRACT_FUNCTION_TPL( // Value for given key. + public (Value const&) (value_for) ( (Key const&) key ) const + precondition( has(key) ) // has key + ) { + return items_.find(key)->second; + } + + // Commands. + + CONTRACT_FUNCTION_TPL( // Put value for given key. + public void (put) ( (Key const&) key, (Value const&) value ) + postcondition( + auto old_count = CONTRACT_OLDOF count(), + count() == old_count + 1, // count increased + has(key), // has key + value_for(key) == value // value for key set + ) + ) { + items_.insert(std::make_pair(key, value)); + } + + CONTRACT_FUNCTION_TPL( // Remove value for given key. + public void (remove) ( (Key const&) key ) + precondition( has(key) ) // has key + postcondition( + auto old_count = CONTRACT_OLDOF count(), + count() == old_count - 1, // count decreased + not has(key) // does not have key + ) + ) { + items_.erase(key); + } + + private: std::map items_; +}; + +int main ( void ) +{ + dictionary ages; + BOOST_TEST(not ages.has("john")); + ages.put("john", 23); + BOOST_TEST(ages.value_for("john") == 23); + ages.remove("john"); + BOOST_TEST(ages.count() == 0); + return boost::report_errors(); +} +//] + diff --git a/example/mitchell02/name_list.cpp b/example/mitchell02/name_list.cpp new file mode 100644 index 0000000..837d3f7 --- /dev/null +++ b/example/mitchell02/name_list.cpp @@ -0,0 +1,40 @@ + +// 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 + +//[mitchell02_name_list +// File: name_list.cpp +#include "name_list.hpp" +#include + +// name_list + +CONTRACT_CONSTRUCTOR_BODY(name_list, name_list) ( void ) {} + +CONTRACT_DESTRUCTOR_BODY(name_list, ~name_list) ( void ) {} + +int name_list::CONTRACT_MEMBER_BODY(count) ( void ) const + { return names_.size(); } + +bool name_list::CONTRACT_MEMBER_BODY(has) ( std::string const& name ) const + { return names_.end() != std::find(names_.begin(), names_.end(), name); } + +void name_list::CONTRACT_MEMBER_BODY(put) ( std::string const& name ) + { names_.push_back(name); } + +// relaxed_name_list + +CONTRACT_CONSTRUCTOR_BODY(relaxed_name_list, relaxed_name_list) ( void ) {} + +CONTRACT_DESTRUCTOR_BODY(relaxed_name_list, ~relaxed_name_list) ( void ) {} + +void relaxed_name_list::CONTRACT_MEMBER_BODY(put) ( std::string const& name ) +{ + // Must use `BODY` to call base functions (to avoid infinite recursion). + if(!has(name)) name_list::CONTRACT_MEMBER_BODY(put)(name); +} +//] + diff --git a/example/mitchell02/name_list.hpp b/example/mitchell02/name_list.hpp new file mode 100644 index 0000000..5a6e7c2 --- /dev/null +++ b/example/mitchell02/name_list.hpp @@ -0,0 +1,99 @@ + +// 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 + +//[mitchell02_name_list_header +// File: name_list.hpp +#ifndef NAME_LIST_HPP_ +#define NAME_LIST_HPP_ + +#include +#include +#include + +CONTRACT_CLASS( // List of names. + class (name_list) +) { + CONTRACT_CLASS_INVARIANT( count() >= 0 ) // non-negative count + + CONTRACT_CONSTRUCTOR( // Create an empty list. + public (name_list) ( void ) + postcondition( count() == 0 ) // empty list + ) ; // Deferred body definition. + + CONTRACT_DESTRUCTOR( // Destroy list. + public virtual (~name_list) ( void ) + ) ; + + CONTRACT_FUNCTION( // Number of names in list. + public int (count) ( void ) const + // postcondition: non-negative count already in class invariants + ) ; + + CONTRACT_FUNCTION( // Is name in list? + public bool (has) ( (std::string const&) name ) const + postcondition( + auto result = return, + if(count() == 0) ( not result ) // does not have is empty + ) + ) ; + + CONTRACT_FUNCTION( // Add name to list. + public virtual void (put) ( (std::string const&) name ) + precondition( + not has(name) // not already in list + ) + postcondition( + auto old_has_name = CONTRACT_OLDOF has(name), + auto old_count = CONTRACT_OLDOF count(), + // Following if-guard allows to relax subcontracts. + if(not old_has_name) ( + has(name), // name on list + count() == old_count + 1 // number of names increased + ) + ) + ) ; + + private: std::list names_; +}; + +CONTRACT_CLASS( // List of names that allows for duplicates. + class (relaxed_name_list) extends( public name_list ) // Subcontracting. +) { + CONTRACT_CLASS_INVARIANT( void ) // no subcontracted invariants + + // Creation. + + CONTRACT_CONSTRUCTOR( // Create an empty list. + public (relaxed_name_list) ( void ) + postcondition( count() == 0 ) + ) ; + + CONTRACT_DESTRUCTOR( // Destroy list. + public virtual (~relaxed_name_list) ( void ) + ) ; + + // Commands. + + CONTRACT_FUNCTION( // Add name to list. + public void (put) ( (std::string const&) name ) + precondition( // Relax inherited precondition. + has(name) // already in list + ) + postcondition( + auto old_has_name = CONTRACT_OLDOF has(name), + auto old_count = CONTRACT_OLDOF count(), + // Inherited postconditions not checked because of its if-guard. + if(old_has_name) ( + count() == old_count // unchanged if name already in list + ) + ) + ) ; +}; + +#endif // #include guard +//] + diff --git a/example/mitchell02/name_list_main.cpp b/example/mitchell02/name_list_main.cpp new file mode 100644 index 0000000..b0a14e5 --- /dev/null +++ b/example/mitchell02/name_list_main.cpp @@ -0,0 +1,27 @@ + +// 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 + +//[mitchell02_name_list_main +// File: name_list_main.cpp +#include "name_list.hpp" +#include + +int main ( void ) +{ + relaxed_name_list rl; + rl.put("abc"); + BOOST_TEST(rl.has("abc")); + rl.put("abc"); // Note: Can call `put("abc")` this gain. + + name_list nl; + nl.put("abc"); + BOOST_TEST(nl.has("abc")); + // Note: Cannot call `put("abc")` again. + return boost::report_errors(); +} +//] + diff --git a/example/mitchell02/observer/observer.hpp b/example/mitchell02/observer/observer.hpp new file mode 100644 index 0000000..634fd05 --- /dev/null +++ b/example/mitchell02/observer/observer.hpp @@ -0,0 +1,46 @@ + +// 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 + +//[mitchell02_observer_header +// File: observer/observer.hpp +#ifndef OBSERVER_HPP_ +#define OBSERVER_HPP_ + +#include + +CONTRACT_CLASS( // Observer. + class (observer) +) { + CONTRACT_CLASS_INVARIANT( void ) // no invariant + + friend class subject; + + // Creation. + + CONTRACT_CONSTRUCTOR( // Create observer. + public (observer) ( void ) + ) {} + + CONTRACT_DESTRUCTOR( // Destroy observer. + public virtual (~observer) ( void ) + ) {} + + // Commands. + + CONTRACT_FUNCTION( // If up to date with its subject. + protected virtual bool (up_to_date_with_subject) ( void ) const new + ) = 0; + + CONTRACT_FUNCTION( // Update and inform its subject. + protected virtual void (update) ( void ) new + postcondition( up_to_date_with_subject() ) // up-to-date + ) = 0; +}; + +#endif // #include guard +//] + diff --git a/example/mitchell02/observer/subject.hpp b/example/mitchell02/observer/subject.hpp new file mode 100644 index 0000000..0222610 --- /dev/null +++ b/example/mitchell02/observer/subject.hpp @@ -0,0 +1,151 @@ + +// 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 + +//[mitchell02_subject_header +// File: observer/subject.hpp +#ifndef SUBJECT_HPP_ +#define SUBJECT_HPP_ + +#include "observer.hpp" +#include +#include +#include + +// Assertion requirements used to model assertion computational complexity. +#define O_1 0 // O(1) constant (default) +#define O_N 1 // O(n) linear +#define COMPLEXITY_MAX O_1 + +CONTRACT_CLASS( // Subject for observer design pattern. + class (subject) +) { + CONTRACT_CLASS_INVARIANT( + all_observers_valid(observers()), // observes valid + requires O_N <= COMPLEXITY_MAX + ) + + // Creation. + + CONTRACT_CONSTRUCTOR( // Construct subject with no observer. + public (subject) ( void ) + ) {} + + CONTRACT_DESTRUCTOR( // Destroy subject. + public virtual (~subject) ( void ) + ) {} + + // Queries. + + CONTRACT_FUNCTION( // If given observer is attached. + public bool (attached) ( (observer const* const) obs ) const + precondition( obs ) // not null + ) { + return std::find(observers_.begin(), observers_.end(), obs) != + observers_.end(); + } + + // Commands. + + CONTRACT_FUNCTION( // Remember given object as an observer. + public void (attach) ( (observer* const) obs ) + precondition( + obs, // not null + not attached(obs) // not already attached + ) + postcondition( + auto old_observers = CONTRACT_OLDOF observers(), + attached(obs), // attached + other_observers_unchanged(old_observers, observers(), obs), + // others not changed (frame rule) + requires O_N <= COMPLEXITY_MAX + ) + ) { + observers_.push_back(obs); + } + + // Queries. + + CONTRACT_FUNCTION( // All observers attached to this subject. + protected (std::list) (observers) ( void ) const + ) { + // Create list of pointers to const observers. + std::list obs; + for(std::list::const_iterator + i = observers_.begin(); i != observers_.end(); ++i) { + obs.push_back(*i); + } + return obs; + } + + // Commands. + + CONTRACT_FUNCTION( // Update all attached observers. + protected void (notify) ( void ) + postcondition( all_observers_updated(observers()) ) // all updated + ) { + for(std::list::iterator + i = observers_.begin(); i != observers_.end(); ++i) { + // Class invariant ensures no null pointers in observers but + // class invariants not checked for non-public members so check. + CONTRACT_BLOCK_INVARIANT( const( i ) 0 != *i ) // pointer not null + (*i)->update(); + } + } + + // Contract helpers. + + CONTRACT_FUNCTION( + private static bool (all_observers_valid) ( + (std::list const&) observers ) + ) { + for(std::list::const_iterator + i = observers.begin(); i != observers.end(); ++i) { + if(!(*i)) return false; + } + return true; + } + + CONTRACT_FUNCTION( + private bool (other_observers_unchanged) ( + (std::list const&) old, + (std::list const&) now, + (observer const*) obs + ) const + precondition( obs ) // not null + ) { + std::list remaining = now; + std::remove(remaining.begin(), remaining.end(), obs); + + std::list::const_iterator + remaining_it = remaining.begin(); + std::list::const_iterator old_it = old.begin(); + while(remaining.end() != remaining_it && old.end() != old_it) { + if(*remaining_it != *old_it) return false; + ++remaining_it; + ++old_it; + } + return true; + } + + CONTRACT_FUNCTION( + private bool (all_observers_updated) ( + (std::list const&) observers ) const + ) { + for(std::list::const_iterator + i = observers.begin(); i != observers.end(); ++i) { + if(!(*i)) return false; + if(!(*i)->up_to_date_with_subject()) return false; + } + return true; + } + + private: std::list observers_; +}; + +#endif // #include guard +//] + diff --git a/example/mitchell02/observer_main.cpp b/example/mitchell02/observer_main.cpp new file mode 100644 index 0000000..024b482 --- /dev/null +++ b/example/mitchell02/observer_main.cpp @@ -0,0 +1,74 @@ + +// 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 + +//[mitchell02_observer_main +// File: observer_main.cpp +#include "observer/observer.hpp" +#include "observer/subject.hpp" +#include +#include + +int state_check; // For unit testing. + +class concrete_subject : public subject // Implement an actual subject. +{ + public: typedef int state; // Some state being observed. + + public: concrete_subject ( void ) : state_() {} + + public: void set_state (state const& the_state) { + state_ = the_state; + BOOST_TEST(state_ == state_check); + notify(); // Notify observers. + } + + public: state get_state ( void ) const { return state_; } + + private: state state_; +}; + +CONTRACT_CLASS( // Implement of actual observer. + class (concrete_observer) extends( public observer ) +) { + CONTRACT_CLASS_INVARIANT( void ) + + CONTRACT_CONSTRUCTOR( // Create concrete observer. + public explicit (concrete_observer) ( + (concrete_subject const&) the_subject ) + initialize( subject_(the_subject), observed_state_() ) + ) {} + + // Implement base virtual functions. + + CONTRACT_FUNCTION( + private bool (up_to_date_with_subject) ( void ) const override final + ) { + return true; // For simplicity, always up-to-date. + } + + CONTRACT_FUNCTION( + private void (update) ( void ) override final + ) { + observed_state_ = subject_.get_state(); + BOOST_TEST(observed_state_ == state_check); + } + + private: concrete_subject const& subject_; + private: concrete_subject::state observed_state_; +}; + +int main ( void ) +{ + concrete_subject sbj; + concrete_observer ob(sbj); + sbj.attach(&ob); + sbj.set_state(state_check = 123); + sbj.set_state(state_check = 456); + return boost::report_errors(); +} +//] + diff --git a/example/mitchell02/simple_queue.cpp b/example/mitchell02/simple_queue.cpp new file mode 100644 index 0000000..67bddee --- /dev/null +++ b/example/mitchell02/simple_queue.cpp @@ -0,0 +1,170 @@ + +// 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 + +//[mitchell02_simple_queue +// File: simple_queue.cpp +#include +#include +#include + +// Assertion requirements used to model assertion computational complexity. +#define O_1 0 // O(1) constant (default) +#define O_N 1 // O(n) linear +#define COMPLEXITY_MAX O_1 + +CONTRACT_CLASS( + template( typename T ) + class (simple_queue) +) { + CONTRACT_CLASS_INVARIANT( count() >= 0 ) // non-negative count + + // Creation. + + CONTRACT_CONSTRUCTOR_TPL( // Create empty queue. + public explicit (simple_queue) ( int const the_capacity ) + precondition( the_capacity > 0 ) // positive capacity + postcondition( + capacity() == the_capacity, // capacity set + is_empty() // empty + ) + ) { + items_.reserve(the_capacity); + } + + CONTRACT_DESTRUCTOR_TPL( // Destroy queue. + public virtual (~simple_queue) ( void ) + ) {} + + // Basic queries. + + CONTRACT_FUNCTION_TPL( // Items in the queue (in their order). + public (std::vector const&) (items) ( void ) const + ) { + return items_; + } + + CONTRACT_FUNCTION_TPL( // Max number of items queue can hold. + public int (capacity) ( void ) const + ) { + return items_.capacity(); + } + + // Derived queries. + + CONTRACT_FUNCTION_TPL( // Number of items. + public int (count) ( void ) const + postcondition( + auto result = return, + result == int(items().size()) // return items count + ) + ) { + return items_.size(); + } + + CONTRACT_FUNCTION_TPL( // Item at head. + public (T const&) (head) ( void ) const + precondition( not is_empty() ) + postcondition( + auto result = return, + result == items().at(0) // return item on top + ) + ) { + return items_.at(0); + } + + CONTRACT_FUNCTION_TPL( // If queue contains no item. + public bool (is_empty) ( void ) const + postcondition( + auto result = return, + result == (count() == 0) // consistent with count + ) + ) { + return items_.size() == 0; + } + + CONTRACT_FUNCTION_TPL( // If queue has no room for another item. + public bool (is_full) ( void ) const + postcondition( + auto result = return, + // consistent with size and capacity + result == (capacity() == int(items().size())) + ) + ) { + return items_.size() == items_.capacity(); + } + + // Commands. + + CONTRACT_FUNCTION_TPL( // Remove head item and shift all other items. + public void (remove) ( void ) + precondition( not is_empty() ) + postcondition( + auto old_count = CONTRACT_OLDOF count(), + auto old_items = CONTRACT_OLDOF items(), + count() == old_count - 1, // count decreased + // Expensive assertion to check so marked with its complexity. + all_equal(items(), old_items, 1 /* shifted */), + requires O_N <= COMPLEXITY_MAX + ) + ) { + items_.erase(items_.begin()); + } + + CONTRACT_FUNCTION_TPL( // Add item to tail. + public void (put) ( (T const&) item ) + precondition( count() < capacity() ) + postcondition( + auto old_count = CONTRACT_OLDOF count(), + auto old_items = CONTRACT_OLDOF items(), + count() == old_count + 1, // count increased + items().at(count() - 1) == item, // second last item + if(count() >= 2) ( + // Computationally expensive assertion to check. + all_equal(items(), old_items), + requires O_N <= COMPLEXITY_MAX + ) + ) + ) { + items_.push_back(item); + } + + CONTRACT_FUNCTION_TPL( // Contract helper. + private static bool (all_equal) ( + (std::vector const&) left, + (std::vector const&) right, + size_t offset, default 0 + ) + precondition( + right.size() == left.size() + offset // correct offset + ) + ) { + for(size_t i = offset; i < right.size(); ++i) + if(left.at(i - offset) != right.at(i)) return false; + return true; + } + + private: std::vector items_; +}; + +int main ( void ) +{ + simple_queue q(10); + q.put(123); + q.put(456); + std::vector const& items = q.items(); + BOOST_TEST(items[0] == 123); + BOOST_TEST(items[1] == 456); + BOOST_TEST(q.capacity() == 10); + BOOST_TEST(q.head() == 123); + BOOST_TEST(not q.is_empty()); + BOOST_TEST(not q.is_full()); + q.remove(); + BOOST_TEST(q.count() == 1); + return boost::report_errors(); +} +//] + diff --git a/example/mitchell02/stack.cpp b/example/mitchell02/stack.cpp new file mode 100644 index 0000000..82e20b8 --- /dev/null +++ b/example/mitchell02/stack.cpp @@ -0,0 +1,110 @@ + +// 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 + +//[mitchell02_stack +// File: stack.cpp +#include +#include +#include + +CONTRACT_CLASS( // Simple stack. + template( typename T ) + class (stack) +) { + CONTRACT_CLASS_INVARIANT_TPL( count() >= 0 ) // non-negative count + + // Creation. + + CONTRACT_CONSTRUCTOR_TPL( // Create empty stack. + public (stack) ( void ) + postcondition( count() == 0 ) // empty + ) {} + + CONTRACT_DESTRUCTOR_TPL( // Destroy stack. + public virtual (~stack) ( void ) + ) {} + + // Basic queries. + + CONTRACT_FUNCTION_TPL( // Number of items. + public int (count) ( void ) const + ) { + return items_.size(); + } + + CONTRACT_FUNCTION_TPL( // Item at index in [1, count()] (as in Eiffel). + public (T const&) (item_at) ( int const index ) const + precondition( + index > 0, // positive index + index <= count() // index within count + ) + ) { + return items_.at(index - 1); + } + + // Derived queries. + + CONTRACT_FUNCTION_TPL( // If no items. + public bool (is_empty) ( void ) const + postcondition( + auto result = return, + result == (count() == 0) // consistent with count + ) + ) { + return count() == 0; + } + + CONTRACT_FUNCTION_TPL( // Top item. + public (T const&) (item) ( void ) const + precondition( count() > 0 ) // not empty + postcondition( + auto result = return, + result == item_at(count()) // item on top + ) + ) { + return item_at(count()); + } + + // Commands. + + CONTRACT_FUNCTION_TPL( // Push item to the top. + public void (put) ( (T const&) new_item ) + postcondition( + auto old_count = CONTRACT_OLDOF count(), + count() == old_count + 1, // count increased + item() == new_item // item set + ) + ) { + items_.push_back(new_item); + } + + CONTRACT_FUNCTION_TPL( // Pop top item. + public void (remove) ( void ) + precondition( count() > 0 ) // not empty + postcondition( + auto old_count = CONTRACT_OLDOF count(), + count() == old_count - 1 // count decreased + ) + ) { + items_.resize(items_.size() - 1); + } + + private: std::vector items_; +}; + +int main ( void ) +{ + stack s; + BOOST_TEST(s.count() == 0); + s.put(123); + BOOST_TEST(s.item_at(1) == 123); + s.remove(); + BOOST_TEST(s.is_empty()); + return boost::report_errors(); +} +//] + diff --git a/example/n1962/block_invariant.cpp b/example/n1962/block_invariant.cpp new file mode 100644 index 0000000..4e5ee67 --- /dev/null +++ b/example/n1962/block_invariant.cpp @@ -0,0 +1,25 @@ + +// 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 + +//[n1962_block_invariant +// File: block_invariant.cpp +#include +#include +#include + +int main ( void ) +{ + int i = 0; + for(i = 0; i < 100; ++i) + { + CONTRACT_BLOCK_INVARIANT( const( i ) i >= 0 ) + } + BOOST_TEST(i == 100); + return boost::report_errors(); +} +//] + diff --git a/example/n1962/circle.cpp b/example/n1962/circle.cpp new file mode 100644 index 0000000..ee50f2e --- /dev/null +++ b/example/n1962/circle.cpp @@ -0,0 +1,57 @@ + +// 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 + +//[n1962_circle +// File: circle.cpp +#include +#include + +CONTRACT_CLASS( + class (shape) +) { + CONTRACT_CLASS_INVARIANT( void ) // Must always specify class invariants. + + CONTRACT_DESTRUCTOR( + public virtual (~shape) ( void ) + ) {} + + CONTRACT_FUNCTION( + public virtual int (compute_area) ( void ) const + // No base preconditions so all derived preconditions true. + postcondition( auto result = return, result > 0 ) + ) = 0; // Contract for pure virtual function. +}; + +CONTRACT_CLASS( + class (circle) extends( public shape ) // Subcontract from base `shape`. +) { + CONTRACT_CLASS_INVARIANT( void ) // In AND with base class invariants. + + public: int radius() const { return 2; } + + CONTRACT_FUNCTION( // Also using `override` specifier (optional). + public virtual int (compute_area) ( void ) const override + // Eventual preconditions in OR with base function preconditions. + postcondition( // In AND with base function postconditions. + auto result = return, + result == pi * radius() * radius() + ) + ) { + return pi * radius() * radius(); + } + + private: static const int pi = 3; // Truncated from 3.14... +}; + +int main ( void ) +{ + circle c; + BOOST_TEST(c.compute_area() == 12); + return boost::report_errors(); +} +//] + diff --git a/example/n1962/equal.hpp b/example/n1962/equal.hpp new file mode 100644 index 0000000..3472948 --- /dev/null +++ b/example/n1962/equal.hpp @@ -0,0 +1,29 @@ + +// 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 + +//[n1962_equal_header +// File: equal.hpp +#ifndef EQUAL_HPP_ +#define EQUAL_HPP_ + +#include "equal_not.hpp" +#include + +CONTRACT_FUNCTION_TPL( + template( typename T ) + bool operator(==)(equal) ( (T const&) left, (T const&) right ) + postcondition( + auto result = return, + result == !(left != right) + ) +) { + return left.value == right.value; +} + +#endif // #include guard +//] + diff --git a/example/n1962/equal_main.cpp b/example/n1962/equal_main.cpp new file mode 100644 index 0000000..83ed3d9 --- /dev/null +++ b/example/n1962/equal_main.cpp @@ -0,0 +1,26 @@ + +// 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 + +//[n1962_equal_main +// File: equal_main.cpp +#include "equal.hpp" +#include "equal_not.hpp" +#include + +struct number { int value; }; + +int main ( void ) +{ + number n; + n.value = 123; + + BOOST_TEST((n == n) == true); + BOOST_TEST((n != n) == false); + return boost::report_errors(); +} +//] + diff --git a/example/n1962/equal_not.hpp b/example/n1962/equal_not.hpp new file mode 100644 index 0000000..564e645 --- /dev/null +++ b/example/n1962/equal_not.hpp @@ -0,0 +1,29 @@ + +// 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 + +//[n1962_equal_not_header +// File: equal_not.hpp +#ifndef EQUAL_NOT_HPP_ +#define EQUAL_NOT_HPP_ + +#include "equal.hpp" +#include + +CONTRACT_FUNCTION_TPL( + template( typename T ) + bool operator(!=)(not_equal) ( (T const&) left, (T const&) right ) + postcondition( + auto result = return, + result == !(left == right) + ) +) { + return left.value != right.value; +} + +#endif // #include guard +//] + diff --git a/example/n1962/factorial.cpp b/example/n1962/factorial.cpp new file mode 100644 index 0000000..0ba99de --- /dev/null +++ b/example/n1962/factorial.cpp @@ -0,0 +1,56 @@ + +// 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 + +//[n1962_factorial +// File: factorial.cpp +#include +#include + +// Assertion requirements used to model assertion computational complexity. +#define O_1 0 // O(1) constant (default). +#define O_N 1 // O(n) linear. +#define O_NN 2 // O(n * n) quadratic. +#define O_NX 3 // O(n^x) polynomial. +#define O_FACTN 4 // O(n!) factorial. +#define O_EXPN 5 // O(e^n) exponential. +#define O_ALL 10 +#define COMPLEXITY_MAX O_ALL + +CONTRACT_FUNCTION( + int (factorial) ( int n ) + precondition( + n >= 0, // Non-negative natural number. + n <= 12 // Max function input. + ) + postcondition( + auto result = return, + result >= 1, + if(n < 2) ( // Select assertion. + result == 1 + ) else ( + // Assertions automatically disabled within other assertions. + // Therefore, this postcondition can recursively call the + // function without causing infinite recursion. + result == n * factorial(n - 1), + // This assertion introduces significant run-time + // overhead (same as the function body) so assertion + // requirements are used to selectively disable it. + requires O_FACTN <= COMPLEXITY_MAX + ) + ) +) { + if(n < 2) return 1; + else return n * factorial(n - 1); +} + +int main ( void ) +{ + BOOST_TEST(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..05df517 --- /dev/null +++ b/example/n1962/sqrt.cpp @@ -0,0 +1,31 @@ + +// 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 + +//[n1962_sqrt +// File: sqrt.cpp +#include +#include +#include + +CONTRACT_FUNCTION( // Default value for `precision` parameter. + double (mysqrt) ( double x, double precision, default(1e-6) ) + precondition( x >= 0.0 ) + postcondition( + auto root = return, // Result value named `root`. + fabs(root * root - x) <= precision // Equal within precision. + ) +) { + return sqrt(x); +} + +int main ( void ) +{ + BOOST_TEST(fabs(mysqrt(4.0) - 2.0) <= 1e-6); + 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..476ca62 --- /dev/null +++ b/example/n1962/sum.cpp @@ -0,0 +1,18 @@ + +// 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 + +//[n1962_sum +// File: sum.cpp +#include "sum.hpp" + +int CONTRACT_FREE_BODY(sum) ( int count, int* array ) { + int total = 0; + for(int i = 0; i < count; ++i) total += array[i]; + return total; +} +//] + diff --git a/example/n1962/sum.hpp b/example/n1962/sum.hpp new file mode 100644 index 0000000..d0dd36e --- /dev/null +++ b/example/n1962/sum.hpp @@ -0,0 +1,22 @@ + +// 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 + +//[n1962_sum_header +// File: sum.hpp +#ifndef SUM_HPP_ +#define SUM_HPP_ + +#include + +CONTRACT_FUNCTION( + int (sum)( int count, (int*) array ) + precondition( count % 4 == 0 ) +) ; // Separate body definition from function declaration (see ".cpp" file). + +#endif // #include guard +//] + diff --git a/example/n1962/sum_main.cpp b/example/n1962/sum_main.cpp new file mode 100644 index 0000000..6a8ae90 --- /dev/null +++ b/example/n1962/sum_main.cpp @@ -0,0 +1,20 @@ + +// 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 + +//[n1962_sum_main +// File: sum_main.cpp +#include "sum.hpp" +#include + +int main ( void ) +{ + int a[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + BOOST_TEST(sum(8, a) == 8); + return boost::report_errors(); +} +//] + diff --git a/example/n1962/vector.cpp b/example/n1962/vector.cpp new file mode 100644 index 0000000..87b1f76 --- /dev/null +++ b/example/n1962/vector.cpp @@ -0,0 +1,39 @@ + +// 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 + +//[n1962_vector_main +// File: vector.cpp +#include "vector.hpp" +#include + +int main ( void ) +{ + // Run a few of the operations (could test more of them...). + vector v(3); + BOOST_TEST(v.size() == 3); + BOOST_TEST(boost::algorithm::all_of_equal(v, '\0')); + const vector& cv = v; // A reference so no copy. + + vector w(v); + BOOST_TEST(w == v); + + vector::iterator b = v.begin(); + BOOST_TEST(*b == '\0'); + + vector::const_iterator cb = cv.begin(); + BOOST_TEST(*cb == '\0'); + + v.insert(b, 2, 'a'); + BOOST_TEST(v[0] == 'a'); + BOOST_TEST(v[1] == 'a'); + + v.push_back('b'); + BOOST_TEST(v.back() == 'b'); + return boost::report_errors(); +} +//] + diff --git a/example/n1962/vector.hpp b/example/n1962/vector.hpp new file mode 100644 index 0000000..e29b0b4 --- /dev/null +++ b/example/n1962/vector.hpp @@ -0,0 +1,499 @@ + +// 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 + +//[n1962_vector +// File: vector.hpp +#include +#include +#include +#include +#include +#include +#include + +CONTRACT_CLASS( // Vector wrapper with contracts. + template( class T, class Allocator, default std::allocator ) + class (vector) // No base classes so no subcontracting for this example. +) { + CONTRACT_CLASS_INVARIANT_TPL( // At very beginning of the class declaration. + empty() == (size() == 0), + std::distance(begin(), end()) == int(size()), + std::distance(rbegin(), rend()) == int(size()), + size() <= capacity(), + capacity() <= max_size() + ) // No static or volatile class invariants for this example. + + public: typedef typename std::vector::allocator_type + allocator_type; + public: typedef typename std::vector::pointer pointer; + public: typedef typename std::vector::const_pointer + const_pointer; + public: typedef typename std::vector::reference reference; + public: typedef typename std::vector::const_reference + const_reference; + public: typedef typename std::vector::value_type value_type; + public: typedef typename std::vector::iterator iterator; + public: typedef typename std::vector::const_iterator + const_iterator; + public: typedef typename std::vector::size_type size_type; + public: typedef typename std::vector::difference_type + difference_type; + public: typedef typename std::vector::reverse_iterator + reverse_iterator; + public: typedef typename std::vector::const_reverse_iterator + const_reverse_iterator; + + CONTRACT_CONSTRUCTOR_TPL( + public (vector) ( void ) // Always specify access level `public`, etc. + postcondition( not empty() ) + initialize( vector_() ) // Member initializers. + ) {} + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (vector) ( (const Allocator&) allocator ) + postcondition( + empty(), + allocator == get_allocator() + ) + initialize( vector_(allocator) ) + ) {} + + CONTRACT_CONSTRUCTOR_TPL( + public explicit (vector) ( (size_type) count ) + postcondition( + size() == count, + boost::algorithm::all_of_equal(begin(), end(), T()), + requires boost::has_equal_to::value // Requirements. + ) + initialize( vector_(count) ) + ) {} + + CONTRACT_CONSTRUCTOR_TPL( + public (vector) ( (size_type) count, (const T&) value ) + postcondition( + size() == count, + boost::algorithm::all_of_equal(begin(), end(), value), + requires boost::has_equal_to::value + ) + initialize( vector_(count, value) ) + ) {} + + CONTRACT_CONSTRUCTOR_TPL( + public (vector) ( (size_type) count, (const T&) value, + (const Allocator&) allocator ) + postcondition( + size() == count, + boost::algorithm::all_of_equal(begin(), end(), value), + requires boost::has_equal_to::value, + allocator == get_allocator() + ) + initialize( vector_(count, value, allocator) ) + ) {} + + CONTRACT_CONSTRUCTOR_TPL( // Contract with concepts. + public template( class Iterator ) + requires( boost::InputIterator ) + (vector) ( (Iterator) first, (Iterator) last ) + postcondition( std::distance(first, last) == int(size()) ) + initialize( vector_(first, last) ) + ) {} + + CONTRACT_CONSTRUCTOR_TPL( + public template( class Iterator ) + requires( boost::InputIterator ) + (vector) ( (Iterator) first, (Iterator) last, + (const Allocator&) allocator ) + postcondition( + std::distance(first, last) == int(size()), + allocator == get_allocator() + ) + initialize( vector_(first, last, allocator) ) + ) {} + + CONTRACT_CONSTRUCTOR_TPL( + public (vector) ( (const vector&) right ) + postcondition( + right == *this, requires boost::has_equal_to::value + ) + initialize( vector_(right.vector_) ) + ) {} + + CONTRACT_FUNCTION_TPL( // Operator symbol and (arbitrary) name `copy`. + public (vector&) operator(=)(copy) ( (const vector&) right ) + postcondition( + auto result = return, // Return value. + result == *this, requires boost::has_equal_to::value, + result == right, requires boost::has_equal_to::value + ) + ) { + return vector_ = right.vector_; + } + + CONTRACT_DESTRUCTOR_TPL( // Destruct contract (check class invariant). + public virtual (~vector) ( void ) + ) {} + + CONTRACT_FUNCTION_TPL( + // Wrapping parenthesis optional for keyword types `void`, `bool`, etc. + public void (reserve) ( (size_type) count ) + precondition( count < max_size() ) + postcondition( capacity() >= count ) + ) { + vector_.reserve(count); + } + + CONTRACT_FUNCTION_TPL( + public (size_type) (capacity) ( void ) const // Constant member. + postcondition( auto result = return, result >= size() ) + ) { + return vector_.capacity(); + } + + CONTRACT_FUNCTION_TPL( + public (iterator) (begin) ( void ) + postcondition( + auto result = return, + if(empty()) ( // Select assertions `if(...) ( ...)`. + result == end() + ) // Omitted optional `else( ... )`. + ) + ) { + return vector_.begin(); + } + + CONTRACT_FUNCTION_TPL( // Contract overloaded function (see above). + public (const_iterator) (begin) ( void ) const + postcondition( + auto result = return, + if(empty()) ( result == end() ) + ) + ) { + return vector_.begin(); + } + + CONTRACT_FUNCTION_TPL( // Contract with no pre/post checks class invariants. + public (iterator) (end) ( void ) + ) { + return vector_.end(); + } + + CONTRACT_FUNCTION_TPL( + public (const_iterator) (end) ( void ) const + ) { + return vector_.end(); + } + + CONTRACT_FUNCTION_TPL( + public (reverse_iterator) (rbegin) ( void ) + postcondition( + auto result = return, + if(empty()) ( result == rend() ) + ) + ) { + return vector_.rbegin(); + } + + CONTRACT_FUNCTION_TPL( + public (const_reverse_iterator) (rbegin) ( void ) const + postcondition( + auto result = return, + if(empty()) ( result == rend() ) + ) + ) { + return vector_.rbegin(); + } + + CONTRACT_FUNCTION_TPL( + public (reverse_iterator) (rend) ( void ) + ) { + return vector_.rend(); + } + + CONTRACT_FUNCTION_TPL( + public (const_reverse_iterator) (rend) ( void ) const + ) { + return vector_.rend(); + } + + CONTRACT_FUNCTION_TPL( + public void (resize) ( (size_type) count ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), // Old value (at entry). + size() == count, + if(count > old_size) ( + boost::algorithm::all_of_equal(begin() + old_size, end(), + T()), requires boost::has_equal_to::value + ) + ) + ) { + vector_.resize(count); + } + + CONTRACT_FUNCTION_TPL( + public void (resize) ( (size_type) count, (T) value ) + postcondition( + (size_type) old_size = CONTRACT_OLDOF size(), // With old type. + size() == count, + count > old_size ? // Ternary operator. + boost::algorithm::all_of_equal(begin() + old_size, end(), + value) + : + true + , requires boost::has_equal_to::value + ) + ) { + vector_.resize(count, value); + } + + CONTRACT_FUNCTION_TPL( + public (size_type) (size) ( void ) const + postcondition( auto result = return, result <= capacity() ) + ) { + return vector_.size(); + } + + CONTRACT_FUNCTION_TPL( + public (size_type) (max_size) ( void ) const + postcondition( auto result = return, result >= capacity() ) + ) { + return vector_.max_size(); + } + + CONTRACT_FUNCTION_TPL( + public bool (empty) ( void ) const + postcondition( + auto result = return, + result == (size() == 0) + ) + ) { + return vector_.empty(); + } + + CONTRACT_FUNCTION_TPL( + public (Allocator) (get_allocator) ( void ) const + ) { + return vector_.get_allocator(); + } + + CONTRACT_FUNCTION_TPL( + public (reference) (at) ( (size_type) index ) + precondition( index < size() ) + ) { + return vector_.at(index); + } + + CONTRACT_FUNCTION_TPL( + public (const_reference) (at) ( (size_type) index ) const + precondition( index < size() ) + ) { + return vector_.at(index); + } + + CONTRACT_FUNCTION_TPL( + public (reference) operator([])(at) ( (size_type) index ) + precondition( index < size() ) + ) { + return vector_[index]; + } + + CONTRACT_FUNCTION_TPL( + public (const_reference) operator([])(at) ( (size_type) index ) const + precondition( index < size() ) + ) { + return vector_[index]; + } + + CONTRACT_FUNCTION_TPL( + public (reference) (front) ( void ) + precondition( not empty() ) // `not` instead of symbol `!`. + ) { + return vector_.front(); + } + + CONTRACT_FUNCTION_TPL( + public (const_reference) (front) ( void ) const + precondition( bool(!empty()) ) // Or, `bool` to wrap symbol `!`. + ) { + return vector_.front(); + } + + CONTRACT_FUNCTION_TPL( + public (reference) (back) ( void ) + precondition( not empty() ) + ) { + return vector_.back(); + } + + CONTRACT_FUNCTION_TPL( + public (const_reference) (back) ( void ) const + precondition( not empty() ) + ) { + return vector_.back(); + } + + CONTRACT_FUNCTION_TPL( + public void (push_back) ( (const T&) value ) + precondition( size() < max_size() ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + auto old_capacity = CONTRACT_OLDOF capacity(), + back() == value, requires boost::has_equal_to::value, + size() == old_size + 1, + capacity() >= old_capacity + ) + ) { + vector_.push_back(value); + } + + CONTRACT_FUNCTION_TPL( + public void (pop_back) ( void ) + precondition( not empty() ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + size() == old_size - 1 + ) + ) { + vector_.pop_back(); + } + + CONTRACT_FUNCTION_TPL( + public template( class Iterator ) + requires( boost::InputIterator ) + void (assign) ( (Iterator) first, (Iterator) last ) + // precondition: [begin(), end()) does not contain [first, last) + postcondition( std::distance(first, last) == int(size()) ) + ) { + vector_.assign(first, last); + } + + CONTRACT_FUNCTION_TPL( + public void (assign) ( (size_type) count, (const T&) value ) + precondition( count <= max_size() ) + postcondition( + boost::algorithm::all_of_equal(begin(), end(), value), + requires boost::has_equal_to::value + ) + ) { + vector_.assign(count, value); + } + + CONTRACT_FUNCTION_TPL( + public (iterator) (insert) ( (iterator) where, (const T&) value ) + precondition( size() < max_size() ) + postcondition( + auto result = return, + auto old_size = CONTRACT_OLDOF size(), + value == *result, requires boost::has_equal_to::value, + size() == old_size + 1 + // if(capacity() > oldof capacity()) + // [begin(), end()) is invalid + // else + // [where, end()) is invalid + ) + ) { + return vector_.insert(where, value); + } + + CONTRACT_FUNCTION_TPL( + public void (insert) ( (iterator) where, (size_type) count, + (const T&) value ) + precondition( size() + count < max_size() ) + postcondition( + using boost::prior, + auto old_size = CONTRACT_OLDOF size(), + auto old_capacity = CONTRACT_OLDOF capacity(), + auto old_where = CONTRACT_OLDOF where, + size() == old_size + count, + capacity() >= old_capacity, + if(capacity() == old_capacity) ( + boost::algorithm::all_of_equal(prior(old_where), + prior(old_where) + count, value), + requires boost::has_equal_to::value + // [where, end()) is invalid + ) // else [begin(), end()) is invalid + ) + ) { + vector_.insert(where, count, value); + } + + CONTRACT_FUNCTION_TPL( + public template( class Iterator ) + requires( boost::InputIterator ) + void (insert) ( (iterator) where, (Iterator) first, (Iterator) last ) + precondition( + // [first, last) is not contained in [begin(), end()) + size() + std::distance(first, last) < max_size() + ) + postcondition( + auto old_size = CONTRACT_OLDOF size(), + auto old_capacity = CONTRACT_OLDOF capacity(), + size() == old_size + std::distance(first, last), + capacity() >= old_capacity + ) + ) { + vector_.insert(where, first, last); + } + + CONTRACT_FUNCTION_TPL( + public (iterator) (erase) ( (iterator) where ) + precondition( + not empty(), + where != end() + ) + postcondition( + auto result = return, + auto old_size = CONTRACT_OLDOF size(), + size() == old_size - 1, + if(empty()) ( result == end() ) + // [where, end()) is invalid + ) + ) { + return vector_.erase(where); + } + + CONTRACT_FUNCTION_TPL( + public (iterator) (erase) ( (iterator) first, (iterator) last ) + precondition( size() >= std::distance(first, last) ) + postcondition( + auto result = return, + auto old_size = CONTRACT_OLDOF size(), + size() == old_size - std::distance(first, last), + if(empty()) ( result == end() ) + // [first, last) is invalid + ) + ) { + return vector_.erase(first, last); + } + + CONTRACT_FUNCTION_TPL( + public void (clear) ( void ) + postcondition( empty() ) + ) { + vector_.clear(); + } + + CONTRACT_FUNCTION_TPL( + public void (swap) ( (vector&) right ) + postcondition( + auto old_self = CONTRACT_OLDOF *this, + auto old_right = CONTRACT_OLDOF right, + right == old_self, requires boost::has_equal_to::value, + old_right == *this, requires boost::has_equal_to::value + ) + ) { + vector_.swap(right); + } + + friend bool operator== ( vector const& left, vector const& right ) + { + return left.vector_ == right.vector_; + } + + private: std::vector vector_; +}; +//] + diff --git a/example/n1962/vector_npaper.hpp b/example/n1962/vector_npaper.hpp new file mode 100644 index 0000000..287df85 --- /dev/null +++ b/example/n1962/vector_npaper.hpp @@ -0,0 +1,499 @@ + +// 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 + +//[n1962_vector_npaper +// File: vector_npaper.cpp +// Extra spaces, newlines, etc used to align text with this library code. + +#include +#include +#include +#include +#include + + +template< class T, class Allocator = std::allocator > +class vector +{ + invariant { + empty() == (size() == 0); + std::distance(begin(), end()) == int(size()); + std::distance(rbegin(), rend()) == int(size()); + size() <= capacity(); + capacity() <= max_size(); + } + + public: typedef typename std::vector::allocator_type + allocator_type; + public: typedef typename std::vector::pointer pointer; + public: typedef typename std::vector::const_pointer + const_pointer; + public: typedef typename std::vector::reference reference; + public: typedef typename std::vector::const_reference + const_reference; + public: typedef typename std::vector::value_type value_type; + public: typedef typename std::vector::iterator iterator; + public: typedef typename std::vector::const_iterator + const_iterator; + public: typedef typename std::vector::size_type size_type; + public: typedef typename std::vector::difference_type + difference_type; + public: typedef typename std::vector::reverse_iterator + reverse_iterator; + public: typedef typename std::vector::const_reverse_iterator + const_reverse_iterator; + + + public: vector ( void ) + postcondition { not empty(); } + : vector_() + {} + + + public: explicit vector ( const Allocator& alllocator ) + postcondition { + empty(); + allocator == get_allocator(); + } + : vector_(allocator) + {} + + + public: explicit vector ( size_type count ) + postcondition { + size() == count; + boost::algorithm::all_of_equal(begin(), end(), T()); + // Assertion requirements not supported by [N1962]. + } + : vector_(count) + {} + + + public: vector ( size_type count, const T& value ) + postcondition { + size() == count; + boost::algorithm::all_of_equal(begin(), end(), value); + + } + : vector_(count, value) + {} + + + public: vector ( size_type count, const T& value, + const Allocator& allocator ) + postcondition { + size() == count; + boost::algorithm::all_of_equal(begin(), end(), value); + + allocator == get_allocator(); + } + : vector_(count, value, allocator) + {} + + + public: template< class Iterator > + requires std::InputIterator + vector ( Iterator first, Iterator last ) + postcondition { std::distance(first, last) == int(size()); } + : vector_(first, last) + {} + + + public: template< class Iterator > + requires std::InputIterator + vector ( Iterator first, Iterator last, + const Allocator& allocator ) + postcondition { + std::distance(first, last) == int(size()); + allocator == get_allocator(); + } + : vector_(first, last, allocator) + {} + + + public: vector ( const vector& right ) + postcondition { + right == *this; + } + : vector_(right.vector_) + {} + + + public: vector& operator= ( const vector& right ) + postcondition(result) { + + right == *this; + result == *this; + } + { + return vect_ = right.vect_; + } + + + public: virtual ~vector ( void ) + {} + + + + public: void reserve ( size_type count ) + precondition { count < max_size(); } + postcondition { capacity() >= count; } + { + vector_.reserve(count); + } + + + public: size_type capacity ( void ) const + postcondition(result) { result >= size(); } + { + return vector_.capacity(); + } + + + public: iterator begin ( void ) + postcondition { + + if(empty()) { + result == end(); + } + } + { + return vector_.begin(); + } + + + public: const_iterator begin ( void ) const + postcondition(result) { + + if(empty()) { result == end(); } + } + { + return vector_.begin(); + } + + + public: iterator end ( void ) + { + return vector_.end(); + } + + + public: const_iterator end ( void ) const + { + return vector_.end(); + } + + + public: reverse_iterator rbegin ( void ) + postcondition(result) { + + if(empty()) { result == rend(); } + } + { + return vector_.rbegin(); + } + + + public: const_reverse_iterator rbegin ( void ) const + postcondition(result) { + + if(empty()) { result == rend(); } + } + { + return vector_.rbegin(); + } + + + public: reverse_iterator rend ( void ) + { + return vector_.rend(); + } + + + public: const_reverse_iterator rend ( void ) const + { + return vector_.rend(); + } + + + public: void resize ( size_type count ) + postcondition { + + size() == count; + if(count > oldof size()) { + boost::algorithm::all_of_equal(begin() + oldof size(), end(), + T()); + } + } + { + vectcor_.resize(count); + } + + + public: void resize ( size_type count, T value ) + postcondition { + + size() == count; + count > oldof size() ? + boost::algorithm::all_of_equal(begin() + oldof size(), end(), + value) + : + true + ; + } + { + vector_.resize(count, value); + } + + + public: size_type size ( void ) const + postcondition(result) { result <= capacity(); } + { + return vector_.size(); + } + + + public: size_type max_size ( void ) const + postcondition(result) { result >= capacity(); } + { + return vector_.max_size(); + } + + + public: bool empty ( void ) const + postcondition(result) { + + result == (size() == 0); + } + { + return vector_.empty(); + } + + + public: Alloctor get_allocator ( void ) const + { + return vector_.get_allocator(); + } + + + public: reference at ( size_type index ) + precondition { index < size(); } + { + return vectcor_.at(index); + } + + + public: const_reference at ( size_type index ) const + precondition { index < size(); } + { + return vector_.at(index); + } + + + public: reference operator[] ( size_type index ) + precondition { index < size(); } + { + return vector_[index]; + } + + + public: const_reference operator[] ( size_type index ) const + precondition { index < size(); } + { + return vectcor_[index]; + } + + + public: reference front ( void ) + precondition { not empty(); } + { + return vectcor_.front(); + } + + + public: const_reference front ( void ) const + precondition { bool(!empty()); } + { + return vector_.front(); + } + + + public: reference back ( void ) + precondition { not empty(); } + { + return vector_.back(); + } + + + public: const_reference back ( void ) const + precondition { not empty(); } + { + return vector_.back(); + } + + + public void push_back ( const T& value ) + precondition { size() < max_size() } + postcondition { + + + static if(boost::has_equal_to::value) { back() == value; } + size() == oldof size() + 1; + capacity() >= oldof capacity() + } + { + vector_.push_back(value); + } + + + public: void pop_back ( void ) + precondition { not empty(); } + postcondition { + + size() == oldof size() - 1; + } + { + vector_.pop_back(); + } + + + public: template< class Iterator > + requires std::InputIterator + void assign ( Iterator first, Iterator last ) + // precondition: [begin(), end()) does not contain [first, last) + postcondition { std::distance(first, last) == int(size()); } + { + vector_.assign(first, last); + } + + + public: void assign ( size_type count, const T& vallue ) + precondition { count <= max_size(); } + postcondition { + boost::algorithm::all_of_equal(begin(), end(), value); + + } + { + vector_.assign(count, value); + } + + + public: iterator insert ( iterator where, const T& value ) + precondition { size() < max_size(); } + postcondition(result) { + + + value == *result; + size() == oldof size() + 1; + // if(capacity() > oldof capacity()) + // [begin(), end()) is invalid + // else + // [where, end()) is invalid + } + { + return vector_.insert(where, value); + } + + + public: void insert ( iterator where, size_type count, + const T& value ) + precondition { size() + count < max_size(); } + postcondition { + + + + + size() == oldof size() + count; + capacity() >= oldof capacity(); + if(capacity() == oldof capacity()) { + boost::algorithm::all_of_equal(boost::prior(oldof where), + boost::prior(oldof where) + count, value); + + // [where, end()) is invalid + } // else [begin(), end()) is invalid + } + { + vector_.insert(where, count, value); + } + + + public: template< class Iterator > + requires std::InputIterator + void insert ( iterator where, Iterator first, Iterator last ) + precondition { + // [first, last) is not contained in [begin(), end()) + size() + std::distance(first, last) < max_size(); + } + postcondition { + + + size() == oldof size() + std::distance(first, last); + capacity() >= oldof capacity(); + } + { + vector_.insert(where, first, last); + } + + + public: iterator erase ( iterator where ) + precondition { + not empty(); + where != end(); + } + postcondition(result) { + + + size() == oldod size() - 1; + if(empty()) { result == end(); } + // [where, end()) is invalid + } + { + return vector_.erase(where); + } + + + public: iterator erase ( iterator first, iterator last ) + precondition { size() >= std::distance(first, lasst); } + postcondition(result) { + + + size() == oldof size() - std::distance(first, last); + if(empty()) { result == end(); } + // [first, last) is invalid + } + { + return vector_.erase(first, last); + } + + + public: void clear ( void ) + postcondition( empty() ) + { + vector_.clear(); + } + + + public: void swap ( vector& right ) + postcondition { + + + right == oldof *this; + oldof right == *this; + } + { + vector_.swap(right); + } + + friend bool operator== ( vector const& left, vector const& right ) + { + return left.vector_ == right.vector_; + } + + private: std::vector vector_; +}; +//] + diff --git a/example/n2081/add.cpp b/example/n2081/add.cpp new file mode 100644 index 0000000..0be71cf --- /dev/null +++ b/example/n2081/add.cpp @@ -0,0 +1,20 @@ + +// 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 + +//[n2081_add +// File: add.cpp +#include "add.hpp" +#include + +int main ( void ) +{ + int x = 10, y = 20; + BOOST_TEST(add(x, y) == 30); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/add.hpp b/example/n2081/add.hpp new file mode 100644 index 0000000..f994eaf --- /dev/null +++ b/example/n2081/add.hpp @@ -0,0 +1,45 @@ + +// 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 + +//[n2081_add_header +// File: add.hpp +#ifndef ADD_HPP +#define ADD_HPP + +#include +#include +#include + +template< typename T > +struct Addable // User-defined concept. +{ + BOOST_CONCEPT_USAGE(Addable) + { + return_type(x + y); // Check addition `T operator+(T x, T y)`. + } + +private: + void return_type ( T const& ) {} // Used to check addition returns type `T`. + + T const& x; + T const& y; +}; + +CONTRACT_FUNCTION( + template( typename T ) requires( Addable ) + (T) (add) ( (T const&) x, (T const&) y ) + postcondition( + auto result = return, + result == x + y, requires boost::has_equal_to::value + ) +) { + return x + y; +} + +#endif // #include guard +//] + diff --git a/example/n2081/add_error.cpp b/example/n2081/add_error.cpp new file mode 100644 index 0000000..02953e9 --- /dev/null +++ b/example/n2081/add_error.cpp @@ -0,0 +1,25 @@ + +// 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 + +//[n2081_add_error +// File: add_error.cpp +#include "add.hpp" + +struct num +{ + int value; + num ( int v = 0 ) : value(v) {}; +}; + +int main ( void ) +{ + num n(10), m(20); + add(n, m); // Error: Correctly fails `add` concept requirements. + return 0; +} +//] + diff --git a/example/n2081/advance.cpp b/example/n2081/advance.cpp new file mode 100644 index 0000000..628085c --- /dev/null +++ b/example/n2081/advance.cpp @@ -0,0 +1,98 @@ + +// 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 + +//[n2081_advance +// File: advance.cpp +#include +#include +#include +#include +#include +#include + +namespace aux { // Tag dispatch helpers (in a private namespace). + +template< typename InputIterator, typename Distance > +void myadvance_dispatch ( InputIterator& i, Distance n, + std::input_iterator_tag ) +{ + CONTRACT_LOOP( while(n--) ) { + CONTRACT_LOOP_VARIANT_TPL( const( n ) n ) + ++i; + } +} + +template< typename BidirectionalIterator, typename Distance > +void myadvance_dispatch ( BidirectionalIterator& i, Distance n, + std::bidirectional_iterator_tag ) +{ + if(n >= 0) { + CONTRACT_LOOP( while(n--) ) { + CONTRACT_LOOP_VARIANT_TPL( const( n ) n ) + ++i; + } + } else { +#ifndef CONTRACT_CONFIG_NO_LOOP_VARIANTS + // Avoid unused variable warning when loop invariants are disabled. + Distance n_max = n; +#endif + CONTRACT_LOOP( while(n++) ) { + CONTRACT_LOOP_VARIANT_TPL( const( n_max, n ) n_max - n ) + --i; + } + } +} + +template< typename RandomAccessIterator, typename Distance > +void myadvance_dispatch ( RandomAccessIterator& i, Distance n, + std::random_access_iterator_tag ) +{ + i += n; +} + +} // namespace aux + +// Contract helper meta-function. +template< typename T > struct is_input_iterator : boost::mpl::false_ {}; +template< > struct is_input_iterator : + boost::mpl::true_ {}; + +CONTRACT_FUNCTION( + template( typename InputIterator, typename Distance ) + void (myadvance) ( (InputIterator&) i, (Distance) n ) + precondition( + // range [i, i + n] is non-singular. + if(is_input_iterator:: + iterator_category>::value) ( + n > 0 // if input iterator, n positive + ) + ) + postcondition( + auto old_i = CONTRACT_OLDOF i, + std::distance(old_i, i) == n // iterator advanced of n + ) +) { + aux::myadvance_dispatch(i, n, typename + std::iterator_traits:: iterator_category()); +} + +int main ( void ) +{ + std::vector v(10); + v[2] = 123; v[3] = -123; + std::vector::iterator r = v.begin(); // Random iterator. + myadvance(r, 3); + BOOST_TEST(*r == -123); + + std::list l(v.begin(), v.end()); + std::list::iterator b = l.begin(); // Bidirectional and not random. + myadvance(b, 2); + BOOST_TEST(*b == 123); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/apply.cpp b/example/n2081/apply.cpp new file mode 100644 index 0000000..9934c58 --- /dev/null +++ b/example/n2081/apply.cpp @@ -0,0 +1,70 @@ + +// 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 + +//[n2081_apply +// File: apply.cpp +#include +#include +#include +#include + +// Use assertion requirements to model assertion computational complexity. +#define O_1 0 // constant computational complexity O(1) +#define O_BODY 10 // same computation complexity of the body +#define COMPLEXITY_MAX O_1 // only check assertions with complexity within O(1) + +CONTRACT_FUNCTION( // Invoke unary functors. + template( typename Result, typename Argument0, typename Function ) + requires( (boost::UnaryFunction) ) + (Result) (apply) ( (Function) function, (Argument0) argument0, + (Result&) result ) + postcondition( + auto return_value = return, + result == function(argument0), + requires O_BODY <= COMPLEXITY_MAX && + boost::has_equal_to::value, + return_value == result, + requires boost::has_equal_to::value + ) +) { + return result = function(argument0); +} + +CONTRACT_FUNCTION( // Overload to invoke binary functors. + template( typename Result, typename Argument0, typename Argument1, + typename Function ) + requires( (boost::BinaryFunction) ) + (Result) (apply) ( (Function) function, (Argument0) argument0, + (Argument1) argument1, (Result&) result ) + postcondition( + auto return_value = return, + result == function(argument0, argument1), + requires O_BODY <= COMPLEXITY_MAX && + boost::has_equal_to::value, + return_value == result, + requires boost::has_equal_to::value + ) +) { + return result = function(argument0, argument1); +} + +int complement ( int x ) { return -x; } +int add ( int x, int y ) { return x + y; } + +int main ( void ) +{ + int r = 0; + apply(complement, 1, r); + BOOST_TEST(r == -1); + + apply(add, 1, 2, r); + BOOST_TEST(r == 3); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/convert.cpp b/example/n2081/convert.cpp new file mode 100644 index 0000000..33bb7b1 --- /dev/null +++ b/example/n2081/convert.cpp @@ -0,0 +1,19 @@ + +// 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 + +//[n2081_convert +// File: convert.cpp +#include "convert.hpp" +#include + +int main ( void ) +{ + BOOST_TEST(convert('\0') == 0); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/convert.hpp b/example/n2081/convert.hpp new file mode 100644 index 0000000..d55a31a --- /dev/null +++ b/example/n2081/convert.hpp @@ -0,0 +1,26 @@ + +// 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 + +//[n2081_convert_header +// File: convert.hpp +#ifndef CONVERT_HPP_ +#define CONVERT_HPP_ + +#include +#include + +CONTRACT_FUNCTION( + template( typename To, typename From ) + requires( (boost::Convertible) ) + (To) (convert) ( (From const&) from ) +) { + return from; +} + +#endif // #include guard +//] + diff --git a/example/n2081/convert_error.cpp b/example/n2081/convert_error.cpp new file mode 100644 index 0000000..9e581d2 --- /dev/null +++ b/example/n2081/convert_error.cpp @@ -0,0 +1,18 @@ + +// 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 + +//[n2081_convert_error +// File: convert_error.cpp +#include "convert.hpp" + +int main ( void ) +{ + convert(10); // Error: Correctly cannot convert type. + return 0; +} +//] + diff --git a/example/n2081/count.cpp b/example/n2081/count.cpp new file mode 100644 index 0000000..7db1c4e --- /dev/null +++ b/example/n2081/count.cpp @@ -0,0 +1,48 @@ + +// 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 + +//[n2081_count +// File: count.cpp +#include +#include +#include +#include + +CONTRACT_FUNCTION( + template( typename Iterator ) + requires( + boost::InputIterator, + boost::EqualityComparable, + boost::EqualityComparable< + typename boost::InputIterator::value_type> + ) + (typename boost::InputIterator::difference_type) (mycount) ( + (Iterator) first, (Iterator) last, + (typename boost::InputIterator::value_type const&) value ) + // precondition: range [first, last) is valid + postcondition( auto result = return, result >= 0 ) +) { + typename boost::InputIterator::difference_type result = 0; + CONTRACT_LOOP( while(first != last) ) { // OK: Iterator has `==`. + CONTRACT_LOOP_VARIANT_TPL( + const( first, last ) std::distance(first, last) ) + if(*first == value) // OK: Value is equality comparable. + ++result; + ++first; // OK: Iterator is input iterator. + } + return result; // OK: Input iterator difference is copy constructible. +} + +int main ( void ) +{ + std::vector v(3); + v[0] = -1; v[1] = 0; v[2] = -1; + BOOST_TEST(mycount(v.begin(), v.end(), -1) == 2); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/deref.cpp b/example/n2081/deref.cpp new file mode 100644 index 0000000..5f24d2b --- /dev/null +++ b/example/n2081/deref.cpp @@ -0,0 +1,43 @@ + +// 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 + +//[n2081_deref +// File: deref.cpp +#include +#include +#include +#include +#include + +CONTRACT_FUNCTION( + template( typename Iterator ) + requires( + boost::InputIterator, + boost::CopyConstructible< + typename boost::InputIterator::value_type> + ) + (typename boost::InputIterator::value_type) (deref) ( + (Iterator) iterator ) + // precondition: iterator is non-singular + postcondition( + auto result = return, + result == *iterator, requires boost::has_equal_to< + typename boost::InputIterator::value_type>::value + ) +) { + return *iterator; +} + +int main ( void ) +{ + std::vector v(1); + v[0] = 123; + BOOST_TEST(deref(v.begin()) == 123); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/equal.cpp b/example/n2081/equal.cpp new file mode 100644 index 0000000..9b10312 --- /dev/null +++ b/example/n2081/equal.cpp @@ -0,0 +1,20 @@ + +// 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 + +//[n2081_equal +// File: equal.cpp +#include "equal.hpp" +#include + +int main ( void) +{ + BOOST_TEST(equal(1, 1) == true); + BOOST_TEST(equal(1, 2) == false); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/equal.hpp b/example/n2081/equal.hpp new file mode 100644 index 0000000..68066e4 --- /dev/null +++ b/example/n2081/equal.hpp @@ -0,0 +1,27 @@ + +// 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 + +//[n2081_equal_header +// File: equal.hpp +#ifndef EQUAL_HPP_ +#define EQUAL_HPP_ + +#include +#include + +CONTRACT_FUNCTION( + template( typename T ) + requires( boost::EqualityComparable ) + bool (equal) ( (T const&) left, (T const&) right ) + postcondition( auto result = return, result == (left == right) ) +) { + return left == right; +} + +#endif // #include guard +//] + diff --git a/example/n2081/equal_error.cpp b/example/n2081/equal_error.cpp new file mode 100644 index 0000000..15ecc2e --- /dev/null +++ b/example/n2081/equal_error.cpp @@ -0,0 +1,24 @@ + +// 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 + +//[n2081_equal_error +// File: equal_error.cpp +#include "equal.hpp" + +struct num +{ + int value; + explicit num ( int v = 0 ) : value(v) {} +}; + +int main ( void ) +{ + equal(num(1), num(1)); // Compiler error. + return 0; +} +//] + diff --git a/example/n2081/find.cpp b/example/n2081/find.cpp new file mode 100644 index 0000000..110201d --- /dev/null +++ b/example/n2081/find.cpp @@ -0,0 +1,22 @@ + +// 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 + +//[n2081_find +// File: find.cpp +#include "find.hpp" +#include +#include + +int main ( void ) +{ + std::vector ints(3); + ints[0] = 1; ints[1] = 2; ints[2] = 3; + BOOST_TEST(*myfind(ints.begin(), ints.end(), 2) == 2); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/find.hpp b/example/n2081/find.hpp new file mode 100644 index 0000000..a805367 --- /dev/null +++ b/example/n2081/find.hpp @@ -0,0 +1,43 @@ + +// 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 + +//[n2081_find_header +// File: find.hpp +#ifndef FIND_HPP_ +#define FIND_HPP_ + +#include +#include + +CONTRACT_FUNCTION( + template( typename Iterator ) + requires( + boost::InputIterator, + boost::EqualityComparable< // Equality needed to find value. + typename boost::InputIterator::value_type> + ) + (Iterator) (myfind) ( (Iterator) first, (Iterator) last, + (typename boost::InputIterator::value_type const&) value ) + // precondition: range [first, last) is valid + postcondition( + auto result = return, + if(result != last) ( + value == *result // if result not last, value found + ) + ) +) { + CONTRACT_LOOP( while(first != last && *first != value) ) { + CONTRACT_LOOP_VARIANT_TPL( + const( first, last ) std::distance(first, last) ) + ++first; + } + return first; +} + +#endif // #include guard +//] + diff --git a/example/n2081/find_error.cpp b/example/n2081/find_error.cpp new file mode 100644 index 0000000..93f8bbb --- /dev/null +++ b/example/n2081/find_error.cpp @@ -0,0 +1,28 @@ + +// 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 + +//[n2081_find_error +// File: find_error.cpp +#include "find.hpp" +#include + +struct num +{ + int value; + explicit num ( int v = 0 ) : value(v) {} +}; + +int main ( void ) +{ + std::vector nums(3); + nums[0] = num(1); nums[1] = num(2); nums[2] = num(3); + // Error: Correctly, num does not meet concept requirements. + myfind(nums.begin(), nums.end(), num(2)); + return 0; +} +//] + diff --git a/example/n2081/for_each.cpp b/example/n2081/for_each.cpp new file mode 100644 index 0000000..9dfd5a4 --- /dev/null +++ b/example/n2081/for_each.cpp @@ -0,0 +1,52 @@ + +// 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 + +//[n2081_for_each +// File: for_each.cpp +#include +#include +#include +#include +#include + +CONTRACT_FUNCTION( + template( typename Iterator, typename Function ) + requires( + boost::InputIterator, + (boost::UnaryFunction::value_type>) + ) + (Function) (my_for_each) ( (Iterator) first, (Iterator) last, + (Function) function ) + // precondition: range [first, last) is valid + postcondition( + auto result = return, + result == function, requires boost::has_equal_to::value + ) +) { + CONTRACT_LOOP( while(first < last) ) { // OK: Iterator is InputIterator. + CONTRACT_LOOP_VARIANT_TPL( + const( first, last ) std::distance(first, last) ) + function(*first); // OK: Function is UnaryFunction. + ++first; // OK: Iterator is InputIterator. + } + return function; +} + +int total = 0; +void add ( int i ) { total += i; } + +int main ( void ) +{ + std::vector v(3); + v[0] = 1; v[1] = 2; v[2] = 3; + my_for_each(v.begin(), v.end(), add); + BOOST_TEST(total == 6); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/less_eq.cpp b/example/n2081/less_eq.cpp new file mode 100644 index 0000000..5bd31d9 --- /dev/null +++ b/example/n2081/less_eq.cpp @@ -0,0 +1,36 @@ + +// 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 + +//[n2081_less_eq +// File: less_eq.cpp +#include +#include +#include + +CONTRACT_FUNCTION( + template( typename T ) + requires( + boost::EqualityComparable, + boost::LessThanComparable + ) + bool (less_eq) ( (T) left, (T) right ) + postcondition( + auto result = return, + result == (left < right || left == right) + ) +) { + return left < right || left == right; +} + +int main ( void ) +{ + BOOST_TEST(less_eq(1, 2) == true); + BOOST_TEST(less_eq(2, 1) == false); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/min.cpp b/example/n2081/min.cpp new file mode 100644 index 0000000..417cea9 --- /dev/null +++ b/example/n2081/min.cpp @@ -0,0 +1,20 @@ + +// 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 + +//[n2081_min +// File: min.cpp +#include "min.hpp" +#include + +int main ( void ) +{ + BOOST_TEST(min(1, 2) == 1); + BOOST_TEST(min(-1, -2) == -2); + return boost::report_errors(); +} +//] + diff --git a/example/n2081/min.hpp b/example/n2081/min.hpp new file mode 100644 index 0000000..7f1e675 --- /dev/null +++ b/example/n2081/min.hpp @@ -0,0 +1,31 @@ + +// 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 + +//[n2081_min_header +// File: min.hpp +#ifndef MIN_HPP_ +#define MIN_HPP_ + +#include +#include +#include + +CONTRACT_FUNCTION( + template( typename T ) requires( boost::LessThanComparable ) + (T const&) (min) ( (T const&) x, (T const&) y ) + postcondition( + auto result = return, + x < y ? result == x : result == y, + requires boost::has_equal_to::value + ) +) { + return x < y ? x : y; // OK: T is less than comparable `<`. +} + +#endif // #include guard +//] + diff --git a/example/n2081/min_error.cpp b/example/n2081/min_error.cpp new file mode 100644 index 0000000..8fe73f2 --- /dev/null +++ b/example/n2081/min_error.cpp @@ -0,0 +1,24 @@ + +// 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 + +//[n2081_min_error +// File: min_error.cpp +#include "min.hpp" + +struct num +{ + int value; + explicit num ( int v = 0 ) : value(v) {} +}; + +int main ( void ) +{ + min(num(1), num(2)); // Compiler error: Fail concept requirements. + return 0; +} +//] + diff --git a/example/n2081/transform.cpp b/example/n2081/transform.cpp new file mode 100644 index 0000000..f2be053 --- /dev/null +++ b/example/n2081/transform.cpp @@ -0,0 +1,68 @@ + +// 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 + +//[n2081_transform +// File: transform.cpp + +#define CONTRACT_CONFIG_FUNCTION_ARITY_MAX 5 // Support for 5 parameters. +#include + +#include +#include +#include +#include +#include + +CONTRACT_FUNCTION( + template( + typename Iterator1, + typename Iterator2, + typename ResultIterator, + typename Function + ) + requires( + boost::InputIterator, + boost::InputIterator, + (boost::OutputIterator::value_type>), + (boost::BinaryFunction::value_type, + typename boost::InputIterator::value_type, + typename boost::InputIterator::value_type>) + ) + (ResultIterator) (mytransform) ( + (Iterator1) first1, + (Iterator1) last1, + (Iterator2) first2, + (ResultIterator) result, + (Function) function + ) + // precondition: [first1, last1) is valid + // precondition: [first2, first2 + (last1 - first1)) is valid + // precondition: result is not an iterator within [first1 + 1, last1) + // or [first2 + 1, first2 + (last1 - first1)) + // precondition: [result, result + (last1 - first1)) is valid +) { + return std::transform(first1, last1, first2, result, function); +} + +int main ( void ) +{ + std::vector v(3); + v[0] = 1; v[1] = 2; v[2] = 3; + std::vector w(3); + w[0] = 10; w[1] = 20; w[2] = 30; + + mytransform(v.begin(), v.end(), w.begin(), v.begin(), std::plus()); + + BOOST_TEST(v[0] == 11); + BOOST_TEST(v[1] == 22); + BOOST_TEST(v[2] == 33); + return boost::report_errors(); +} +//] + diff --git a/example/stroustrup97/string.cpp b/example/stroustrup97/string.cpp new file mode 100644 index 0000000..f5b109c --- /dev/null +++ b/example/stroustrup97/string.cpp @@ -0,0 +1,33 @@ + +// 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 + +//[stroustrup97_string +// File: string.cpp +#include "string.hpp" + +CONTRACT_CONSTRUCTOR_BODY(string, string) ( const char* chars ) + { init(chars); } + +CONTRACT_CONSTRUCTOR_BODY(string, string) ( const string& other ) + { init(other.chars_); } + +CONTRACT_DESTRUCTOR_BODY(string, ~string) ( void ) + { delete[] chars_; } + +char& string::CONTRACT_MEMBER_BODY(operator([])(at)) ( int index ) + { return chars_[index]; } + +int string::CONTRACT_MEMBER_BODY(size) ( void ) const { return size_; } + +void string::CONTRACT_MEMBER_BODY(init) ( const char* chars ) { + size_ = strlen(chars); + chars_ = new char[size_ + 1]; + for(int i = 0; i < size_; ++i) chars_[i] = chars[i]; + chars_[size_] = '\0'; +} +//] + diff --git a/example/stroustrup97/string.hpp b/example/stroustrup97/string.hpp new file mode 100644 index 0000000..0c089b1 --- /dev/null +++ b/example/stroustrup97/string.hpp @@ -0,0 +1,81 @@ + +// 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 + +//[stroustrup97_string_header +// File: string.hpp +#ifndef STRING_HPP_ +#define STRING_HPP_ + +#include +#include + +// Adapted from an example presented in [Stroustrup1997] 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 `CONTRACT_CONFIG_NO_POSTCONDITIONS` macro) because +// postconditions are deliberately not used. +// See [Stroustrup1997] for a discussion on the importance of class invariants, +// and on pros and cons of using pre and post conditions. +CONTRACT_CLASS( + class (string) +) { + CONTRACT_CLASS_INVARIANT( + // It would be better to assert conditions separately so to generate + // more informative error in case they fail. + chars_ ? true : throw invariant_error(), + size_ >= 0 ? true : throw invariant_error(), + too_large >= size_ ? true : throw invariant_error(), + chars_[size_] == '\0' ? true : throw invariant_error() + ) + + // Broken contracts throw user defined exceptions. + public: class range_error {}; + public: class invariant_error {}; + public: class null_error {}; + public: class too_large_error {}; + + public: enum { too_large = 16000 }; // Length limit. + + CONTRACT_CONSTRUCTOR( + public (string) ( (const char*) chars ) + precondition( + chars ? true : throw null_error(), + strlen(chars) <= too_large ? true : throw too_large_error() + ) + ) ; // Deferred body definition. + + CONTRACT_CONSTRUCTOR( + public (string) ( (const string&) other ) + ) ; + + CONTRACT_DESTRUCTOR( + public (~string) ( void ) + ) ; + + CONTRACT_FUNCTION( + public (char&) operator([])(at) ( int index ) + precondition( + index >= 0 ? true : throw range_error(), + size_ > index ? true : throw range_error() + ) + ) ; + + CONTRACT_FUNCTION( + public int (size) ( void ) const + ) ; + + CONTRACT_FUNCTION( // Not public so it does not check class invariants. + private void (init) ( (const char*) q ) + ) ; + + private: int size_; + private: char* chars_; +}; + +#endif // #include guard +//] + diff --git a/example/stroustrup97/string_main.cpp b/example/stroustrup97/string_main.cpp new file mode 100644 index 0000000..b340f2b --- /dev/null +++ b/example/stroustrup97/string_main.cpp @@ -0,0 +1,47 @@ + +// 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 + +//[stroustrup97_string_main +// File: string_main.cpp +#include "string.hpp" +#include + +// Handler that re-throws contract broken exceptions instead of terminating. +void throwing_handler ( contract::from const& context ) +{ + if(context == contract::FROM_DESTRUCTOR) { + // Destructor cannot throw for STL exception safety (ignore error). + std::clog << "Ignored destructor contract failure" << std::endl; + } else { + // Failure handlers always called with active an exception. + throw; // Re-throw active exception thrown by precondition. + } +} + +int main ( void ) +{ + // Setup all contract failure handlers to throw (instead of terminate). + contract::set_precondition_broken(&throwing_handler); + contract::set_postcondition_broken(&throwing_handler); + contract::set_class_invariant_broken(&throwing_handler); + contract::set_block_invariant_broken(&throwing_handler); + contract::set_loop_variant_broken(&throwing_handler); + + string s("abc"); + BOOST_TEST(s[0] == 'a'); + +#ifndef CONTRACT_CONFIG_NO_PRECONDITIONS + bool pass = false; + try { s[3]; } // Out of range. + catch(string::range_error) { pass = true; } + BOOST_TEST(pass); +#endif + + return boost::report_errors(); +} +//] + diff --git a/include/boost/contract/ext_/preprocessor/keyword/alignas.hpp b/include/boost/contract/ext_/preprocessor/keyword/alignas.hpp new file mode 100644 index 0000000..89f9f8d --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/alignas.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNAS_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNAS_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNAS_IS_alignas (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNAS_REM_alignas + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_ALIGNAS(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNAS_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNAS_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNAS_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/alignof.hpp b/include/boost/contract/ext_/preprocessor/keyword/alignof.hpp new file mode 100644 index 0000000..233b9c4 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/alignof.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNOF_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNOF_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNOF_IS_alignof (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNOF_REM_alignof + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_ALIGNOF(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNOF_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNOF_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ALIGNOF_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/and.hpp b/include/boost/contract/ext_/preprocessor/keyword/and.hpp new file mode 100644 index 0000000..5e7c7c5 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/and.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_AND_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AND_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AND_IS_and (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AND_REM_and + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_AND(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_AND_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AND_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_AND_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/and_eq.hpp b/include/boost/contract/ext_/preprocessor/keyword/and_eq.hpp new file mode 100644 index 0000000..b55526e --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/and_eq.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_AND_EQ_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AND_EQ_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AND_EQ_IS_and_eq (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AND_EQ_REM_and_eq + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_AND_EQ(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_AND_EQ_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AND_EQ_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_AND_EQ_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/asm.hpp b/include/boost/contract/ext_/preprocessor/keyword/asm.hpp new file mode 100644 index 0000000..cabf7f9 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/asm.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_ASM_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ASM_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ASM_IS_asm (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ASM_REM_asm + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_ASM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ASM_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ASM_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ASM_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/auto.hpp b/include/boost/contract/ext_/preprocessor/keyword/auto.hpp new file mode 100644 index 0000000..c8a175a --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/auto.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_AUTO_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AUTO_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AUTO_IS_auto (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AUTO_REM_auto + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_AUTO(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_AUTO_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_AUTO_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_AUTO_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/bitand.hpp b/include/boost/contract/ext_/preprocessor/keyword/bitand.hpp new file mode 100644 index 0000000..d945652 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/bitand.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_BITAND_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BITAND_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BITAND_IS_bitand (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BITAND_REM_bitand + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_BITAND(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_BITAND_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BITAND_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_BITAND_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/bitor.hpp b/include/boost/contract/ext_/preprocessor/keyword/bitor.hpp new file mode 100644 index 0000000..bbe3fea --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/bitor.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_BITOR_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BITOR_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BITOR_IS_bitor (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BITOR_REM_bitor + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_BITOR(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_BITOR_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BITOR_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_BITOR_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/bool.hpp b/include/boost/contract/ext_/preprocessor/keyword/bool.hpp new file mode 100644 index 0000000..953e279 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/bool.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_BOOL_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BOOL_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BOOL_IS_bool (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BOOL_REM_bool + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_BOOL(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_BOOL_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BOOL_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_BOOL_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/break.hpp b/include/boost/contract/ext_/preprocessor/keyword/break.hpp new file mode 100644 index 0000000..63869de --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/break.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_BREAK_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BREAK_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BREAK_IS_break (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BREAK_REM_break + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_BREAK(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_BREAK_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_BREAK_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_BREAK_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/case.hpp b/include/boost/contract/ext_/preprocessor/keyword/case.hpp new file mode 100644 index 0000000..de6ab33 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/case.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CASE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CASE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CASE_IS_case (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CASE_REM_case + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CASE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CASE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CASE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CASE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/catch.hpp b/include/boost/contract/ext_/preprocessor/keyword/catch.hpp new file mode 100644 index 0000000..6a55c3c --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/catch.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CATCH_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CATCH_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CATCH_IS_catch (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CATCH_REM_catch + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CATCH(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CATCH_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CATCH_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CATCH_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/char.hpp b/include/boost/contract/ext_/preprocessor/keyword/char.hpp new file mode 100644 index 0000000..66bcc6c --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/char.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR_IS_char (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR_REM_char + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CHAR(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/char16_t.hpp b/include/boost/contract/ext_/preprocessor/keyword/char16_t.hpp new file mode 100644 index 0000000..98128de --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/char16_t.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR16_T_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR16_T_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR16_T_IS_char16_t (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR16_T_REM_char16_t + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CHAR16_T(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR16_T_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR16_T_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR16_T_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/char32_t.hpp b/include/boost/contract/ext_/preprocessor/keyword/char32_t.hpp new file mode 100644 index 0000000..d655271 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/char32_t.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR32_T_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR32_T_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR32_T_IS_char32_t (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR32_T_REM_char32_t + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CHAR32_T(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR32_T_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR32_T_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CHAR32_T_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/class.hpp b/include/boost/contract/ext_/preprocessor/keyword/class.hpp new file mode 100644 index 0000000..95efdc2 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/class.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CLASS_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CLASS_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CLASS_IS_class (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CLASS_REM_class + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CLASS(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CLASS_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CLASS_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CLASS_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/compl.hpp b/include/boost/contract/ext_/preprocessor/keyword/compl.hpp new file mode 100644 index 0000000..e5d4ecf --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/compl.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_COMPL_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_COMPL_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_COMPL_IS_compl (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_COMPL_REM_compl + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_COMPL(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_COMPL_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_COMPL_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_COMPL_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/const.hpp b/include/boost/contract/ext_/preprocessor/keyword/const.hpp new file mode 100644 index 0000000..ae8f633 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/const.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_IS_const (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_REM_const + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CONST(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/const_cast.hpp b/include/boost/contract/ext_/preprocessor/keyword/const_cast.hpp new file mode 100644 index 0000000..bf644cf --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/const_cast.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_CAST_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_CAST_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_CAST_IS_const_cast (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_CAST_REM_const_cast + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CONST_CAST(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_CAST_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_CAST_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CONST_CAST_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/constexpr.hpp b/include/boost/contract/ext_/preprocessor/keyword/constexpr.hpp new file mode 100644 index 0000000..cc0d393 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/constexpr.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CONSTEXPR_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONSTEXPR_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONSTEXPR_IS_constexpr (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONSTEXPR_REM_constexpr + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CONSTEXPR(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CONSTEXPR_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONSTEXPR_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CONSTEXPR_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/continue.hpp b/include/boost/contract/ext_/preprocessor/keyword/continue.hpp new file mode 100644 index 0000000..0d4583f --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/continue.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_CONTINUE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONTINUE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONTINUE_IS_continue (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONTINUE_REM_continue + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CONTINUE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CONTINUE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_CONTINUE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CONTINUE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/contract/extends.hpp b/include/boost/contract/ext_/preprocessor/keyword/contract/extends.hpp new file mode 100644 index 0000000..481f06f --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/contract/extends.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_EXTENDS_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXTENDS_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXTENDS_IS_extends (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXTENDS_REM_extends + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_EXTENDS(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_EXTENDS_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXTENDS_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_EXTENDS_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/contract/postcondition.hpp b/include/boost/contract/ext_/preprocessor/keyword/contract/postcondition.hpp new file mode 100644 index 0000000..92bf62d --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/contract/postcondition.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_POSTCONDITION_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_POSTCONDITION_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_POSTCONDITION_IS_postcondition (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_POSTCONDITION_REM_postcondition + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_POSTCONDITION(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_POSTCONDITION_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_POSTCONDITION_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_POSTCONDITION_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/contract/precondition.hpp b/include/boost/contract/ext_/preprocessor/keyword/contract/precondition.hpp new file mode 100644 index 0000000..f87e8c8 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/contract/precondition.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_PRECONDITION_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PRECONDITION_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PRECONDITION_IS_precondition (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PRECONDITION_REM_precondition + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PRECONDITION(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PRECONDITION_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PRECONDITION_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PRECONDITION_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/contract/verbatim.hpp b/include/boost/contract/ext_/preprocessor/keyword/contract/verbatim.hpp new file mode 100644 index 0000000..f4dad89 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/contract/verbatim.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_VERBATIM_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VERBATIM_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VERBATIM_IS_verbatim (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VERBATIM_REM_verbatim + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_VERBATIM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VERBATIM_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VERBATIM_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VERBATIM_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/decltype.hpp b/include/boost/contract/ext_/preprocessor/keyword/decltype.hpp new file mode 100644 index 0000000..5db88d3 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/decltype.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_DECLTYPE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DECLTYPE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DECLTYPE_IS_decltype (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DECLTYPE_REM_decltype + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_DECLTYPE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DECLTYPE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DECLTYPE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DECLTYPE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/default.hpp b/include/boost/contract/ext_/preprocessor/keyword/default.hpp new file mode 100644 index 0000000..0ffdaec --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/default.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_DEFAULT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DEFAULT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DEFAULT_IS_default (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DEFAULT_REM_default + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_DEFAULT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DEFAULT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DEFAULT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DEFAULT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/delete.hpp b/include/boost/contract/ext_/preprocessor/keyword/delete.hpp new file mode 100644 index 0000000..23dafd1 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/delete.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_DELETE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DELETE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DELETE_IS_delete (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DELETE_REM_delete + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_DELETE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DELETE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DELETE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DELETE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/do.hpp b/include/boost/contract/ext_/preprocessor/keyword/do.hpp new file mode 100644 index 0000000..fda8c17 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/do.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_DO_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DO_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DO_IS_do (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DO_REM_do + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_DO(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DO_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DO_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DO_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/double.hpp b/include/boost/contract/ext_/preprocessor/keyword/double.hpp new file mode 100644 index 0000000..1c907d4 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/double.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_DOUBLE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DOUBLE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DOUBLE_IS_double (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DOUBLE_REM_double + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_DOUBLE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DOUBLE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DOUBLE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DOUBLE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/dynamic_cast.hpp b/include/boost/contract/ext_/preprocessor/keyword/dynamic_cast.hpp new file mode 100644 index 0000000..5563e76 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/dynamic_cast.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_DYNAMIC_CAST_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DYNAMIC_CAST_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DYNAMIC_CAST_IS_dynamic_cast (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DYNAMIC_CAST_REM_dynamic_cast + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_DYNAMIC_CAST(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DYNAMIC_CAST_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_DYNAMIC_CAST_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DYNAMIC_CAST_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/else.hpp b/include/boost/contract/ext_/preprocessor/keyword/else.hpp new file mode 100644 index 0000000..6267a89 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/else.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_ELSE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ELSE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ELSE_IS_else (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ELSE_REM_else + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_ELSE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ELSE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ELSE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ELSE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/enum.hpp b/include/boost/contract/ext_/preprocessor/keyword/enum.hpp new file mode 100644 index 0000000..8960b26 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/enum.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_ENUM_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ENUM_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ENUM_IS_enum (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ENUM_REM_enum + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_ENUM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ENUM_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_ENUM_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_ENUM_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/explicit.hpp b/include/boost/contract/ext_/preprocessor/keyword/explicit.hpp new file mode 100644 index 0000000..23aa992 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/explicit.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_EXPLICIT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXPLICIT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXPLICIT_IS_explicit (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXPLICIT_REM_explicit + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_EXPLICIT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_EXPLICIT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXPLICIT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_EXPLICIT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/export.hpp b/include/boost/contract/ext_/preprocessor/keyword/export.hpp new file mode 100644 index 0000000..2297110 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/export.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_EXPORT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXPORT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXPORT_IS_export (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXPORT_REM_export + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_EXPORT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_EXPORT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXPORT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_EXPORT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/extern.hpp b/include/boost/contract/ext_/preprocessor/keyword/extern.hpp new file mode 100644 index 0000000..4040ab7 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/extern.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_EXTERN_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXTERN_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXTERN_IS_extern (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXTERN_REM_extern + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_EXTERN(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_EXTERN_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_EXTERN_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_EXTERN_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/false.hpp b/include/boost/contract/ext_/preprocessor/keyword/false.hpp new file mode 100644 index 0000000..1d169a2 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/false.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_FALSE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FALSE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FALSE_IS_false (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FALSE_REM_false + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_FALSE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FALSE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FALSE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FALSE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/final.hpp b/include/boost/contract/ext_/preprocessor/keyword/final.hpp new file mode 100644 index 0000000..cb6f558 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/final.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_FINAL_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FINAL_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FINAL_IS_final (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FINAL_REM_final + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_FINAL(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FINAL_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FINAL_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FINAL_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/float.hpp b/include/boost/contract/ext_/preprocessor/keyword/float.hpp new file mode 100644 index 0000000..1e59553 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/float.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_FLOAT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FLOAT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FLOAT_IS_float (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FLOAT_REM_float + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_FLOAT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FLOAT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FLOAT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FLOAT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/for.hpp b/include/boost/contract/ext_/preprocessor/keyword/for.hpp new file mode 100644 index 0000000..37720ed --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/for.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_FOR_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FOR_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FOR_IS_for (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FOR_REM_for + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_FOR(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FOR_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FOR_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FOR_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/friend.hpp b/include/boost/contract/ext_/preprocessor/keyword/friend.hpp new file mode 100644 index 0000000..b2314f6 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/friend.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_FRIEND_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FRIEND_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FRIEND_IS_friend (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FRIEND_REM_friend + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_FRIEND(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FRIEND_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_FRIEND_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_FRIEND_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/generate.py b/include/boost/contract/ext_/preprocessor/keyword/generate.py new file mode 100644 index 0000000..f9add09 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/generate.py @@ -0,0 +1,74 @@ + +# 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 + +import os +import sys +import shutil + +entries = [ + { + 'directory': '.', + 'keywords': [ +'alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', 'bool', 'break', 'case', 'catch', 'char', 'char16_t', 'char32_t', 'class', 'compl', 'const', 'constexpr', 'const_cast', 'continue', 'decltype', 'default', 'delete', 'do', 'double', 'dynamic_cast', 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'final', 'float', 'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new', 'noexcept', 'not', 'not_eq', 'nullptr', 'operator', 'or', 'or_eq', 'override', 'private', 'protected', 'public', 'register', 'reinterpret_cast', 'return', 'short', 'signed', 'sizeof', 'static', 'static_assert', 'static_cast', 'struct', 'switch', 'template', 'this', 'thread_local', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union', 'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq' + ] + }, + { + 'directory': 'contract', + 'keywords': [ +'invariant', 'precondition', 'postcondition', 'extends', 'verbatim' + ] + } +] + +script = os.path.basename(sys.argv[0]) +for entry in entries: + directory = entry['directory'] + keywords = entry['keywords'] + if not os.path.exists(directory): os.makedirs(directory) + for keyword in keywords: + filename = keyword + ".hpp" + path = os.path.join(directory, filename) + try: + shutil.copyfile(path, path + ".bak") + except: + pass + file = open(path, 'w') + + file.write(''' +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "{0}". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_{1}_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_{1}_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_{1}_IS_{2} (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_{1}_REM_{2} + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_{1}(tokens) \\ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \\ + BOOST_CONTRACT_EXT_PP_KEYWORD_{1}_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_{1}_REM(tokens) \\ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \\ + BOOST_CONTRACT_EXT_PP_KEYWORD_{1}_REM_) + +#endif // #include guard + '''.format(script, keyword.upper(), keyword.lower())) + + file.close() + print "Written:", path + diff --git a/include/boost/contract/ext_/preprocessor/keyword/goto.hpp b/include/boost/contract/ext_/preprocessor/keyword/goto.hpp new file mode 100644 index 0000000..8776493 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/goto.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_GOTO_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_GOTO_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_GOTO_IS_goto (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_GOTO_REM_goto + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_GOTO(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_GOTO_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_GOTO_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_GOTO_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/if.hpp b/include/boost/contract/ext_/preprocessor/keyword/if.hpp new file mode 100644 index 0000000..1f0b24b --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/if.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_IF_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IF_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IF_IS_if (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IF_REM_if + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_IF(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IF_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IF_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IF_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/inline.hpp b/include/boost/contract/ext_/preprocessor/keyword/inline.hpp new file mode 100644 index 0000000..7b1b26c --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/inline.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_INLINE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_INLINE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_INLINE_IS_inline (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_INLINE_REM_inline + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_INLINE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_INLINE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_INLINE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_INLINE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/int.hpp b/include/boost/contract/ext_/preprocessor/keyword/int.hpp new file mode 100644 index 0000000..8e68906 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/int.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_INT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_INT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_INT_IS_int (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_INT_REM_int + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_INT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_INT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_INT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_INT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/long.hpp b/include/boost/contract/ext_/preprocessor/keyword/long.hpp new file mode 100644 index 0000000..f7905b7 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/long.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_LONG_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_LONG_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_LONG_IS_long (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_LONG_REM_long + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_LONG(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_LONG_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_LONG_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_LONG_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/mutable.hpp b/include/boost/contract/ext_/preprocessor/keyword/mutable.hpp new file mode 100644 index 0000000..8751853 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/mutable.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_MUTABLE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_MUTABLE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_MUTABLE_IS_mutable (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_MUTABLE_REM_mutable + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_MUTABLE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_MUTABLE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_MUTABLE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_MUTABLE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/namespace.hpp b/include/boost/contract/ext_/preprocessor/keyword/namespace.hpp new file mode 100644 index 0000000..426b7c1 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/namespace.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_NAMESPACE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NAMESPACE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NAMESPACE_IS_namespace (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NAMESPACE_REM_namespace + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_NAMESPACE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NAMESPACE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NAMESPACE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NAMESPACE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/new.hpp b/include/boost/contract/ext_/preprocessor/keyword/new.hpp new file mode 100644 index 0000000..1d048fb --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/new.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_NEW_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NEW_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NEW_IS_new (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NEW_REM_new + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_NEW(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NEW_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NEW_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NEW_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/noexcept.hpp b/include/boost/contract/ext_/preprocessor/keyword/noexcept.hpp new file mode 100644 index 0000000..20547e0 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/noexcept.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_NOEXCEPT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOEXCEPT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOEXCEPT_IS_noexcept (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOEXCEPT_REM_noexcept + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_NOEXCEPT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NOEXCEPT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOEXCEPT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NOEXCEPT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/not.hpp b/include/boost/contract/ext_/preprocessor/keyword/not.hpp new file mode 100644 index 0000000..00caac8 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/not.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_IS_not (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_REM_not + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_NOT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/not_eq.hpp b/include/boost/contract/ext_/preprocessor/keyword/not_eq.hpp new file mode 100644 index 0000000..e898fa2 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/not_eq.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_EQ_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_EQ_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_EQ_IS_not_eq (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_EQ_REM_not_eq + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_NOT_EQ(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_EQ_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_EQ_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NOT_EQ_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/nullptr.hpp b/include/boost/contract/ext_/preprocessor/keyword/nullptr.hpp new file mode 100644 index 0000000..61320da --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/nullptr.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_NULLPTR_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NULLPTR_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NULLPTR_IS_nullptr (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NULLPTR_REM_nullptr + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_NULLPTR(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NULLPTR_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_NULLPTR_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_NULLPTR_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/operator.hpp b/include/boost/contract/ext_/preprocessor/keyword/operator.hpp new file mode 100644 index 0000000..fede7e0 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/operator.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_OPERATOR_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OPERATOR_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OPERATOR_IS_operator (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OPERATOR_REM_operator + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_OPERATOR(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_OPERATOR_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OPERATOR_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_OPERATOR_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/or.hpp b/include/boost/contract/ext_/preprocessor/keyword/or.hpp new file mode 100644 index 0000000..d649643 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/or.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_OR_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OR_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OR_IS_or (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OR_REM_or + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_OR(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_OR_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OR_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_OR_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/or_eq.hpp b/include/boost/contract/ext_/preprocessor/keyword/or_eq.hpp new file mode 100644 index 0000000..35eb7b8 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/or_eq.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_OR_EQ_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OR_EQ_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OR_EQ_IS_or_eq (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OR_EQ_REM_or_eq + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_OR_EQ(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_OR_EQ_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OR_EQ_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_OR_EQ_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/override.hpp b/include/boost/contract/ext_/preprocessor/keyword/override.hpp new file mode 100644 index 0000000..692e47e --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/override.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_OVERRIDE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OVERRIDE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OVERRIDE_IS_override (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OVERRIDE_REM_override + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_OVERRIDE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_OVERRIDE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_OVERRIDE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_OVERRIDE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/private.hpp b/include/boost/contract/ext_/preprocessor/keyword/private.hpp new file mode 100644 index 0000000..fc03a8b --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/private.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_PRIVATE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PRIVATE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PRIVATE_IS_private (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PRIVATE_REM_private + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PRIVATE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PRIVATE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PRIVATE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PRIVATE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/protected.hpp b/include/boost/contract/ext_/preprocessor/keyword/protected.hpp new file mode 100644 index 0000000..02eea6d --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/protected.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_PROTECTED_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PROTECTED_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PROTECTED_IS_protected (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PROTECTED_REM_protected + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PROTECTED(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PROTECTED_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PROTECTED_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PROTECTED_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/public.hpp b/include/boost/contract/ext_/preprocessor/keyword/public.hpp new file mode 100644 index 0000000..d925165 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/public.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_PUBLIC_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PUBLIC_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PUBLIC_IS_public (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PUBLIC_REM_public + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PUBLIC(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PUBLIC_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_PUBLIC_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PUBLIC_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/register.hpp b/include/boost/contract/ext_/preprocessor/keyword/register.hpp new file mode 100644 index 0000000..2bf273c --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/register.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_REGISTER_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_REGISTER_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_REGISTER_IS_register (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_REGISTER_REM_register + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_REGISTER(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_REGISTER_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_REGISTER_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_REGISTER_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/reinterpret_cast.hpp b/include/boost/contract/ext_/preprocessor/keyword/reinterpret_cast.hpp new file mode 100644 index 0000000..586e120 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/reinterpret_cast.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_REINTERPRET_CAST_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_REINTERPRET_CAST_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_REINTERPRET_CAST_IS_reinterpret_cast (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_REINTERPRET_CAST_REM_reinterpret_cast + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_REINTERPRET_CAST(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_REINTERPRET_CAST_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_REINTERPRET_CAST_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_REINTERPRET_CAST_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/return.hpp b/include/boost/contract/ext_/preprocessor/keyword/return.hpp new file mode 100644 index 0000000..1703ed9 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/return.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_RETURN_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_RETURN_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_RETURN_IS_return (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_RETURN_REM_return + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_RETURN(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_RETURN_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_RETURN_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_RETURN_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/short.hpp b/include/boost/contract/ext_/preprocessor/keyword/short.hpp new file mode 100644 index 0000000..d477dae --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/short.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_SHORT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SHORT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SHORT_IS_short (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SHORT_REM_short + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_SHORT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_SHORT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SHORT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_SHORT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/signed.hpp b/include/boost/contract/ext_/preprocessor/keyword/signed.hpp new file mode 100644 index 0000000..49ac441 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/signed.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_SIGNED_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SIGNED_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SIGNED_IS_signed (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SIGNED_REM_signed + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_SIGNED(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_SIGNED_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SIGNED_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_SIGNED_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/sizeof.hpp b/include/boost/contract/ext_/preprocessor/keyword/sizeof.hpp new file mode 100644 index 0000000..25ef8b5 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/sizeof.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_SIZEOF_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SIZEOF_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SIZEOF_IS_sizeof (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SIZEOF_REM_sizeof + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_SIZEOF(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_SIZEOF_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SIZEOF_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_SIZEOF_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/static.hpp b/include/boost/contract/ext_/preprocessor/keyword/static.hpp new file mode 100644 index 0000000..1eee289 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/static.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_IS_static (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_REM_static + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_STATIC(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/static_assert.hpp b/include/boost/contract/ext_/preprocessor/keyword/static_assert.hpp new file mode 100644 index 0000000..98fcd70 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/static_assert.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_ASSERT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_ASSERT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_ASSERT_IS_static_assert (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_ASSERT_REM_static_assert + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_STATIC_ASSERT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_ASSERT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_ASSERT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_ASSERT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/static_cast.hpp b/include/boost/contract/ext_/preprocessor/keyword/static_cast.hpp new file mode 100644 index 0000000..22397a3 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/static_cast.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_CAST_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_CAST_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_CAST_IS_static_cast (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_CAST_REM_static_cast + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_STATIC_CAST(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_CAST_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_CAST_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_STATIC_CAST_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/struct.hpp b/include/boost/contract/ext_/preprocessor/keyword/struct.hpp new file mode 100644 index 0000000..8a1445a --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/struct.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_STRUCT_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STRUCT_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STRUCT_IS_struct (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STRUCT_REM_struct + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_STRUCT(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_STRUCT_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_STRUCT_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_STRUCT_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/switch.hpp b/include/boost/contract/ext_/preprocessor/keyword/switch.hpp new file mode 100644 index 0000000..98b7f95 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/switch.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_SWITCH_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SWITCH_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SWITCH_IS_switch (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SWITCH_REM_switch + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_SWITCH(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_SWITCH_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_SWITCH_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_SWITCH_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/template.hpp b/include/boost/contract/ext_/preprocessor/keyword/template.hpp new file mode 100644 index 0000000..a0f7a73 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/template.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_IS_template (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_REM_template + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TEMPLATE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/this.hpp b/include/boost/contract/ext_/preprocessor/keyword/this.hpp new file mode 100644 index 0000000..408928c --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/this.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_THIS_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THIS_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THIS_IS_this (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THIS_REM_this + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_THIS(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_THIS_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THIS_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_THIS_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/thread_local.hpp b/include/boost/contract/ext_/preprocessor/keyword/thread_local.hpp new file mode 100644 index 0000000..46959a5 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/thread_local.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_THREAD_LOCAL_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THREAD_LOCAL_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THREAD_LOCAL_IS_thread_local (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THREAD_LOCAL_REM_thread_local + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_THREAD_LOCAL(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_THREAD_LOCAL_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THREAD_LOCAL_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_THREAD_LOCAL_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/throw.hpp b/include/boost/contract/ext_/preprocessor/keyword/throw.hpp new file mode 100644 index 0000000..baa2cee --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/throw.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_THROW_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THROW_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THROW_IS_throw (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THROW_REM_throw + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_THROW(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_THROW_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_THROW_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_THROW_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/true.hpp b/include/boost/contract/ext_/preprocessor/keyword/true.hpp new file mode 100644 index 0000000..a0b1ebc --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/true.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_TRUE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TRUE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TRUE_IS_true (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TRUE_REM_true + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TRUE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TRUE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TRUE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TRUE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/try.hpp b/include/boost/contract/ext_/preprocessor/keyword/try.hpp new file mode 100644 index 0000000..e2ea01e --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/try.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_TRY_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TRY_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TRY_IS_try (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TRY_REM_try + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TRY(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TRY_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TRY_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TRY_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/typedef.hpp b/include/boost/contract/ext_/preprocessor/keyword/typedef.hpp new file mode 100644 index 0000000..a6246cd --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/typedef.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEDEF_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEDEF_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEDEF_IS_typedef (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEDEF_REM_typedef + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TYPEDEF(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEDEF_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEDEF_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEDEF_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/typeid.hpp b/include/boost/contract/ext_/preprocessor/keyword/typeid.hpp new file mode 100644 index 0000000..a861951 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/typeid.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEID_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEID_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEID_IS_typeid (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEID_REM_typeid + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TYPEID(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEID_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEID_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TYPEID_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/typename.hpp b/include/boost/contract/ext_/preprocessor/keyword/typename.hpp new file mode 100644 index 0000000..3103609 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/typename.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_TYPENAME_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPENAME_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPENAME_IS_typename (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPENAME_REM_typename + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TYPENAME(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TYPENAME_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_TYPENAME_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TYPENAME_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/union.hpp b/include/boost/contract/ext_/preprocessor/keyword/union.hpp new file mode 100644 index 0000000..37fac4c --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/union.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_UNION_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UNION_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UNION_IS_union (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UNION_REM_union + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_UNION(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UNION_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UNION_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UNION_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/unsigned.hpp b/include/boost/contract/ext_/preprocessor/keyword/unsigned.hpp new file mode 100644 index 0000000..4336ebf --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/unsigned.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_UNSIGNED_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UNSIGNED_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UNSIGNED_IS_unsigned (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UNSIGNED_REM_unsigned + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_UNSIGNED(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UNSIGNED_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UNSIGNED_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UNSIGNED_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/using.hpp b/include/boost/contract/ext_/preprocessor/keyword/using.hpp new file mode 100644 index 0000000..3cd9045 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/using.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_USING_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_USING_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_USING_IS_using (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_USING_REM_using + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_USING(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_USING_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_USING_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_USING_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/utility/is.hpp b/include/boost/contract/ext_/preprocessor/keyword/utility/is.hpp new file mode 100644 index 0000000..7ad1dec --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/utility/is.hpp @@ -0,0 +1,34 @@ + +// 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 + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS_HPP_ + +#include +#include +#include +#include + +// PRIVATE // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS_(a, b) \ + BOOST_CONTRACT_EXT_PP_HAS_PAREN(BOOST_PP_CAT(a, b)) + +// PUBLIC // + +// `checking_prefix ## tokens` expand to unary (e.g., `(1)`) iff `tokens` start +// with keyword to check. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS( \ + tokens, checking_prefix) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_HAS_PAREN(tokens), \ + 0 BOOST_PP_TUPLE_EAT(2) \ + , \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS_ \ + )(checking_prefix, tokens) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/keyword/utility/rem.hpp b/include/boost/contract/ext_/preprocessor/keyword/utility/rem.hpp new file mode 100644 index 0000000..0ea3867 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/utility/rem.hpp @@ -0,0 +1,31 @@ + +// 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 + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM_HPP_ + +#include + +// PRIVATE // + +// Adapted from BOOST_PP_EXPAND. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REMOVE_EXPAND_I_(tokens) \ + tokens +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM_EXPAND_(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REMOVE_EXPAND_I_(tokens) + +// PUBLIC // + +// `removing_prefix ## ` must expand to nothing, else 0. +// Precondition: Tokens start with keyword to remove (see KEYWORD_UTILITY_IS). +// IMPLEMENTATION: Below without EXPAND doesn't expand on MSVC. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, removing_prefix) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM_EXPAND_( \ + BOOST_PP_CAT(removing_prefix, tokens)) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/keyword/virtual.hpp b/include/boost/contract/ext_/preprocessor/keyword/virtual.hpp new file mode 100644 index 0000000..08ef0ac --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/virtual.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_VIRTUAL_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VIRTUAL_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VIRTUAL_IS_virtual (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VIRTUAL_REM_virtual + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_VIRTUAL(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VIRTUAL_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VIRTUAL_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VIRTUAL_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/void.hpp b/include/boost/contract/ext_/preprocessor/keyword/void.hpp new file mode 100644 index 0000000..9ab0808 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/void.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_VOID_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VOID_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VOID_IS_void (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VOID_REM_void + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_VOID(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VOID_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VOID_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VOID_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/volatile.hpp b/include/boost/contract/ext_/preprocessor/keyword/volatile.hpp new file mode 100644 index 0000000..7a0d03f --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/volatile.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_VOLATILE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VOLATILE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VOLATILE_IS_volatile (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VOLATILE_REM_volatile + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_VOLATILE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VOLATILE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_VOLATILE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VOLATILE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/wchar_t.hpp b/include/boost/contract/ext_/preprocessor/keyword/wchar_t.hpp new file mode 100644 index 0000000..d121f66 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/wchar_t.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_WCHAR_T_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_WCHAR_T_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_WCHAR_T_IS_wchar_t (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_WCHAR_T_REM_wchar_t + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_WCHAR_T(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_WCHAR_T_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_WCHAR_T_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_WCHAR_T_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/while.hpp b/include/boost/contract/ext_/preprocessor/keyword/while.hpp new file mode 100644 index 0000000..d639f98 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/while.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_WHILE_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_WHILE_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_WHILE_IS_while (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_WHILE_REM_while + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_WHILE(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_WHILE_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_WHILE_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_WHILE_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/xor.hpp b/include/boost/contract/ext_/preprocessor/keyword/xor.hpp new file mode 100644 index 0000000..ece8b44 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/xor.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_IS_xor (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_REM_xor + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_XOR(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/keyword/xor_eq.hpp b/include/boost/contract/ext_/preprocessor/keyword/xor_eq.hpp new file mode 100644 index 0000000..5d2da2d --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/keyword/xor_eq.hpp @@ -0,0 +1,30 @@ + +// WARNING: FILE AUTOMATICALLY GENERATED, DO NOT MODIFY IT! +// Instead, modify and run the related generation script "generate.py". + +#ifndef BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_EQ_HPP_ +#define BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_EQ_HPP_ + +#include +#include + +// PRIVATE // + +// NOTE: These are not local macros, do NOT #undefine them. +// The following macro must expand to a unary token: `(1)`, etc. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_EQ_IS_xor_eq (1) +// The following macro must expand to nothing. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_EQ_REM_xor_eq + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_IS_XOR_EQ(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_IS(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_EQ_IS_) + +#define BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_EQ_REM(tokens) \ + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REM(tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_XOR_EQ_REM_) + +#endif // #include guard + \ No newline at end of file diff --git a/include/boost/contract/ext_/preprocessor/paren/eat.hpp b/include/boost/contract/ext_/preprocessor/paren/eat.hpp new file mode 100644 index 0000000..ebd3995 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/paren/eat.hpp @@ -0,0 +1,18 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_PAREN_EAT_HPP_ +#define BOOST_CONTRACT_EXT_PP_PAREN_EAT_HPP_ + +// PRIVATE // + +// IMPLEMENTATION: Must expand to nothing (so to "eat" the first paren). +#define BOOST_CONTRACT_EXT_PP_PAREN_EAT_(...) + +// PUBLIC // + +// Precondition: tokens == `(...[, ...]*) ...[, ...]*`. +// Expand to trailing ...[, ...]* above, "eating" parenthesized tokens in front. +#define BOOST_CONTRACT_EXT_PP_PAREN_EAT(tokens) \ + BOOST_CONTRACT_EXT_PP_PAREN_EAT_ tokens + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/paren/first.hpp b/include/boost/contract/ext_/preprocessor/paren/first.hpp new file mode 100644 index 0000000..9ad4474 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/paren/first.hpp @@ -0,0 +1,20 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_PAREN_FIRST_HPP_ +#define BOOST_CONTRACT_EXT_PP_PAREN_FIRST_HPP_ + +#include + +// PRIVATE // + +#define BOOST_CONTRACT_EXT_PP_PAREN_FIRST_SPLIT_(...) (__VA_ARGS__) , + +// PUBLIC // + +// Precondition: tokens == `(...[, ...]*) ...[, ...]*`. +// Expand to `(...[, ...]*)` in front above (discarding any trailing tokens). +#define BOOST_CONTRACT_EXT_PP_PAREN_FIRST(tokens) \ + BOOST_PP_TUPLE_ELEM(2, 0, \ + ( BOOST_CONTRACT_EXT_PP_PAREN_FIRST_SPLIT_ tokens )) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/paren/has.hpp b/include/boost/contract/ext_/preprocessor/paren/has.hpp new file mode 100644 index 0000000..e007c32 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/paren/has.hpp @@ -0,0 +1,29 @@ + +// 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 + +#ifndef BOOST_CONTRACT_EXT_PP_HAS_PAREN_HPP_ +#define BOOST_CONTRACT_EXT_PP_HAS_PAREN_HPP_ + +#include + +// PRIVATE // + +// Variadic so handle any arity. +#define BOOST_CONTRACT_EXT_PP_HAS_PAREN_CHECK(...) \ + 1 + +#define BOOST_PP_CHECK_RESULT_BOOST_CONTRACT_EXT_PP_HAS_PAREN_CHECK \ + 0, BOOST_PP_NIL + +// PUBLIC // + +// Adapted from BOOST_PP_IS_UNARY but for variadic macros. +#define BOOST_CONTRACT_EXT_PP_HAS_PAREN(tokens) \ + BOOST_PP_CHECK(tokens, BOOST_CONTRACT_EXT_PP_HAS_PAREN_CHECK) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/aux_/adt.hpp b/include/boost/contract/ext_/preprocessor/traits/aux_/adt.hpp new file mode 100644 index 0000000..4e41c03 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/aux_/adt.hpp @@ -0,0 +1,23 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ADT_PUSH_BACK_HPP_ +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ADT_PUSH_BACK_HPP_ + +#include +#include + +// NOTE: These macros Abstract the Data Type (ADT) used to implement the traits +// (pp-sequence, pp-array, pp-list, etc.). + +// PUBLIC // + +// ELEM(index, traits) +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM BOOST_PP_SEQ_ELEM + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK(traits, trait) \ + traits (trait) + +// REPLACE(traits, index, trait) +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_REPLACE BOOST_PP_SEQ_REPLACE + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/aux_/func_index.hpp b/include/boost/contract/ext_/preprocessor/traits/aux_/func_index.hpp new file mode 100644 index 0000000..db591a6 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/aux_/func_index.hpp @@ -0,0 +1,14 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_HPP_ +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_HPP_ + +// WARNING: These indexes must match order traits are parsed (see func.hpp). +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_ACCESS 0 +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_VERBATIM 1 +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_EXPORT 2 +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_TEMPLATE 3 +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_TPARAMS 4 +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_DONE 5 + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/aux_/keyword.hpp b/include/boost/contract/ext_/preprocessor/traits/aux_/keyword.hpp new file mode 100644 index 0000000..e22c8d8 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/aux_/keyword.hpp @@ -0,0 +1,101 @@ + +// 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 + +#ifndef BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_HPP_ +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_HPP_ + +#include +#include +#include +#include +#include + +// PUBLIC // + +// A keyword (among 1 single possible one). + +// IMPLEMENTATION: EXPAND needed for MSVC. +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD( \ + tokens, \ + is_keyword_macro, keyword \ +) \ + BOOST_PP_EXPR_IIF(BOOST_PP_EXPAND(is_keyword_macro(tokens)), keyword) + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_SKIP( \ + tokens, \ + is_keyword_macro, remove_keyword_macro \ +) \ + BOOST_PP_IIF(is_keyword_macro(tokens), \ + remove_keyword_macro \ + , \ + BOOST_PP_TUPLE_REM(1) \ + )(tokens) + +// A keyword among 2 possible ones. + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD2( \ + tokens, \ + is_keyword_macro1, keyword1, \ + is_keyword_macro2, keyword2 \ +) \ + BOOST_PP_IIF(is_keyword_macro1(tokens), \ + keyword1 BOOST_PP_EMPTY \ + , BOOST_PP_IIF(is_keyword_macro2(tokens), \ + keyword2 BOOST_PP_EMPTY \ + , \ + BOOST_PP_EMPTY \ + ))() + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD2_SKIP( \ + tokens, \ + is_keyword_macro1, remove_keyword_macro1, \ + is_keyword_macro2, remove_keyword_macro2 \ +) \ + BOOST_PP_IIF(is_keyword_macro1(tokens), \ + remove_keyword_macro1 \ + , BOOST_PP_IIF(is_keyword_macro2(tokens), \ + remove_keyword_macro2 \ + , \ + BOOST_PP_TUPLE_REM(1) \ + ))(tokens) + +// A keyword among 3 possible ones. + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD3( \ + tokens, \ + is_keyword_macro1, keyword1, \ + is_keyword_macro2, keyword2, \ + is_keyword_macro3, keyword3 \ +) \ + BOOST_PP_IIF(is_keyword_macro1(tokens), \ + keyword1 BOOST_PP_EMPTY \ + , BOOST_PP_IIF(is_keyword_macro2(tokens), \ + keyword2 BOOST_PP_EMPTY \ + , BOOST_PP_IIF(is_keyword_macro3(tokens), \ + keyword3 BOOST_PP_EMPTY \ + , \ + BOOST_PP_EMPTY \ + )))() + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD3_SKIP(\ + tokens, \ + is_keyword_macro1, remove_keyword_macro1, \ + is_keyword_macro2, remove_keyword_macro2, \ + is_keyword_macro3, remove_keyword_macro3 \ +) \ + BOOST_PP_IIF(is_keyword_macro1(tokens), \ + remove_keyword_macro1 \ + , BOOST_PP_IIF(is_keyword_macro2(tokens), \ + remove_keyword_macro2 \ + , BOOST_PP_IIF(is_keyword_macro3(tokens), \ + remove_keyword_macro3 \ + , \ + BOOST_PP_TUPLE_REM(1) \ + )))(tokens) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/aux_/keyword_paren.hpp b/include/boost/contract/ext_/preprocessor/traits/aux_/keyword_paren.hpp new file mode 100644 index 0000000..275e686 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/aux_/keyword_paren.hpp @@ -0,0 +1,35 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN_HPP_ +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN_HPP_ + +#include +#include +#include +#include + +// PRIVATE // + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN_( \ + tokens, remove_keyword_macro, paren_macro) \ + paren_macro(remove_keyword_macro(tokens)) + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN( \ + tokens, is_keyword_macro, remove_keyword_macro) \ + BOOST_PP_IIF(is_keyword_macro(tokens), \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN_ \ + , \ + BOOST_PP_TUPLE_EAT(3) \ + )(tokens, remove_keyword_macro, BOOST_CONTRACT_EXT_PP_PAREN_FIRST) + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN_SKIP( \ + tokens, is_keyword_macro, remove_keyword_macro) \ + BOOST_PP_IIF(is_keyword_macro(tokens), \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN_ \ + , \ + tokens BOOST_PP_TUPLE_EAT(3) \ + )(tokens, remove_keyword_macro, BOOST_CONTRACT_EXT_PP_PAREN_EAT) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/aux_/params.hpp b/include/boost/contract/ext_/preprocessor/traits/aux_/params.hpp new file mode 100644 index 0000000..784fd5c --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/aux_/params.hpp @@ -0,0 +1,109 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_HPP_ +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// PRIVATE // + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_REPLACE_LAST_DEFAULT_( \ + s, sign, d, param_parse_macro, default_replace_macro, traits, last) \ + BOOST_PP_LIST_APPEND_D(d, \ + BOOST_PP_LIST_FIRST_N_D(d, last, traits), \ + ( \ + BOOST_PP_TUPLE_ELEM(2, 1, \ + default_replace_macro(d, s, \ + ( \ + sign, \ + BOOST_PP_LIST_AT_D(d, traits, last) \ + ) \ + ) \ + ), \ + BOOST_PP_NIL \ + ) \ + ) + +// Now parsing `default ...` so replace default value of last parsed parameter. +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_REPLACE_DEFAULT_( \ + s, sign, d, param_parse_macro, default_replace_macro, traits) \ + ( \ + d, \ + param_parse_macro, \ + default_replace_macro, \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_REPLACE_LAST_DEFAULT_( \ + s, sign, d, param_parse_macro, default_replace_macro, traits, \ + BOOST_PP_DEC(BOOST_PP_LIST_SIZE_D(d, traits))) \ + ) + +// Now paring parameter declaration (assume default is EMPTY at first). +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_APPEND_PARAM_( \ + s, sign, d, param_parse_macro, default_replace_macro, traits) \ + ( \ + d, \ + param_parse_macro, \ + default_replace_macro, \ + BOOST_PP_LIST_APPEND_D(d, \ + traits, \ + ( \ + BOOST_PP_TUPLE_ELEM(2, 1, \ + param_parse_macro(d, s, \ + ( \ + sign, \ + BOOST_PP_EMPTY() \ + ) \ + ) \ + ), \ + BOOST_PP_NIL \ + ) \ + ) \ + ) + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_( \ + s, d_param_default_traits, sign) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_DEFAULT(sign), \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_REPLACE_DEFAULT_ \ + , \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_APPEND_PARAM_ \ + )( \ + s, \ + sign, \ + BOOST_PP_TUPLE_ELEM(4, 0, d_param_default_traits), \ + BOOST_PP_TUPLE_ELEM(4, 1, d_param_default_traits), \ + BOOST_PP_TUPLE_ELEM(4, 2, d_param_default_traits), \ + BOOST_PP_TUPLE_ELEM(4, 3, d_param_default_traits) \ + ) + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_D_S( \ + d, s, sign, param_parse_macro, default_replace_macro) \ + BOOST_PP_TUPLE_ELEM(4, 3, \ + BOOST_PP_SEQ_FOLD_LEFT_ ## s( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_, \ + ( \ + d, \ + param_parse_macro, \ + default_replace_macro, \ + BOOST_PP_NIL \ + ), \ + BOOST_PP_TUPLE_TO_SEQ(sign) \ + ) \ + ) + +// Expand specified pp-tuple of parameters signatures into a pp-list +// of parameters traits (also handles default arguments). +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS(sign) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_D_S(1, 1, sign) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/aux_/tparam_index.hpp b/include/boost/contract/ext_/preprocessor/traits/aux_/tparam_index.hpp new file mode 100644 index 0000000..86c3dbe --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/aux_/tparam_index.hpp @@ -0,0 +1,10 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_TRAITS_AUX_TPARAM_INDEX_HPP_ +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_TPARAM_INDEX_HPP_ + +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_TPARAM_INDEX_KIND 0 +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_TPARAM_INDEX_NAME 1 +#define BOOST_CONTRACT_EXT_PP_TRAITS_AUX_TPARAM_INDEX_DEFAULT 2 + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/func.hpp b/include/boost/contract/ext_/preprocessor/traits/func.hpp new file mode 100644 index 0000000..af3edbf --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/func.hpp @@ -0,0 +1,89 @@ + +// 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 + +#ifndef BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_HPP_ +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +// PRIVATE // + +// You can set this internal macro to stop and debug at a func-trait index. +// define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_ + +#if defined(BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_) && \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_ < \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_AUX_TEMPLATE_INDEX +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_(sign_traits) \ + sign_traits +#else +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_(sign_traits) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_PARSE(sign_traits) +#endif + +#if defined(BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_) && \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_ < \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_AUX_EXPORT_INDEX +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_(sign_traits) \ + sign_traits +#else +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_(sign_traits) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_PARSE(sign_traits) +#endif + +#if defined(BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_) && \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_ < \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_AUX_VERBATIM_INDEX +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_(sign_traits) \ + sign_traits +#else +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_(sign_traits) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_PARSE(sign_traits) +#endif + +#if defined(BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_) && \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_ < \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_AUX_ACCESS_INDEX +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_(sign_traits) \ + sign_traits +#else +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_(sign_traits) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_PARSE(sign_traits) +#endif + +#if defined(BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_) && \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_ < \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_AUX_DONE_INDEX +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DONE_(sign_traits) \ + sign_traits +#else +# define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DONE_(sign_traits) \ + BOOST_PP_TUPLE_ELEM(2, 1, sign_traits) +#endif + +// PUBLIC // + +// Expand specified function signature into its traits. Function traits are +// are inspected using the FUNC_TRAITS macros. +// WARNING: Order of these macros must match ..._INDEX values (see index.hpp). +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS(sign) \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DONE_( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_( \ + ( sign, BOOST_PP_EMPTY() ) \ + ))))) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/func/access.hpp b/include/boost/contract/ext_/preprocessor/traits/func/access.hpp new file mode 100644 index 0000000..4487041 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/func/access.hpp @@ -0,0 +1,60 @@ + +// 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 + +#ifndef BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_HPP_ +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +// PRIVATE // + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_SIGN_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD3_SKIP( \ + sign, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PUBLIC, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PUBLIC_REM, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PROTECTED, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PROTECTED_REM, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PRIVATE, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_PRIVATE_REM \ + ) + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_TRAIT_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK(traits, \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD3( \ + sign, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PUBLIC, public, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PROTECTED, protected, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_PRIVATE, private \ + ) \ + BOOST_PP_EMPTY \ + ) + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_PARSE(sign_traits) \ + ( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_SIGN_ sign_traits \ + , \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS_TRAIT_ sign_traits \ + ) + +// Expand to `public | protected | private | EMPTY()`. +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS(traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_ACCESC, \ + traits \ + )() + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/func/export.hpp b/include/boost/contract/ext_/preprocessor/traits/func/export.hpp new file mode 100644 index 0000000..8da68bc --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/func/export.hpp @@ -0,0 +1,54 @@ + +// 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 + +#ifndef BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_HPP_ +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_HPP_ + +#include +#include +#include +#include +#include + +// NOTE: The `export` keyword for templates was deprecated in C++11 but it is +// supported here for compliance and compatibility with C++03. + +// PRIVATE // + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_SIGN_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_SKIP( \ + sign, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_EXPORT, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_EXPORT_REM \ + ) + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_TRAIT_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK( \ + traits, \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD(sign, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_EXPORT, export) \ + BOOST_PP_EMPTY \ + ) + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_PARSE(sign_traits) \ + ( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_SIGN_ sign_traits \ + , \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_TRAIT_ sign_traits \ + ) + +// Expand to `export | EMPTY()`. +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT(traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_EXPORT, \ + traits \ + )() + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/func/template.hpp b/include/boost/contract/ext_/preprocessor/traits/func/template.hpp new file mode 100644 index 0000000..463def7 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/func/template.hpp @@ -0,0 +1,75 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_HPP_ +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_HPP_ + +#include +#include +#include +#include + +// PRIVATE // + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_SIGN_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN_SKIP( \ + sign, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TEMPLATE, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_REM \ + ) + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_TRAIT_YES_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK( \ + traits, \ + template BOOST_PP_EMPTY \ + ), \ + BOOST_CONTRACT_EXT_PP_TPARAMS_TRAITS( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN( \ + sign, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TEMPLATE, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_REM \ + ) \ + ) + ) + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_TRAIT_NO_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK( \ + traits, \ + BOOST_PP_EMPTY \ + ), \ + BOOST_PP_NIL + ) + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_TRAIT_(sign, traits) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TEMPLATE(sign), \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_TRAIT_YES_ \ + , \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_TRAIT_NO_ \ + )(sign, traits) + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_PARSE(sign_traits) \ + ( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_SIGN_ sign_traits \ + , \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE_TRAIT_ sign_traits \ + ) + +// Expand to `template | EMPTY()`. +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE(traits) + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEMxx( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_TEMPLATE, \ + traits \ + )() + +// Expand to pp-list of function template parameters. Each single template +// parameter in this pp-list is inspected using TPARAM_TRAITS macros. +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TPARAMS(traits) + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEMxx( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_TPARAMS, \ + traits \ + ) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/func/verbatim.hpp b/include/boost/contract/ext_/preprocessor/traits/func/verbatim.hpp new file mode 100644 index 0000000..d533c62 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/func/verbatim.hpp @@ -0,0 +1,48 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_HPP_ +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_HPP_ + +#include +#include +#include +#include +#include + +// PRIVATE // + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_SIGN_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN_SKIP( \ + sign, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_VERBATIM, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VERBATIM_REM \ + ) + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_TRAIT_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK( \ + traits, \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN( \ + sign, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_VERBATIM, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_VERBATIM_REM \ + ) \ + BOOST_PP_EMPTY \ + ) + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_PARSE(sign_traits) \ + ( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_SIGN_ sign_traits \ + , \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM_TRAIT_ sign_traits \ + ) + +// Expand to `(,,,) | EMPTY()`. +#define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM(traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_FUNC_INDEX_VERBATIM, \ + traits \ + )() + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/tparam/default.hpp b/include/boost/contract/ext_/preprocessor/traits/tparam/default.hpp new file mode 100644 index 0000000..c883d46 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/tparam/default.hpp @@ -0,0 +1,60 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_HPP_ +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +// PRIVATE // + +// Precondition: sign is `default ...`. +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_REPLACE_(sign, traits) \ + ( \ + BOOST_PP_EMPTY(), \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_REPLACE( \ + traits, \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_TPARAM_INDEX_DEFAULT, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_DEFAULT_REM(sign) \ + BOOST_PP_EMPTY \ + ) \ + ) + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_PARSE_EMPTY(sign_traits) \ + ( \ + BOOST_PP_TUPLE_ELEM(2, 0, sign_traits), \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK( \ + BOOST_PP_TUPLE_ELEM(2, 1, sign_traits), \ + BOOST_PP_EMPTY \ + ) \ + ) + +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_PARSE_REPLACE_D_S( \ + d, s, sign_traits) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_DEFAULT( \ + BOOST_PP_TUPLE_ELEM(2, 0, sign_traits)), \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_REPLACE_ \ + , \ + sign_traits BOOST_PP_TUPLE_EAT(2) \ + ) sign_traits + +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_PARSE_REPLACE(sign_traits) \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_PARSE_REPLACE_D_S(1, 1, \ + sign_traits) + +// Expand to `(,,,) | EMPTY()`. +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT(traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_TPARAM_INDEX_DEFAULT, \ + traits \ + )() + +#endif // #include guard + + diff --git a/include/boost/contract/ext_/preprocessor/traits/tparam/kind.hpp b/include/boost/contract/ext_/preprocessor/traits/tparam/kind.hpp new file mode 100644 index 0000000..5f68bb3 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/tparam/kind.hpp @@ -0,0 +1,79 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_HPP_ +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include + +// PRIVATE // + +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_SIGN_(sign, traits) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TYPENAME(sign), \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TYPENAME_REM \ + , BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CLASS(sign), \ + BOOST_CONTRACT_EXT_PP_KEYWORD_CLASS_REM \ + , BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TEMPLATE(sign), \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_TEMPLATE_SIGN_ \ + , \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PAREN_TYPE_SKIP \ + )))(sign) + +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_TRAIT_(sign, traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK( \ + traits, \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TYPENAME(sign), \ + typename BOOST_PP_TUPLE_EAT(1) \ + , BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_CLASS(sign), \ + class BOOST_PP_TUPLE_EAT(1) \ + , BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TEMPLATE(sign), \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_TEMPLATE_TRAIT_ \ + , \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PAREN_TYPE \ + )))(sign) \ + ) + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_PARSE(sign_traits) \ + ( \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_SIGN_ sign_traits, \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_TRAIT_ sign_traits \ + ) + +// Expand to `typename | class | (,,,) | template( ,,, ) class` (for type, +// value, and template template parameters respectively). See also +// KIND_TEMPLATE macros below for template template parameters. +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND(traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_TPARAM_INDEX_KIND, \ + traits \ + ) + +// Expand `template( ,,, ) ...` to `( ,,, )` (this is useful to get the +// pp-tuple with the template parameters of a template template parameter). +// Precondition: tokens are `template( ,,, ) ...`. +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_TEMPLATE_PARAMS(tokens) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN( \ + tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TEMPLATE, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_REM \ + ) + +// Expand `template( ,,, ) ...` to `...` (this is useful to get the class +// specifier of a template template parameter, without assuming it is `class`). +// Precondition: tokens are `template( ,,, ) ...`. +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_TEMPLATE_CLASS(tokens) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_KEYWORD_PAREN_SKIP( \ + tokens, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_IS_TEMPLATE, \ + BOOST_CONTRACT_EXT_PP_KEYWORD_TEMPLATE_REM \ + ) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/tparam/name.hpp b/include/boost/contract/ext_/preprocessor/traits/tparam/name.hpp new file mode 100644 index 0000000..ad041a0 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/tparam/name.hpp @@ -0,0 +1,31 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_NAME_HPP_ +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_NAME_HPP_ + +#include +#include +#include +#include + +// PUBLIC // + +// Precondition: name must always be the last remaining token in signature. +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_NAME_PARSE(sign_traits) \ + ( \ + BOOST_PP_EMPTY(), \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PUSH_BACK( \ + BOOST_PP_TUPLE_ELEM(2, 1, sign_traits), \ + BOOST_PP_TUPLE_ELEM(2, 0, sign_traits) \ + BOOST_PP_EMPTY \ + ) \ + ) + +// Expand to `[...] name | EMPTY()` (ellipses `...` for variadic templates). +#define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_NAME(traits) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_ELEM( \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_TPARAM_INDEX_NAME, \ + traits \ + )() + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/traits/tparams.hpp b/include/boost/contract/ext_/preprocessor/traits/tparams.hpp new file mode 100644 index 0000000..56e47d3 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/traits/tparams.hpp @@ -0,0 +1,36 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_TPARAMS_TRAITS_HPP_ +#define BOOST_CONTRACT_EXT_PP_TPARAMS_TRAITS_HPP_ + +#include +#include +#include +#include + +// PRIVATE // + +// When first parsed, a parameter is assumed to have no default value. +#define BOOST_CONTRACT_EXT_PP_TPARAMS_TRAITS_TPARAM_PARSE_D_S_( \ + d, s, sign_traits) \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_PARSE_EMPTY( \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_NAME_PARSE( \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_PARSE( \ + sign_traits \ + ))) + +// PUBLIC // + +#define BOOST_CONTRACT_EXT_PP_TPARAMS_TRAITS_D_S(d, s, sign) \ + BOOST_CONTRACT_EXT_PP_TRAITS_AUX_PARAMS_D_S(d, s, \ + sign, \ + BOOST_CONTRACT_EXT_PP_TPARAMS_TRAITS_TPARAM_PARSE_D_S_, \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_DEFAULT_PARSE_REPLACE_D_S \ + ) + +// Expand specified pp-tuple with template parameters signature into pp-list +// of template parameter traits to inspect using TPARAM_TRAITS macros. +#define BOOST_CONTRACT_EXT_PP_TPARAMS_TRAITS(sign) \ + BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_D_S(1, 1, sign) + +#endif // #include guard + diff --git a/include/boost/contract/ext_/preprocessor/utility/is_empty.hpp b/include/boost/contract/ext_/preprocessor/utility/is_empty.hpp new file mode 100644 index 0000000..593e25f --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/utility/is_empty.hpp @@ -0,0 +1,21 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_IS_EMPTY_HPP_ +#define BOOST_CONTRACT_EXT_PP_IS_EMPTY_HPP_ + +#include +#include +#include +#include + +// PUBLIC // + +// Expand to 1 if tokens are EMPTY(), 0 otherwise (handle tokens with paren). +#define BOOST_CONTRACT_EXT_PP_IS_EMPTY(tokens) \ + BOOST_PP_IIF(BOOST_CONTRACT_EXT_PP_HAS_PAREN(tokens), \ + 0 BOOST_PP_TUPLE_EAT(1) \ + , \ + BOOST_PP_IS_EMPTY \ + )(tokens) + +#endif // #include guard + diff --git a/test/aux_/pp_traits.hpp b/test/aux_/pp_traits.hpp new file mode 100644 index 0000000..3f8b46c --- /dev/null +++ b/test/aux_/pp_traits.hpp @@ -0,0 +1,20 @@ + +#ifndef BOOST_CONTRACT_TEST_AUX_PP_TRAITS_HPP_ +#define BOOST_CONTRACT_TEST_AUX_PP_TRAITS_HPP_ + +#include +#include + +#ifndef BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_DEBUG_AT_ +# define BOOST_CONTRACT_TEST_AUX_PP_TRAITS_CHECK_EQUAL( \ + traits_macro, trait_macro, sign, trait) \ + BOOST_TEST(BOOST_PP_STRINGIZE(trait_macro(traits_macro(sign))) == \ + BOOST_PP_STRINGIZE(trait)); +#else +# define BOOST_CONTRACT_TEST_AUX_PP_TRAITS_CHECK_EQUAL( \ + traits_macro, trait_macro, sign, trait) \ + sign ==> traits_macro(sign) ==> trait +#endif + +#endif // #include guard + diff --git a/test/pp_func_traits/access.cpp b/test/pp_func_traits/access.cpp new file mode 100644 index 0000000..b1b2770 --- /dev/null +++ b/test/pp_func_traits/access.cpp @@ -0,0 +1,23 @@ + +#include "../aux_/pp_traits.hpp" +#include +#include +#include + +#define BOOST_CONTRACT_TEST_(trait) \ + BOOST_CONTRACT_TEST_AUX_PP_TRAITS_CHECK_EQUAL( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS, \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_ACCESS, \ + trait (int&) (f) ( int x, (int&) y ), \ + trait \ + ) + +int main ( ) { + BOOST_CONTRACT_TEST_( BOOST_PP_EMPTY() ) + BOOST_CONTRACT_TEST_( public ) + BOOST_CONTRACT_TEST_( protected ) + BOOST_CONTRACT_TEST_( private ) + + return boost::report_errors(); +} + diff --git a/test/pp_func_traits/export.cpp b/test/pp_func_traits/export.cpp new file mode 100644 index 0000000..fd0fbbe --- /dev/null +++ b/test/pp_func_traits/export.cpp @@ -0,0 +1,21 @@ + +#include "../aux_/pp_traits.hpp" +#include +#include +#include + +#define BOOST_CONTRACT_TEST_(trait) \ + BOOST_CONTRACT_TEST_AUX_PP_TRAITS_CHECK_EQUAL( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS, \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT, \ + trait (int&) (f) ( int x, (int&) y ), \ + trait \ + ) + +int main ( ) { + BOOST_CONTRACT_TEST_( BOOST_PP_EMPTY() ) + BOOST_CONTRACT_TEST_( export ) + + return boost::report_errors(); +} + diff --git a/test/pp_func_traits/template.cpp b/test/pp_func_traits/template.cpp new file mode 100644 index 0000000..8492efd --- /dev/null +++ b/test/pp_func_traits/template.cpp @@ -0,0 +1,83 @@ + +#include "../aux_/pp_traits.hpp" +#include +#include +#include + +#include + +#define BOOST_CONTRACT_TEST_(trait) \ + BOOST_CONTRACT_TEST_AUX_PP_TRAITS_CHECK_EQUAL( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS, \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_TEMPLATE, \ + trait (int&) (f) ( int x, (int&) y ), \ + trait \ + ) + +int main ( ) { + BOOST_CONTRACT_TEST_( BOOST_PP_EMPTY() ) + + BOOST_CONTRACT_TEST_( + template( + typename T, + class U, default (std::pair), + typename... V + ) + ) + + //BOOST_CONTRACT_TEST_( template( class... T ) ) + + //BOOST_CONTRACT_TEST_( template( typename T ) ) + //BOOST_CONTRACT_TEST_( template( typename... T ) ) + + //BOOST_CONTRACT_TEST_( class T, default (std::pair) ) + //BOOST_CONTRACT_TEST_( typename T, default (std::pair) ) + +/* + BOOST_CONTRACT_TEST_( + template( + typename T, + class U, + bool B, + (std::size_t) S, + (std::pair::first_type) I, + template( + typename TT, + class UU, + bool BB, + std::pair::first_type II, + template< + typename TTT, + class UUU, + bool BBB, + std::pair::first_type III + > class PP + ) class P + ) + ) + + BOOST_CONTRACT_TEST_( // Without names. + template( + typename, + class, + bool, + std::size_t, // Also without parenthesis. + (std::pair::first_type), + template( + typename, + class, + bool, + std::pair::first_type, + template< + typename, + class, + bool, + std::pair::first_type + > class + ) class + ) + ) +*/ + return boost::report_errors(); +} + diff --git a/test/pp_func_traits/verbatim.cpp b/test/pp_func_traits/verbatim.cpp new file mode 100644 index 0000000..272c4fe --- /dev/null +++ b/test/pp_func_traits/verbatim.cpp @@ -0,0 +1,48 @@ + +#include "../aux_/pp_traits.hpp" +#include +#include +#include +#include +#include + +#define BOOST_CONTRACT_TEST_(trait) \ + BOOST_CONTRACT_TEST_AUX_PP_TRAITS_CHECK_EQUAL( \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS, \ + BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_VERBATIM, \ + BOOST_PP_EXPR_IIF(BOOST_PP_COMPL( \ + BOOST_CONTRACT_DETAIL_PP_IS_EMPTY(trait)), \ + verbatim trait \ + ) \ + (int&) (f) ( int x, (int&) y ), \ + trait \ + ) + +int main ( ) { + // None. + BOOST_CONTRACT_TEST_( BOOST_PP_EMPTY() ) + + // C++11 attributes with commas. + BOOST_CONTRACT_TEST_( ([[noreturn, deprecated("reason")]]) ) + // Multiple C++11 attributes. + BOOST_CONTRACT_TEST_( ([[noreturn]] [[deprecated("reason")]]) ) + // Single C++11 attribute. + BOOST_CONTRACT_TEST_( ([[export]]) ) + + // MSVC declaration specifications do not allow for commas. + // Multiple MSVC declaration specifications. + BOOST_CONTRACT_TEST_( + (__declspec(noreturn) __declspec(deprecated("reason"))) ) + // Single MSVC declaration specification. + BOOST_CONTRACT_TEST_( (__declspec(dllexport)) ) + + // GCC attributes do not allow for commas. + // Multiple GCC attributes. + BOOST_CONTRACT_TEST_( + (__attribute__((noreturn)) __attribute__((deprecated("reason")))) ) + // Single GCC attribute. + BOOST_CONTRACT_TEST_( (__attribute__((dllexport))) ) + + return boost::report_errors(); +} + diff --git a/tool/boost_setup/cygwin-boost-env.sh b/tool/boost_setup/cygwin-boost-env.sh new file mode 100644 index 0000000..3811c5b --- /dev/null +++ b/tool/boost_setup/cygwin-boost-env.sh @@ -0,0 +1,15 @@ + +# Copyright (C) 2009-2011 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). + +#export BOOST_ROOT="$HOME/Desktop/code/boost/trunk.cyg" +export BOOST_ROOT="$HOME/Desktop/code/boost_1_50_0.cyg" +export PATH="$BOOST_ROOT:$PATH" + +echo "HOME=$HOME" +echo "BOOST_ROOT=$BOOST_ROOT" +echo +echo "Make sure \"$HOME/user-config.jam\" exists and it is correct" + diff --git a/tool/boost_setup/cygwin-user-config.jam b/tool/boost_setup/cygwin-user-config.jam new file mode 100644 index 0000000..311beb2 --- /dev/null +++ b/tool/boost_setup/cygwin-user-config.jam @@ -0,0 +1,10 @@ + +# Copyright (C) 2009-2011 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). + +# Toolset. +using gcc ; +using python ; + diff --git a/tool/boost_setup/linux-boost-env.sh b/tool/boost_setup/linux-boost-env.sh new file mode 100644 index 0000000..95dd4de --- /dev/null +++ b/tool/boost_setup/linux-boost-env.sh @@ -0,0 +1,15 @@ + +# 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 + +export BOOST_ROOT="$HOME/Desktop/code/boost/trunk.linux" +export PATH="$BOOST_ROOT:$PATH" + +echo "HOME=$HOME" +echo "BOOST_ROOT=$BOOST_ROOT" +echo +echo "Make sure \"$HOME/user-config.jam\" exists and it is correct" + diff --git a/tool/boost_setup/linux-user-config.jam b/tool/boost_setup/linux-user-config.jam new file mode 100644 index 0000000..6c8ef93 --- /dev/null +++ b/tool/boost_setup/linux-user-config.jam @@ -0,0 +1,19 @@ + +# 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 + +using gcc ; +using python ; + +# Documentation tools. +using quickbook ; +using xsltproc ; +using boostbook + : "/usr/share/xml/docbook/stylesheet/nwalsh" + : "/usr/share/xml/docbook/schema/dtd/4.2" + ; +using doxygen ; + diff --git a/tool/boost_setup/windows-boost-env.bat b/tool/boost_setup/windows-boost-env.bat new file mode 100644 index 0000000..6239d6e --- /dev/null +++ b/tool/boost_setup/windows-boost-env.bat @@ -0,0 +1,17 @@ + +REM Copyright (C) 2009-2011 Lorenzo Caminiti +REM Use, modification, and distribution is subject to the Boost Software +REM License, Version 1.0 (see accompanying file LICENSE_1_0.txt or a +REM copy at http://www.boost.org/LICENSE_1_0.txt). + +@ECHO OFF + +set BOOST_ROOT=%HOMEDRIVE%%HOMEPATH%\Desktop\code\boost_1_50_0.win +set PATH="C:\PROGRA~2\boost\xml\bin";%BOOST_ROOT%;%PATH% + +ECHO HOME=%HOMEDRIVE%%HOMEPATH% +ECHO BOOST_ROOT=%BOOST_ROOT% +ECHO BOOST_BUILD_PATH=%BOOST_BUILD_PATH% +ECHO. +ECHO Make sure "%HOMEDRIVE%%HOMEPATH%\user-config.jam" exists and it is correct + diff --git a/tool/boost_setup/windows-user-config.jam b/tool/boost_setup/windows-user-config.jam new file mode 100644 index 0000000..84c0838 --- /dev/null +++ b/tool/boost_setup/windows-user-config.jam @@ -0,0 +1,24 @@ + +# Copyright (C) 2009-2011 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). + +# Toolset. +using msvc ; +using python ; + +# Documentation tools +using quickbook : "C:/PROGRA~2/boost/xml/bin/quickbook.exe" : ; +using xsltproc : "C:/PROGRA~2/boost/xml/bin/xsltproc.exe" ; +using boostbook + : "C:/PROGRA~2/boost/xml/docbook-xsl" + : "C:/PROGRA~2/boost/xml/docbook-xml" + ; +using doxygen : "C:/PROGRA~2/doxygen/bin/doxygen.exe" ; +# For PDF documentation. +using fop + : "C:/PROGRA~1/RenderX/XEP/xep.bat" + : "C:/PROGRA~1/Java/jre6/bin" + ; + diff --git a/tool/copyright_header.py b/tool/copyright_header.py new file mode 100644 index 0000000..b7b7fd9 --- /dev/null +++ b/tool/copyright_header.py @@ -0,0 +1,121 @@ + +# 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 + +import sys +import os; +import re; +import getopt; +import sh; + +def parse_args(): + COMMENT_FOR_FILE = { # Comment line start and end characters. + '.cpp': ['// ', ''], + '.hpp': ['// ', ''], + '.qbk': ['[/ ', ' ]'], + '.jam': ['# ', ''], + '.v2': ['# ', ''], + '.py': ['# ', ''], + '.sh': ['# ', ''], + '.bat': ['REM ', ''], + } + START_WORD_DFLT = 'Copyright' # Default header starting word. + HEADER_FILE_DFLT = "../COPYRIGHT.txt" # Default header text file. + + try: + (opts, args) = getopt.getopt(sys.argv[1:], '', []) + if len(args) == 0: + raise getopt.GetoptError('Missing DIR argument') + elif len(args) == 1: + dir = args[0] + header_file = HEADER_FILE_DFLT + start_word = START_WORD_DFLT + elif len(args) == 2: + dir = args[0] + header_file = args[1] + start_word = START_WORD_DFLT + elif len(args) == 3: + dir = args[0] + header_file = args[1] + start_word = args[2] + else: + raise getopt.GetoptError('Too many arguments') + except getopt.GetoptError, err: + print "Error: ", err + print """ +Usage: python %s DIR [HEADER_FILE] [START_WORD] +Replace text starting with the work START_WORD at file's header with the test +from HEADER_FILE. + +All files in DIR with the following extensions are recursively processed: + %s + +Defaults: + HEADER_FILE %s + START_WORD %s +""" % (os.path.split(sys.argv[0])[1], COMMENT_FOR_FILE.keys(), + HEADER_FILE_DFLT, START_WORD_DFLT) + exit(1) + return (dir, header_file, start_word, COMMENT_FOR_FILE) + +class header: + def __init__(self, header_file): + f = open(header_file, 'rU') + self.__lines = [] + for ln in f.xreadlines(): self.__lines.append(ln.rstrip('\n')) + f.close(); + + def text(self, line_start = '// ', line_end = ''): + s = '' + for ln in self.__lines: s = s + line_start + ln + line_end + '\n' + return s + +class replace_header: + def __init__(self, header_file, start_word, comment_for_file): + self.__header = header(header_file) + self.__start_word = start_word + self.__comment_for_file = comment_for_file + + def __call__(self, ln, inheader, file_path, line_num): + if line_num <= 1: sh.info('Updating "' + file_path + '"...') + (ret_ln, ret_inheader) = ('', None) + + (file_root, file_ext) = os.path.splitext(file_path) + comment_start = self.__comment_for_file[file_ext][0] + comment_end = self.__comment_for_file[file_ext][1] + new_header = '\n' + self.__header.text(comment_start, + comment_end) + '\n' + header_start_re = '^' + re.escape(comment_start + + self.__start_word) + '.*$' + header_continue_re = '^' + re.escape(comment_start) + '.*$' + + if inheader is None: # At very top of file. + if re.match('^ *$', ln): # Skip empty lines at top. + (ret_ln, ret_inheader) = ('', None) + elif re.match(header_start_re, ln): # Old header starts. + (ret_ln, ret_inheader) = ('', True) + else: # Old header ends -- replace it. + (ret_ln, ret_inheader) = (new_header + ln, False) + elif inheader: + if re.match(header_continue_re, ln): # In old header -- skip it. + (ret_ln, ret_inheader) = ('', True) + elif re.match('^ *$', ln): # Skip empty lines after old header. + (ret_ln, ret_inheader) = ('', True) + else: # Old header ends -- replace it. + (ret_ln, ret_inheader) = (new_header + ln, False) + else: # Not in nor entering header. + (ret_ln, ret_inheader) = (ln, False) + return (ret_ln, ret_inheader) + +(dir, header_file, start_word, comment_for_file) = parse_args() +replacer = replace_header(header_file, start_word, comment_for_file) +name_re = '' +for file_ext in comment_for_file.keys(): + if name_re != '': name_re = name_re + '|' + name_re = name_re + '(.*' + re.escape(file_ext) + '$)' + +sh.replace(dir, name_re, replacer) + diff --git a/tool/release_instructions.txt b/tool/release_instructions.txt new file mode 100644 index 0000000..c269cbc --- /dev/null +++ b/tool/release_instructions.txt @@ -0,0 +1,54 @@ + +RELEASE INSTRUCTIONS +==================== + +How to release this library version X.Y.Z from SVN trunk to SourceForge (SF). + +1. PREPARE TO RELEASE + +* Make sure all examples and test compiles. +* Make sure that documentation, release version, and release notes are up-to-date. +* Make sure that "trunk/index.html" redirects to "releases/contractpp_X_Y_Z/doc/html/index.html". + +Commit everything (code, documentation, etc) to SVN trunk. + +2. RELEASE BRANCH + +Create a SVN branch for the release X.Y.Z for example from trunk, make sure all code is correctly checked into trunk, then: + + $ svn cp https://contractpp.svn.sourceforge.net/svnroot/contractpp/trunk https://contractpp.svn.sourceforge.net/svnroot/contractpp/releases/contractpp_X_Y_Z + +3. ZIP FILE + +Create a "contractpp_X_Y_Z.zip" file from the release branch (this ZIP file +should not go in SVN, just uploaded it on SF as explained in the next step): + + $ zip contractpp/release/contractpp_X_Y_Z contractpp_X_Y_Z.zip + +4. UPLOAD ZIP FILE TO SF + +Log in to SF website and go to Contract++ page, click Files, then "releases", and then Add File to upload "contract_X_Y_Z.zip". +Click the information icon ("I" icon on the right-hand-side of the file) and select the newly added file as the "Default Download" for all platform then click Save (the file should now show as the "latest version" on the top of the page and SF will link it to the "Download" from the library documentation). + +5. UPLOAD DOCUMENTATION INDEX.HTML + +Using FileZilla connect to the location below and drag-and-drop releases/contract_X_Y_Z/index.html to the project-web/contractpp/htdocs/ localtion: + + Host web.sourceforge.net + Protocol SFTP + Port 22 + Username ... + Password ... + Upload to /home/project-web/contractpp/htdocs + +The LICENSE_1_0.txt and COPYRIGHT.txt files should be copied to this location also (but they might already be there). + +6. FINAL CHECKS + +* Go to the project web http://contractpp.sourceforge.net and check that the latest documentation shows up. +* Click on "Download" for the documentation and check that contractpp_X_Y_Z.zip is downloaded (correct version). + +7. UPDATE INFORMATION ON SF (IF NEEDED) + +Update the information on SF if needed: library release status (pre-alpha, beta, etc), library logo on SF, name, description, feature list, screenshots, etc. + diff --git a/tool/sh.py b/tool/sh.py new file mode 100644 index 0000000..4ed2c18 --- /dev/null +++ b/tool/sh.py @@ -0,0 +1,118 @@ + +# 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 + +import sys +import os +import shutil +import re +import tempfile +import time + +silent = False + +def info(msg, newline = True): + if not silent: + if newline: print msg + else: sys.stdout.write(msg) + +def err(msg): + print "Error:", msg + +def run(cmd): + if os.system(cmd) != 0: + err('Unable to execute command "' + cmd + '"') + exit() + +def quit_if_exist_is(path, exist, err_msg = ""): + if os.access(path, os.F_OK) == exist: + if err_msg == "": + if not exist: err('File path "' + path + '" not found') + else: err('File path "' + path + '" already exists') + else: err(err_msg) + exit() + +def cp(src, dst): + info("Copying: " + src + " -> " + dst) + quit_if_exist_is(src, False) + if os.path.isdir(src): + quit_if_exist_is(dst, True) # `copytree()` requires dst not exist. + shutil.copytree(src, dst) + else: + shutil.copy2(src, dst) + +def mkdir(dir): + if not os.access(dir, os.F_OK): os.makedirs(dir) + +def read(msg = '', default = ''): + if msg != '': info(msg, False) + s = raw_input() + if s == '': s = default + return s + +def rm(path, interactive = True): + if os.access(path, os.F_OK): + if interactive: user_in = '' + else: user_in = 'y' + while user_in != 'y' and user_in != 'n': + user_in = read( + 'Warning: If "y", existing file(s) will be lost!\n' + + 'Override existing path "' + path + '"? (y/n) ') + if user_in == 'y': + if os.path.isdir(path): shutil.rmtree(path) + else: os.remove(path) + else: + err('Unable to override existing path "' + path + + '" -- manually remove it first') + exit() + +def find(dir, name_re, exec_func = None): + found = [] + for root, dirs, files in os.walk(dir): + for dir in dirs: + path = os.path.join(root, dir) + if re.match(name_re, path): + if not exec_func is None: exec_func(path) + found.append(path) + for file in files: + path = os.path.join(root, file) + if re.match(name_re, path): + if not exec_func is None: exec_func(path) + found.append(path) + return found + +# Can be passed as `replace_func` to `replace()` for simple text replace. +class replace_text: + def __init__(self, find_re, repl_txt): + self.__find_re = find_re + self.__repl_txt = repl_txt + def __call__(self, ln, unused, file_name, line_num): + return (re.sub(self.__find_re, self.__repl_txt, ln), unused) + +def replace(dir, name_re, replace_func, data = None): + class _replace_func: + def __init__(self, func, data): + self.__func = func + self.__data = data + def __call__(self, ifile_name): + ifile = open(ifile_name, 'rU') + ofile_name = ifile_name + str(time.time()) # Time for temp file. + ofile = open(ofile_name, 'w') + func = self.__func + data = self.__data # Copy data so self's data not changed. + ln_num = 0 + for ln in ifile.xreadlines(): + ln_num = ln_num + 1 + (repl_ln, repl_data) = func(ln, data, ifile_name, ln_num) + data = repl_data # Update data within this file replacement. + ofile.write(repl_ln) + ifile.close() + ofile.close() + os.remove(ifile.name) + os.rename(ofile.name, ifile.name) + f = _replace_func(replace_func, data) + find(dir, name_re, f) +