From 53dd64c8b2a03816fd4769b5df3cf28e576aa4fc Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Mon, 28 Aug 2017 20:46:52 -0700 Subject: [PATCH] added all release files for 0.3.469 --- COPYRIGHT.txt | 4 + LICENSE_1_0.txt | 27 + Makefile | 62 + README.txt | 23 + bin/README.txt | 1 + bin/env-MSVC8.sh | 18 + bin/release | 78 + bin/release.dat | 4 + doc/Jamfile.v2 | 69 + doc/README.txt | 1 + doc/html/CONTRACT_ASSERT.html | 68 + doc/html/CONTRACT_ASSERT_BLOCK_INVARIANT.html | 75 + .../CONTRACT_ASSERT_BLOCK_INVARIANT_MSG.html | 81 + doc/html/CONTRACT_ASSERT_LOOP_VARIANT.html | 80 + .../CONTRACT_ASSERT_LOOP_VARIANT_MSG.html | 67 + doc/html/CONTRACT_ASSERT_MSG.html | 73 + doc/html/CONTRACT_BODY.html | 80 + doc/html/CONTRACT_CHECK_BLOCK_INVARIANT.html | 47 + doc/html/CONTRACT_CHECK_CLASS_INVARIANT.html | 47 + doc/html/CONTRACT_CHECK_POSTCONDITION.html | 47 + doc/html/CONTRACT_CHECK_PRECONDITION.html | 47 + .../CONTRACT_CONFIG_MAX_FUNCTION_ARITY.html | 65 + ...TRACT_CONFIG_MAX_MULTIPLE_INHERITANCE.html | 46 + doc/html/CONTRACT_CONSTRUCTOR.html | 100 + doc/html/CONTRACT_CONSTRUCTOR_BODY.html | 139 + doc/html/CONTRACT_DESTRUCTOR.html | 92 + doc/html/CONTRACT_DESTRUCTOR_BODY.html | 83 + doc/html/CONTRACT_FUNCTION.html | 103 + doc/html/CONTRACT_INIT_LOOP_VARIANT.html | 57 + doc/html/CONTRACT_INVARIANT.html | 95 + doc/html/CONTRACT_OLDOF.html | 70 + doc/html/CONTRACT_WRAP_TYPE.html | 96 + doc/html/contract/block_invariant_failed.html | 60 + doc/html/contract/class_invariant_failed.html | 60 + doc/html/contract/constructor.html | 177 ++ .../contract/contract_failed_handler.html | 63 + doc/html/contract/copy.html | 159 ++ doc/html/contract/copyable.html | 74 + doc/html/contract/destructor.html | 129 + doc/html/contract/failure.html | 139 + doc/html/contract/from.html | 66 + doc/html/contract/loop_variant_type.html | 56 + doc/html/contract/nonmember_function.html | 166 ++ .../contract/nonstatic_member_function.html | 284 ++ doc/html/contract/postcondition_failed.html | 60 + doc/html/contract/precondition_failed.html | 60 + .../contract/set_block_invariant_failed.html | 63 + .../contract/set_class_invariant_failed.html | 63 + .../contract/set_postcondition_failed.html | 63 + .../contract/set_precondition_failed.html | 63 + doc/html/contract/state.html | 51 + doc/html/contract/static_member_function.html | 175 ++ doc/html/contract/wrap.html | 49 + doc/html/contract/wrap_void_T__id2348632.html | 75 + doc/html/contract__/bibliography.html | 129 + doc/html/contract__/contract_programming.html | 885 ++++++ doc/html/contract__/examples.html | 539 ++++ doc/html/contract__/getting_started.html | 219 ++ doc/html/contract__/license.html | 67 + doc/html/contract__/release_history.html | 154 ++ doc/html/contract__/throw_on_failure.html | 147 + doc/html/contract__/todo.html | 147 + doc/html/contract__/tutorial.html | 2454 +++++++++++++++++ doc/html/contract__/without_the_macros.html | 1407 ++++++++++ doc/html/doc/html/boostbook.css | 594 ++++ doc/html/doc/html/images/alert.png | Bin 0 -> 603 bytes doc/html/doc/html/images/blank.png | Bin 0 -> 374 bytes doc/html/doc/html/images/caution.png | Bin 0 -> 1250 bytes doc/html/doc/html/images/draft.png | Bin 0 -> 17454 bytes doc/html/doc/html/images/home.png | Bin 0 -> 358 bytes doc/html/doc/html/images/important.png | Bin 0 -> 722 bytes doc/html/doc/html/images/next.png | Bin 0 -> 336 bytes doc/html/doc/html/images/next_disabled.png | Bin 0 -> 1110 bytes doc/html/doc/html/images/note.png | Bin 0 -> 490 bytes doc/html/doc/html/images/prev.png | Bin 0 -> 334 bytes doc/html/doc/html/images/prev_disabled.png | Bin 0 -> 1109 bytes doc/html/doc/html/images/smiley.png | Bin 0 -> 867 bytes doc/html/doc/html/images/tip.png | Bin 0 -> 449 bytes doc/html/doc/html/images/toc-blank.png | Bin 0 -> 318 bytes doc/html/doc/html/images/toc-minus.png | Bin 0 -> 259 bytes doc/html/doc/html/images/toc-plus.png | Bin 0 -> 264 bytes doc/html/doc/html/images/up.png | Bin 0 -> 370 bytes doc/html/doc/html/images/up_disabled.png | Bin 0 -> 1115 bytes doc/html/doc/html/images/warning.png | Bin 0 -> 1241 bytes doc/html/doc/src/images/callouts/1.png | Bin 0 -> 391 bytes doc/html/doc/src/images/callouts/1.svg | 15 + doc/html/doc/src/images/callouts/10.png | Bin 0 -> 485 bytes doc/html/doc/src/images/callouts/10.svg | 18 + doc/html/doc/src/images/callouts/11.png | Bin 0 -> 410 bytes doc/html/doc/src/images/callouts/11.svg | 16 + doc/html/doc/src/images/callouts/12.png | Bin 0 -> 488 bytes doc/html/doc/src/images/callouts/12.svg | 18 + doc/html/doc/src/images/callouts/13.png | Bin 0 -> 509 bytes doc/html/doc/src/images/callouts/13.svg | 20 + doc/html/doc/src/images/callouts/14.png | Bin 0 -> 499 bytes doc/html/doc/src/images/callouts/14.svg | 17 + doc/html/doc/src/images/callouts/15.png | Bin 0 -> 507 bytes doc/html/doc/src/images/callouts/15.svg | 19 + doc/html/doc/src/images/callouts/16.svg | 20 + doc/html/doc/src/images/callouts/17.svg | 17 + doc/html/doc/src/images/callouts/18.svg | 21 + doc/html/doc/src/images/callouts/19.svg | 20 + doc/html/doc/src/images/callouts/2.png | Bin 0 -> 446 bytes doc/html/doc/src/images/callouts/2.svg | 17 + doc/html/doc/src/images/callouts/20.svg | 20 + doc/html/doc/src/images/callouts/21.svg | 18 + doc/html/doc/src/images/callouts/22.svg | 20 + doc/html/doc/src/images/callouts/23.svg | 22 + doc/html/doc/src/images/callouts/24.svg | 19 + doc/html/doc/src/images/callouts/25.svg | 21 + doc/html/doc/src/images/callouts/26.svg | 22 + doc/html/doc/src/images/callouts/27.svg | 19 + doc/html/doc/src/images/callouts/28.svg | 23 + doc/html/doc/src/images/callouts/29.svg | 22 + doc/html/doc/src/images/callouts/3.png | Bin 0 -> 431 bytes doc/html/doc/src/images/callouts/3.svg | 19 + doc/html/doc/src/images/callouts/30.svg | 22 + doc/html/doc/src/images/callouts/4.png | Bin 0 -> 441 bytes doc/html/doc/src/images/callouts/4.svg | 16 + doc/html/doc/src/images/callouts/5.png | Bin 0 -> 423 bytes doc/html/doc/src/images/callouts/5.svg | 18 + doc/html/doc/src/images/callouts/6.png | Bin 0 -> 431 bytes doc/html/doc/src/images/callouts/6.svg | 19 + doc/html/doc/src/images/callouts/7.png | Bin 0 -> 397 bytes doc/html/doc/src/images/callouts/7.svg | 16 + doc/html/doc/src/images/callouts/8.png | Bin 0 -> 434 bytes doc/html/doc/src/images/callouts/8.svg | 20 + doc/html/doc/src/images/callouts/9.png | Bin 0 -> 420 bytes doc/html/doc/src/images/callouts/9.svg | 19 + doc/html/example/Crowl2006/README.txt | 2 + doc/html/example/Crowl2006/block/main.cpp | 21 + doc/html/example/Crowl2006/circle/main.cpp | 60 + doc/html/example/Crowl2006/factorial/main.cpp | 35 + .../Crowl2006/operator_equal/equal.hpp | 27 + .../example/Crowl2006/operator_equal/main.cpp | 24 + .../Crowl2006/operator_equal/not_equal.hpp | 26 + doc/html/example/Crowl2006/sqrt/main.cpp | 35 + doc/html/example/Crowl2006/sum/main.cpp | 16 + doc/html/example/Crowl2006/sum/sum.cpp | 13 + doc/html/example/Crowl2006/sum/sum.hpp | 23 + doc/html/example/Crowl2006/vector/main.cpp | 617 +++++ doc/html/example/Makefile | 135 + doc/html/example/Meyer1997/README.txt | 2 + doc/html/example/Meyer1997/gcd/main.cpp | 54 + doc/html/example/Meyer1997/maxarray/main.cpp | 41 + doc/html/example/Meyer1997/stack3/main.cpp | 38 + doc/html/example/Meyer1997/stack3/stack3.hpp | 186 ++ doc/html/example/Meyer1997/stack4/main.cpp | 38 + doc/html/example/Meyer1997/stack4/stack4.hpp | 227 ++ doc/html/example/Mitchell2002/README.txt | 2 + .../example/Mitchell2002/counter/counter.hpp | 69 + .../Mitchell2002/counter/decrement_button.hpp | 123 + .../example/Mitchell2002/counter/main.cpp | 38 + .../Mitchell2002/counter/push_button.hpp | 79 + .../Mitchell2002/counter/view_of_counter.hpp | 52 + .../example/Mitchell2002/courier/couriers.cpp | 44 + .../example/Mitchell2002/courier/couriers.hpp | 175 ++ .../example/Mitchell2002/courier/main.cpp | 34 + .../customer_manager/customer_manager.cpp | 39 + .../customer_manager/customer_manager.hpp | 159 ++ .../Mitchell2002/customer_manager/main.cpp | 32 + .../Mitchell2002/dictionary/dictionary.hpp | 117 + .../example/Mitchell2002/dictionary/main.cpp | 32 + .../example/Mitchell2002/name_list/main.cpp | 28 + .../example/Mitchell2002/name_list/names.cpp | 47 + .../example/Mitchell2002/name_list/names.hpp | 127 + .../example/Mitchell2002/observe/main.cpp | 81 + .../example/Mitchell2002/observe/observe.hpp | 184 ++ .../Mitchell2002/simple_queue/main.cpp | 46 + .../simple_queue/simple_queue.hpp | 164 ++ doc/html/example/Mitchell2002/stack/main.cpp | 32 + doc/html/example/Mitchell2002/stack/stack.hpp | 127 + doc/html/example/README.txt | 6 + doc/html/example/Stroustrup1997/README.txt | 1 + .../example/Stroustrup1997/string/main.cpp | 19 + .../example/Stroustrup1997/string/string.cpp | 24 + .../example/Stroustrup1997/string/string.hpp | 70 + doc/html/example/commas/README.txt | 1 + doc/html/example/commas/main.cpp | 58 + doc/html/example/myvector/README.txt | 1 + doc/html/example/myvector/basic_begin.hpp | 32 + doc/html/example/myvector/boundable.hpp | 34 + doc/html/example/myvector/main.cpp | 46 + doc/html/example/myvector/main_nomacros.cpp | 27 + doc/html/example/myvector/myvector.hpp | 245 ++ .../example/myvector/myvector_nomacros.hpp | 320 +++ doc/html/example/myvector/pushable.hpp | 38 + doc/html/example/throw/README.txt | 2 + doc/html/example/throw/main.cpp | 75 + doc/html/index.html | 377 +++ doc/html/reference.html | 233 ++ doc/html/standalone_HTML.manifest | 56 + doc/qbk/README.txt | 1 + doc/qbk/bibliography.qbk | 47 + doc/qbk/contract.qbk | 176 ++ doc/qbk/contract_programming.qbk | 236 ++ doc/qbk/examples.qbk | 180 ++ doc/qbk/getting_started.qbk | 86 + doc/qbk/introduction.qbk | 61 + doc/qbk/license.qbk | 41 + doc/qbk/navbar.xsl | 345 +++ doc/qbk/release_history.qbk | 50 + doc/qbk/src/README.txt | 1 + doc/qbk/src/contract.hpp | 76 + doc/qbk/src/contract/README.txt | 1 + doc/qbk/src/contract/assert.hpp | 265 ++ doc/qbk/src/contract/block.hpp | 237 ++ doc/qbk/src/contract/body.hpp | 179 ++ doc/qbk/src/contract/config.hpp | 59 + doc/qbk/src/contract/constructor.hpp | 116 + doc/qbk/src/contract/destructor.hpp | 78 + doc/qbk/src/contract/from.hpp | 40 + doc/qbk/src/contract/macros.hpp | 332 +++ doc/qbk/src/contract/nonmember_function.hpp | 114 + .../contract/nonstatic_member_function.hpp | 202 ++ doc/qbk/src/contract/old.hpp | 194 ++ doc/qbk/src/contract/state.hpp | 29 + .../src/contract/static_member_function.hpp | 116 + doc/qbk/src/contract/wrap.hpp | 110 + doc/qbk/stubs/README.txt | 2 + doc/qbk/stubs/myvector_stub.cpp | 41 + doc/qbk/throw_on_failure.qbk | 18 + doc/qbk/todo.qbk | 213 ++ doc/qbk/tutorial.qbk | 1071 +++++++ doc/qbk/without_the_macros.qbk | 583 ++++ example/Crowl2006/README.txt | 2 + example/Crowl2006/block/main.cpp | 21 + example/Crowl2006/circle/main.cpp | 60 + example/Crowl2006/factorial/main.cpp | 35 + example/Crowl2006/operator_equal/equal.hpp | 27 + example/Crowl2006/operator_equal/main.cpp | 24 + .../Crowl2006/operator_equal/not_equal.hpp | 26 + example/Crowl2006/sqrt/main.cpp | 35 + example/Crowl2006/sum/main.cpp | 16 + example/Crowl2006/sum/sum.cpp | 13 + example/Crowl2006/sum/sum.hpp | 23 + example/Crowl2006/vector/main.cpp | 617 +++++ example/Makefile | 135 + example/Meyer1997/README.txt | 2 + example/Meyer1997/gcd/main.cpp | 54 + example/Meyer1997/maxarray/main.cpp | 41 + example/Meyer1997/stack3/main.cpp | 38 + example/Meyer1997/stack3/stack3.hpp | 186 ++ example/Meyer1997/stack4/main.cpp | 38 + example/Meyer1997/stack4/stack4.hpp | 227 ++ example/Mitchell2002/README.txt | 2 + example/Mitchell2002/counter/counter.hpp | 69 + .../Mitchell2002/counter/decrement_button.hpp | 123 + example/Mitchell2002/counter/main.cpp | 38 + example/Mitchell2002/counter/push_button.hpp | 79 + .../Mitchell2002/counter/view_of_counter.hpp | 52 + example/Mitchell2002/courier/couriers.cpp | 44 + example/Mitchell2002/courier/couriers.hpp | 175 ++ example/Mitchell2002/courier/main.cpp | 34 + .../customer_manager/customer_manager.cpp | 39 + .../customer_manager/customer_manager.hpp | 159 ++ .../Mitchell2002/customer_manager/main.cpp | 32 + .../Mitchell2002/dictionary/dictionary.hpp | 117 + example/Mitchell2002/dictionary/main.cpp | 32 + example/Mitchell2002/name_list/main.cpp | 28 + example/Mitchell2002/name_list/names.cpp | 47 + example/Mitchell2002/name_list/names.hpp | 127 + example/Mitchell2002/observe/main.cpp | 81 + example/Mitchell2002/observe/observe.hpp | 184 ++ example/Mitchell2002/simple_queue/main.cpp | 46 + .../simple_queue/simple_queue.hpp | 164 ++ example/Mitchell2002/stack/main.cpp | 32 + example/Mitchell2002/stack/stack.hpp | 127 + example/README.txt | 6 + example/Stroustrup1997/README.txt | 1 + example/Stroustrup1997/string/main.cpp | 19 + example/Stroustrup1997/string/string.cpp | 24 + example/Stroustrup1997/string/string.hpp | 70 + example/commas/README.txt | 1 + example/commas/main.cpp | 58 + example/myvector/README.txt | 1 + example/myvector/basic_begin.hpp | 32 + example/myvector/boundable.hpp | 34 + example/myvector/main.cpp | 46 + example/myvector/main_nomacros.cpp | 27 + example/myvector/myvector.hpp | 245 ++ example/myvector/myvector_nomacros.hpp | 320 +++ example/myvector/pushable.hpp | 38 + example/throw/README.txt | 2 + example/throw/main.cpp | 75 + src/README.txt | 1 + src/contract.hpp | 60 + src/contract/README.txt | 1 + src/contract/assert.hpp | 136 + src/contract/aux_/README.txt | 4 + src/contract/aux_/arg.hpp | 71 + src/contract/aux_/assert.hpp | 88 + src/contract/aux_/check01.hpp | 47 + src/contract/aux_/checking.hpp | 18 + src/contract/aux_/debug.hpp | 39 + src/contract/aux_/function/README.txt | 1 + .../function/contract_class_implement.hpp | 729 +++++ .../aux_/function/local_macros_define.hpp | 322 +++ .../aux_/function/local_macros_undef.hpp | 56 + .../aux_/function/void_base_contract.hpp | 126 + src/contract/aux_/macros/README.txt | 1 + src/contract/aux_/macros/code_/README.txt | 1 + src/contract/aux_/macros/code_/args.hpp | 28 + src/contract/aux_/macros/code_/body.hpp | 23 + .../aux_/macros/code_/contract_class.hpp | 151 + .../aux_/macros/code_/contract_name.hpp | 70 + .../aux_/macros/code_/contracted_function.hpp | 58 + .../aux_/macros/code_/function_sign.hpp | 91 + .../aux_/macros/code_/function_template.hpp | 110 + src/contract/aux_/macros/code_/kind.hpp | 14 + .../aux_/macros/code_/postcondition.hpp | 102 + .../aux_/macros/code_/precondition.hpp | 61 + .../aux_/macros/code_/static_error.hpp | 20 + .../aux_/macros/code_/static_validate.hpp | 44 + src/contract/aux_/macros/code_function.hpp | 158 ++ src/contract/aux_/macros/code_invariant.hpp | 29 + src/contract/aux_/macros/function.hpp | 52 + src/contract/aux_/macros/invariant.hpp | 67 + src/contract/aux_/old.hpp | 38 + src/contract/aux_/preprocessor/README.txt | 1 + .../aux_/preprocessor/keyword/README.txt | 1 + .../aux_/preprocessor/keyword/check_.hpp | 32 + .../aux_/preprocessor/keyword/is_body.hpp | 20 + .../aux_/preprocessor/keyword/is_class.hpp | 20 + .../aux_/preprocessor/keyword/is_const.hpp | 20 + .../aux_/preprocessor/keyword/is_copyable.hpp | 20 + .../aux_/preprocessor/keyword/is_inherit.hpp | 20 + .../aux_/preprocessor/keyword/is_operator.hpp | 20 + .../preprocessor/keyword/is_postcondition.hpp | 20 + .../preprocessor/keyword/is_precondition.hpp | 20 + .../aux_/preprocessor/keyword/is_private.hpp | 20 + .../preprocessor/keyword/is_protected.hpp | 20 + .../aux_/preprocessor/keyword/is_public.hpp | 20 + .../aux_/preprocessor/keyword/is_static.hpp | 20 + .../aux_/preprocessor/keyword/is_template.hpp | 20 + .../aux_/preprocessor/keyword/is_virtual.hpp | 20 + .../aux_/preprocessor/keyword/is_void.hpp | 20 + src/contract/aux_/preprocessor/seq.hpp | 30 + .../aux_/preprocessor/sign/README.txt | 1 + .../aux_/preprocessor/sign/access.hpp | 31 + src/contract/aux_/preprocessor/sign/arg.hpp | 60 + src/contract/aux_/preprocessor/sign/args.hpp | 30 + .../aux_/preprocessor/sign/base_types.hpp | 28 + src/contract/aux_/preprocessor/sign/body.hpp | 16 + src/contract/aux_/preprocessor/sign/class.hpp | 20 + .../aux_/preprocessor/sign/class_type.hpp | 23 + src/contract/aux_/preprocessor/sign/const.hpp | 20 + .../aux_/preprocessor/sign/function_name.hpp | 53 + .../sign/function_template_args.hpp | 34 + .../aux_/preprocessor/sign/parse_/README.txt | 1 + .../aux_/preprocessor/sign/parse_/access.hpp | 76 + .../aux_/preprocessor/sign/parse_/args.hpp | 287 ++ .../preprocessor/sign/parse_/base_types.hpp | 83 + .../aux_/preprocessor/sign/parse_/body.hpp | 20 + .../aux_/preprocessor/sign/parse_/class.hpp | 17 + .../preprocessor/sign/parse_/class_type.hpp | 51 + .../aux_/preprocessor/sign/parse_/const.hpp | 26 + .../sign/parse_/function_name.hpp | 16 + .../sign/parse_/postcondition.hpp | 59 + .../preprocessor/sign/parse_/precondition.hpp | 29 + .../preprocessor/sign/parse_/result_type.hpp | 26 + .../aux_/preprocessor/sign/parse_/static.hpp | 26 + .../preprocessor/sign/parse_/template.hpp | 48 + .../sign/parse_/utility/README.txt | 1 + .../sign/parse_/utility/append_traits.hpp | 27 + .../sign/parse_/utility/apply.hpp | 41 + .../sign/parse_/utility/block.hpp | 120 + .../sign/parse_/utility/copyable.hpp | 36 + .../sign/parse_/utility/match_not.hpp | 43 + .../preprocessor/sign/parse_/utility/next.hpp | 30 + .../sign/parse_/utility/optional.hpp | 44 + .../sign/parse_/utility/required.hpp | 69 + .../sign/parse_/utility/returns.hpp | 34 + .../preprocessor/sign/parse_/validate.hpp | 146 + .../aux_/preprocessor/sign/parse_/virtual.hpp | 26 + .../preprocessor/sign/parse_constructor.hpp | 50 + .../preprocessor/sign/parse_destructor.hpp | 50 + .../aux_/preprocessor/sign/parse_function.hpp | 82 + .../aux_/preprocessor/sign/postcondition.hpp | 22 + .../aux_/preprocessor/sign/precondition.hpp | 17 + .../aux_/preprocessor/sign/result_type.hpp | 22 + src/contract/aux_/preprocessor/sign/seq_.hpp | 74 + .../aux_/preprocessor/sign/static.hpp | 21 + .../aux_/preprocessor/sign/virtual.hpp | 21 + src/contract/aux_/symbol.hpp | 19 + src/contract/aux_/sync.hpp | 27 + src/contract/block.hpp | 91 + src/contract/body.hpp | 54 + src/contract/config.hpp | 80 + src/contract/constructor.hpp | 165 ++ src/contract/destructor.hpp | 85 + src/contract/from.hpp | 27 + src/contract/macros.hpp | 31 + src/contract/nonmember_function.hpp | 104 + src/contract/nonstatic_member_function.hpp | 141 + src/contract/old.hpp | 84 + src/contract/state.hpp | 69 + src/contract/static_member_function.hpp | 155 ++ src/contract/wrap.hpp | 57 + svnignore | 5 + test/Makefile | 48 + test/README.txt | 2 + test/overloading/main.cpp | 167 ++ test/subcontracting/main.cpp | 161 ++ test/templates/main.cpp | 38 + test/usages/main.cpp | 156 ++ 406 files changed, 33285 insertions(+) create mode 100755 COPYRIGHT.txt create mode 100755 LICENSE_1_0.txt create mode 100755 Makefile create mode 100755 README.txt create mode 100755 bin/README.txt create mode 100755 bin/env-MSVC8.sh create mode 100755 bin/release create mode 100755 bin/release.dat create mode 100755 doc/Jamfile.v2 create mode 100755 doc/README.txt create mode 100755 doc/html/CONTRACT_ASSERT.html create mode 100755 doc/html/CONTRACT_ASSERT_BLOCK_INVARIANT.html create mode 100755 doc/html/CONTRACT_ASSERT_BLOCK_INVARIANT_MSG.html create mode 100755 doc/html/CONTRACT_ASSERT_LOOP_VARIANT.html create mode 100755 doc/html/CONTRACT_ASSERT_LOOP_VARIANT_MSG.html create mode 100755 doc/html/CONTRACT_ASSERT_MSG.html create mode 100755 doc/html/CONTRACT_BODY.html create mode 100755 doc/html/CONTRACT_CHECK_BLOCK_INVARIANT.html create mode 100755 doc/html/CONTRACT_CHECK_CLASS_INVARIANT.html create mode 100755 doc/html/CONTRACT_CHECK_POSTCONDITION.html create mode 100755 doc/html/CONTRACT_CHECK_PRECONDITION.html create mode 100755 doc/html/CONTRACT_CONFIG_MAX_FUNCTION_ARITY.html create mode 100755 doc/html/CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE.html create mode 100755 doc/html/CONTRACT_CONSTRUCTOR.html create mode 100755 doc/html/CONTRACT_CONSTRUCTOR_BODY.html create mode 100755 doc/html/CONTRACT_DESTRUCTOR.html create mode 100755 doc/html/CONTRACT_DESTRUCTOR_BODY.html create mode 100755 doc/html/CONTRACT_FUNCTION.html create mode 100755 doc/html/CONTRACT_INIT_LOOP_VARIANT.html create mode 100755 doc/html/CONTRACT_INVARIANT.html create mode 100755 doc/html/CONTRACT_OLDOF.html create mode 100755 doc/html/CONTRACT_WRAP_TYPE.html create mode 100755 doc/html/contract/block_invariant_failed.html create mode 100755 doc/html/contract/class_invariant_failed.html create mode 100755 doc/html/contract/constructor.html create mode 100755 doc/html/contract/contract_failed_handler.html create mode 100755 doc/html/contract/copy.html create mode 100755 doc/html/contract/copyable.html create mode 100755 doc/html/contract/destructor.html create mode 100755 doc/html/contract/failure.html create mode 100755 doc/html/contract/from.html create mode 100755 doc/html/contract/loop_variant_type.html create mode 100755 doc/html/contract/nonmember_function.html create mode 100755 doc/html/contract/nonstatic_member_function.html create mode 100755 doc/html/contract/postcondition_failed.html create mode 100755 doc/html/contract/precondition_failed.html create mode 100755 doc/html/contract/set_block_invariant_failed.html create mode 100755 doc/html/contract/set_class_invariant_failed.html create mode 100755 doc/html/contract/set_postcondition_failed.html create mode 100755 doc/html/contract/set_precondition_failed.html create mode 100755 doc/html/contract/state.html create mode 100755 doc/html/contract/static_member_function.html create mode 100755 doc/html/contract/wrap.html create mode 100755 doc/html/contract/wrap_void_T__id2348632.html create mode 100755 doc/html/contract__/bibliography.html create mode 100755 doc/html/contract__/contract_programming.html create mode 100755 doc/html/contract__/examples.html create mode 100755 doc/html/contract__/getting_started.html create mode 100755 doc/html/contract__/license.html create mode 100755 doc/html/contract__/release_history.html create mode 100755 doc/html/contract__/throw_on_failure.html create mode 100755 doc/html/contract__/todo.html create mode 100755 doc/html/contract__/tutorial.html create mode 100755 doc/html/contract__/without_the_macros.html create mode 100755 doc/html/doc/html/boostbook.css create mode 100755 doc/html/doc/html/images/alert.png create mode 100755 doc/html/doc/html/images/blank.png create mode 100755 doc/html/doc/html/images/caution.png create mode 100755 doc/html/doc/html/images/draft.png create mode 100755 doc/html/doc/html/images/home.png create mode 100755 doc/html/doc/html/images/important.png create mode 100755 doc/html/doc/html/images/next.png create mode 100755 doc/html/doc/html/images/next_disabled.png create mode 100755 doc/html/doc/html/images/note.png create mode 100755 doc/html/doc/html/images/prev.png create mode 100755 doc/html/doc/html/images/prev_disabled.png create mode 100755 doc/html/doc/html/images/smiley.png create mode 100755 doc/html/doc/html/images/tip.png create mode 100755 doc/html/doc/html/images/toc-blank.png create mode 100755 doc/html/doc/html/images/toc-minus.png create mode 100755 doc/html/doc/html/images/toc-plus.png create mode 100755 doc/html/doc/html/images/up.png create mode 100755 doc/html/doc/html/images/up_disabled.png create mode 100755 doc/html/doc/html/images/warning.png create mode 100755 doc/html/doc/src/images/callouts/1.png create mode 100755 doc/html/doc/src/images/callouts/1.svg create mode 100755 doc/html/doc/src/images/callouts/10.png create mode 100755 doc/html/doc/src/images/callouts/10.svg create mode 100755 doc/html/doc/src/images/callouts/11.png create mode 100755 doc/html/doc/src/images/callouts/11.svg create mode 100755 doc/html/doc/src/images/callouts/12.png create mode 100755 doc/html/doc/src/images/callouts/12.svg create mode 100755 doc/html/doc/src/images/callouts/13.png create mode 100755 doc/html/doc/src/images/callouts/13.svg create mode 100755 doc/html/doc/src/images/callouts/14.png create mode 100755 doc/html/doc/src/images/callouts/14.svg create mode 100755 doc/html/doc/src/images/callouts/15.png create mode 100755 doc/html/doc/src/images/callouts/15.svg create mode 100755 doc/html/doc/src/images/callouts/16.svg create mode 100755 doc/html/doc/src/images/callouts/17.svg create mode 100755 doc/html/doc/src/images/callouts/18.svg create mode 100755 doc/html/doc/src/images/callouts/19.svg create mode 100755 doc/html/doc/src/images/callouts/2.png create mode 100755 doc/html/doc/src/images/callouts/2.svg create mode 100755 doc/html/doc/src/images/callouts/20.svg create mode 100755 doc/html/doc/src/images/callouts/21.svg create mode 100755 doc/html/doc/src/images/callouts/22.svg create mode 100755 doc/html/doc/src/images/callouts/23.svg create mode 100755 doc/html/doc/src/images/callouts/24.svg create mode 100755 doc/html/doc/src/images/callouts/25.svg create mode 100755 doc/html/doc/src/images/callouts/26.svg create mode 100755 doc/html/doc/src/images/callouts/27.svg create mode 100755 doc/html/doc/src/images/callouts/28.svg create mode 100755 doc/html/doc/src/images/callouts/29.svg create mode 100755 doc/html/doc/src/images/callouts/3.png create mode 100755 doc/html/doc/src/images/callouts/3.svg create mode 100755 doc/html/doc/src/images/callouts/30.svg create mode 100755 doc/html/doc/src/images/callouts/4.png create mode 100755 doc/html/doc/src/images/callouts/4.svg create mode 100755 doc/html/doc/src/images/callouts/5.png create mode 100755 doc/html/doc/src/images/callouts/5.svg create mode 100755 doc/html/doc/src/images/callouts/6.png create mode 100755 doc/html/doc/src/images/callouts/6.svg create mode 100755 doc/html/doc/src/images/callouts/7.png create mode 100755 doc/html/doc/src/images/callouts/7.svg create mode 100755 doc/html/doc/src/images/callouts/8.png create mode 100755 doc/html/doc/src/images/callouts/8.svg create mode 100755 doc/html/doc/src/images/callouts/9.png create mode 100755 doc/html/doc/src/images/callouts/9.svg create mode 100755 doc/html/example/Crowl2006/README.txt create mode 100755 doc/html/example/Crowl2006/block/main.cpp create mode 100755 doc/html/example/Crowl2006/circle/main.cpp create mode 100755 doc/html/example/Crowl2006/factorial/main.cpp create mode 100755 doc/html/example/Crowl2006/operator_equal/equal.hpp create mode 100755 doc/html/example/Crowl2006/operator_equal/main.cpp create mode 100755 doc/html/example/Crowl2006/operator_equal/not_equal.hpp create mode 100755 doc/html/example/Crowl2006/sqrt/main.cpp create mode 100755 doc/html/example/Crowl2006/sum/main.cpp create mode 100755 doc/html/example/Crowl2006/sum/sum.cpp create mode 100755 doc/html/example/Crowl2006/sum/sum.hpp create mode 100755 doc/html/example/Crowl2006/vector/main.cpp create mode 100755 doc/html/example/Makefile create mode 100755 doc/html/example/Meyer1997/README.txt create mode 100755 doc/html/example/Meyer1997/gcd/main.cpp create mode 100755 doc/html/example/Meyer1997/maxarray/main.cpp create mode 100755 doc/html/example/Meyer1997/stack3/main.cpp create mode 100755 doc/html/example/Meyer1997/stack3/stack3.hpp create mode 100755 doc/html/example/Meyer1997/stack4/main.cpp create mode 100755 doc/html/example/Meyer1997/stack4/stack4.hpp create mode 100755 doc/html/example/Mitchell2002/README.txt create mode 100755 doc/html/example/Mitchell2002/counter/counter.hpp create mode 100755 doc/html/example/Mitchell2002/counter/decrement_button.hpp create mode 100755 doc/html/example/Mitchell2002/counter/main.cpp create mode 100755 doc/html/example/Mitchell2002/counter/push_button.hpp create mode 100755 doc/html/example/Mitchell2002/counter/view_of_counter.hpp create mode 100755 doc/html/example/Mitchell2002/courier/couriers.cpp create mode 100755 doc/html/example/Mitchell2002/courier/couriers.hpp create mode 100755 doc/html/example/Mitchell2002/courier/main.cpp create mode 100755 doc/html/example/Mitchell2002/customer_manager/customer_manager.cpp create mode 100755 doc/html/example/Mitchell2002/customer_manager/customer_manager.hpp create mode 100755 doc/html/example/Mitchell2002/customer_manager/main.cpp create mode 100755 doc/html/example/Mitchell2002/dictionary/dictionary.hpp create mode 100755 doc/html/example/Mitchell2002/dictionary/main.cpp create mode 100755 doc/html/example/Mitchell2002/name_list/main.cpp create mode 100755 doc/html/example/Mitchell2002/name_list/names.cpp create mode 100755 doc/html/example/Mitchell2002/name_list/names.hpp create mode 100755 doc/html/example/Mitchell2002/observe/main.cpp create mode 100755 doc/html/example/Mitchell2002/observe/observe.hpp create mode 100755 doc/html/example/Mitchell2002/simple_queue/main.cpp create mode 100755 doc/html/example/Mitchell2002/simple_queue/simple_queue.hpp create mode 100755 doc/html/example/Mitchell2002/stack/main.cpp create mode 100755 doc/html/example/Mitchell2002/stack/stack.hpp create mode 100755 doc/html/example/README.txt create mode 100755 doc/html/example/Stroustrup1997/README.txt create mode 100755 doc/html/example/Stroustrup1997/string/main.cpp create mode 100755 doc/html/example/Stroustrup1997/string/string.cpp create mode 100755 doc/html/example/Stroustrup1997/string/string.hpp create mode 100755 doc/html/example/commas/README.txt create mode 100755 doc/html/example/commas/main.cpp create mode 100755 doc/html/example/myvector/README.txt create mode 100755 doc/html/example/myvector/basic_begin.hpp create mode 100755 doc/html/example/myvector/boundable.hpp create mode 100755 doc/html/example/myvector/main.cpp create mode 100755 doc/html/example/myvector/main_nomacros.cpp create mode 100755 doc/html/example/myvector/myvector.hpp create mode 100755 doc/html/example/myvector/myvector_nomacros.hpp create mode 100755 doc/html/example/myvector/pushable.hpp create mode 100755 doc/html/example/throw/README.txt create mode 100755 doc/html/example/throw/main.cpp create mode 100755 doc/html/index.html create mode 100755 doc/html/reference.html create mode 100755 doc/html/standalone_HTML.manifest create mode 100755 doc/qbk/README.txt create mode 100755 doc/qbk/bibliography.qbk create mode 100755 doc/qbk/contract.qbk create mode 100755 doc/qbk/contract_programming.qbk create mode 100755 doc/qbk/examples.qbk create mode 100755 doc/qbk/getting_started.qbk create mode 100755 doc/qbk/introduction.qbk create mode 100755 doc/qbk/license.qbk create mode 100755 doc/qbk/navbar.xsl create mode 100755 doc/qbk/release_history.qbk create mode 100755 doc/qbk/src/README.txt create mode 100755 doc/qbk/src/contract.hpp create mode 100755 doc/qbk/src/contract/README.txt create mode 100755 doc/qbk/src/contract/assert.hpp create mode 100755 doc/qbk/src/contract/block.hpp create mode 100755 doc/qbk/src/contract/body.hpp create mode 100755 doc/qbk/src/contract/config.hpp create mode 100755 doc/qbk/src/contract/constructor.hpp create mode 100755 doc/qbk/src/contract/destructor.hpp create mode 100755 doc/qbk/src/contract/from.hpp create mode 100755 doc/qbk/src/contract/macros.hpp create mode 100755 doc/qbk/src/contract/nonmember_function.hpp create mode 100755 doc/qbk/src/contract/nonstatic_member_function.hpp create mode 100755 doc/qbk/src/contract/old.hpp create mode 100755 doc/qbk/src/contract/state.hpp create mode 100755 doc/qbk/src/contract/static_member_function.hpp create mode 100755 doc/qbk/src/contract/wrap.hpp create mode 100755 doc/qbk/stubs/README.txt create mode 100755 doc/qbk/stubs/myvector_stub.cpp create mode 100755 doc/qbk/throw_on_failure.qbk create mode 100755 doc/qbk/todo.qbk create mode 100755 doc/qbk/tutorial.qbk create mode 100755 doc/qbk/without_the_macros.qbk create mode 100755 example/Crowl2006/README.txt create mode 100755 example/Crowl2006/block/main.cpp create mode 100755 example/Crowl2006/circle/main.cpp create mode 100755 example/Crowl2006/factorial/main.cpp create mode 100755 example/Crowl2006/operator_equal/equal.hpp create mode 100755 example/Crowl2006/operator_equal/main.cpp create mode 100755 example/Crowl2006/operator_equal/not_equal.hpp create mode 100755 example/Crowl2006/sqrt/main.cpp create mode 100755 example/Crowl2006/sum/main.cpp create mode 100755 example/Crowl2006/sum/sum.cpp create mode 100755 example/Crowl2006/sum/sum.hpp create mode 100755 example/Crowl2006/vector/main.cpp create mode 100755 example/Makefile create mode 100755 example/Meyer1997/README.txt create mode 100755 example/Meyer1997/gcd/main.cpp create mode 100755 example/Meyer1997/maxarray/main.cpp create mode 100755 example/Meyer1997/stack3/main.cpp create mode 100755 example/Meyer1997/stack3/stack3.hpp create mode 100755 example/Meyer1997/stack4/main.cpp create mode 100755 example/Meyer1997/stack4/stack4.hpp create mode 100755 example/Mitchell2002/README.txt create mode 100755 example/Mitchell2002/counter/counter.hpp create mode 100755 example/Mitchell2002/counter/decrement_button.hpp create mode 100755 example/Mitchell2002/counter/main.cpp create mode 100755 example/Mitchell2002/counter/push_button.hpp create mode 100755 example/Mitchell2002/counter/view_of_counter.hpp create mode 100755 example/Mitchell2002/courier/couriers.cpp create mode 100755 example/Mitchell2002/courier/couriers.hpp create mode 100755 example/Mitchell2002/courier/main.cpp create mode 100755 example/Mitchell2002/customer_manager/customer_manager.cpp create mode 100755 example/Mitchell2002/customer_manager/customer_manager.hpp create mode 100755 example/Mitchell2002/customer_manager/main.cpp create mode 100755 example/Mitchell2002/dictionary/dictionary.hpp create mode 100755 example/Mitchell2002/dictionary/main.cpp create mode 100755 example/Mitchell2002/name_list/main.cpp create mode 100755 example/Mitchell2002/name_list/names.cpp create mode 100755 example/Mitchell2002/name_list/names.hpp create mode 100755 example/Mitchell2002/observe/main.cpp create mode 100755 example/Mitchell2002/observe/observe.hpp create mode 100755 example/Mitchell2002/simple_queue/main.cpp create mode 100755 example/Mitchell2002/simple_queue/simple_queue.hpp create mode 100755 example/Mitchell2002/stack/main.cpp create mode 100755 example/Mitchell2002/stack/stack.hpp create mode 100755 example/README.txt create mode 100755 example/Stroustrup1997/README.txt create mode 100755 example/Stroustrup1997/string/main.cpp create mode 100755 example/Stroustrup1997/string/string.cpp create mode 100755 example/Stroustrup1997/string/string.hpp create mode 100755 example/commas/README.txt create mode 100755 example/commas/main.cpp create mode 100755 example/myvector/README.txt create mode 100755 example/myvector/basic_begin.hpp create mode 100755 example/myvector/boundable.hpp create mode 100755 example/myvector/main.cpp create mode 100755 example/myvector/main_nomacros.cpp create mode 100755 example/myvector/myvector.hpp create mode 100755 example/myvector/myvector_nomacros.hpp create mode 100755 example/myvector/pushable.hpp create mode 100755 example/throw/README.txt create mode 100755 example/throw/main.cpp create mode 100755 src/README.txt create mode 100755 src/contract.hpp create mode 100755 src/contract/README.txt create mode 100755 src/contract/assert.hpp create mode 100755 src/contract/aux_/README.txt create mode 100755 src/contract/aux_/arg.hpp create mode 100755 src/contract/aux_/assert.hpp create mode 100755 src/contract/aux_/check01.hpp create mode 100755 src/contract/aux_/checking.hpp create mode 100755 src/contract/aux_/debug.hpp create mode 100755 src/contract/aux_/function/README.txt create mode 100755 src/contract/aux_/function/contract_class_implement.hpp create mode 100755 src/contract/aux_/function/local_macros_define.hpp create mode 100755 src/contract/aux_/function/local_macros_undef.hpp create mode 100755 src/contract/aux_/function/void_base_contract.hpp create mode 100755 src/contract/aux_/macros/README.txt create mode 100755 src/contract/aux_/macros/code_/README.txt create mode 100755 src/contract/aux_/macros/code_/args.hpp create mode 100755 src/contract/aux_/macros/code_/body.hpp create mode 100755 src/contract/aux_/macros/code_/contract_class.hpp create mode 100755 src/contract/aux_/macros/code_/contract_name.hpp create mode 100755 src/contract/aux_/macros/code_/contracted_function.hpp create mode 100755 src/contract/aux_/macros/code_/function_sign.hpp create mode 100755 src/contract/aux_/macros/code_/function_template.hpp create mode 100755 src/contract/aux_/macros/code_/kind.hpp create mode 100755 src/contract/aux_/macros/code_/postcondition.hpp create mode 100755 src/contract/aux_/macros/code_/precondition.hpp create mode 100755 src/contract/aux_/macros/code_/static_error.hpp create mode 100755 src/contract/aux_/macros/code_/static_validate.hpp create mode 100755 src/contract/aux_/macros/code_function.hpp create mode 100755 src/contract/aux_/macros/code_invariant.hpp create mode 100755 src/contract/aux_/macros/function.hpp create mode 100755 src/contract/aux_/macros/invariant.hpp create mode 100755 src/contract/aux_/old.hpp create mode 100755 src/contract/aux_/preprocessor/README.txt create mode 100755 src/contract/aux_/preprocessor/keyword/README.txt create mode 100755 src/contract/aux_/preprocessor/keyword/check_.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_body.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_class.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_const.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_copyable.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_inherit.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_operator.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_postcondition.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_precondition.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_private.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_protected.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_public.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_static.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_template.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_virtual.hpp create mode 100755 src/contract/aux_/preprocessor/keyword/is_void.hpp create mode 100755 src/contract/aux_/preprocessor/seq.hpp create mode 100755 src/contract/aux_/preprocessor/sign/README.txt create mode 100755 src/contract/aux_/preprocessor/sign/access.hpp create mode 100755 src/contract/aux_/preprocessor/sign/arg.hpp create mode 100755 src/contract/aux_/preprocessor/sign/args.hpp create mode 100755 src/contract/aux_/preprocessor/sign/base_types.hpp create mode 100755 src/contract/aux_/preprocessor/sign/body.hpp create mode 100755 src/contract/aux_/preprocessor/sign/class.hpp create mode 100755 src/contract/aux_/preprocessor/sign/class_type.hpp create mode 100755 src/contract/aux_/preprocessor/sign/const.hpp create mode 100755 src/contract/aux_/preprocessor/sign/function_name.hpp create mode 100755 src/contract/aux_/preprocessor/sign/function_template_args.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/README.txt create mode 100755 src/contract/aux_/preprocessor/sign/parse_/access.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/args.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/base_types.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/body.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/class.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/class_type.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/const.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/function_name.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/postcondition.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/precondition.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/result_type.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/static.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/template.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/README.txt create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/append_traits.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/apply.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/block.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/copyable.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/match_not.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/next.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/optional.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/required.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/utility/returns.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/validate.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_/virtual.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_constructor.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_destructor.hpp create mode 100755 src/contract/aux_/preprocessor/sign/parse_function.hpp create mode 100755 src/contract/aux_/preprocessor/sign/postcondition.hpp create mode 100755 src/contract/aux_/preprocessor/sign/precondition.hpp create mode 100755 src/contract/aux_/preprocessor/sign/result_type.hpp create mode 100755 src/contract/aux_/preprocessor/sign/seq_.hpp create mode 100755 src/contract/aux_/preprocessor/sign/static.hpp create mode 100755 src/contract/aux_/preprocessor/sign/virtual.hpp create mode 100755 src/contract/aux_/symbol.hpp create mode 100755 src/contract/aux_/sync.hpp create mode 100755 src/contract/block.hpp create mode 100755 src/contract/body.hpp create mode 100755 src/contract/config.hpp create mode 100755 src/contract/constructor.hpp create mode 100755 src/contract/destructor.hpp create mode 100755 src/contract/from.hpp create mode 100755 src/contract/macros.hpp create mode 100755 src/contract/nonmember_function.hpp create mode 100755 src/contract/nonstatic_member_function.hpp create mode 100755 src/contract/old.hpp create mode 100755 src/contract/state.hpp create mode 100755 src/contract/static_member_function.hpp create mode 100755 src/contract/wrap.hpp create mode 100755 svnignore create mode 100755 test/Makefile create mode 100755 test/README.txt create mode 100755 test/overloading/main.cpp create mode 100755 test/subcontracting/main.cpp create mode 100755 test/templates/main.cpp create mode 100755 test/usages/main.cpp diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt new file mode 100755 index 00000000..99f76842 --- /dev/null +++ b/COPYRIGHT.txt @@ -0,0 +1,4 @@ +Copyright (C) 2009-2010 Lorenzo Caminiti. +Use, modification, and distribution is subject to the +Contract++ Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt.) diff --git a/LICENSE_1_0.txt b/LICENSE_1_0.txt new file mode 100755 index 00000000..d98771b6 --- /dev/null +++ b/LICENSE_1_0.txt @@ -0,0 +1,27 @@ +(File: LICENSE_1_0.txt) + +Contract Programming for C++ (Contract++) Software License, Version 1.0 +April 19th, 2009 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/Makefile b/Makefile new file mode 100755 index 00000000..f39f818f --- /dev/null +++ b/Makefile @@ -0,0 +1,62 @@ +# Copyright (C) 2009-2010 Lorenzo Caminiti. +# Use, modification, and distribution is subject to the +# Contract++ Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt.) + +# Default target. +help: + @echo "Contract Programming for C++ (Contract++)" + @echo + @echo "This library does not need to be built. It is composed of " + @echo "C++ header files only (contained in the \"src/\" directory)." + @echo + @echo "make [OPTION] example" + @echo " Build example programs to \"build/example/\" and their" + @echo " code documentation to \"codedoc/example/\"." + @echo + @echo "make [OPTION] test" + @echo " Build test programs to \"build/test/\" and their" + @echo " code documentation to \"codedoc/test/\"." + @echo + @echo "make doc" + @echo " Build libaray HTML documentation into \"doc/html/\" (requires" + @echo " Boost.QuickBook to be installed and compiled on your system)." + @echo + @echo "make clean" + @echo " Clean all (build etc)." + @echo + @echo "OPTION" + @echo " CXX Specify 'GCC' to use GNU C++ compiler 'g++' (e.g., on" + @echo " Linux) or 'MSVC' to use Microsoft Visual C++ compiler " + @echo " (e.g., MSVC version 8 under Cygwin). CXX=GCC by default." + @echo " debug Specify '1' to enable library debug messages and" + @echo " C++ debug symbols." + @echo + @echo "EXAMPLE" + @echo " # Build all examples using g++ with debug messages enabled." + @echo " make CXX=GCC debug=1 example# Build all examples using g++" + exit 0 + +force_: + +clean: force_ + rm -rf build/* + +example: force_ + make -f example/Makefile + +test: force_ + make -f test/Makefile + +doc: force_ + # Requires Boost.QuickBook to be installed and compiled on your system. + # Workaround: QuickBook uses all full paths but the ones relative to "boost/", Perl removes full path prefixes from HTML. + cd ../boost-quickbook/doc && bjam --v2 && perl -p -i -e 'use Cwd; $$x=getcwd()."/qbk/src/contract"; s/$$x/contract/g' html/*.html html/contract/*.html + # Copies documentation examples into doc/html directory. + tmp="/tmp/contract-example.`date +%s`" && mkdir -p $$tmp && cp -R example $$tmp && find $$tmp -depth -name ".svn" -exec rm -rf {} \; && cp -R $$tmp/example doc/html +clean_doc: force_ + rm -rf doc/html/*.html + rm -rf doc/html/contract/*.html + rm -rf doc/html/contract__/*.html + find doc/html/example -depth -name "*.[hc]pp -exec rm -rf {} \; + diff --git a/README.txt b/README.txt new file mode 100755 index 00000000..34859d71 --- /dev/null +++ b/README.txt @@ -0,0 +1,23 @@ + +Contract Programming for C++ (Contract++) +========================================= + +See "doc/html/index.html" for the library documentation. + +All Contract Programming features of the Eiffel programming language +are supported by this library, among others: +* Optional compilation and checking of invariants, preconditions, + and postconditions. +* Customizable actions on contract failure (terminate by default + but it can throw, exit, etc). +* Subcontracting for derived classes (with support for multiple + inheritance). +* Access to "old" variable values (before body execution) and + return value "result" in postconditions. +* Block invariants and loop variants. + +Files organization: +* All library source is in the "src/" directory. +* Examples are in "example/" and test programs in "test/". +* Run `make' in the main directory to see how to build examples, etc. + diff --git a/bin/README.txt b/bin/README.txt new file mode 100755 index 00000000..bf270c39 --- /dev/null +++ b/bin/README.txt @@ -0,0 +1 @@ +Binary tools to support library maintainance. diff --git a/bin/env-MSVC8.sh b/bin/env-MSVC8.sh new file mode 100755 index 00000000..1ca9f508 --- /dev/null +++ b/bin/env-MSVC8.sh @@ -0,0 +1,18 @@ +# source this `$ source THIS_FILE'. + +# Can be executed, for example under Cygwin, to setup enviroment to run +# Microsoft Visual C++ command line compiler `cl.exe'. + +msvc="E:\bin\Microsoft Visual Studio 8" +echo "bin/env-MSVC8.sh: Assuming MVSC 8 installed at \"$msvc\" -- is this correct?" + +# Setup Cygwin PATH. +export PATH="$PATH:/cygdrive/c/Program Files/Microsoft Visual Studio 8/Common7/IDE:/cygdrive/c/Program Files/Microsoft Visual Studio 8/VC/BIN:/cygdrive/c/Program Files/Microsoft Visual Studio 8/Common7/Tools:/cygdrive/c/Program Files/Microsoft Visual Studio 8/Common7/Tools/bin:/cygdrive/c/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/bin:/cygdrive/c/Program Files/Microsoft Visual Studio 8/SDK/v2.0/bin:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v2.0.50727:/cygdrive/c/Program Files/Microsoft Visual Studio 8/VC/VCPackages:/cygdrive/c/oracle/ora81/bin:/cygdrive/c/Program Files/Oracle/jre/1.1.7/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem:/cygdrive/c/Program Files/TortoiseSVN/bin:/cygdrive/c/Program Files/Windows Imaging/:" + +# MSVC INCLUDE for this libray ./include, Boost 1.34.0, and MSVC 8. +export INCLUDE="./include;C:\Program Files\boost\boost_1_34_0;$msvc\VC\ATLMFC\INCLUDE;$msvc\VC\INCLUDE;$msvc\VC\PlatformSDK\include;$msvc\SDK\v2.0\include;" + +# MSVC LIB. +export LIB="$msvc\VC\ATLMFC\LIB;$msvc\VC\LIB;$msvc\VC\PlatformSDK\lib;$msvc\SDK\v2.0\lib;" + + diff --git a/bin/release b/bin/release new file mode 100755 index 00000000..5e72b1ce --- /dev/null +++ b/bin/release @@ -0,0 +1,78 @@ +#!/bin/bash + +dbc_dir=`pwd` + +# Preconditions. +echo -en "Did you add the release notes in the documentation? (Y/n) "; read ci +if [ "$ci" != "Y" ]; then + echo -en "ERROR: You must add the release notes before releasing\n" + exit 1; +fi +echo -en "Did you commit to SVN? (Y/n) "; read ci +if [ "$ci" != "Y" ]; then + echo -en "ERROR: You must commit before releasing\n" + exit 1; +fi + +# Load release number. + +old_major=`cat $dbc_dir/bin/release.dat | egrep "^Major: .*$" | sed 's/^Major: //'` +old_minor=`cat $dbc_dir/bin/release.dat | egrep "^Minor: .*$" | sed 's/^Minor: //'` +old_rev=`cat $dbc_dir/bin/release.dat | egrep "^Revision: .*$" | sed 's/^Revision: //'` + +new_rev=`svn info | egrep "^Revision: .*$" | sed 's/^Revision: //'` + +echo +echo "release-number := major.minor.subversion-revision" +echo -en "New major release number [old = $old_major]: "; read new_major +if [ -z "$new_major" ]; then new_major=$old_major; fi +echo -en "New minor release number [old = $old_minor]: "; read new_minor +if [ -z "$new_minor" ]; then new_minor=$old_minor; fi +echo -en "New revision: $new_rev (current SVN revision)\n" + +name=contractpp_${new_major}_${new_minor}_${new_rev} + +# Tar ball from trunk. +echo +echo "Exporting SVN repository..." +cd /tmp +svn export https://dbcpp.svn.sourceforge.net/svnroot/dbcpp/trunk $name +tar czf $name.tar.gz $name + +# Save release number. +echo """# Lateset release-number := major.minor.subversion-revision +Major: $new_major +Minor: $new_minor +Revision: $new_rev" > $dbc_dir/bin/release.dat + +# Manual steps. +echo -en """ +IMPORTANT: To complete the release do the following manual steps. + +RELEASE FILE +1. Log into 'http://sourceforge.net/projects/dbcpp/' as administrator. +2. In the Summary page, click EDIT next to the download area. +3. Left click on the gear next to the \"/releases\" directory. +4. Click 'Upload here' and upload \"/tmp/$name.tar.gz\". +5. Select the uploaded files and click Save (no need to specify label, etc). + The latest uploaded files is automatically set to the download file. + +DOCUMENTATION +1. Open Places > Home and click on Go > Location. +2. Enter 'sftp://,dbcpp@web.sourceforge.net' and type the password. +3. Go to 'home/groups/d/db/dbcpp/htdocs' (website directory). +4. Remove all files from this directory (old documentation). +5. Copy (drag-n-drop) all files from 'trunk/doc/html/*' into the 'htdocs' + directory opened via sftp. + +DEVELOPMENT STATUS +0. Update release status (Alpha, Beta, etc) but only if really necessary. +1. Log into 'http://sourceforge.net/projects/dbcpp/' as administrator. +2. In the Summary page, click EDIT next to the library title. +3. Click Edit Trove Categorization (on the right). +4. Edit the Development Status. + +SUBVERSION +1. Commit this sandbox to SVN -- local modiciations made by this script. +""" + diff --git a/bin/release.dat b/bin/release.dat new file mode 100755 index 00000000..1ec8c557 --- /dev/null +++ b/bin/release.dat @@ -0,0 +1,4 @@ +# Lateset release-number := major.minor.subversion-revision +Major: 0 +Minor: 3 +Revision: 467 diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 new file mode 100755 index 00000000..5d9a5db6 --- /dev/null +++ b/doc/Jamfile.v2 @@ -0,0 +1,69 @@ +# Copyright (C) 2009-2010 Lorenzo Caminiti. +# Use, modification, and distribution is subject to the +# Contract++ Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt.) + +# To compile the documention: +# 1. Boost source code must be compiled and installed on your system. +# 2. Compiled Boost code must be at the same level as trunk. +# 3. Create symbolic links in compiled Boost code directory to the trunk files. + +import path ; +import quickbook ; +using boostbook ; +using doxygen ; + +path-constant here : . ; + +doxygen reference + : + # This order does not matter (always alphabetic in doc). + $(here)/qbk/src/contract.hpp + [ glob $(here)/qbk/src/contract/*.hpp ] + : + # Most of these Doxygen options seem not to work... maybe they are overridden by Boost... + CREATE_SUBDIRS=NO + # Header files are included anyway -- user will get an error... + VERBATIM_HEADERS=NO + INLINE_SOURCES=NO + # Full path is used anyway for anything but "boost/*"... + FULL_PATH_NAMES=NO + STRIP_FROM_PATH=$(here)/qbk/src/ + STRIP_FROM_INC_PATH=$(here)/qbk/src/ + # These options seem to work instead. + EXTRACT_ALL=YES + HIDE_UNDOC_MEMBERS=NO + EXTRACT_PRIVATE=NO + SEARCH_INCLUDES=NO + # Special Doxygen commands required by this doc. + ALIASES=" Params=\"Parameters: \" Param{2}=\"\" EndParams=\"
\\1\\2
\" Returns=\"Returns:\" Note=\"Note:\" Warning=\"Warning:\" See=\"See:\" " + "Reference" + ; + +xml contract + : + qbk/contract.qbk + : + qbk/introduction.qbk + qbk/getting_started.qbk + qbk/tutorial.qbk + qbk/without_the_macros.qbk + qbk/throw_on_failure.qbk + qbk/contract_programming.qbk + qbk/examples.qbk + reference + qbk/bibliography.qbk + qbk/release_history.qbk + qbk/license.qbk + qbk/todo.qbk + ; + +boostbook standalone + : + contract + : + toc.max.depth=1 + boost.root="." + html.stylesheet=doc/html/boostbook.css + ; + diff --git a/doc/README.txt b/doc/README.txt new file mode 100755 index 00000000..8810750b --- /dev/null +++ b/doc/README.txt @@ -0,0 +1 @@ +The library documentation. diff --git a/doc/html/CONTRACT_ASSERT.html b/doc/html/CONTRACT_ASSERT.html new file mode 100755 index 00000000..e436ea04 --- /dev/null +++ b/doc/html/CONTRACT_ASSERT.html @@ -0,0 +1,68 @@ + + + +Macro CONTRACT_ASSERT + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_ASSERT

+

CONTRACT_ASSERT

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+CONTRACT_ASSERT(boolean_condition)
+
+

Description

+

Macro used to assert contract conditions for class invariants, preconditions, and postconditions.

+

Whenever possible, it is recommended to use this macro instead of throwing contract::failure directly. For example (see the Tutorial section for more information):

+
    CONTRACT_ASSERT( true );
+
+

The code asserting the specified boolean condition is used as the description of the assertion (otherwise use CONTRACT_ASSERT_MSG()).

+

Parameters:

+
++++ + + + + +
boolean_conditionThe boolean contract condition being asserted.
+

+

+

Returns: This macro expands to code equivalent to the following (see the Without the Macros section):

+
    if (!(boolean_condition))
+        throw contract::failure(__FILE__, __LINE__, # boolean_condition);
+
+

Note how __FILE__ and __LINE__ are automatically used by the macro to improve error reporting. (The preprocessor operator # makes a string from the specified token.)

+

See: CONTRACT_ASSERT_MSG(), contract::failure

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_ASSERT_BLOCK_INVARIANT.html b/doc/html/CONTRACT_ASSERT_BLOCK_INVARIANT.html new file mode 100755 index 00000000..95c4f41d --- /dev/null +++ b/doc/html/CONTRACT_ASSERT_BLOCK_INVARIANT.html @@ -0,0 +1,75 @@ + + + +Macro CONTRACT_ASSERT_BLOCK_INVARIANT + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_ASSERT_BLOCK_INVARIANT

+

CONTRACT_ASSERT_BLOCK_INVARIANT

+
+

Synopsis

+
// In header: <contract/block.hpp>
+
+CONTRACT_ASSERT_BLOCK_INVARIANT(boolen_condition)
+
+

Description

+

Macro used to assert invariant contract conditions from within a code block.

+

To assert class invariants, preconditions, and postcondition use CONTRACT_ASSERT() instead.

+

The code asserting the boolean condition is also used as the description of the condition. For example (see the Tutorial section for more information):

+
    ...
+    { // From within this code block.
+        int x = 0;
+        CONTRACT_ASSERT_BLOCK_INVARIANT( x == 0 );
+    }
+    ...
+
+

Parameters:

+
++++ + + + + +
boolean_conditionThe boolean contract condition being asserted.
+

+

+

Returns: This macro expands to code that will automatically invoke contract::block_invariant_failed() if the specified condition is evaluated to be false. The macro expands to code equivalent to the following:

+
    try {
+        CONTRACT_ASSERT( boolean_condition );
+    } catch (...) {
+        contract::block_invariant_failed(contract::FROM_BLOCK);
+    }
+
+

See: CONTRACT_ASSERT_BLOCK_INVARIANT_MSG()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_ASSERT_BLOCK_INVARIANT_MSG.html b/doc/html/CONTRACT_ASSERT_BLOCK_INVARIANT_MSG.html new file mode 100755 index 00000000..6e42c63f --- /dev/null +++ b/doc/html/CONTRACT_ASSERT_BLOCK_INVARIANT_MSG.html @@ -0,0 +1,81 @@ + + + +Macro CONTRACT_ASSERT_BLOCK_INVARIANT_MSG + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_ASSERT_BLOCK_INVARIANT_MSG

+

CONTRACT_ASSERT_BLOCK_INVARIANT_MSG

+
+

Synopsis

+
// In header: <contract/block.hpp>
+
+CONTRACT_ASSERT_BLOCK_INVARIANT_MSG(boolean_condition, string_description)
+
+

Description

+

Macro used to assert invariant contract conditions from within a code block specifying also a human readable message.

+

To assert class invariants, preconditions, and postcondition use CONTRACT_ASSERT_MSG() instead.

+

For example (see the Tutorial section for more information):

+
    ...
+    { // From within this code block.
+        int x = 0;
+        CONTRACT_ASSERT_BLOCK_INVARIANT_MSG( x == 0, "x is zero" );
+    }
+    ...
+
+

Parameters:

+
++++ + + + + + + + + + + +
boolean_conditionThe boolean contract condition being asserted.
string_descriptionA string providing a human readable description of the condition being asserted. (used for error reporting).
+

+

+

Returns: This macro expands to code that will automatically invoke contract::block_invariant_failed() if the specified condition is evaluated to be false. The macro expands to code equivalent to the following:

+
    try {
+        CONTRACT_ASSERT_MSG( boolean_condition, string_description );
+    } catch (...) {
+        contract::block_invariant_failed(contract::FROM_BLOCK);
+    }
+
+

See: CONTRACT_ASSERT_BLOCK_INVARIANT()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_ASSERT_LOOP_VARIANT.html b/doc/html/CONTRACT_ASSERT_LOOP_VARIANT.html new file mode 100755 index 00000000..4d29d382 --- /dev/null +++ b/doc/html/CONTRACT_ASSERT_LOOP_VARIANT.html @@ -0,0 +1,80 @@ + + + +Macro CONTRACT_ASSERT_LOOP_VARIANT + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_ASSERT_LOOP_VARIANT

+

CONTRACT_ASSERT_LOOP_VARIANT

+
+

Synopsis

+
// In header: <contract/block.hpp>
+
+CONTRACT_ASSERT_LOOP_VARIANT(integer_expression)
+
+

Description

+

Macro used to assert loop variant.

+

At each loop iteration, the value of the specified loop variant expression is automatically evaluated and asserted to be positive (> 0) and to decrease (<) from the variant value at previous loop iteration. A loop can only have one variant.

+

Note: Loop variants can be used to check loop correctness (see the Tutorial section and related references): Because the loop variant decreases monotonically at each loop iteration and it cannot be zero or smaller than zero, it is possible to guarantee loop termination.

+

The macro CONTRACT_INIT_LOOP_VARIANT must be used (once and only once) before asserting the loop variant and within the same or higher scope of the block containing CONTRACT_ASSERT_LOOP_VARIANT().

+

Loops are code blocks that repeat themselves in iteration. Therefore, it is possible to use CONTRACT_ASSERT_BLOCK_INVARIANT() (or CONTRACT_ASSERT_BLOCK_INVARIANT_MSG()) to assert loop invariants together with loop variants. A loop can have multiple invariants.

+

For example (see the Tutorial section for more information):

+
    ...
+    {
+        CONTRACT_INIT_LOOP_VARIANT; // Declare variant within scope.
+        for (i = 0; i < v.size(); ++i) {
+            // Loop invariants.
+            CONTRACT_ASSERT_BLOCK_INVARIANT( i >= 0 );
+            CONTRACT_ASSERT_BLOCK_INVARIANT( i < v.size() );
+            // Loop variant (assert always positive and decreasing).
+            CONTRACT_ASSERT_LOOP_VARIANT( v.size() - i );
+            
+            std::cout << v[i] << std::endl;
+    }
+    ...
+
+

The variant expression code is used as a human readable description of the variant (see CONTRACT_ASSERT_LOOP_VARIANT_MSG()).

+

Parameters:

+
++++ + + + + +
integer_expressionThe integer expression which is evaluated at each loop iteration and asserted to be positive and decreasing from one iteration to the next one.
+

+

+

Returns: This macro expands to code that will automatically invoke contract::block_invariant_failed() if the specified variant is not positive or it does not decrease.

+

See: CONTRACT_INIT_LOOP_VARIANT, CONTRACT_ASSERT_LOOP_VARIANT_MSG()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_ASSERT_LOOP_VARIANT_MSG.html b/doc/html/CONTRACT_ASSERT_LOOP_VARIANT_MSG.html new file mode 100755 index 00000000..0862e94e --- /dev/null +++ b/doc/html/CONTRACT_ASSERT_LOOP_VARIANT_MSG.html @@ -0,0 +1,67 @@ + + + +Macro CONTRACT_ASSERT_LOOP_VARIANT_MSG + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_ASSERT_LOOP_VARIANT_MSG

+

CONTRACT_ASSERT_LOOP_VARIANT_MSG

+
+

Synopsis

+
// In header: <contract/block.hpp>
+
+CONTRACT_ASSERT_LOOP_VARIANT_MSG(integer_expression, string_description)
+
+

Description

+

Macro used to assert loop variant specifying also a human readable description.

+

See CONTRACT_ASSERT_LOOP_VARIANT() explanations and examples.

+

Parameters:

+
++++ + + + + + + + + + + +
integer_expressionThe integer expression which is evaluated at each loop iteration and asserted to be positive and decreasing from one iteration to the next one.
string_descriptionA human readable description of the loop variant expression (used for error reporting).
+

+

+

Returns: This macro expands to code that will automatically invoke contract::block_invariant_failed() if the specified variant is not positive or it does not decrease.

+

See: CONTRACT_INIT_LOOP_VARIANT(), CONTRACT_ASSERT_LOOP_VARIANT()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_ASSERT_MSG.html b/doc/html/CONTRACT_ASSERT_MSG.html new file mode 100755 index 00000000..4026932a --- /dev/null +++ b/doc/html/CONTRACT_ASSERT_MSG.html @@ -0,0 +1,73 @@ + + + +Macro CONTRACT_ASSERT_MSG + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_ASSERT_MSG

+

CONTRACT_ASSERT_MSG

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+CONTRACT_ASSERT_MSG(boolean_condition, string_description)
+
+

Description

+

Macro used to assert contract conditions for class invariants, preconditions, and postconditions specifying also a human readable message.

+

When possible, it is recommended to use this macro instead of throwing contract::failure directly. For example (see the Tutorial section for more information):

+
    CONTRACT_ASSERT_MSG( true, "always true" );
+
+

Parameters:

+
++++ + + + + + + + + + + +
boolean_conditionThe boolean contract condition being asserted.
string_descriptionA string providing a human readable description of the condition being (used for error reporting).
+

+

+

Returns: This macro expands to code equivalent to the following (see the Without the Macros section):

+
    if (!(boolean_condition))
+        throw contract::failure(__FILE__, __LINE__, string_description);
+
+

Note how __FILE__ and __LINE__ are automatically used by the macro to improve error reporting.

+

See: CONTRACT_ASSERT(), contract::failure

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_BODY.html b/doc/html/CONTRACT_BODY.html new file mode 100755 index 00000000..4bfc6ef7 --- /dev/null +++ b/doc/html/CONTRACT_BODY.html @@ -0,0 +1,80 @@ + + + +Macro CONTRACT_BODY + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_BODY

+

CONTRACT_BODY

+
+

Synopsis

+
// In header: <contract/body.hpp>
+
+CONTRACT_BODY(function_name)
+
+

Description

+

Macro used to name the function body when separating the function definition from its declaration.

+

This macro is used when the function is defined separately from its declaration (for example in a separate ".cpp" file) to name the body function:

+
    ... // Function return type, class-type:: prefix, etc.
+    CONTRACT_BODY(function_name)
+            (...) { // Function arguments.
+        ... // Function implementation.
+    }
+
+

Parameters:

+
++++ + + + + +
function_nameThe name of the function. For operators the name must be operator(symbol, word) where word must contain no special operator symbol and it must match what specified in the contract declaration (see the Tutorial section).
+

+

+

Returns: This macro expands to code equivalent to the following:

+
    ... // Function return type, class-type:: prefix, etc.
+    #if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+            defined CONTRACT_CHECK_PRECONDITION || \
+            defined CONTRACT_CHECK_POSTCONDITION
+        contract_body_ ## function_name ## _ // Body function name.
+    #else
+        function_name // Function name (contracts off).
+    #endif
+            (...) { // Function arguments.
+        ... // Function implementation.
+    }
+
+

(The preprocessor operator ## concatenates the specified tokens.)

+

See: Tutorial section, CONTRACT_FUNCTION()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_CHECK_BLOCK_INVARIANT.html b/doc/html/CONTRACT_CHECK_BLOCK_INVARIANT.html new file mode 100755 index 00000000..ca629fe7 --- /dev/null +++ b/doc/html/CONTRACT_CHECK_BLOCK_INVARIANT.html @@ -0,0 +1,47 @@ + + + +Macro CONTRACT_CHECK_BLOCK_INVARIANT + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_CHECK_BLOCK_INVARIANT

+

CONTRACT_CHECK_BLOCK_INVARIANT

+
+

Synopsis

+
// In header: <contract.hpp>
+
+CONTRACT_CHECK_BLOCK_INVARIANT
+
+

Description

+

Block invariants (and therefore also loop variants) are compiled and checked at run-time only when this macro is #defined (#undefined by default).

+

When this macro is #undefined, block invariants (and loop variants) are not compiled in the object code and no block invariant (and loop variants) contract overhead is added.

+

See: Getting Started section for more information.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_CHECK_CLASS_INVARIANT.html b/doc/html/CONTRACT_CHECK_CLASS_INVARIANT.html new file mode 100755 index 00000000..88da6758 --- /dev/null +++ b/doc/html/CONTRACT_CHECK_CLASS_INVARIANT.html @@ -0,0 +1,47 @@ + + + +Macro CONTRACT_CHECK_CLASS_INVARIANT + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_CHECK_CLASS_INVARIANT

+

CONTRACT_CHECK_CLASS_INVARIANT

+
+

Synopsis

+
// In header: <contract.hpp>
+
+CONTRACT_CHECK_CLASS_INVARIANT
+
+

Description

+

Class invariants are compiled and checked at run-time only when this macro is #defined (#undefined by default).

+

When this macro is #undefined, class invariants are not compiled in the object code and no class invariant contract overhead is added.

+

See: Getting Started section for more information.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_CHECK_POSTCONDITION.html b/doc/html/CONTRACT_CHECK_POSTCONDITION.html new file mode 100755 index 00000000..754b359a --- /dev/null +++ b/doc/html/CONTRACT_CHECK_POSTCONDITION.html @@ -0,0 +1,47 @@ + + + +Macro CONTRACT_CHECK_POSTCONDITION + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_CHECK_POSTCONDITION

+

CONTRACT_CHECK_POSTCONDITION

+
+

Synopsis

+
// In header: <contract.hpp>
+
+CONTRACT_CHECK_POSTCONDITION
+
+

Description

+

Postconditions are compiled and checked at run-time only when this macro is #defined (#undefined by default).

+

When this macro is #undefined, postconditions are not compiled in the object code and no postcondition contract overhead is added.

+

See: Getting Started section for more information.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_CHECK_PRECONDITION.html b/doc/html/CONTRACT_CHECK_PRECONDITION.html new file mode 100755 index 00000000..500c1f4f --- /dev/null +++ b/doc/html/CONTRACT_CHECK_PRECONDITION.html @@ -0,0 +1,47 @@ + + + +Macro CONTRACT_CHECK_PRECONDITION + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_CHECK_PRECONDITION

+

CONTRACT_CHECK_PRECONDITION

+
+

Synopsis

+
// In header: <contract.hpp>
+
+CONTRACT_CHECK_PRECONDITION
+
+

Description

+

Preconditions are compiled and checked at run-time only when this macro is #defined (#undefined by default).

+

When this macro is #undefined, preconditions are not compiled in the object code and no precondition contract overhead is added.

+

See: Getting Started section for more information.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_CONFIG_MAX_FUNCTION_ARITY.html b/doc/html/CONTRACT_CONFIG_MAX_FUNCTION_ARITY.html new file mode 100755 index 00000000..6005ef6d --- /dev/null +++ b/doc/html/CONTRACT_CONFIG_MAX_FUNCTION_ARITY.html @@ -0,0 +1,65 @@ + + + +Macro CONTRACT_CONFIG_MAX_FUNCTION_ARITY + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_CONFIG_MAX_FUNCTION_ARITY

+

CONTRACT_CONFIG_MAX_FUNCTION_ARITY

+
+

Synopsis

+
// In header: <contract/config.hpp>
+
+CONTRACT_CONFIG_MAX_FUNCTION_ARITY
+
+

Description

+

The maximum number of function arguments supported by this library.

+

Warning: Increasing this number can significantly increase compilation time. If possible, do not increase this number.

+

If you need to write a contract for a function with a number of arguments larger than the one specified by this macro default value, consider alternatives like wrapping the arguments within a struct. For example, consider the function:

+
    // Many arguments thus need to increase configuration macro value.
+    void f(int i1, int i2, int i3, int i4, int i5, int i6, int i7);
+
+

However, this function could be rewritten as a single argument function using a struct:

+
    struct ints {
+        int i1;
+        int i2;
+        int i3;
+        int i4;
+        int i5;
+        int i6;
+        int i7;
+    };
+
+    // Just one argument and default macro value suffice.    
+    void f(ints i);
+
+

Now the contract for f only requires one argument and this macro value does not need to be increased.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE.html b/doc/html/CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE.html new file mode 100755 index 00000000..7d2b1da9 --- /dev/null +++ b/doc/html/CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE.html @@ -0,0 +1,46 @@ + + + +Macro CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE

+

CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE

+
+

Synopsis

+
// In header: <contract/config.hpp>
+
+CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE
+
+

Description

+

The maximum number of base classes supported when subcontracting with multiple inheritance.

+

Warning: Increasing this number can significantly increase compilation time. If possible, do not increase this number.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_CONSTRUCTOR.html b/doc/html/CONTRACT_CONSTRUCTOR.html new file mode 100755 index 00000000..6a87240c --- /dev/null +++ b/doc/html/CONTRACT_CONSTRUCTOR.html @@ -0,0 +1,100 @@ + + + +Macro CONTRACT_CONSTRUCTOR + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_CONSTRUCTOR

+

CONTRACT_CONSTRUCTOR

+
+

Synopsis

+
// In header: <contract/macros.hpp>
+
+CONTRACT_CONSTRUCTOR(sequence)
+
+

Description

+

Macro used to write contracts for constructors.

+

This macro must be used right after the constructor declaration -- and after the member initialization list if such a list is specified. There is no need for a trailing ";" after the macro closing parenthesis ")".

+

For example (see the Tutorial section for more information):

+
    template<typename T>
+    class myvector {
+        ... // Invariants.
+
+    public:
+        explicit myvector(size_type count) // Constructor declaration.
+                : vector_(count) // Member initialization list.
+        CONTRACT_COSTRUCTOR( (class) (myvector)
+                (public) (myvector)( (size_type)(count) )
+        (precondition) ({
+            ... // Assert constructor preconditions.
+        })
+        (postcondition) ({
+            ... // Assert constructor postconditions.
+        }) 
+        (body) ({
+            ... // Actual constructor implementation.
+        }) ) // No need for ";" after macro closing parenthesis ")".
+    
+        ... // Rest of the class.
+    };
+
+

Parameters:

+
++++ + + + + +
sequenceA Boost.Preprocessor sequence of tokens (1st-token)(2nd-token)...(last-token) that repeats the constructor signature syntactic elements and specifies the contract.
    +
  • The signature tokens are needed by the library to generate the contract code with the function name, the argument types and names, etc as discussed in the Without the Macros section (e.g., the argument names are needed to actually name the precondition and postcondition function arguments).

  • +
  • The extra parenthesis () around the tokens are mandatory (they are the ones making the preprocessor sequence).

  • +
  • It is recommended to use CONTRACT_ASSERT() to assert preconditions and postconditions within the relative code blocks.

  • +
  • Within the postcondition code block, CONTRACT_OLDOF(argument-name) is a constant reference to the related old argument value (as the value was before body execution) but only if the argument-type was tagged (copyable) in sequence.

  • +
  • For the body block, ";" can be used to separate the constructor definition from its declaration (see CONTRACT_CONSTRUCTOR_BODY()).

  • +
  • As explained in the Tutorial section, the tokens in sequence appear in the exact same order as they appear in the constructor declaration followed by the optional preconditions, optional postconditions, and mandatory body.

  • +
  • The constructor sequence syntax is as follows ([] for optional tokens, {} tokens resulting from parenthesis contents evaluation, || one token or the other, + tokens repeated 1 or more times):

  • +
+ [(class)] (class-type) {(public) || (protected) || (private)} [(template)( {(function-template-parameter-type)(function-template-parameter-name)}+ )] (class-name)( {(void) || {[(copyable)](argument-type)(argument-name)}+} ) [(precondition) ({ ... })] [(postcondition) ({ ... })] (body) ({ ... })
+

+

+

Returns: See the Without the Macro section for examples of the code generated by this macro expansion.

+
    +
  • If contract compilation is turned on, this macro expands to the constructor contract.

  • +
  • Otherwise, if contract compilation is turned off, this macro expands to just the constructor function body using the given body code block (and no contract overhead is added).

  • +
+

+Note: For functions with no argument (class-name)( (void) ), and not just (class-name)( ), must be used to specify the empty argument list within sequence. This is because ISO standard C++ does not allow for empty macro parameters (this library also supports (class-name)( ) but this will only compile on C99 so its use is not recommended -- see the Tutorial section for more information).

+

Note: In comparing the sequence syntax of constructors with the one of member functions from CONTRACT_FUNCTION(), note the following differences (see also the Constructor Call Semantics in the Tutorial section): There is no (copyable) before class-type because there is no object before construction body execution; There is no (inherit) because constructors cannot directly subcontract; There is no (static) or (virtual) because constructors cannot be static or virtual; There is no (result-type) because constructors have no return value; The function-name must be the class-name as always for constructors; There is no trailing (const) because constructor cannot be constant members.

+

See: CONTRACT_ASSERT(), CONTRACT_INVARIANT(), CONTRACT_DESTRUCTOR(), CONTRACT_FUNCTION()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_CONSTRUCTOR_BODY.html b/doc/html/CONTRACT_CONSTRUCTOR_BODY.html new file mode 100755 index 00000000..2bb962ac --- /dev/null +++ b/doc/html/CONTRACT_CONSTRUCTOR_BODY.html @@ -0,0 +1,139 @@ + + + +Macro CONTRACT_CONSTRUCTOR_BODY + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_CONSTRUCTOR_BODY

+

CONTRACT_CONSTRUCTOR_BODY

+
+

Synopsis

+
// In header: <contract/body.hpp>
+
+CONTRACT_CONSTRUCTOR_BODY(class_type, class_name)
+
+

Description

+

Macro used to name the constructor body when separating constructor definition from its declaration.

+

This macro is used when the constructor is defined outside the class declaration (for example in a separate ".cpp" file) to name the constructor body function:

+
    BOOST_CONTRACT_CONSTRUCTOR_BODY(class_type, class_name)
+            (...) { // Constructor arguments.
+        ... // Constructor implementation.
+    }
+
+

Parameters:

+
++++ + + + + + + + + + + +
class_typeThe type of the class. For class templates this must also list the template parameters.
class_nameThe constructor name which is the class type name. For class templates this shall not list the template parameters.
+

+

+

Returns: This macro expands to code equivalent to the following:

+
    #if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+            defined CONTRACT_CHECK_PRECONDITION || \
+            defined CONTRACT_CHECK_POSTCONDITION
+        void class_type::contract_body_constructor_ // Constructor body function name.
+    #else
+        class_type::class_name // Constructor function (contracts off).
+    #endif
+            (...) { // Constructor arguments.
+        ... // Constructor implementation.
+    }
+
+

Member Initialization List

+

A limitation of this mechanism is that it does not directly support constructor member initialization list. If a member initialization list is specified then the constructor definition must be provided together with its declaration (for example in the header file). (This library could overcome this limitation in the future if upcoming C++ standard revisions were to support delegating constructors.)

+

If the constructor implementation must be separated from its declaration, a possible workaround is to:

+
    +
  1. Delegate the construction job to a special initialization function which must be named "constructor" (and it should be private to avoid other code from messing with the object construction).

  2. +
  3. Program the real constructor to just invoke the initialization function.

  4. +
  5. Write the contract for the initialization function instead that for the real constructor (but using CONTRACT_CONSTRUCTOR() instead of CONTRACT_FUNCTION()).

  6. +
+

+

+

If this is done then both the constructor and the initialization function body definitions can be separated from the contract declaration. For example:

+
    // Declaration.
+    
+    template<typename T>
+    class myvector {
+        ... // Invariants.
+        
+    public:
+        typedef typename std::vector<T>::size_type size_type;
+        typedef typename std::vector<T>::const_reference const_reference;
+
+        explicit myvector(size_type count); // Separated definition.
+        
+        ... // Rest of the class.
+
+    private:
+        // The initialization function is private and must be named "constructor
+".
+        void constructor(size_type count)
+        // Specify the contract for the initialization function instead of the real constructor.
+        CONTRACT_CONSTRUCTOR( (class) (myvector)
+                (private) (myvector)( (size_type)(count) ), {
+            // Constructor preconditions (none in this case).
+        }, {
+            // Constructor postconditions.
+            CONTRACT_ASSERT(self.now.size() == count.now,
+                    "size set to count");
+        }, ;) // Now we can separate the body definition using ";".
+        
+        std::vector<T> vector_;
+    };
+    
+    // Separated definition (possibly in a different file).
+    
+    template<typename T>
+    myvector<T>::myvector(size_type count):
+            vector_(count) { // Member initialization list.
+        constructor(count); // Just invoke the initialization function.
+    }
+        
+    template<typename T>
+    void myvector<T>::CONTRACT_BODY(constructor)(size_type count) {
+        // Actual constructor implementation (do nothing in this case).
+    }
+
+

To allow for this workaround, the CONTRACT_CONSTRUCTOR() macro can follow a member function but only when the member function is named "constructor", it has a void return type, and it is not const (essentially, only when its signature matches the one of a constructor). Be aware that for this special "constructor" member function, class invariants will not be checked before body execution (because the CONTRACT_CONSTRUCTOR() macro implements the Constructor Call Semantics and not the Member Function Call Semantics as explained in the Tutorial section).

+

See: Tutorial section, CONTRACT_CONSTRUCTOR()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_DESTRUCTOR.html b/doc/html/CONTRACT_DESTRUCTOR.html new file mode 100755 index 00000000..9792ec7f --- /dev/null +++ b/doc/html/CONTRACT_DESTRUCTOR.html @@ -0,0 +1,92 @@ + + + +Macro CONTRACT_DESTRUCTOR + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_DESTRUCTOR

+

CONTRACT_DESTRUCTOR

+
+

Synopsis

+
// In header: <contract/macros.hpp>
+
+CONTRACT_DESTRUCTOR(sequence)
+
+

Description

+

Macro used to write contracts for destructors.

+

This macro must be used right after the destructor declaration. There is no need for a trailing ";" after the macro closing parenthesis ")".

+

For example (see the Tutorial section for more information):

+
    template<typename T>
+    class myvector {
+        ... // Invariants.
+
+    public:
+        virtual ~myvector(void) // Destructor declaration.
+        BOOST_CONTRACT_DESTRUCTOR( (class) (myvector)
+                (public) (virtual) (myvector)( (void) )
+        // Never preconditions or postconditions for destructors.
+        (body ({
+            ... // Actual destructor implementation.
+        }) ) // No need for ";" after macro closing parenthesis ")".
+        
+        ... // Rest of the class.
+    };
+
+

Parameters:

+
++++ + + + + +
signature_sequenceA Boost.Preprocessor sequence of tokens (1st-token)(2nd-token)...(last-token) that repeats the destructor signature syntactic elements.
    +
  • The signature tokens are needed by the library to generate the contract code with the function name, the argument types and names, etc as discussed in the Without the Macros section.

  • +
  • The extra parenthesis () around the tokens are mandatory (they are the ones making the preprocessor sequence).

  • +
  • For the body code block, ";" can be specified to separate the destructor definition from its declaration (see CONTRACT_DESTRUCTOR_BODY()).

  • +
  • As explained in the Tutorial section, the tokens in sequence appear in the exact same order as they appear in the destructor declaration followed by the mandatory body code block.

  • +
  • The destructor sequence syntax is as follows ([] for optional tokens, {} tokens resulting from parenthesis contents evaluation, || one token or the other):

  • +
+ [(template)] (class-type) {(public) || (protected) || (private)} [(virtual)] (class-name)( (void) ) (body) ({ ... })
+

+

+

Returns: See the Without the Macro section for examples of the code generated by this macro expansion.

+
    +
  • If contract compilation is turned on, this macro expands to the destructor contract.

  • +
  • Otherwise, if contract compilation is turned off, this macro expands to just the destructor function body using body code block (and no contract overhead is added).

  • +
+

+Note: Destructor have no argument so (void) must always be used in (class-name)( (void) ) to specify the empty argument list within sequence. This is because ISO standard C++ does not allow for empty macro parameters (this library also supports (class-name)( ) but this will only compile on C99 so its use is not recommended -- see the Tutorial section for more information).

+

Note: In comparing the sequence syntax of destructors with the one of member functions from CONTRACT_FUNCTION(), note the following differences (see also the Destructor Call Semantics in the Tutorial section): There is no (copyable) before class-type because there are no postconditions; There is no (inherit) because destructors cannot directly subcontract; There is no function template keyword and arguments because destructors cannot be template functions; There is no (static) because destructors cannot be static; There is no (result-type) because destructors have no return value; The function-name must be the class-name as always for destructors; The function argument list must be (void) because destructors take no argument; There is no trailing (const) because constructor cannot be constant members.

+

See: CONTRACT_ASSERT(), CONTRACT_INVARIANT(), CONTRACT_CONSTRUCTOR(), CONTRACT_FUNCTION()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_DESTRUCTOR_BODY.html b/doc/html/CONTRACT_DESTRUCTOR_BODY.html new file mode 100755 index 00000000..44414a32 --- /dev/null +++ b/doc/html/CONTRACT_DESTRUCTOR_BODY.html @@ -0,0 +1,83 @@ + + + +Macro CONTRACT_DESTRUCTOR_BODY + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_DESTRUCTOR_BODY

+

CONTRACT_DESTRUCTOR_BODY

+
+

Synopsis

+
// In header: <contract/body.hpp>
+
+CONTRACT_DESTRUCTOR_BODY(class_type, class_name)
+
+

Description

+

Macro used to name the destructor body when separating destructor definition from its declaration.

+

This macro is used when the destructor is defined outside the class declaration (for example in a separate ".cpp" file) to name the destructor body function:

+
    CONTRACT_DESTRUCTOR_BODY(class_type, class_name)
+            (void) { // Destructors have no argument.
+        ... // Destructor implementation.
+    }
+
+

Parameters:

+
++++ + + + + + + + + + + +
class_typeThe type of the class. For class templates this must also list the template parameters.
class_nameThe constructor name which is the class type name -- do not prefixed the class name with "~" (this is the class name and not the destructor name). For class templates this shall not list the template parameters.
+

+

+

Returns: This macro expands to code equivalent to the following:

+
    #if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+            defined CONTRACT_CHECK_PRECONDITION || \
+            defined CONTRACT_CHECK_POSTCONDITION
+        void class_type::contract_body_destructor_ // Destructor body function name.
+    #else
+        class_type::~class_name // Destructor function (contracts off).
+    #endif
+            (void) { // Destructor have no argument.
+        ... // Destructor implementation.
+    }
+
+

See: Tutorial section, CONTRACT_DESTRUCTOR()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_FUNCTION.html b/doc/html/CONTRACT_FUNCTION.html new file mode 100755 index 00000000..0c42c2f2 --- /dev/null +++ b/doc/html/CONTRACT_FUNCTION.html @@ -0,0 +1,103 @@ + + + +Macro CONTRACT_FUNCTION + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_FUNCTION

+

CONTRACT_FUNCTION

+
+

Synopsis

+
// In header: <contract/macros.hpp>
+
+CONTRACT_FUNCTION(sequence)
+
+

Description

+

Macro used to write contracts for functions (non-static members, static members, and non-members but not for constructors and destructors).

+

This macro must be used right after the member function declaration. There is no need for a trailing ";" after the macro closing parenthesis ")".

+

For example (see the Tutorial section for more information):

+
    template<typename T>
+    class myvector {
+        ... // Invariants.
+        
+    public:
+        void push_back(const T& element) // Function declaration.
+        CONTRACT_FUNCTION( (class) (copyable)(myvector)
+                (public) (void) (push_back)( (const T&)(element) )
+        (precondition) ({
+            ... // Assert function preconditions.
+        })
+        (postcondition) ({
+            ... // Assert function postconditions.
+        })
+        (body) ({
+            ... // Actual function implementation.
+        }) ) // No need for ";" after macro closing parenthesis ")".
+
+        ... // Rest of the class.
+    };
+
+

Parameters:

+
++++ + + + + +
sequenceA Boost.Preprocessor sequence of tokens (1st-token)(2nd-token)...(last-token) that repeats the function signature syntactic elements and specifies the contract.
    +
  • The signature tokens are needed by the library to generate the contract code with the function name, the argument types and names, etc as explained in the the Without the Macros section (e.g., the argument names are needed to actually name the arguments for the precondition and postcondition functions).

  • +
  • The extra parenthesis () around the tokens are mandatory (they are the ones making the preprocessor sequence).

  • +
  • It is recommended to use CONTRACT_ASSERT() to assert preconditions and postconditions within the relative code blocks.

  • +
  • Within the postcondition code block, CONTRACT_OLDOF(this) is a constant pointer to the object old value (as it was before body execution) but only if class-type was tagged (copyable) in sequence. Similarly, CONTRACT_OLDOF(argument-name) is a constant reference to the related old argument value (as is was before body execution) but only if the argument-type was tagged (copyable) in sequence.

  • +
  • Within the postcondition code block, result-name (with the actual name specified in sequence) is a constant reference to the value being returned but only when result-type is specified different from void in sequence.

  • +
  • For the body block, ";" can be used to separate the constructor definition from its declaration (see CONTRACT_CONSTRUCTOR_BODY()). Also, "= 0;" can be specified when writing contracts for pure virtual member functions.

  • +
  • As explained in the Tutorial section, the tokens in sequence appear in the exact same order as they appear in the member function declaration followed by the optional preconditions, optional postconditions, and mandatory body.

  • +
  • The function sequence syntax is as follows ([] for optional tokens, {} tokens resulting from parenthesis contents evaluation, || one token or the other, * tokens repeated 0 or more times, + tokens repeated 1 or more times, {}:: tokens specified only for member functions, {}? tokens specified only for non-void functions):

  • +
+ {[(template)] [(copyable)](class-type) {(inherit)(base-class-type)}* {(public) || (protected) || (private)}}:: [(template)( {(function-template-parameter-type)(function-template-parameter-name)}+ )] [{(static) || (virtual)}] (result-type) (function-name)( {(void) || {[(copyable)](argument-type)(argument-name)}+} ) [(const)] [(precondition) ({ ... })] [(postcondition) {(result-name)}? ({ ... })] (body) ({ ... })
+

+

+

Returns: See Without the Macro section for examples of the code generated by this macro expansion.

+
    +
  • If contract compilation is turned on, this macro expands to the function contract (see the Without the Macros section).

  • +
  • Otherwise, if contract compilation is turned off, this macro expands to just the function body using body_code_block (and no contract overhead is added).

  • +
+

+The usual C++ restrictions on the function signature apply. For example, static member functions cannot be virtual or const, plus they cannot subcontract so (inherit) cannot be specified. The library will generate compile-time errors if sequence violates these constraints.

+

For operators, the operator name must also be spelled out in words and passed as (operator(symbol, word)) (this is because operator names usually contain symbols, like "[]", that are not valid preprocessor token so they cannot be used by this library). The spelled out operator name is arbitrary but it cannot contain operator special symbols (see the Tutorial for more information). For example, for operator[] the function name passed to sequence could be (operator([], at)).

+

Overloaded functions, with same number of arguments and constant qualifier, must have different argument names (and not just different argument types). This is necessary otherwise this library will not be able to distinguish the contract of the overloaded functions from each other and it will generate a compile-time error. (C++ uses the argument types and not their names to distinguish overloaded functions from each other but this library cannot use the argument types because, in general, they are not valid preprocessor tokens -- see the Tutorial for more information on this topic.)

+

Note: For functions with no argument (function-name)( (void) ), and not just (function-name)( ), must be used to specify the empty argument list within sequence. This is because ISO standard C++ does not allow for empty macro parameters (this library also supports (function-name)( ) but this will only compile on C99 so its use is not recommended -- see the Tutorial section for more information).

+

Warning: While there is only a limited amount of compile-time error checking that the library can do on sequence, the current library implementation does not uses the best possible error detection and reporting mechanism for missuses of the sequence syntax. In some cases, and depending on the compiler used, an error in programming sequence might result in cryptic compiler errors (involving library internal templates and preprocessor macros, Boost.Preprocessor internal macros BOOST_PP_..., and only referring to the contract macro first line number). The best way to resolve these errors is usually to inspect the sequence by eye instead of trying to make sense of the compiler error messages. Also, try first to compile with contracts turned off so to make sure that the errors are actually in the contract code. Rarely, it might be useful to look at the code generated by the contract macro expansion after preprocessing using your compiler related options ("-E -P" on GCC, "\EP" on Microsoft Visual C++, etc).

+

See: CONTRACT_ASSERT(), CONTRACT_INVARIANT(), CONTRACT_CONSTRUCTOR(), CONTRACT_DESTRUCTOR()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_INIT_LOOP_VARIANT.html b/doc/html/CONTRACT_INIT_LOOP_VARIANT.html new file mode 100755 index 00000000..83d2cfee --- /dev/null +++ b/doc/html/CONTRACT_INIT_LOOP_VARIANT.html @@ -0,0 +1,57 @@ + + + +Macro CONTRACT_INIT_LOOP_VARIANT + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_INIT_LOOP_VARIANT

+

CONTRACT_INIT_LOOP_VARIANT

+
+

Synopsis

+
// In header: <contract/block.hpp>
+
+CONTRACT_INIT_LOOP_VARIANT
+
+

Description

+

Initialize the evaluation of the loop variant expression of type contract::loop_variant_type.

+

It must be used once, and only once, in a given code block. It must be used before using CONTRACT_ASSERT_LOOP_VARIANT() (or CONTRACT_ASSERT_LOOP_VARIANT_MSG()) at same of higher scope level.

+

It can also be used within a for loop initialization argument, for example:

+
    void offset(int& i) {
+        ...
+        for (CONTRACT_INIT_LOOP_VARIANT; i < MAX; ) {
+            CONTRACT_ASSERT_LOOP_VARIANT( MAX - i );
+            ...
+            i += DELTA;
+        }
+    }
+
+

See: contract::loop_variant_type, CONTRACT_ASSERT_LOOP_VARIANT(), CONTRACT_ASSERT_LOOP_VARIANT_MSG()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_INVARIANT.html b/doc/html/CONTRACT_INVARIANT.html new file mode 100755 index 00000000..9e166f7c --- /dev/null +++ b/doc/html/CONTRACT_INVARIANT.html @@ -0,0 +1,95 @@ + + + +Macro CONTRACT_INVARIANT + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_INVARIANT

+

CONTRACT_INVARIANT

+
+

Synopsis

+
// In header: <contract/macros.hpp>
+
+CONTRACT_INVARIANT(sequence)
+
+

Description

+

Macro used to write (static and non) class invariants.

+

This macro should be used in a private section at the beginning of the class declaration. There is no need for a trailing ";" after the macro closing parenthesis ")".

+

For example (see the Tutorial section for more information):

+
    template<typename T>
+    class myvector {
+
+        CONTRACT_INVARIANT( (static) ({
+            ... // Assert static class invariants.
+        }) ({
+            ... // Assert non-static class invariants.
+        }) ) // No need for ";" after macro closing parenthesis ")".
+        
+        ... // Rest of the class.
+    };
+
+

Parameters:

+
++++ + + + + +
sequenceA Boost.Preprocesor sequence of tokens (1st-token)(2nd-token)...(last-token) that specifies static and non-static class invariants.
    +
  • At least one of the class invariants must be specified (i.e., you can specify only non-static class invariants, only static class invariants, or both static and non-static class invariants).

  • +
  • The code block ({ ... }) following (static) should assert static class invariants. The other code block should assert non-static class invariants.

  • +
  • The class invariant sequence syntax is as follows ([] for optional tokens):

  • +
+ [(static)({ ... })] ({ ... })
+

+

+

Returns: See the Without the Macro section for examples of the code generated by this macro expansion.

+
    +
  • If contract compilation is turned on, this macro expands to the augmented state member variable named contract_state_.

  • +
  • Furthermore, if invariants compilation is specifically turned on, this macro expands to the static member function contract_static_invariant_ and the non-static member function contract_invariant_ defined respectively using the two code blocks from (static)({ ... }) and ({ ... }).

  • +
  • Otherwise, if contract compilation is turned off, this macro expands to nothing (and no contract overhead is added).

  • +
+

+Note: Even if a class has no invariants, you must still use this macro (with an empty code block) otherwise the library will generate a compile-time error saying that it cannot find the invariant check function for your class (see the Tutorial section for more information):

+
    class myclass {
+
+        // Assert no invariant (mandatory).
+        CONTRACT_INVARIANT( ({}) )
+        
+        ... // Rest of the class.
+    };
+
+

In this case, CONTRACT_INVARIANT() cannot be used instead of CONTRACT_INVARIANT( ({}) ). This is because ISO standard C++ does not allow for empty macro parameters (this library also supports CONTRACT_INVARIANT() but this will only compile on C99 so its use is not recommended -- see the Tutorial section for more information).

+

See: CONTRACT_ASSERT(), CONTRACT_CONSTRUCTOR(), CONTRACT_DESTRUCTOR(), CONTRACT_FUNCTION()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_OLDOF.html b/doc/html/CONTRACT_OLDOF.html new file mode 100755 index 00000000..928b490c --- /dev/null +++ b/doc/html/CONTRACT_OLDOF.html @@ -0,0 +1,70 @@ + + + +Macro CONTRACT_OLDOF + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_OLDOF

+

CONTRACT_OLDOF

+
+

Synopsis

+
// In header: <contract/old.hpp>
+
+CONTRACT_OLDOF(variable_name)
+
+

Description

+

Macro used to access old value for the variable with the specified name in postconditions.

+

The library automatically declares variables to hold old values of types tagged contract::copyable and makes then accessible in the postconditions code block (and from the postconditions code block only). This macro simply expands the specified name to the name of the old variable automatically declared by the library.

+

For example, in postconditions of a member function void myvector<T>::push_back(const T& element), if both the class type myvector and the element argument type const T& have been tagged copyable (see the sequence parameter of CONTRACT_FUNCTION() and contract::copy) then the following old values are available:

+
    CONTRACT_OLDOF(this)->...   // Object old value.
+    CONTRACT_OLDOF(element)...  // Old value of function argument `element`.
+
+

Parameters:

+
++++ + + + + +
variable_nameUse this to access a pointer to the old object value. Use one of the function argument names to access the old value of that argument. The type of the variable with the specified name must be tagged contract::copyable in the signature sequence its old value to be available (otherwise the use of this macro will generate a compile-time error with noold in the error message).
+

+

+

Returns: This macro expands to code equivalent to the following:

+
    contract_old_ ## variable_name ## _
+
+

(The preprocessor operator ## concatenates the specified tokens.)

+

Note: Shallow copies are performed for old values of pointer types (unless the pointed type defines a different copy constructor or contract::copy has been specialized for the pointed type to perform a different copy operation). Therefore, if a pointer type is tagged contract::copyable, the old pointer value will be available in the postconditions and not the old pointed value -- this might not be what you intended. The notable exception is the object which is passed by pointer (like this) but its old value is automatically deep copied by the library.

+

Note: The library supports old values for the object and all the function argument types. This is a subset of the old values supported by Eiffel which are old values for any expression that can be evaluated in postconditions. However, the old values supported by the library are usually enough to program the postconditions.

+

See: contract::copy, contract::copyable

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/CONTRACT_WRAP_TYPE.html b/doc/html/CONTRACT_WRAP_TYPE.html new file mode 100755 index 00000000..614ae8c5 --- /dev/null +++ b/doc/html/CONTRACT_WRAP_TYPE.html @@ -0,0 +1,96 @@ + + + +Macro CONTRACT_WRAP_TYPE + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Macro CONTRACT_WRAP_TYPE

+

CONTRACT_WRAP_TYPE

+
+

Synopsis

+
// In header: <contract/wrap.hpp>
+
+CONTRACT_WRAP_TYPE(parenthesized_type)
+
+

Description

+

Macro used to pass type expressions with unwrapped commas as macro parameters.

+

The C++ ISO standard preprocessor only recognizes the parenthesis () and it does not recognize any other parenthesis like <>, {}, [], etc.

+

As a consequence, any comma within a macro parameter which is not wrapped by the () parenthesis will be interpreted by the preprocessor as a separation token (the end of the current macro parameter and the start of the next macro parameter). See also the Tutorial section for more explanation and examples.

+

Value Expressions

+

Value expressions passed as macro parameters and containing unwrapped commas can be wrapped by and extra set of parenthesis ().

+

For example, this is OK because the comma `,` is already wrapped by the parenthesis () of the add() function call:

+
    CONTRACT_ASSERT( add(1, 2) == 3 ); // OK.
+
+

This is incorrect instead because the comma `,` is not wrapped. It is interpreted as a call to CONTRACT_ASSERT() passing two distinct macro parameters `std::map<double` and `int>().empty()` separated by the comma `,`:

+
    CONTRACT_ASSERT( std::map<double, int>().empty() ); // Error.
+
+

However, it can be fixed by using and extra set of parenthesis to wrap the value expression:

+
    CONTRACT_ASSERT( (std::map<double, int>().empty()) ); // OK.
+
+

Type Expressions

+

A similar issue arises when type expressions with unwrapped commas are passed as macro parameters (including when they are passed as preprocessor sequence elements):

+
    std::map<dobule, int> m(void)
+    CONTRACT_FUNCTION( (std::map<double, int>) (m)( (void) ) // Error.
+        ...
+    )
+
+

This is interpreted as a preprocessor 2-tuple with two elements `std::map<double` and `int>` separated by the comma `,` instead that one single element of the preprocessor sequence.

+

Note: Unfortunately, the approach followed for value expressions cannot be used for macro parameters that represent type expressions. That is because types wrapped by an extra set of parenthesis () can introduce syntax or semantics errors depending on the context where they are used. For example, with respect to std::map<double, int>, the wrapped type expression (std::map<double, int>) could be compiled a C-style type cast potentically introducing a semantic error, or it could generate a syntax error if it were used to declare a variable.

+

The macro CONTRACT_WRAP_TYPE() (or equivalently the contract::wrap class template) is be used to overcome this limitation:

+
    std::map<dobule, int> m(void)
+    CONTRACT_FUNCTION( (CONTRACT_WRAP_TYPE( (std::map<double, int>) )) //OK.
+            (m)( (void) )
+        ...
+    )
+
+

Note that the extra pair of parenthesis () used in invoking the macro are mandatory as they wrap the comma(s) so one parameter (not many) is passed to the macro.

+

Parameters:

+
++++ + + + + +
parenthesized_typeThe type expression wrapped within an extra set of mandatory parenthesis ().
+

+

+

Returns: The macro in the example above expands to code equivalent to the following:

+
    std::map<dobule, int> m(void)
+    CONTRACT_FUNCTION( (contract::wrap<void(std::map<double, int>)>::type)
+            (m)( (void) )
+        ...
+    )
+
+

See: contract::wrap, Tutorial section

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/block_invariant_failed.html b/doc/html/contract/block_invariant_failed.html new file mode 100755 index 00000000..9589b60a --- /dev/null +++ b/doc/html/contract/block_invariant_failed.html @@ -0,0 +1,60 @@ + + + +Function block_invariant_failed + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Function block_invariant_failed

+

contract::block_invariant_failed

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+void block_invariant_failed(const from & where);
+
+

Description

+

Automatically invoked by this library when a block invariant condition fails.

+

It calls std::terminate() by default but it can be redefined using contract::set_block_invariant_failed(). When this function is called, the exception raised by the contract failure is the active unhandled exception (which can be re-thrown using throw and then caught, see Throw on Failure annex).

+

Parameters:

+
++++ + + + + +
whereThe source that found the the block invariant failure.
+

+

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/class_invariant_failed.html b/doc/html/contract/class_invariant_failed.html new file mode 100755 index 00000000..1fc40865 --- /dev/null +++ b/doc/html/contract/class_invariant_failed.html @@ -0,0 +1,60 @@ + + + +Function class_invariant_failed + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Function class_invariant_failed

+

contract::class_invariant_failed

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+void class_invariant_failed(const from & where);
+
+

Description

+

Automatically invoked by this library when a class invariant condition fails.

+

It calls std::terminate() by default but it can be redefined using contract::set_class_invariant_failed(). When this function is called, the exception raised by the contract failure is the active unhandled exception (which can be re-thrown using throw and then caught, see Throw on Failure annex).

+

Parameters:

+
++++ + + + + +
whereThe source that found the the invariant failure.
+

+

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/constructor.html b/doc/html/contract/constructor.html new file mode 100755 index 00000000..b15905bd --- /dev/null +++ b/doc/html/contract/constructor.html @@ -0,0 +1,177 @@ + + + +Class template constructor + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Class template constructor

+

contract::constructor

+
+

Synopsis

+
// In header: <contract/constructor.hpp>
+
+template<typename F> 
+class constructor : public contract::nonstatic_member_function< F > {
+public:
+  // construct/copy/destruct
+  constructor(__BodyFunctionPointer__, __PreconditionFunctionPointer__, 
+              __PostconditionFunctionPointer__);
+  ~constructor();
+
+  // public member functions
+  void call(__MaybeConstClassPointer__, ArgumentType1, ..., ArgumetnTypeN) ;
+};
+
+

Description

+

Class template used to write contracts for constructors.

+

Note: Only the differences between this class and the contract::nonstatic_member_function class are documented here. Read the contract::nonstatic_member_function documentation first.

+

The CONTRACT_CONSTRUCTOR() macro expands to code that uses this class template (see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. Rarely, it might be needed to use this class template directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard.

+

Parameters:

+
++++ + + + + +
FThe function type of the constructor function being contracted.
+

+

+

Base contract classes cannot be specified because constructors do not directly subcontract (C++ object construction mechanism will automatically invoke base class contracts when they are present).

+

The function type F must be specified as follows:

+
    void (ClassType*, ArgumentType1, ..., ArgumentTypeN)
+
+

Note:

+
    +
  • The result type is always void because constructors return no value.

  • +
  • ClassType is never const because constructors can never be constant members (as they modify the object by constructing it).

  • +
  • ClassType cannot be tagged contract::copyable because there is no object before constructor body execution (it has not been constructed yet) -- the library will generate a compile-time error otherwise.

  • +
+

+See: Without the Macros section, contract::nonstatic_member_function

+
+

+constructor + public + construct/copy/destruct

+
    +
  1. +
    constructor(__BodyFunctionPointer__ body_function, 
    +            __PreconditionFunctionPointer__ precondition_function, 
    +            __PostconditionFunctionPointer__ postcondition_function);
    +

    Construct this contract object using the specified body, preconditions, and postconditions functions.

    +

    Parameters:

    +
    ++++ + + + + + + + + + + + + + + +
    body_functionA pointer to the function executing the body.
    precondition_functionA pointer to the function asserting the preconditions.
    postcondition_functionA pointer to the function asserting the postconditions.
    +

    +

    +

    Refer to the contract::nonstatic_member_function documentation for the definition of metaprogramming constructs used below (__IfCopyable__, etc).

    +

    The body function pointer type is defined as follows:

    +
            typedef void (ClassType::* __BodyFunctionPointer__)
    +                (   __RemoveCopyable__< ArgumentType1 >,
    +                    ..., 
    +                    __RemoveCopyable__< ArgumentTypeN >
    +                );
    +
    +

    The precondition function pointer type is defined as follows:

    +
            typedef void (* __PreconditionFunctionPointer__)
    +                (   boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type,
    +                    ..., 
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type
    +                );
    +
    +

    +
      +
    • This is a static member function (because is does not specify the class type using (*) instead of (ClassType::*)). This ensures that constructor preconditions do not access the object (as before constructor body no object has been constructed yet).

    • +
    • The precondition function is never const (because is must be static).

    • +
    +

    +The postcondition function pointer type is defined as follows:

    +
            typedef void (ClassType::* __PreconditionFunctionPointer__)
    +                (   contract::noold,
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type,
    +                    __IfCopyable__< ArgumentType1,
    +                            boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type >,
    +                    ..., 
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type,
    +                    __IfCopyable__< ArgumentTypeN,
    +                            boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type >
    +                ) const;
    +
    +

    +
    • The old object value is never available (it is always of type contract::noold). This ensure that constructor postconditions never access the object old value (as there was no object before constructor body execution).

    +

    +

    +
  2. +
  3. +
    ~constructor();
    +

    Destroy this contract object.

    +
  4. +
+
+
+

+constructor public member functions

+
  1. +
    void call(__MaybeConstClassPointer__ object, ArgumentType1 argument1, ..., 
    +          ArgumetnTypeN argumentN) ;
    +

    Check the contract and executes the member function body.

    +

    Refer to the contract::nonstatic_member_function documentation.

    +

    Accordingly with F, the call() function always returns void.

    +
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/contract_failed_handler.html b/doc/html/contract/contract_failed_handler.html new file mode 100755 index 00000000..52d80309 --- /dev/null +++ b/doc/html/contract/contract_failed_handler.html @@ -0,0 +1,63 @@ + + + +Type definition contract_failed_handler + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Type definition contract_failed_handler

+

contract_failed_handler

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+typedef __ContractFailedHandler__ contract_failed_handler;
+
+

Description

+

Function pointer type of the contract condition failure handler functions.

+

Where the function pointer type __ContractFailedHandler__ is defined as follows:

+
    typedef void (* contract_failed_handler)(const from& where);
+
+

Parameters:

+
++++ + + + + +
whereThe source that found the condition failure. This is useful for example to program failure handlers that throw exceptions in general but never from within destructors.
+

+

+

See: Throw on Failure annex for an example.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/copy.html b/doc/html/contract/copy.html new file mode 100755 index 00000000..1374fe25 --- /dev/null +++ b/doc/html/contract/copy.html @@ -0,0 +1,159 @@ + + + +Class template copy + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Class template copy

+

contract::copy

+
+

Synopsis

+
// In header: <contract/old.hpp>
+
+template<typename T> 
+class copy {
+public:
+  // construct/copy/destruct
+  copy(__ConstRef__);
+  __ConstType__ value;
+};
+
+

Description

+

Copy wrapper used by the library to make the actual copy of variables for which old values are needed in postconditions.

+

Parameters:

+
++++ + + + + +
TType of the object being copied.
+

+

+

Note: Under most circumstances programmers do not need to use this class which is usually just used internally by the library.

+

Specifically, if the copied type T already has a public constant-correct copy constructor then the contract::copy template will use such a constructor by default and programmers do not need to define any specialization of the contract::copy template.

+
    class T {
+    public:
+        T(const T& source); // Public constant-correct copy constructor.
+
+        ...
+    };
+
+

The constructor needs to be public for the library to access it and it needs to be contract-correct for the library to use it while still ensuring the contract-correctness of the contract checking code.

+

However, the contract::copy template can be specialized by programmers to expose a non-public constant-correct copy constructor to the library via friendship:

+
    class x {
+        ... // User class with no public copy constructor.
+
+    private:
+        // Only the library can access this copy constructor via friendship.
+        friend class contract::copy<x>;
+        x(const x* source); // Constant-correct (private) copy constructor.
+    };
+
+

Furthermore, programmers can specialize the contract::copy template for a user defined type in order to relax the library requirement of an accessible constant-correct copy constructor all together (it is recommended not to do this unless strictly necessary).

+
    class y: boost::noncopyable { // User class with no copy constructor at all.
+        // Self backup copy maintained by the class itself.
+        y backup_copy; // Use this as the old value.
+
+        ...
+    };
+    
+    namespace contract {
+    
+    // Specialization to handle y old value without copying it.
+    template<>
+    class copy<y> {
+    public:
+        // It must declare a member variable named `value`.
+        const y& value; // Maintains constant-correctness by using const member.
+        
+        // It must defined this copy constructor. It must maintains
+        // constant-correctness taking a constant reference to `source`.
+        copy(const y& source):
+                // This does not copy `source` (`value` is a reference).
+                // Instead it uses its `source` existing backup copy.
+                value(source.backup_copy) {}
+    };
+    
+    } // namespace
+
+

The contract::copy template can also be specialized to alter the copy semantics for a type (it is recommended not to do this unless strictly necessary). For example, by default a pointer to a double number double* is copied by copying the pointer value and not by copying the pointed number (this is the usual C++ copy semantic for pointers). The following specialization of contract::copy copies the pointed number instead of the pointer value for postcondition old values of argument of type double*.

+
    namespace contract {
+    
+    template<>
+    class copy<double*> {
+    private:
+        double number_; // Copied pointed number value.
+    public:
+        const double* value; // Pointer to number_.
+        
+        copy(const double* number_ptr): number_(), value(&number_) {
+            // Check pointer is valid.
+            if (!number_ptr) throw std::logic_error("Invalid number pointer");
+            number_ = *number_ptr; // Copy the *pointed* number.
+        }
+    };
+    
+    } // namespace
+
+

See also the Examples section for a concrete example that specializes contract::copy to relax the accessible constant-correct constructor requirement.

+
+

+copy + public + construct/copy/destruct

+
  1. +
    copy(__ConstRef__ source);
    +

    Constructor which copies the specified object.

    +

    The copy is done by constructing the member variable `value` using an accessible constant-correct copy constructor for T (which must be available otherwise the library will generate a compile-time error).

    +

    Note: Source is a constant reference so to ensure contract checking constant-correctness (correctly, this constraint cannot be relaxed not even by specializing this class template).

    +

    The constant reference type is defined as follows:

    +
            typedef typename boost::add_reference<const_type>::type __ConstRef__;
    +
    +

    Parameters:

    +
    ++++ + + + + +
    sourceThe source object to be copied into the value member variable.
    +

    +

    +
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/copyable.html b/doc/html/contract/copyable.html new file mode 100755 index 00000000..a50a8383 --- /dev/null +++ b/doc/html/contract/copyable.html @@ -0,0 +1,74 @@ + + + +Class template copyable + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Class template copyable

+

contract::copyable

+
+

Synopsis

+
// In header: <contract/old.hpp>
+
+template<typename T> 
+class copyable {
+};
+
+

Description

+

Tag the specified type T copyable.

+

In general, you should tag a type copyable only when the related variable old value (before body execution) is really needed in postconditions because:

+
    +
  1. The correspondent variable value will be copied before body execution adding run-time overhead. The library performs the extra copy to support old values in postconditions only for variables of types tagged copyable and only when the CONTRACT_CHECK_POSTCONDITION macro is defined.

  2. +
  3. +

    A type tagged copyable has the extra requirement that it must define an accessible constant-correct copy constructor (otherwise the library will generate a compile-time error). The copy constructor is constant-correct when it accesses the copied value via a constant reference argument (this way the copied value cannot be mistakenly modified while it is being copied to check contracts):

    +
        T::T(const T& source) { ... } // Must be accessible and construct from a const&.
    +
    +

    See contract::copy to relax this requirement.

    +
  4. +
+

+

+

Parameters:

+
++++ + + + + +
TThe type to be tagged. The entire type with eventual const, &, *, etc qualifier should be tagged copyable. For example, if the type is const int& then contract::copyable<const int&> should be used (and not const contract::copyable<int>&).
+

+

+

Note: When using the contract macros, (copyable)(T) is used instead of contract::copyable<T> to tag the type T copyable in the macro sequence parameter.

+

See: CONTRACT_OLDOF(), contract::copy

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/destructor.html b/doc/html/contract/destructor.html new file mode 100755 index 00000000..1d52cd9c --- /dev/null +++ b/doc/html/contract/destructor.html @@ -0,0 +1,129 @@ + + + +Class template destructor + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Class template destructor

+

contract::destructor

+
+

Synopsis

+
// In header: <contract/destructor.hpp>
+
+template<typename F> 
+class destructor : public contract::nonstatic_member_function< F > {
+public:
+  // construct/copy/destruct
+  destructor(__BodyFunctionPointer__);
+  ~destructor();
+
+  // public member functions
+  void call(__MaybeConstClassPointer__) ;
+};
+
+

Description

+

Class template used to write contracts for destructors.

+

Note: Only the differences between this class and the contract::nonstatic_member_function class are documented here. Read the contract::nonstatic_member_function documentation first.

+

The CONTRACT_DESTRUCTOR() macro expands to code that uses this class template (see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. Rarely, it might be needed to use this class template directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard.

+

Parameters:

+
++++ + + + + +
FThe function type for the destructor being contracted.
+

+

+

Base contract classes cannot be specified because destructors do not directly subcontract (C++ object destruction mechanism will automatically invoke base class contracts when they are present).

+

The function type F must be specified as follows:

+
    void (ClassType::*)()
+
+

Note:

+
    +
  • The result type is always void because destructors return no value.

  • +
  • ClassType is never const because destructors can never be constant members (as they modify the object by destructing it).

  • +
  • ClassType cannot be tagged contract::copyable because there is no object before destructor body execution (it has not been destructed yet) -- the library will generate a compile-time error otherwise.

  • +
  • There is no function argument type because destructors take no argument.

  • +
+

+See: Without the Macros section, contract::nonstatic_member_function

+
+

+destructor + public + construct/copy/destruct

+
    +
  1. +
    destructor(__BodyFunctionPointer__ body_function);
    +

    Construct this contract object using the specified body.

    +

    No precondition and no postcondition function is specified (destructors only check class invariants). This is because destructors have no arguments so there are no preconditions, in addition there is no object after destructor body execution so there are no postconditions (see Tutorial section for more information).

    +

    Parameters:

    +
    ++++ + + + + +
    body_functionA pointer to the function executing the body.
    +

    +

    +

    The body function pointer type is defined as follows:

    +
            typedef void (ClassType::* __BodyFunctionPointer__)();
    +
    +

    +
    • Destructor body takes no argument.

    +

    +

    +
  2. +
  3. +
    ~destructor();
    +

    Destroy this contract object.

    +
  4. +
+
+
+

+destructor public member functions

+
  1. +
    void call(__MaybeConstClassPointer__ object) ;
    +

    Check the contract and executes the member function body.

    +

    Refer to the contract::nonstatic_member_function documentation.

    +

    Accordingly with F, the call() function always returns void and it takes no argument.

    +
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/failure.html b/doc/html/contract/failure.html new file mode 100755 index 00000000..259e40ce --- /dev/null +++ b/doc/html/contract/failure.html @@ -0,0 +1,139 @@ + + + +Class failure + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Class failure

+

contract::failure

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+class failure {
+public:
+  // construct/copy/destruct
+  failure(const char *, const unsigned long &, const char * = "");
+  failure(const failure &);
+  failure& operator=(const failure &);
+  ~failure();
+
+  // public member functions
+  const char * what() const;
+  const char * file() const;
+  unsigned long line() const;
+  const char * description() const;
+};
+
+

Description

+

Default exception thrown when a contract condition is found to be false.

+

It is recommended to assert contract conditions using the CONTRACT_ASSERT() macro instead of throwing this exception directly.

+

The library handles exceptions (any exception, not just this one) when thrown from within block invariants (plus loop variants), class invariants, preconditions, and postconditions invoking contract::block_invariant_failed(), contract::class_invariant_failed(), contract::precondition_failed(), and contract::postcondition_failed() respectively (see the Without the Macros section).

+

Therefore, throwing this exception on a contract condition failure does not imply that an exception will be thrown overall to handle the failure. It only implies that the correct contract failure handler function will be automatically invoked by the library (after checking eventual overridden contracts for subcontracting, etc). It is not possible to call the failure handler functions directly instead of throwing the exception because that will not allow the library to check overridden contracts when subcontracting. The failure handler functions will then decide the action to take (the default handlers provided by the library invoke std::terminate() but programmers can redefine this behaviour using contract::set_block_invariant_failed(), contract::set_class_invariant_failed(), contract::set_precondition_failed(), and contract::set_postcondition_failed()).

+

The member functions of this class do not throw (their exception specification is thow()) so they can be safely used when checking contracts in compliance with STL C++ exception safety requirements at all times.

+

See: Without the Macros section.

+
+

+failure + public + construct/copy/destruct

+
    +
  1. +
    failure(const char * file, const unsigned long & line, 
    +        const char * description = "");
    +

    Create a condition failure object.

    +

    All the constructor parameters are used to provide more descriptive error messages in case of contract condition failure. At least the file and line number must be specified so to uniquely identify the point of the contract condition failure.

    +

    Parameters:

    +
    ++++ + + + + + + + + + + + + + + +
    fileThe source code file containing the failed contract condition (use __FILE__).
    lineThe source code line number containing the failed contract condition (use __LINE__).
    descriptionAn optional human readable description of the contract condition failure ("" if not specified).
    +

    +

    +
  2. +
  3. +
    failure(const failure & source);
    +

    Create a condition failure object copying it from the specified one.

    +
  4. +
  5. +
    failure& operator=(const failure & source);
    +

    Copy a condition failure from the specified one.

    +
  6. +
  7. +
    ~failure();
    +

    Destroy the condition failure object.

    +
  8. +
+
+
+

+failure public member functions

+
    +
  1. +
    const char * what() const;
    +

    Return a human readable message explaining the nature of the condition failure.

    +

    Returns: The actual message text is library implementation specific but it will contain the condition description, the file name, and the line number (when specified). For example, the returned message could look like this:

    +
            contract "size increased by 1" failed at myvector.cpp:40
    +
    +

    +
  2. +
  3. +
    const char * file() const;
    +

    Return the condition failure source file.

    +
  4. +
  5. +
    unsigned long line() const;
    +

    Return the condition failure source line number.

    +
  6. +
  7. +
    const char * description() const;
    +

    Return the condition failure description ("" if not specified).

    +
  8. +
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/from.html b/doc/html/contract/from.html new file mode 100755 index 00000000..4222b713 --- /dev/null +++ b/doc/html/contract/from.html @@ -0,0 +1,66 @@ + + + +Type from + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Type from

+

contract::from

+
+

Synopsis

+ +
+

Description

+

Source that found the contract condition failure.

+

For example, this is used in the Throw on Failure annex to ensure that destructors never throw to comply with C++ STL exception safety requirements.

+

These failure sources are identified separately because they all have different contract checking semantics with respect to each other (see the Tutorial section).

+

Warning: You must not assume any specific integer value for these enumerated values. Only use the enumerated values because the integer values they map to are library implementation specific and they could change in future revisions of the library.

+

See: contract::contract_failed_handler

+
+
FROM_CONSTRUCTOR
+

Contract condition failed from a constructor.

+
FROM_DESTRUCTOR
+

Contract condition failed from a destructor.

+
FROM_NON_STATIC_MEMBER_FUNCTION
+

Contract condition failed from a non-static member function.

+
FORM_STATIC_MEMBER_FUNCTION
+

Contract condition failed from a static member function.

+
FROM_NON_MEMBER_FUNCTION
+

Contract condition failed from a non-member function.

+
FROM_BLOCK
+

Contract condition failed from a code block.

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/loop_variant_type.html b/doc/html/contract/loop_variant_type.html new file mode 100755 index 00000000..8428c83b --- /dev/null +++ b/doc/html/contract/loop_variant_type.html @@ -0,0 +1,56 @@ + + + +Type definition loop_variant_type + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Type definition loop_variant_type

+

loop_variant_type

+
+

Synopsis

+
// In header: <contract/block.hpp>
+
+
+typedef __Integer__ loop_variant_type;
+
+

Description

+

The type of the loop variant expression.

+

The __Integer__ type is a signed integer type but its actual type is library implementation specific.

+

Note: While the loop variant expression type is signed, the loop variant value is asserted to be always positive (> 0).

+

For example, you can use this type to convert (not cast) the variant expression into the variant type:

+
    CONTRACT_INIT_LOOP_VARIANT;
+    for (size_t i = 0; i < v.size(); ++i) {
+        CONTRACT_ASSERT_LOOP_VARIANT( loop_variant_type(v.size() - i) );
+        ...
+    }
+
+

Note this is not a type cast so it will generate a compile-time error if the type conversion if not possible.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/nonmember_function.html b/doc/html/contract/nonmember_function.html new file mode 100755 index 00000000..de1d6c96 --- /dev/null +++ b/doc/html/contract/nonmember_function.html @@ -0,0 +1,166 @@ + + + +Class template nonmember_function + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Class template nonmember_function

+

contract::nonmember_function

+
+

Synopsis

+
// In header: <contract/nonmember_function.hpp>
+
+template<typename F> 
+class nonmember_function {
+public:
+  // construct/copy/destruct
+  nonmember_function(__BodyFunctionPointer__, __PreconditionFunctionPointer__, 
+                     __PostconditionFunctionPointer__);
+  ~nonmember_function();
+
+  // public member functions
+  ResultType call(ArgumentType1, ..., ArgumetnTypeN) ;
+};
+
+

Description

+

Class template used to write contracts for non-member functions.

+

Note: Only the differences between this class and the contract::nonstatic_member_function class are documented here. Read the contract::nonstatic_member_function documentation first.

+

The CONTRACT_FUNCTION() macro expands to code that uses this class template (when no (class) is specified in the function signature sequence, see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. Rarely, it might be needed to use this template class directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard.

+

Parameters:

+
++++ + + + + +
FThe function type of the non-member function being contracted.
+

+

+

The function type F must be specified as follows:

+
    ResultType (ArgumentType1, ..., ArgumentTypeN)
+
+

See: Without the Macros section, contract::nonstatic_member_function

+
+

+nonmember_function + public + construct/copy/destruct

+
    +
  1. +
    nonmember_function(__BodyFunctionPointer__ body_function, 
    +                   __PreconditionFunctionPointer__ precondition_function, 
    +                   __PostconditionFunctionPointer__ postcondition_function);
    +

    Construct this contract object using the specified body, preconditions, and postconditions functions.

    +

    Parameters:

    +
    ++++ + + + + + + + + + + + + + + +
    body_functionA pointer to the function executing the body.
    precondition_functionA pointer to the function asserting the preconditions.
    postcondition_functionA pointer to the function asserting the postconditions.
    +

    +

    +

    Refer to the contract::nonstatic_member_function documentation for the definition of metaprogramming constructs used below (__IfCopyable__, etc).

    +

    Note the followings for the function pointer types defined below:

    +
      +
    • They are non-member functions.

    • +
    • There is no old object value in postconditions, not even contract::noold (because non-member functions have no object).

    • +
    +

    +The body function pointer type is defined as follows:

    +
            typedef ResultType (* __BodyFunctionPointer__)
    +                (   __RemoveCopyable__< ArgumentType1 >,
    +                    ..., 
    +                    __RemoveCopyable__< ArgumentTypeN >
    +                );
    +
    +

    The precondition function pointer type is defined as follows:

    +
            typedef ResultType (* __PreconditionFunctionPointer__)
    +                (   boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type,
    +                    ..., 
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type
    +                );
    +
    +

    The postcondition function pointer type is defined as follows:

    +
            typedef ResultType (* __PreconditionFunctionPointer__)
    +                (   boost::add_reference<boost::add_const<
    +                            __RemoveCopyable< ArgumentType1 > >::type>::type,
    +                    __IfCopyable__< ArgumentType1,
    +                            boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type >,
    +                    ..., 
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type,
    +                    __IfCopyable__< ArgumentTypeN,
    +                            boost::add_reference<boost::add_const<
    +                            __RemoveCopyable< ArgumentTypeN > >::type>::type >,
    +                    __IfNonVoid__< boost::add_reference<boost::add_const<
    +                            ResultType>::type>::type >
    +                ) const;
    +
    +

    +
  2. +
  3. +
    ~nonmember_function();
    +

    Destroy this contract object.

    +
  4. +
+
+
+

+nonmember_function public member functions

+
  1. +
    ResultType call(ArgumentType1 argument1, ..., ArgumetnTypeN argumentN) ;
    +

    Check the contract and executes the member function body.

    +

    Refer to the contract::nonstatic_member_function documentation.

    +

    The call() function takes no object (because the contracted function is not a member).

    +
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/nonstatic_member_function.html b/doc/html/contract/nonstatic_member_function.html new file mode 100755 index 00000000..3d8c49ce --- /dev/null +++ b/doc/html/contract/nonstatic_member_function.html @@ -0,0 +1,284 @@ + + + +Class template nonstatic_member_function + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Class template nonstatic_member_function

+

contract::nonstatic_member_function

+
+

Synopsis

+
// In header: <contract/nonstatic_member_function.hpp>
+
+template<typename F, typename BaseContractClass1 = void, ... , 
+         typename BaseContractClassM = void> 
+class nonstatic_member_function {
+public:
+  // construct/copy/destruct
+  nonstatic_member_function(__BodyFunctionPointer__, 
+                            __PreconditionFunctionPointer__, 
+                            __PostconditionFunctionPointer__);
+  ~nonstatic_member_function();
+
+  // public member functions
+  ResultType call(__MaybeConstClassPointer__, ArgumentType1, ..., 
+                  ArgumetnTypeN) ;
+};
+
+

Description

+

Class template used to write contracts for non-static member functions.

+

Note: This class is used to write contracts for non-static member functions but it cannot be used for static-member functions (see contract::static_member), constructors (see contract::constructor), destructors (see contract::destructor), and non-m ember functions (see contract::nonmember_function) because they have different contract checking semantics.

+

The CONTRACT_FUNCTION() macro expands to code that uses this class template (see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. Rarely, it might be needed to use this class template directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard.

+

Parameters:

+
++++ + + + + + + + + + + +
FThe function type of the function being contracted.
BaseContractClass1, ..., BaseContractClassMThese are the contracts from which the member function is subcontracting. These are all optional, they are only specified when the member function is subcontracting: no base contract is specified if no subcontracting, only BaseContractClass1 is specified to subcontract from 1 base class only, and more base contract classes are specified to support subcontracting with multiple inheritance.
    +
  • Each of these types must inherit from contract::nonstatic_member_function (so to be a contract class) and its class type must be a base class of the contracted class (otherwise the library will generate a compile-time error).

  • +
  • When multiple base contract classes are specified, the overridden contracts are checked following the order of the specified template parameters. The derived class contract is checked last.

  • +
  • The maximum number of supported base class contracts M is specified by the CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE configuration macro.

  • +
+
+

+

+

The following metaprogramming constructs (e.g., __AMetaprogrammingConstruct__) are used in this documentation to define the different types:

+
    +
  • If S is contract::copyable<T> then __RemoveCopyable__< S > is T, otherwise it is S (i.e., this removes the eventual contract::copyable tag from the specified type).

  • +
  • If F is a member function pointer then __UncopyableClassType__ is __RemoveCopyable__< ClassType >:: (`::` included), otherwise it is nothing.

  • +
  • If F is a constant member then __ConstIfConstantMember__ is const, otherwise it is nothing.

  • +
  • If S is tagged contract::copyable then __IfCopyable__< S, T > is the T, otherwise it is the contract::noold.

  • +
  • If F has a non-void ResultType then __IfNonVoid__< C > is C, otherwise it is nothing.

  • +
  • If F is a non-constant member functions then __MaybeConstClassPointer__ is boost::add_pointer< __UncopyableClassType__ >::type, otherwise is is boost::add_pointer<boost::add_const< __UnopyableClassType__ >::type>:: type.

  • +
+

+

+

These metaporgramming constructs are not templates. They are internally implemented by the library using both preprocessor and template metaprogramming (in a way that is intentionally not documented here because it is library implementation specific).

+

The function type template parameter F must be specified as follows:

+
    // For member functions.
+    ResultType (ClassType __ConstIfConstantMember__*, ArgumentType1, ..., ArgumentTypeN) 
+
+

Where:

+
    +
  • The ResultType is the function result type (use void for functions that have no return value).

  • +
  • The ClassType is the type of the class the function is member of.

  • +
  • For constant member functions const qualifies the class type.

  • +
  • The class type ClassType (together with its eventual const qualifier) can be tagged contract::copyable as in contract::copyable<ClassType __ConstIfContractMemeber__>* if the object old value CONTRACT_OLDOF(this) is needed in the postconditions (in this case the class must have an accessible constant-correct copy constructor, see contract::copy). Note that contract::copyable does not wrap the pointer operator (i.e., contract::copyable<ClassType __ConstIfContractMemeber__*> is invalid).

  • +
  • +

    The class type must declare a (private) mutable member variable of a friend type contract::state with the predefined name contract_state_ otherwise the library will generate a compile-time error. This member variable is mainly used by the library to keep track of when contracts are being checked so to disable assertion checking in nested member function calls that could otherwise result in infinite recursion (see the Without the Macros section).

    +
        class ClassType {
    +    
    +    // Optional contract compilation.
    +    #if defined BOOST_CONTRACT_CHECK_CLASS_INVARIANT || \
    +            defined BOOST_CONTRACT_CHECK_PRECONDITION || \
    +            defined BOOST_CONTRACT_CHECK_POSTCONDITION
    +        // Augmented state.
    +        friend contract::state;
    +        mutable contract::state contract_state_;
    +    #endif
    +        
    +        ... // Rest of the class.
    +    };
    +
    +

    Whenever possible, use the CONTRACT_INVARIANT() macro instead of declaring contract_state_ directly.

    +
  • +
  • The function argument types ArgumentType1, ..., ArgumentTypeN are all optional (specify none for a function with no argument, only ArgumentType1 is specified for a function with one argument, etc).

  • +
  • Any of the argument type can be tagged contract::copyable if the old value CONTRACT_OLDOF(argument-name) (before body execution) of the related argument is needed in postconditions. Types tagged contract::copyable must have an accessible constant-correct copy constructor (otherwise the library will generate a compile-time error, see contract::copy). The eventual contract::copyable tag must wrap the entire argument type (including the pointer operator if present, this is different from the class type).

  • +
  • The maximum number of supported function arguments N is specified by the CONTRACT_CONFIG_MAX_FUNCTION_ARITY configuration macro.

  • +
+

+See: Without the Macros section

+
+

+nonstatic_member_function + public + construct/copy/destruct

+
    +
  1. +
    nonstatic_member_function(__BodyFunctionPointer__ body_function, 
    +                          __PreconditionFunctionPointer__ precondition_function, 
    +                          __PostconditionFunctionPointer__ postcondition_function);
    +

    Construct this contract object using the specified body, preconditions, and postconditions functions.

    +

    Parameters:

    +
    ++++ + + + + + + + + + + + + + + +
    body_functionA pointer to the function executing the body.
    precondition_functionA pointer to the function asserting the preconditions.
    postcondition_functionA pointer to the function asserting the postconditions.
    +

    +

    +

    The body function pointer type is defined as follows:

    +
            typedef ResultType (__UncopyableClassType__* __BodyFunctionPointer__)
    +                (   __RemoveCopyable__< ArgumentType1 >,
    +                    ..., 
    +                    __RemoveCopyable__< ArgumentTypeN >
    +                ) __ConstIfConstantMember__;
    +
    +

    +
      +
    • The body function pointer type matches the signature of the contracted function.

    • +
    • The contract::copyable tag is removed from the class and argument types.

    • +
    • The function type is the const only if the contracted function is a constant member.

    • +
    +

    +The precondition function pointer type is defined as follows:

    +
            typedef void (__UncopyableClassType__* __PreconditionFunctionPointer__)
    +                (   boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type,
    +                    ..., 
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type
    +                ) const;
    +
    +

    +
      +
    • The precondition function pointer type always has a void return type.

    • +
    • The contract::copyable tag is removed from the class and argument types.

    • +
    • Each function argument is passed as a contract reference.

    • +
    • The function type is always const if the contracted function is a member.

    • +
    +

    +The postcondition function pointer type is defined as follows:

    +
            typedef void (__UncopyableClassType__* __PreconditionFunctionPointer__)
    +                (   __IfCopyable__< ClassType,
    +                            boost::add_pointer<boost::add_const<
    +                            ClassType>::type>::type >,
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type,
    +                    __IfCopyable__< ArgumentType1,
    +                            boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type >,
    +                    ..., 
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type,
    +                    __I fCopyable__< ArgumentTypeN,
    +                            boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type >,
    +                    __IfNonVoid__< boost::add_reference<boost::add_const<
    +                            ResultType>::type>::type >
    +                ) const;
    +
    +

    +
      +
    • The postcondition function pointer type always has a void return type.

    • +
    • The contract::copyable tag is removed from the class and argument types.

    • +
    • The first argument is a constant pointer to the object old value if the class type was tagged contract::copyable, otherwise it is of type contract::noold (indicating that no object old value is available because the class type was not tagged contract::copyable).

    • +
    • Each function argument is passed as contract reference and it is followed by its old value. Each old value is a constant reference to the argument old value if the argument type was tagged contract::copayble, otherwise it is of type contract::noold (indicating that no object old value is available because the argument type was not tagged contract::copyable).

    • +
    • The function type is always const if the contracted function is a member.

    • +
    +

    +

    +
  2. +
  3. +
    ~nonstatic_member_function();
    +

    Destroy this contract object.

    +
  4. +
+
+
+

+nonstatic_member_function public member functions

+
  1. +
    ResultType call(__MaybeConstClassPointer__ object, ArgumentType1 argument1, 
    +                ..., ArgumetnTypeN argumentN) ;
    +

    Check the contract and execute the member function body.

    +

    This function implements the correct contract checking semantics for the function call (see the Tutorial section). In summary:

    +
      +
    • It checks class invariants and preconditions (also of overridden contracts when subcontracting), it executes the member function body, then it checks class invariants and postconditions (also of overridden contracts when subcontracting).

    • +
    • If the body throws an exception, only class invariants (and not postconditions) are checked on function exit.

    • +
    • Non-member functions do not check class invariants and they do not subcontract.

    • +
    +

    +Parameters:

    +
    ++++ + + + + + + + + + + +
    objectA pointer to the object (present only if F is a member function pointer type). The object pointer is const only if F is a constant member function pointer type (to handle constant member functions).
    argument1, ..., argumentNThe function arguments.
    +

    +

    +

    Returns: The function return value but only when F is a non-void function pointer type.

    +

    Note: When F is a member function pointer type, the call() function checks class invariants by calling a constant member function with the contract_invariant_ predefined name and it also checks static class invariants by calling a static member function with the contract_static_invariant_ predefined name (see the Without the Macros section for more information):

    +
            class ClassType {
    +
    +        #if defined BOOST_CONTRACT_CHECK_INVARIANT
    +            void contract_static_invariant_(void) {
    +                ... // Assert static class invariants.
    +            }
    +            void contract_invariant_ (void) const {
    +                ... // Assert class invariants.
    +            }
    +        #endif
    +                    
    +            ... // Rest of the class.
    +        };
    +
    +

    Note the #if guard to declare the function only when invariant compilation and checking is turned on. Such function must be defined and accessible otherwise the library will generate a compile-time error. Whenever possible, use the CONTRACT_INVARIANT() macro instead of programming the contract_invariant_ and contract_static_invariant_ functions directly.

    +
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/postcondition_failed.html b/doc/html/contract/postcondition_failed.html new file mode 100755 index 00000000..68c983df --- /dev/null +++ b/doc/html/contract/postcondition_failed.html @@ -0,0 +1,60 @@ + + + +Function postcondition_failed + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Function postcondition_failed

+

contract::postcondition_failed

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+void postcondition_failed(const from & where);
+
+

Description

+

Automatically invoked by this library when a postcondition fails.

+

It calls std::terminate() by default but it can be redefined using contract::set_postcondition_failed(). When this function is called, the exception raised by the contract failure is the active unhandled exception (which can be re-thrown using throw and then caught, see Throw on Failure annex).

+

Parameters:

+
++++ + + + + +
whereThe source that found the the invariant failure.
+

+

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/precondition_failed.html b/doc/html/contract/precondition_failed.html new file mode 100755 index 00000000..c31e6d65 --- /dev/null +++ b/doc/html/contract/precondition_failed.html @@ -0,0 +1,60 @@ + + + +Function precondition_failed + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Function precondition_failed

+

contract::precondition_failed

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+void precondition_failed(const from & where);
+
+

Description

+

Automatically invoked by this library when a precondition fails.

+

It calls std::terminate() by default but it can be redefined using contract::set_precondition_failed(). When this function is called, the exception raised by the contract failure is the active unhandled exception (which can be re-thrown using throw and then caught, see Throw on Failure annex).

+

Parameters:

+
++++ + + + + +
whereThe source that found the the invariant failure.
+

+

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/set_block_invariant_failed.html b/doc/html/contract/set_block_invariant_failed.html new file mode 100755 index 00000000..09f7c850 --- /dev/null +++ b/doc/html/contract/set_block_invariant_failed.html @@ -0,0 +1,63 @@ + + + +Function set_block_invariant_failed + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Function set_block_invariant_failed

+

contract::set_block_invariant_failed

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+contract_failed_handler 
+set_block_invariant_failed(contract_failed_handler handler);
+
+

Description

+

Set the specified user defined handler function to call on block invariant failure.

+

This function can be used by programmers to specify an action to take in case of block invariant failure different from the default to terminate the program.

+

Parameters:

+
++++ + + + + +
handlerA pointer to the new handler function. Passing an invalid pointer, including 0, has undefined behaviour and it will likely result in a segmentation fault.
+

+

+

Returns: The previously set handler function pointer.

+

See: Throw on Failure annex for an example.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/set_class_invariant_failed.html b/doc/html/contract/set_class_invariant_failed.html new file mode 100755 index 00000000..b1593679 --- /dev/null +++ b/doc/html/contract/set_class_invariant_failed.html @@ -0,0 +1,63 @@ + + + +Function set_class_invariant_failed + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Function set_class_invariant_failed

+

contract::set_class_invariant_failed

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+contract_failed_handler 
+set_class_invariant_failed(contract_failed_handler handler);
+
+

Description

+

Set the specified user defined handler function to call on class invariant failure.

+

This function can be used by programmers to specify an action to take in case of class invariant failure different from the default to terminate the program.

+

Parameters:

+
++++ + + + + +
handlerA pointer to the new handler function. Passing an invalid pointer, including 0, has undefined behaviour and it will likely result in a segmentation fault.
+

+

+

Returns: The previously set handler function pointer.

+

See: Throw on Failure annex for an example.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/set_postcondition_failed.html b/doc/html/contract/set_postcondition_failed.html new file mode 100755 index 00000000..09fd930b --- /dev/null +++ b/doc/html/contract/set_postcondition_failed.html @@ -0,0 +1,63 @@ + + + +Function set_postcondition_failed + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Function set_postcondition_failed

+

contract::set_postcondition_failed

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+contract_failed_handler 
+set_postcondition_failed(contract_failed_handler handler);
+
+

Description

+

Set the specified user defined handler function to call on postcondition failure.

+

This function can be used by programmers to specify an action to take in case of postcondition failure different from the default to terminate the program.

+

Parameters:

+
++++ + + + + +
handlerA pointer to the new handler function. Passing an invalid pointer, including 0, has undefined behaviour and it will likely result in a segmentation fault.
+

+

+

Returns: The previously set handler function pointer.

+

See: Throw on Failure annex for an example.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/set_precondition_failed.html b/doc/html/contract/set_precondition_failed.html new file mode 100755 index 00000000..589ab471 --- /dev/null +++ b/doc/html/contract/set_precondition_failed.html @@ -0,0 +1,63 @@ + + + +Function set_precondition_failed + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Function set_precondition_failed

+

contract::set_precondition_failed

+
+

Synopsis

+
// In header: <contract/assert.hpp>
+
+
+contract_failed_handler 
+set_precondition_failed(contract_failed_handler handler);
+
+

Description

+

Set the specified user defined handler function to call on precondition failure.

+

This function can be used by programmers to specify an action to take in case of precondition failure different from the default to terminate the program.

+

Parameters:

+
++++ + + + + +
handlerA pointer to the new handler function. Passing an invalid pointer, including 0, has undefined behaviour and it will likely result in a segmentation fault.
+

+

+

Returns: The previously set handler function pointer.

+

See: Throw on Failure annex for an example.

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/state.html b/doc/html/contract/state.html new file mode 100755 index 00000000..4171f409 --- /dev/null +++ b/doc/html/contract/state.html @@ -0,0 +1,51 @@ + + + +Class state + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Class state

+

contract::state

+
+

Synopsis

+
// In header: <contract/state.hpp>
+
+
+class state {
+};
+
+

Description

+

Augmented object state internally used by the library.

+

As illustrated by the contract::nonstatic_member_function documentation, the class being contracted must declare a (private) member variable named contract_state_ of mutable type contract::state (see contract::nonstatic_member_function for example code). The type contract::state must be declared a friend of the class. This member variable is automatically declared when the CONTRACT_INVARIANT() macro is used (recommended).

+

This library will generate a compile-time error if this state variable is not declared and accessible to the contracts.

+

Note: This member variable is used internally by this library mainly to track when assertions are being checked so to disable assertion checking in nested function calls that could otherwise lead to infinite recursion (this is a common requirement for Contract Programming). The friendship is requires so the library internally has access to the entire user class including non public members.

+

See: contract::nonstatic_member_function, Without the Macros section

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/static_member_function.html b/doc/html/contract/static_member_function.html new file mode 100755 index 00000000..40e4bc7f --- /dev/null +++ b/doc/html/contract/static_member_function.html @@ -0,0 +1,175 @@ + + + +Class template static_member_function + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Class template static_member_function

+

contract::static_member_function

+
+

Synopsis

+
// In header: <contract/static_member_function.hpp>
+
+template<typename F> 
+class static_member_function {
+public:
+  // construct/copy/destruct
+  static_member_function(__BodyFunctionPointer__, 
+                         __PreconditionFunctionPointer__, 
+                         __PostconditionFunctionPointer__);
+  ~static_member_function();
+
+  // public member functions
+  ResultType call(ArgumentType1, ..., ArgumetnTypeN) ;
+};
+
+

Description

+

Class template used to write contracts for static member functions.

+

Note: Only the differences between this class and the contract::nonstatic_member_function class are documented here. Read the contract::nonstatic_member_function documentation first.

+

The CONTRACT_FUNCTION() macro expands to code that uses this class template (when (static) is specified in the function signature sequence, see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. Rarely, it might be needed to use this template class directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard.

+

Parameters:

+
++++ + + + + +
FThe function type of the static member function being contracted.
+

+

+

Base contract classes cannot be specified because static member functions cannot be virtual and they cannot override base virtual functions so they cannot subcontract.

+

The function type F must be specified as follows:

+
    ResultType (ClassType*, ArgumentType1, ..., ArgumentTypeN)
+
+

Note:

+
    +
  • ClassType is never const because static member functions cannot be constant member functions (there is no object to not modify).

  • +
  • ClassType cannot be tagged contract::copyable because there is no object for static member functions -- the library will generate a compile-time error otherwise.

  • +
+

+See: Without the Macros section, contract::nonstatic_member_function

+
+

+static_member_function + public + construct/copy/destruct

+
    +
  1. +
    static_member_function(__BodyFunctionPointer__ body_function, 
    +                       __PreconditionFunctionPointer__ precondition_function, 
    +                       __PostconditionFunctionPointer__ postcondition_function);
    +

    Construct this contract object using the specified body, preconditions, and postconditions functions.

    +

    Parameters:

    +
    ++++ + + + + + + + + + + + + + + +
    body_functionA pointer to the function executing the body.
    precondition_functionA pointer to the function asserting the preconditions.
    postcondition_functionA pointer to the function asserting the postconditions.
    +

    +

    +

    Refer to the contract::nonstatic_member_function documentation for the definition of metaprogramming constructs used below (__IfCopyable__, etc).

    +

    Note the followings for the function pointer types defined below:

    +
      +
    • They are static member functions (they do not specify the class type as in (ClassType::*) but only the function pointer (*)).

    • +
    • They are never const member functions because they are static.

    • +
    • There is no old object value in postconditions, not even contract::noold (because static member functions have no object).

    • +
    +

    +The body function pointer type is defined as follows:

    +
            typedef ResultType (* __BodyFunctionPointer__)
    +                (   __RemoveCopyable__< ArgumentType1 >,
    +                    ..., 
    +                    __RemoveCopyable__< ArgumentTypeN >
    +                );
    +
    +

    The precondition function pointer type is defined as follows:

    +
            typedef ResultType (* __PreconditionFunctionPointer__)
    +                (   boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type,
    +                    ..., 
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type
    +                );
    +
    +

    The postcondition function pointer type is defined as follows:

    +
            typedef ResultType (* __PreconditionFunctionPointer__)
    +                (   boost::add_reference<boost::add_const<
    +                            __RemoveCopyable< ArgumentType1 > >::type>::type,
    +                    __IfCopyable__< ArgumentType1,
    +                            boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentType1 > >::type>::type >,
    +                    ..., 
    +                    boost::add_reference<boost::add_const<
    +                            __RemoveCopyable__< ArgumentTypeN > >::type>::type,
    +                    __IfCopyable__< ArgumentTypeN,
    +                            boost::add_reference<boost::add_const<
    +                            __RemoveCopyable< ArgumentTypeN > >::type>::type >,
    +                    __IfNonVoid__< boost::add_reference<boost::add_const<
    +                            ResultType>::type>::type >
    +                ) const;
    +
    +

    +
  2. +
  3. +
    ~static_member_function();
    +

    Destroy this contract object.

    +
  4. +
+
+
+

+static_member_function public member functions

+
  1. +
    ResultType call(ArgumentType1 argument1, ..., ArgumetnTypeN argumentN) ;
    +

    Check the contract and executes the member function body.

    +

    Refer to the contract::nonstatic_member_function documentation.

    +

    The call() function takes no object (because the contracted function is static).

    +
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/wrap.html b/doc/html/contract/wrap.html new file mode 100755 index 00000000..5a73a8fc --- /dev/null +++ b/doc/html/contract/wrap.html @@ -0,0 +1,49 @@ + + + +Struct template wrap + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Struct template wrap

+

contract::wrap

+
+

Synopsis

+
// In header: <contract/wrap.hpp>
+
+template<typename T> 
+struct wrap {
+};
+
+

Description

+

Metafunction used to wrap type expressions containing commas so they can be passed as macro parameters.

+

Warning: Attempting to use this template directly will generate a compile-time error. Only the template specialization contract::wrap<void(T)> can be used.

+

See: contract::wrap<void(T)> specialization, CONTRACT_WRAP_TYPE()

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract/wrap_void_T__id2348632.html b/doc/html/contract/wrap_void_T__id2348632.html new file mode 100755 index 00000000..5a7980c1 --- /dev/null +++ b/doc/html/contract/wrap_void_T__id2348632.html @@ -0,0 +1,75 @@ + + + +Struct template wrap<void(T)> + + + + + + + + +
+PrevUpHomeNext +
+
+
+
+
+

Struct template wrap<void(T)>

+

contract::wrap<void(T)>

+
+

Synopsis

+
// In header: <contract/wrap.hpp>
+
+template<typename T> 
+struct wrap<void(T)> {
+  // types
+  typedef T type;
+};
+
+

Description

+

Metafunction used to wrap type expressions containing commas so they can be passed as macro parameters.

+

This metafunction first wrap the specified type T within parenthesis () (so T can be passed as a single macro parameter even if it contains commas) forming a void-function type with one argument of type T. Then the application of the metafunction via its member type returns the wrapped type T.

+

Parameters:

+
++++ + + + + +
TType to be wrapped so it can be passed within a macro parameter even if it contains commas.
+

+

+

See: CONTRACT_WRAP_TYPE() for more explanation and examples

+
+

+wrap + public + types

+
  1. +

    +typedef T type;

    +

    The type T.

    +
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract__/bibliography.html b/doc/html/contract__/bibliography.html new file mode 100755 index 00000000..4bb3bbdf --- /dev/null +++ b/doc/html/contract__/bibliography.html @@ -0,0 +1,129 @@ + + + +Bibliography + + + + + + + + +
+PrevUpHomeNext +
+
+
+ +

+ [Abrahams2005] D. Abrahams, L. Crowl, T. Ottosen, and J. Widman. Proposal + to add Contract Programming to C++ (revision 2). The C++ Standards + Committee, n1773, + 2005. +

+

+ [Bright2004] W. Bright. Contract + Programming for the D Programming Language. 2004. +

+

+ [Bright2004b] W. Bright. Contract + Programming for the Digital Mars C++ Compiler. 2004. +

+

+ [C^2] Aechmea. C^2 + Contract Programming add-on for C++. 2005. +

+

+ [Chrome2002] RemObjects. Chromes: + Contract Programming for Object Pascal in .NET. 2002. +

+

+ [Crowl2005] L. Crowl and T. Ottosen. Proposal to add Contract Programming + to C++ (revision 3). The C++ Standards Committee, n1866, + 2005. +

+

+ [Crowl2006] L. Crowl and T. Ottosen. Proposal to add Contract Programming + to C++ (revision 4). The C++ Standards Committee, n1962, + 2006. +

+

+ [iContract] O. Enseling. iContract: + Contract Programming for Java. 2001. +

+

+ [Jcontract] Parasoft. Jcontract: + Contract Programming for Java. +

+

+ [Maley1999] D. Maley and I. Spence. Emulating + Design by Contract in C++. Proceedings of TOOLS, IEEE Computer + Society, 1999. +

+

+ [Meyer1997] B. Meyer. Object Oriented Software Construction. + Prentice-Hall, 2nd edition, 1997. +

+

+ [Mitchell2002] R. Mitchell and J. McKim. Design by Contract, by Example. + Addison-Wesley, 2002. +

+

+ [Nelson2004] C. Nelson. Working draft changes for C99 preprocessor + synchronization. C++ Standards Committee n1653, + 2004. +

+

+ [Ottosen2004] T. Ottosen. Proposal to add Design by Contract to C++. + The C++ Standards Committee, n1613, + 2004. +

+

+ [Ottosen2004b] T. Ottosen. Proposal to add Contract Programming to + C++ (revision 1). The C++ Standards Committee, n1669, + 2004. +

+

+ [SPARKAda] Praxis. SPARKAda + (Ada-like Language with Contract Programming). +

+

+ [Spec#] Microsoft. Spec# + (C# Extension). +

+

+ [Stroustrup1997] B. Stroustrup. The C++ Programming Language. + Prentice-Hall, 2nd Edition, 1997 +

+

+ [Sutter2005] H. Sutter and F. Glassborow. Delegating Constructors, + revision 2. C++ Standards Committee, n1895, + 2005. +

+

+ [Tandin2004] A. Tandin. Design + by Contract macros for C++ and link to Doxygen. 2004. +

+

+ [Wilson2006] M. Wilson. Contract Programming 101 -- The Nuclear Reactor + and the Deep Space Probe. The + C++ Source, 2006. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract__/contract_programming.html b/doc/html/contract__/contract_programming.html new file mode 100755 index 00000000..3bb881aa --- /dev/null +++ b/doc/html/contract__/contract_programming.html @@ -0,0 +1,885 @@ + + + +Annex: Contract Programming + + + + + + + + +
+PrevUpHomeNext +
+
+
+ + +

+ This section continues the discussion on Contract Programming started in Contract Programming + Overview. +

+
+ +

+ The following table compares features between this library, the proposal + for adding Contract Programming to the C++ standard [Crowl2006] + (see also [Crowl2005], [Abrahams2005], [Ottosen2004b], + and [Ottosen2004]) + [16] + , the Eiffel programming language [Meyer1997], + and the D programming language [Bright2004]. +

+
+

Table 1. Contract Programming Feature Comparison

+
+++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Feature +

+
+

+ This Library +

+
+

+ C++ Standard Proposal +

+
+

+ ISE Eiffel 5.4 +

+
+

+ D +

+
+

+ Keywords +

+
+

+ In contract macros preprocessor sequence: (precondition), + (postcondition), (body), (copyable), + (inherit) +

+
+

+ 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 (might throw) +

+
+

+ Default to std::terminate() + but can be customized (might throw) +

+
+

+ Throw exception +

+
+

+ Throw exception +

+
+

+ Return value in postconditions +

+
+

+ Yes, (postcondition)(result-name) +

+
+

+ Yes, postcondition (result-name) +

+
+

+ Yes, result keyword +

+
+

+ No +

+
+

+ Old values in postconditions +

+
+

+ Yes, CONTRACT_OLDOF(name) + (but only for class and argument types tagged contract::copyable) +

+
+

+ Yes, oldof keyword +

+
+

+ Yes, old keyword +

+
+

+ No +

+
+

+ Subcontracting +

+
+

+ Yes, also support multiple base contracts for multiple inheritance +

+
+

+ Yes, also support multiple base contracts but only base classes can + specify preconditions +

+
+

+ Yes +

+
+

+ Yes +

+
+

+ Contracts for abstract functions +

+
+

+ Yes +

+
+

+ Yes +

+
+

+ Yes +

+
+

+ No (planned) +

+
+

+ Arbitrary code in contracts +

+
+

+ Yes (but recommended to limit contracts to a list of assertions CONTRACT_ASSERT() + and to use only public members in preconditions) +

+
+

+ No, assertions only +

+
+

+ No, assertions only plus preconditions can only access public members +

+
+

+ Yes +

+
+

+ Constant-correct +

+
+

+ Yes +

+
+

+ Yes +

+
+

+ Yes +

+
+

+ No +

+
+

+ Function code ordering +

+
+

+ In contract macros preprocessor sequence: Preconditions -> postconditions + -> body +

+
+

+ Preconditions, postconditions, body +

+
+

+ Preconditions, body, postconditions +

+
+

+ Preconditions, postconditions, body +

+
+

+ Static assertions +

+
+

+ No (but Boost.MPL + can be used within contracts) +

+
+

+ No +

+
+

+ No +

+
+

+ Yes +

+
+

+ Block invariants +

+
+

+ Yes, CONTRACT_ASSERT_BLOCK_INVARIANT() +

+
+

+ Yes, invariant +

+
+

+ No, but support loop invariants (loops are special code blocks that + iterate) +

+
+

+ No +

+
+

+ Loop variants +

+
+

+ Yes, CONTRACT_ASSERT_LOOP_VARIANT() and CONTRACT_INIT_LOOP_VARIANT +

+
+

+ No +

+
+

+ Yes +

+
+

+ No +

+
+

+ Disable assertion checking within assertions checking (policy) +

+
+

+ Yes (to prevent infinite recursion) +

+
+

+ Yes, but not in preconditions +

+
+

+ Yes +

+
+

+ No +

+
+

+ Nested function calls (policy) +

+
+

+ Disable checking of class invariants (static and non) +

+
+

+ Disable nothing +

+
+

+ Disable all checks +

+
+

+ Disable nothing +

+
+

+ Non-static class invariants checking (policy) +

+
+

+ At constructor exit, around any non-static function, at destructor + entry, and at function exit due to exception -- but only if programmers + specifies contracts for those (e.g., if no contract specified for a + private function then no class invariant and no contract is checked + for that function) +

+
+

+ At constructor exit, around public functions, at destructor entry, + and at function exit due to exception +

+
+

+ At constructor exit, and around public functions +

+
+

+ At constructor exit, around public functions, and at destructor entry +

+
+

+ Static class invariants checking (policy) +

+
+

+ At entry and exit of any (also static) member function, constructor, + and destructor +

+
+

+ No static class invariants +

+
+

+ No static class invariants +

+
+

+ No static class invariants +

+
+

+ Removable from object code +

+
+

+ Yes, any combinations of CONTRACT_CHECK_BLOCK_INVARIANT, + CONTRACT_CHECK_CLASS_INVARIANT, + CONTRACT_CHECK_PRECONDITION, + and CONTRACT_CHECK_POSTCONDITION +

+
+

+ Yes +

+
+

+ Yes (but predefined combinations only) +

+
+

+ Yes +

+
+
+
+
+
+ +

+ The design of this library was largely based on the requirements identified + by the different revisions of the proposal for adding Contract Programming + to the C++ standard [Crowl2006, etc] + and by the Eiffel programming language [Meyer1997]. +

+

+ This is a list of some of the specific requirements considered for the library + design: +

+
    +
  1. + Implement Contract Programming within ISO standard C++ (without using external + preprcessing tools, etc). +
  2. +
  3. + Support optional contract compilation and checking. Programmers can select + any combination among invariants, preconditions, and postconditions to + be compiled and checked (e.g., compile and check invariants and postconditions + only). +
  4. +
  5. + Programmers can decide the action to take on contract failure. +
  6. +
  7. + Programmers can completely remove contract code for compilation. In other + words, if no invariants, no preconditions, and no postconditions are compiled + and checked then the user code should remain unchanged (for object size, + execution time, compilation-time, etc). +
  8. +
  9. + Support old values in postconditions for copyable types. Plus allow programmers + to remove the extra copy overhead even for copyable types if the old value + is not needed in postconditions (e.g., by not specifying the type copyable). +
  10. +
  11. + Support result value in postconditions. +
  12. +
  13. + Support subcontracting with multiple inheritance. +
  14. +
  15. + Enforce contract constant-correctness at compile-time. +
  16. +
  17. + Do not alter the user code public API. +
  18. +
  19. + Support contract for all C++ constructs (operators, template class, template + functions, static members, non-members, non-static members, constructors, + destructors, pure virtual members, etc). +
  20. +
  21. + Program contracts together with function and class declarations (not definitions) + because contracts are part of the specifications. +
  22. +
  23. + Support contract when function (body) definition is separated from (contract) + declaration. +
  24. +
  25. + Support block invariants. +
  26. +
  27. + Support loop variants and invariants. +
  28. +
+

+ In addition, library early implementations were somewhat inspired by the + work of [Maley1999]. +

+
+
+ +

+ The main use of Contract Programming is to improve software quality. [Meyer1997] discusses how Contract + Programming can be used as the basic tool to write "correct" software. + The following is a short summary of the benefits associated with Contract + Programming mainly taken from [Ottosen2004]. + See also [Wilson2006] for + a discussion of Contract Programming applied to the C++ programming language. + Furhtermore, [Stroustrup1997] + discusses the key importance of class invariants plus advantages and disadvantages + of using preconditions and postconditions. +

+
    +
  1. + 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 object life-cycle + checking the class invariants one last time before destroying the object. +
  2. +
  3. + 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 the old value + in postconditions, Contract Programming provides a mechanism that allows + programmers to compare values of an expression before and after the executions + of the function body. This mechanism is powerful enough to enable programmers + to express many constraints within the code -- constraints that would otherwise + have to be captured at the best only informally by the code documentation. +
  4. +
  5. + Because contracts are embedded directly into 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 source code itself. +
  6. +
  7. + 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 that in some later stage + of the program in an apparently unrelated manner. In general, 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. + [17] +
  8. +
  9. + 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 + inputs cause it to exit normally. +
  10. +
  11. + 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. +
  12. +
  13. + Contract Programming formalizes the virtual function overriding mechanism + via the concept of subcontracting. This keeps the base class programmers + in control as overriding functions still have to fully satisfy the base + class contracts. +
  14. +
  15. + Contract Programming assertions can replace defensive programming + checks localizing these checks within the contract and making the code + more readable. +
  16. +
+
+
+

+Costs +

+

+ Contract Programming benefits come to the cost of performance as discussed + in detail by both [Stroustrup1997] + and [Meyer1997]. +

+

+ The run-time performances are negatively impacted by Contract Programming + mainly because of the following: +

+
    +
  1. + The extra processing required to check the assertions. +
  2. +
  3. + The extra processing required by the additional function calls (additional + functions are invoked to check class invariants, preconditions, and postconditions). +
  4. +
  5. + The extra processing required to copy object and function arguments when + their old values are accessed in postconditions. +
  6. +
+

+ To alleviate some of these run-time performance impacts, you can selectively + turn off some of the contract compilation and the related run-time checking. + In reality, you will have to decide based on the performance trade-offs required + by your system but a reasonable approach might be to + [18] + : +

+
    +
  • + Always write contracts to clarify the semantics of your design embedding + them directly into the code and its documentation. +
  • +
  • + Turn on class invariants, preconditions, and postconditions compilation + and checking during early testing. +
  • +
  • + Turn on only preconditions (and possibly class invariants) during release + testing and for the final release. (Postconditions are usually more expensive + to check.) +
  • +
+

+ Compile-time performances are also impacted by this library as compilation + time and compiler memory usage increase mainly because: +

+
    +
  1. + The contracts appear in the class declaration (usually header files) so + they have to be re-compiled for each translation unit. +
  2. +
  3. + The library implementation extensively uses C++ preprocessor and template + metaprogramming which can significantly stress some compilers. +
  4. +
+

+ In addition, Contract Programming might induce a false sense of security + on the correctness of the software. However, Contract Programming is proposed + here as a tool to complement (and not to substitute) testing. +

+

+ In general, Contract Programming is an essential approach to improve software + quality even if it comes at a performance cost. 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 a system that quickly and efficiently provides the incorrect output. +

+
+
+ +

+ Contract Programming is also supported by the following tools (this is not + a complete list): +

+
    +
  • +[Bright2004b] is the Digital + Mars C++ compiler with added Contract Programming support. +
  • +
  • +[C^2] implements Contract + Programming for C++ using an external preprocessing tool. +
  • +
  • +[Spec#] extends C# with + Contract Programming. +
  • +
  • +[iContract] and [Jcontract] + are external preprocessing tools that implement Contract Programming for + Java. +
  • +
  • +[Chrome2002] is Object Pascal + in .NET with Contract Programming support. +
  • +
  • +[SPARKAda] 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. +

+
+
+

+

[16] + These are all revisions of the same proposal for adding Contract Programming + to the C++ standard. +

+

[17] + 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 they 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 they + make a mistake twice (in the body and in the contract) + is lower than the probability that the mistake is made just once (in + the body). +

+

[18] + This approach is generally reasonable because in well tested production + code, validating the function body implementation via postconditions + and class invariants is rarely needed since the function has shown itself + to be "correct" during testing. On the other hand, checking + arguments has continuing need because of the evolution of the callers. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract__/examples.html b/doc/html/contract__/examples.html new file mode 100755 index 00000000..da3d5deb --- /dev/null +++ b/doc/html/contract__/examples.html @@ -0,0 +1,539 @@ + + + +Examples + + + + + + + + +
+PrevUpHomeNext +
+
+
+ +

+ This section provides source code of fully working examples that can all be + compiled and executed using this library. The most interesting examples (from + the authors' prospective) have highlighted keywords in their purpose descriptions. +

+

+ All examples presented in the Contract Programming proposal for the C++ standard + [Crowl2006] are programmed here + using the library. Most of the other examples have been ported to C++ from + Eiffel code using this library and they were originally presented in [Meyer1997] and [Mitchell2002]. +

+
++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Source +

+
+

+ Name +

+
+

+ Purpose +

+
+

+ Files +

+
+

+ [Crowl2006] +

+
+

+ STL Vector +

+
+

+ Complete contracts for STL vector. +

+
+

+ main.cpp +

+
+

+ [Crowl2006] +

+
+

+ Block +

+
+

+ Block invariants. +

+
+

+ main.cpp +

+
+

+ [Crowl2006] +

+
+

+ Circle +

+
+

+ Subcontracting. +

+
+

+ main.cpp +

+
+

+ [Crowl2006] +

+
+

+ Factorial +

+
+

+ Contracts with recursion. +

+
+

+ main.cpp +

+
+

+ [Crowl2006] +

+
+

+ Operator Equal +

+
+

+ Contracts for operators. +

+
+

+ main.cpp +

+
+

+ [Crowl2006] +

+
+

+ Square Root +

+
+

+ Contracts for non-member functions. +

+
+

+ main.cpp +

+
+

+ [Crowl2006] +

+
+

+ Sum +

+
+

+ Contracts for non-member functions (with separated definition). +

+
+

+ sum.hpp sum.cpp + main.cpp +

+
+

+ [Mitchell2002] +

+
+

+ Name List +

+
+

+ Relax base class preconditions using subcontracting. +

+
+

+ names.hpp + names.cpp + main.cpp +

+
+

+ [Mitchell2002] +

+
+

+ Courier +

+
+

+ Relax base class preconditions using subcontracting. +

+
+

+ couriers.hpp + couriers.cpp + main.cpp +

+
+

+ [Mitchell2002] +

+
+

+ Dictionary +

+
+

+ Contracts for a dictionary (map-like) data-type. +

+
+

+ dictionary.hpp + main.cpp +

+
+

+ [Mitchell2002] +

+
+

+ Stack +

+
+

+ Contracts for a stack. +

+
+

+ stack.hpp + main.cpp +

+
+

+ [Mitchell2002] +

+
+

+ Simple Queue +

+
+

+ Contracts for a queue. +

+
+

+ simple_queue.hpp + main.cpp +

+
+

+ [Mitchell2002] +

+
+

+ Customer Manager +

+
+

+ Contracts for a class manging customers. +

+
+

+ customer_manager.hpp + customer_manager.cpp + main.cpp +

+
+

+ [Mitchell2002] +

+
+

+ Observe +

+
+

+ Contracts for the observer design pattern. +

+
+

+ observe.hpp + main.cpp +

+
+

+ [Mitchell2002] +

+
+

+ Counter +

+
+

+ Relaxe the accessible copy constructor requirement + for old decrement_button + objects in postconditions. +

+
+

+ counter.hpp + view_of_counter.hpp + push_button.hpp + decrement_button.hpp + main.cpp +

+
+

+ [Meyer1997] +

+
+

+ Stack3 +

+
+

+ Contracts for functions returning error codes. +

+
+

+ stack3.hpp + main.cpp +

+
+

+ [Meyer1997] +

+
+

+ Stack4 +

+
+

+ Contracts for stack. +

+
+

+ stack4.hpp + main.cpp +

+
+

+ [Meyer1997] +

+
+

+ Greatest Common Divisor +

+
+

+ Block invariants and loop variants. +

+
+

+ main.cpp +

+
+

+ [Meyer1997] +

+
+

+ Max Array +

+
+

+ Block invariants and loop variants. +

+
+

+ main.cpp +

+
+

+ [Stroustrup1997] +

+
+

+ String +

+
+

+ Precondition and invariants (no postconditions). +

+
+

+ string.hpp + string.cpp + main.cpp +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract__/getting_started.html b/doc/html/contract__/getting_started.html new file mode 100755 index 00000000..cb480292 --- /dev/null +++ b/doc/html/contract__/getting_started.html @@ -0,0 +1,219 @@ + + + +Getting Started + + + + + + + + +
+PrevUpHomeNext +
+
+
+ + +

+ This section illustrates how to setup your system to use this library. +

+
+ +

+ This library requires the Boost.MPL + and Boost.Preprocessor + libraries. The Boost library is + a collection of highly portable C++ libraries. You should be able to download, + compile, and install Boost for + your operating system from the Boost + website. Precompiled Boost installation + packages are also available for most common operating systems and they might + already be installed on your system. +

+

+ This library is composed of header files only. Therefore there are no library + precompiled object files which need to be installed. Just instruct your C++ + compiler where to find the library header files (e.g., using the '-I' option + for GCC or '/I' for MSVC). For example, if you have uncompressed the library + files in a directory named "$HOME/libs/contractpp/" + then you can compile with GCC using: +

+
$ g++ -I$HOME/libs/contractpp/src/ ...
+
+

+ Note that the path of the library source files (contained in the "src/" subdirectory) is specified. +

+
+
+ +

+ The library headers are simply included in your C++ source code as follow: +

+
#include <contract.hpp>
+
+

+ In general, there is no need to include the header files from the "contract/" + directory separately and the one include above is enough. In this documentation, + the #include <contract.hpp> + will occasionally be assumed and omitted from the example code. +

+
+
+ +

+ This library provides the following macro symbols to selectively turn on + or off contract compilation and run-time checking: +

+
    +
  • +Block invariants and loop + variants are compiled and checked only if the CONTRACT_CHECK_BLOCK_INVARIANT + is #defined. By default, this macro symbol is not + #defined. +
  • +
  • +Class invariants are compiled and checked + only if the CONTRACT_CHECK_CLASS_INVARIANT + is #defined. By default, this macro symbol is not + #defined. +
  • +
  • +Preconditions are compiled and checked + only if the CONTRACT_CHECK_PRECONDITION + is #defined. By default, this macro symbol is not + #defined. +
  • +
  • +Postconditions are compiled and checked + only if the CONTRACT_CHECK_POSTCONDITION + is #defined. By default, this macro symbol is not + #defined. In addition, the library copies variables to support old values + in postconditions only when CONTRACT_CHECK_POSTCONDITION + is #defined (in this case, these extra copy operations will introduce some + run-time overhead). +
  • +
+
+ + + + + +
[Important]Important
+

+ Contracts Off by Default +

+

+ All these symbols are #undefined by default so you must define them when + compiling otherwise the library will do nothing. +

+
+

+ In Contract Programming, it is usually important to be able to selectively + turn off compilation of invariants, preconditions, and/or postconditions + for the sake of run-time efficiency and to reduce the size of the compiled + object code. +

+

+ These macros must be #defined before the library first + #include. Your compiler options to #define macros can be used to this purpose + ("-D" and "-U" for GCC, "/D" and "/U" + for Microsoft Visual C++, etc). +

+

+ For example, let's assume we only want to check class invariants and preconditions + but no postconditions and block invariants. Then we have to #define CONTRACT_CHECK_CLASS_INVARIANT + and CONTRACT_CHECK_PRECONDITION + but leave CONTRACT_CHECK_POSTCONDITION + and CONTRACT_CHECK_BLOCK_INVARIANT + #undefined. If we are using the GCC compiler, we can do this using the following + command line options: +

+
$ g++ -DCONTRACT_CHECK_CLASS_INVARIANT -DCONTRACT_CHECK_PRECONDITION
+  -UCONTRACT_CHECK_POSTCONDITION -UCONTRACT_CHECK_BLOCK_INVARIANT ...
+
+
+
+ +

+ All library names are defined within the contract + namespace. All library macros start with the CONTRACT + prefix. Any library names, macros, files, directories, etc that end with + an underscore "_" + are library implementation specific and should not be + used directly in user code by programmers. +

+

+ This library needs to augment the user code with special + symbols to implement the contracts. These symbols need to be defined within + the user code namespace. All these symbols start with the contract + prefix and end with an underscore "_" + to prevent name clashes with user code. Again, these symbols end with an + underscore "_" + so they are library implementation specific and should not + be used directly in user code by programmers. +

+

+ Finally, all library names in the contract::aux namespace + and symbols starting with CONTRACT_AUX + are also library implementation specific and should not + be used directly in user code by programmers. +

+
+
+ +

+ Some of the library behaviour can be changed at compile-time #defining special + configuration macros (CONTRACT_CONFIG_MAX_FUNCTION_ARITY, + CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + etc). If configuration macros are not #defined, the library will use appropriate + default values for them. +

+

+ The library configuration macros can be #defined using your compiler options + similarly to what discussed above. However, it is strongly recommended not + to change the library compile-time configuration unless strictly necessary. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract__/license.html b/doc/html/contract__/license.html new file mode 100755 index 00000000..55308023 --- /dev/null +++ b/doc/html/contract__/license.html @@ -0,0 +1,67 @@ + + + +License + + + + + + + + +
+PrevUpHomeNext +
+
+
+ +
Copyright (C) 2009-2010 Lorenzo Caminiti.
+Use, modification, and distribution is subject to the
+Contract++ Software License, Version 1.0.
+(See accompanying file LICENSE_1_0.txt.)
+
+
(File: LICENSE_1_0.txt)
+
+Contract Programming for C++ (Contract++) Software License, Version 1.0
+April 19th, 2009
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract__/release_history.html b/doc/html/contract__/release_history.html new file mode 100755 index 00000000..88011129 --- /dev/null +++ b/doc/html/contract__/release_history.html @@ -0,0 +1,154 @@ + + + +Release History + + + + + + + + +
+PrevUpHomeNext +
+
+
+ + +

+ List of releases from the newest to the oldest. +

+
release-number := major.minor.subversion-revision
+
+
+ +
    +
  1. + 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. +
  2. +
  3. + Added (precondition), (postcondition), + and (body) to specify contracts within the function + signature sequence. If no preconditions then (precondition) + ({...}) is simply omitted from + sequence (same for postconditions, + body is mandatory instead). For non-void functions, user can name the result + argument with (postcondition) (result-name) ({...}). +
  4. +
  5. + Changed contract class template to use same syntax as Boost.Function (i.e., + F function type). +
  6. +
  7. + Added support for non-member and static functions. +
  8. +
  9. + Added support for subcontracting with multiple inheritance. +
  10. +
  11. + Added static class invariants which are always checked (also at constructors + entry, destructor exit, and by static member functions). +
  12. +
  13. + Added block invariants and Eiffel-like loop variants. +
  14. +
  15. + Added functions to customize action on contract failure (default to std::terminate()). +
  16. +
  17. + Removed feature for automatic contract documentation using Doxygen (this + is not compatible with added (precondition), + (postcondition), and (body) + because Doxygen preprocessor is not intended to handle Boost.Preprocessor + sequences). +
  18. +
  19. + Rewritten entire documentation (now using Boost.Quickbook instead of Doxygen). +
  20. +
+
+
+ +
    +
  1. + Compiled on both GCC (Linux and Cygwin) and Microsoft Visual C++ (Windows + XP). +
  2. +
  3. + Required to use void to specify + empty function argument list. This is to comply with C++ ISO standard that + does not allow to pass empty macro parameters so it does not support empty + preprocessor sequence elements (). +
  4. +
+
+
+ +
  1. + Completed first documentation draft. +
+
+
+ +
    +
  1. + Reorganized files to cleanup root directory. +
  2. +
  3. + Added installation program. +
  4. +
+
+
+ +
  1. + First public release. +
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract__/throw_on_failure.html b/doc/html/contract__/throw_on_failure.html new file mode 100755 index 00000000..7ae02b77 --- /dev/null +++ b/doc/html/contract__/throw_on_failure.html @@ -0,0 +1,147 @@ + + + +Annex: Throw on Failure + + + + + + + + +
+PrevUpHomeNext +
+
+
+ +

+ This example shows how to setup the library to throw exceptions on contract + condition failure (overriding the library default behaviour to call std::terminate() to handle contract failures). +

+

+ Specifically: +

+
    +
  1. + Any exception (including user defined ones) that is thrown when checking + a contract condition is re-thrown by the contract failure handlers defined + below. +
  2. +
  3. + However, if a contract condition fails from a destructor, exceptions cannot + be thrown (to comply with C++ STL exception safety requirements) so a message + is logged to std::clog and the program execution continues. + [15] +
  4. +
  5. + In addition, the postcondition failure handler catches any exception derived + from std::exception to print the exception description + what() + on std::clog before re-throwing it (this is to + show how the contract failure handlers can selectively catch exceptions). +
  6. +
+

+

+

+ +

+
#include <contract.hpp>
+#include <iostream>
+
+// User defined exception (not even derived from `std::exception`).
+class not_a_number {};
+
+double sqrt(double x)
+CONTRACT_FUNCTION( (double) (sqrt)( (double)(x) )
+(precondition) ({
+    // Eventually throws user-defined exception.
+    if (!( x >= 0.0 )) throw not_a_number();
+})
+(postcondition) (root) ({
+    // Eventually throw library defined exception `contract::failure`.
+    CONTRACT_ASSERT( (root * root) == x );
+})
+(body) ({
+    return 0.0; // Intentionally incorrect to fail postcondition.
+}) )
+
+void throwing_handler(const contract::from& where) {
+    if (where == contract::FROM_DESTRUCTOR) {
+        // Cannot throw from within destructor for STL exception safety.
+        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.
+    }
+}
+
+void postcondition_throwing_handler(const contract::from& where) {
+    // try/catch/re-throw to get active exception (for logging, etc.).
+    try {
+        throw; // Re-throw active exception thrown by precondition.
+    } catch (std::exception& error) { // Get exception object.
+        std::clog << "Throwing '" << error.what() << "'" << std::endl;
+        
+        throw; // Re-throw.
+    } // Non standard exception also thrown.
+}
+
+int main() {
+    // Setup contract failure handlers that throw (instead of terminate).
+    contract::set_precondition_failed(&throwing_handler);
+    contract::set_postcondition_failed(&postcondition_throwing_handler);
+    // Invariants not used by this examples but set anyway...
+    contract::set_class_invariant_failed(&throwing_handler);
+    contract::set_block_invariant_failed(&throwing_handler);
+
+    try {
+        std::cout << sqrt(-1.0) << std::endl;
+    } catch (not_a_number&) {
+        std::clog << "Ignored not a number exception" << std::endl;
+    }
+
+    try {
+        std::cout << sqrt(4.0) << std::endl;
+    } catch (...) {
+        std::clog << "Unable to calculate square root" << std::endl;
+    }
+
+    return 0;
+}
+
+
+

+

+

+

+
+

+

[15] + Continuing the program in this case assumes that the destructors body + will be able to somehow execute correctly even if the class invariants + do not hold true. This is usually not a safe assumption + and it is made here only for simplicity. You could chose to still terminate + in case class invariants fail for a destructor or to attempt to recover + from such an error in some other, more sophisticated, way. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract__/todo.html b/doc/html/contract__/todo.html new file mode 100755 index 00000000..19a57087 --- /dev/null +++ b/doc/html/contract__/todo.html @@ -0,0 +1,147 @@ + + + +TODO + + + + + + + +
+PrevUpHome +
+
+
+

+TODO +

+ +

+ This section lists open items under consideration for future development of + this library. It is mainly intended as a memorandum for the library authors. +

+
+ +

+ The current implementation for syntax error detection and reporting for the + sequence parameter of the + contract macros should be improved. For example, if I forget the sequence + element for the result type (result-type), + the preprocessor given a ton of errors most of which are about Boost.Preprocessor + internal macros and make no sense to the user. While there are some fundamental + limitations to the amount of syntax checking I can implement with the preprocessor + for sequence, I should be + able to improve the current implementation. +

+
+
+ +

+ Can the contract macros overcome the constructor member initialization list + limitation when separating definition from declaration? However, this would + have to work for all combinations of the followings: (1) with and without + contracts, (2) definition together and separated from declaration, (3) with + and without member initialization list. +

+
+
+ +

+ The library checks constructor preconditions after executing the member initialization + list: {Default AND Pre}Body{Post AND Inv} (Default is the member initialization + list). +

+

+ This is what Eiffel does but is this what C++ should do or {Pre AND Default} + is a better approach for C++? Why does Eiffel do {Default AND Pre}? Does + any of the CP proposals for C++ mention this issue explicitly? +

+

+ If {Pre AND Default} is a better approach, {Default AND Pre} should be documented + as a library limitation. If {Default and Pre} is a better approach, I should + document why. +

+
+
+ +

+ Look if the contract macro sequence + syntax can be unified with the one of other Boost libraries. +

+

+ Specifically, is this possible with Boost.ConceptCheck and how concept checking + interacts with this Contract Programming library? Same questions respect + to Boost.Parameter. Any other Boost library I should look in these regards? +

+
+
+ +
    +
  1. + I have a template library that is well tested so I want to disable postcondition + checking. However, that is a template so it cannot be precompiled separately + with postconditions off. I must compile it together with the rest of the + code. Therefore, if the rest of the code needs to check postconditions, + I must check postconditions for the well tested template library as well! +
  2. +
  3. + There might be contract conditions which are very inefficient to test so + I might want to turn only the inefficient condition checking off. +
  4. +
+

+ If I could disable contract checking (at least at run-time) based on class + name or class+function name, I could address the template issue. And/or if + I could disable contract checking (at least at run-time) based on some assertion + priority (or level of inefficiency), I could address the second issue (one + of the CP C++ proposal might suggest to attach a priority label to the assertions... + I am not sure). +

+
+
+ + + +
+
+
+PrevUpHome +
+ + diff --git a/doc/html/contract__/tutorial.html b/doc/html/contract__/tutorial.html new file mode 100755 index 00000000..968a2e30 --- /dev/null +++ b/doc/html/contract__/tutorial.html @@ -0,0 +1,2454 @@ + + + +Tutorial + + + + + + + + +
+PrevUpHomeNext +
+
+
+ + +

+ This section gives an overview of Contract Programming and explains how this + library can be used to write contracts. At the end of the section there is + a fully working example that can be compiled and executed. +

+
+ +

+ Contract Programming is characterized at least by the following assertion + mechanisms (see [Meyer1997], + [Ottosen2004], or [Crowl2006]): +

+
    +
  1. + It is possible to describe 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 member function with a contract, and before the destructor + is executed (e.g., class invariants can define a valid state for all objects + of a class). It is possible to describe static class + invariants also which are expected to be true before and after + the execution of any member function with a contract (including static + member functions, constructor entry, and destructor exit). +
  2. +
  3. + It is possible to describe function preconditions. + These are logical conditions that programmers except to be true when the + function is called (e.g., to check constraints on input function arguments). +
  4. +
  5. + It is possible to describe function 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). +
  6. +
  7. + It is possible to formalize the notion of overriding a virtual member function + via subcontracting. Subcontracting can + be justified by substitution principles and it consists of the following + rules that the overriding function must obey: +
      +
    1. + Preconditions cannot be strengthen. +
    2. +
    3. + Postconditions cannot be weaken. +
    4. +
    5. + Class invariants cannot be weaken. +
    6. +
    +
  8. +
  9. + It is possible to describe block invariants. + These are logical conditions that programmes 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 function like loop invariants asserting + conditions that are excepted to be true for every loop iteration. +
  10. +
  11. + It is possible to describe a loop variant. + This a positive integer expression with a value that is expected to decrease + at every subsequent loop iteration. +
  12. +
+

+ Based on these definitions of invariants, preconditions, postconditions, + and subcontracting it is possible to specify the semantics of the invocation + of a function for which a contract has been specified. +

+
+ + Non-Member + Function Call Semantics +
+

+ A non-member function call should execute the following steps: +

+
    +
  1. + Check preconditions. +
  2. +
  3. + Execute function body. +
  4. +
  5. + Check postconditions. +
  6. +
+
+ + Member + Function Call Semantics +
+

+ A member function call should execute the following steps: +

+
    +
  1. + Check static class invariants. +
  2. +
  3. + Check non-static class invariants AND, when subcontracting, + check the base class invariants (for non-static member functions only + [2] + ). +
  4. +
  5. + Check preconditions OR, when subcontracting, check + the overridden function preconditions. +
  6. +
  7. + Execute function body. +
  8. +
  9. + Check static class invariants (even if body throws an exception). +
  10. +
  11. + Check non-static class invariants AND, when subcontracting, + check base class invariants (for non-static member functions only plus + checked even if body throws an exception). +
  12. +
  13. + Check postconditions AND, when subcontracting, check + overridden function postconditions (only if body did not throw an exception). +
  14. +
+

+ Where AND and OR are the logical + "and" and "or" operators evaluated in short-circuit (i.e., + A AND B evaluates B only if A is evaluated to be true, + A OR B evaluates B only if A is evaluated to be false). +

+

+ When a member function overrides more than one virtual function due to multiple + inheritance: +

+
    +
  • + Class invariants are checked in AND with the invariants + of all the base classes (following the inheritance + order). +
  • +
  • + Preconditions are checked in OR with the preconditions + of all the overridden functions (following the inheritance + order). +
  • +
  • + Postconditions are checked in AND with the postconditions + of all the overridden functions (following the inheritance + order). +
  • +
+
+ + Constructor + Call Semantics +
+

+ A constructor call should execute the following steps: +

+
    +
  1. + Initialize member variables via the constructor member initialization list + (if such a list is specified). +
  2. +
  3. + Check static class invariants (but not the non-static class invariants). +
  4. +
  5. + Check preconditions. +
  6. +
  7. + Execute constructor body. +
  8. +
  9. + Check static class invariants (even if body throws an exception). +
  10. +
  11. + Check class invariants (even if body throws an exception). +
  12. +
  13. + Check postconditions (only if body did not throw an exception). +
  14. +
+

+ Before constructor body execution, there is no object therefore: +

+
    +
  • + Non-static class invariants do not have to hold true and they are not checked + at constructor entry. +
  • +
  • + Preconditions cannot access the object. +
  • +
  • + Postconditions cannot access the old object value (as it was before body + execution). +
  • +
+
+ + Destructor + Call Semantics +
+

+ A destructor call should execute the following steps: +

+
    +
  1. + Check static class invariants. +
  2. +
  3. + Check class invariants. +
  4. +
  5. + Execute destructor body. +
  6. +
  7. + Check static class invariants (but not the non-static class invariants + plus checked even if body throws an exception + [3] + ). +
  8. +
+

+ Note that: +

+
    +
  • + Destructors have no arguments so they have no preconditions. +
  • +
  • + After destructor body execution, there is no object anymore (because it + has been destroyed) so non-static class invariants do not have to hold + true and they are not checked at destructor exit. +
  • +
  • + Destructors have no postconditions as there is no function argument and + after body execution there is no object. +
  • +
+
+
+ +

+ After programmers specify contracts, this library provides a mechanism to + automatically check if class invariants, preconditions, postconditions, block + invariants, and loop variants hold true at run-time or not. +

+

+ If a class invariant, precondition, postcondition, block invariant, or loop + variant asserted via CONTRACT_ASSERT(), CONTRACT_ASSERT_BLOCK_INVARIANT(), or CONTRACT_ASSERT_LOOP_VARIANT() is checked to be false, the library invokes + the contract::class_invariant_failed(), contract::precondition_failed(), contract::postcondition_failed(), contract::block_invariant_failed() (for both block invariant and loop variant + failures) function respectively. These functions invoke std::terminate() by default but programmers can redefine + them to take a different action using contract::set_class_invariant_failed(), contract::set_precondition_failed(), contract::set_postcondition_failed(), and contract::set_block_invariant_failed(). +

+

+ This mechanism is similarly to the one of C++ std::set_terminate() (see Throw + on Failure for an example). +

+
+ + Exceptions +
+

+ When an exception if thrown while checking invariants, preconditions, or + postconditions then the contract condition is considered failed (because + it was not possible to check it as being true) and the relative contract + failure handler function is invoked. +

+

+ When an exception if thrown while executing the body then the class invariants + are checked (for member functions only) and, if they hold true, the exception + is passed up to the caller as usual (otherwise the class invariant failed + handler function is invoked). Therefore, exception specifications will work + as usual as long as the member function body does not fail the class invariant + when it throws the exception. +

+
+ + Constant-Correctness +
+

+ Contracts are only supposed to check the object state + in order to ensure its compliance with the software specifications. Therefore, + contract checking should not be allowed to modify the object state and exclusively + "read-only" operations (or queries) should + be used to specify contracts. +

+

+ This library enforces + [4] + this constraint at compile-time using the C++ const + qualifier. Contracts only have access to the object, function arguments, + and return value via constant references thus only constant members can be + accessed when checking contracts. Furthermore, pointers are passed as const T* so the pointed object is constants and cannot + be changed (note that the pointer value itself is not constant, because it + is not passed as const T* const, and + it could be changed by the contract but such a change will be local to the + contract function therefore still ensuring the const-correctness of the contract). +

+
+
+ +

+ The following overview of the contract macros and their usages should be + enough to understand the working example at the end of this section, most + of the examples in the Examples + annex, and to start writing contracts on your own. Consult the library Reference documentation for more information. +

+
+ + Contract + Macros +
+

+ This is a summary of the macros provided by this library to program contracts + [5] + . +

+

+ CONTRACT_INVARIANT( + (static)({ ... }) ({ ... }) ) +

+

+ This macro is used to program class invariants. It should appear within a + private section at the very beginning of the class declaration. It takes + one parameter which is a Boost.Preprocessor + sequence of the following elements: +

+
    +
  • +(static) ({ ... + }): The code block { ... }[6] + asserting static class invariants. This is optional and it can be omitted. +
  • +
  • +({ ... + }): A secondary code block { ... } + asserting non-static class invariants. This is mandatory but an empty code + block ({}) can be specified + if there are no class invariants (using CONTRACT_INVARIANT() instead of CONTRACT_INVARIANT( ({}) ) will generate a preprocessor error). +
  • +
+

+ If contract compilation is turned off, this macro expands to nothing (and + no contract overhead is added). Otherwise, it expands to code that checks + the class invariants (see Without + the Macros for details). +

+

+ CONTRACT_FUNCTION( + signature-sequence (precondition)({ ... }) (postcondition)(result-name)({ + ... }) (body)({ ... }) ) +

+

+ CONTRACT_CONSTRUCTOR( + signature-sequence (precondition)({ ... }) (postcondition)({ + ... }) (body)({ ... }) ) +

+

+ These macros are used to program preconditions and postconditions for functions + (members and non) and constructors respectively. They should appear right + after the function and constructor declaration, and after the constructor + members initialization list when such a list is specified. They both take + the following parameters: +

+
    +
  • +signature-sequence: A Boost.Preprocessor + sequence with the function or constructor signature tokens (see subsections + below). +
  • +
  • +(precondition) ({ ... + }): An optional code block { ... } + asserting the preconditions. +
  • +
  • +(postcondition) (result-name) ({ ... + }): An optional code block { ... } + asserting the postconditions. The (result-name) element is only specified for non-void + functions (so never for constructors) and it names the variable used to + access the return value within postconditions (e.g., result). +
  • +
  • +(body)({ ... }): A mandatory code block { ... } + implementing the function or constructor body. +
  • +
+

+ If contract compilation is turned off, these macros simply expand to the + body code block (and no contract overhead is added). Otherwise, they expand + to code that implements the Member + Function Call Semantics and Constructor + Call Semantics respectively thus checking class invariants, preconditions, + and postconditions (see Without + the Macros for details). +

+

+ CONTRACT_DESTRUCTOR( + signature-sequence (body)({ ... }) ) +

+

+ This macro is used to program destructor contracts. It should appear right + after the destructor declaration. It takes the following parameters: +

+
    +
  • +signature-sequence: The destructor signature tokens + (see below). +
  • +
  • +(body) ({ ... + }): A mandatory code block { ... } + implementing the destructor body. +
  • +
+

+ If contract compilation is turned off, this macro simply expands to the body + code block (and no contract overhead is added). Otherwise, it expands to + code that implements the Destructor + Call Semantics checking the class invariants (see Without + the Macros for details). +

+

+ CONTRACT_OLDOF( + variable_name ) +

+

+ This macro is used to access the old value for the variable with the specified + name in postconditions. It takes the following parameter: +

+
  • +name: The name of the variable. + As usual, this can be used + as the variable name for the object so CONTRACT_OLDOF(this) + is used to access the object old value. Otherwise, any of the function + argument variable names can be specified. The variable type (class or argument + type) must be tagged copyable in the signature sequence for the variable + old value to be available (see below). The library generates a compile-time + error (containing the text contract::noold) + if this macro is used on a variable name of a type which was not tagged + copyable. +
+
+ + + + + +
[Note]Note

+ This library does not support old values for any expression + that can be evaluated in postcondition as supported by Eiffel and required + [Crowl2006] instead. The + library supports old values for the object and all the function argument + types, and this is a subset of the old values supported by Eiffel and required + by [Crowl2006]. However, + the old values supported by the library are usually enough to program the + postconditions (e.g., all Eiffel examples from [Meyer1997], + [Mitchell2002], and all + C++ examples from [Crowl2006] + were successfully programmed using just these old values, see the Examples section). +

+

+ The old value variable are only declared locally within postconditions therefore + they cannot be mistakenly accessed outside the related postcondition code + block (see Without the Macros + for details). +

+
+ + + + + +
[Note]Note
+

+ If pointer types are tagged copyable, then the pointer value, and not + the pointed value, is copied. Therefore the old pointer value will be available + in postconditions via CONTRACT_OLDOF() and not the old + pointed value. In other words, as usual, shallow copies are performed for + pointers (unless the pointed type defines a different copy operation). + Be careful as this might not be what you intended when using CONTRACT_OLDOF() + on a pointer + [7] + . +

+

+ The notable exception is the object this + which is passed to the contract functions by pointer but its old value + is automatically deep copied by the library. +

+
+

+ CONTRACT_ASSERT( + boolean_condition ) +

+

+ This macro is used to assert conditions within the class invariant, precondition, + and postcondition code blocks (see also CONTRACT_ASSERT_MSG()). + It takes the following parameter: +

+
  • +boolean_condition: The + boolean condition being asserted. +
+

+ If contract compilation is turned off, this macro expands to nothing (and + no contract overhead is added). Otherwise, this macro expands to code that + triggers the invocation of contract::class_invariant_failed(), contract::precondition_failed(), or contract::postcondition_failed() in case the asserted boolean condition + is evaluated to be false at run-time from within invariants, preconditions, + or postconditions respectively (see Without + the Macros for details). +

+

+ CONTRACT_ASSERT_BLOCK_INVARIANT( + boolean_condition ) +

+

+ This macro is used to assert invariant within a generic code block (see also + CONTRACT_ASSERT_BLOCK_INVARIANT_MSG()). + This macro can also be used within loops to assert loop invariants. It takes + the following parameter: +

+
  • +boolean_condition: The + boolean condition being asserted. +
+

+ If contract compilation is turned off, this macro expands to nothing (and + no contract overhead is added). Otherwise, this macro expands to code that + triggers the invocation of contract::block_invariant_failed() in case the asserted boolean condition + is evaluated to be false at run-time (see Without + the Macros for details). +

+
+ + + + + +
[Note]Note

+ This macro is similar to the C assert() macro as it can be used at any point + within a block of code. However, in case the asserted condition either + throws an exception or it is evaluated to be false, + this macro invokes contract::block_invariant_failed() instead of calling abort(). +

+

+ CONTRACT_ASSERT_LOOP_VARIANT( + integer_expression ) +

+

+ CONTRACT_INIT_LOOP_VARIANT +

+

+ This macro is used to assert loop variants (see also CONTRACT_ASSERT_LOOP_VARIANT_MSG()). + It must be used after CONTRACT_INIT_LOOP_VARIANT + has been called once within the same code block scope (see below). +

+
  • +integer_expression: An + integer expression which is evaluated at each loop iteration as the loop + variant. It must be always positive (not negative and not zero) and it + must strictly decrease at each subsequent loop iteration (of 1 or more). +
+

+ If contract compilation is turned off, this macro expands to nothing (and + no contract overhead is added). Otherwise, this macro expands to code that + triggers the invocation of contract::block_invariant_failed() at run-time in case the specified variant + expression is either not positive or it does not decrease from one loop iteration + to the next (see Without the + Macros for details). +

+
+ + Step-by-Step + Example +
+

+ Let's assume we want to write a myvector + class template that wraps the C++ STL vector template std::vector + adding contracts to it. Here we show, step-by-step, how to program a contract + for the push_back() + function. +

+

+ Step 1) First, we implement myvector::push_back() + to call std::vector::push_back() + and we can sketch the contract using comments. +

+
template<typename T>
+class myvector {
+    // Invariant: (size() == 0) == empty()
+
+public:
+    // Precondition: size() < max_size()
+    // Postcondition: size() == (oldof size() + 1)
+    void push_back(const T& element) { vector_.push_back(element); }
+
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_;        
+};
+
+

+ Where "oldof size()" indicates the value size() + has before the push_back() function is executed. +

+

+ To keep this example simple, we intentionally did not write the full contract + but we only wrote one invariant, one precondition, and one postcondition + (see the STL Vector Example for + the complete push_back() + contract). These contract conditions specify the followings: +

+
    +
  1. + The class invariant asserts that the vector is empty if and only if its + size is zero. +
  2. +
  3. + The precondition asserts that the vector size must be smaller than the + maximum size when push_back() is called (so there is available space + to add one extra vector element). +
  4. +
  5. + The postcondition asserts that the vector size must increase by 1 after + push_back() + has been executed (to reflect the newly added vector element). +
  6. +
+

+ Step 2) The library provides the CONTRACT_FUNCTION() + macro to write member function contracts. This macro must be used right + after the push_back() function declaration. The push_back() + function definition { vector_.push_back(); } is moved + within the macro becoming the last element of the Boost.Preprocessor + sequence passed as the macro parameter: +

+
template<typename T>
+class myvector {
+    // Invariant: (size() == 0) == empty()
+
+public:
+    // Precondition: size() < max_size()
+    // Postcondition: size() == (old size()) + 1
+    void push_back(const T& element)
+    CONTRACT_FUNCTION( signature-sequence
+    precondition-sequence
+    postcondition-sequence
+    (body) ({
+        vector_.push_back(element);
+    }) ) // No need for ";" after the macro closing parenthesis ")".
+
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_;        
+};
+
+

+ There is no need for ";" + after the macro closing parenthesis ")". +

+

+ Step 3) We now program the postconditions + using CONTRACT_ASSERT() inside a code block { + ... } + specifying the postcondition-sequence elements: +

+
template<typename T>
+class myvector {
+    // Invariant: (size() == 0) == empty()
+
+public:
+    // Precondition: size() < max_size()
+    void push_back(const T& element)
+    CONTRACT_FUNCTION( signature-sequence
+    precondition-sequence
+    (postcondition) ({
+        CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) );
+    })
+    (body) ({
+        vector_.push_back(element);
+    }) )
+
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_;        
+};
+
+

+ Note how CONTRACT_OLDOF(this) is used + to access the old object value as it was before body execution. +

+

+ Step 4) Similarly, we program the preconditions + in a code block { ... + } specifying the precondition-sequence + elements: +

+
template<typename T>
+class myvector {
+    // Invariant: (size() == 0) == empty()
+
+public:
+    void push_back(const T& element)
+    CONTRACT_FUNCTION( signature-sequence
+    (precondition) ({
+        CONTRACT_ASSERT( size() < max_size() );
+    })
+    (postcondition) ({
+        CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) );
+
+    })
+    (body) ({
+        vector_.push_back(element);
+    }) )
+
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_;        
+};
+
+

+ Step 5) The signature-sequence + elements are discussed separately (see below) and for now we will leave them + unresolved. +

+

+ Step 6) Similarly to what we did with for + preconditions and postconditions, we program the class invariants in a code + block { ... + } specifying sequence elements passed + to the CONTRACT_INVARIANT() macro: +

+
template<typename T>
+class myvector {
+    
+    CONTRACT_INVARIANT( ({
+        CONTRACT_ASSERT( (size() == 0) == empty() );
+    }) ) // Again, no need for ";" after the macro closing parenthesis ")".
+
+public:
+    void push_back(const T& element)
+    CONTRACT_FUNCTION( signature-sequence
+    (precondition) ({
+        CONTRACT_ASSERT( size() < max_size() );
+    })
+    (postcondition) ({
+        CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) );
+
+    })
+    (body) ({
+        vector_.push_back(element);
+    }) )
+
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_;        
+};
+
+

+ Again, there is no need for ";" + after the macro closing parenthesis ")". +

+

+ Step 7) The same step-by-step process can + be applied to understand the usage of CONTRACT_CONSTRUCTOR() and CONTRACT_DESTRUCTOR() (see the example at the very end of this + section). +

+
+ + Contract + Code Blocks +
+

+ This library allows for arbitrary constant-correct code within the class + invariant, precondition, and postcondition code blocks ({ + ... }). +

+

+ In other words, the class invariant, precondition, and postcondition code + blocks can contain any legal C++ code and they can access any constant class + member (private, protected, or public). However, writing complex code in + the contracts will increase the probability of introducing bugs in the contracts + themselves so it is better to limit the contract code to a simple list of + assertions with occasional if-statements to guard them. Furthermore, if non-public + members are used in preconditions then the callers will not be able to fully + check the preconditions to make sure the contract is satisfied before calling + the function so it is best to only use public members at least in preconditions + [8] + . +

+

+ In addition, this library checks class invariants (as well as preconditions + and postconditions) only for functions that have a contract. For example, + if a private member function is allowed to temporarily + brake the class invariants, you can omit the contract for that one private + function so no invariants (as well as no preconditions and no postconditions) + will be checked when that function is called. However, it should never be + the case that public member functions can brake class invariants. It is recommended + to write contracts for all functions (public and non) with the rare exceptions + of a private member function that cannot be programmed without allowing for + it to temporarily brake the class invariants. +

+
+ + + + + +
[Important]Important
+

+ Recommended Practices +

+

+ 1. Limit the contract code to a list of assertions with occasional if-statements + to guard them. +

+

+ 2. Only access public class members when asserting preconditions. +

+

+ 3. Write contracts at least for all public member functions (even if they + have no preconditions and no postconditions) so they check the class invariants. +

+
+

+ These practices are followed by all the examples of this documentation. +

+
+
+ +

+ The very first elements of the Boost.Preprocessor + sequence passed to the macros CONTRACT_CONSTRUCTOR(), CONTRACT_DESTRUCTOR(), and CONTRACT_FUNCTION() are the elements of the signature-sequence + [9] + . The signature-sequence repeats the syntactic elements + of the function declaration. +

+

+ The syntax of signature-sequence is somewhat unusual + (even if it is all legal ISO standard C++). However, there is a convenient + rule for remembering this syntax: +

+
+ + + + + +
[Important]Important
+

+ Signature Sequence Mnemonic +

+

+ The tokens in the signature sequence appear in the exact same order as + they appear in the relative function declaration. +

+
+
+ + An Example +
+

+ Let's consider the following example (with respect to the myvector + example above, we have added the base class pushable + to show how to subcontract): +

+
template<typename T>
+class myvector: public pushable<T> {
+public:
+    void push_back(const T& element)
+    CONTRACT_FUNCTION( signature-sequence ... )
+    ...
+};
+
+

+ Applying the mnemonic rule, we read the declaration of push_back() from top to bottom and we find the following + tokens in the listed order (we have to start all the way up to the top of + the myvector class declaration): +

+
    +
  1. + The class keyword for + myvector (this indicates + that push_back is a member + function). +
  2. +
  3. + The myvector class + type (this indicates that push_back + is a member function of myvector). +
  4. +
  5. + The pushable<T> + base class which is repeated in signature-sequence + as (inherit)(pushable<T>) but only when the function is subcontracting + from the specified base class (because ":" + is not a valid preprocessor token (inherit) + is used instead; also the inheritance access level, the public + keyword in this case, is not relevant and it is not repeated in signature-sequence). +
  6. +
  7. + The public access level + of the push_back() + member function. +
  8. +
  9. + The void return type. +
  10. +
  11. + The push_back function + name. +
  12. +
  13. + The parenthesis "(" + to open the function argument list. +
  14. +
  15. + The const T& function + argument type. +
  16. +
  17. + The element function + argument name. +
  18. +
  19. + The parenthesis ")" + to close the function argument list. +
  20. +
+

+ Wrapping all these tokens within parenthesis () + and listing them in the exact order as they appear in the function declaration, + we obtain the signature-sequence elements for this example. + The parenthesis () around the + tokens are mandatory because they are the ones actually creating the Boost.Preprocessor + sequence. New lines and spaces do not matter within preprocessor sequences. +

+
(class) (copyable)(myvector) (inherit)(vector_interface<T>)
+(public) (void) (push_back)( (const T&)(element) )
+
+

+ The myvector class type is + preceded by (copyable) because, for this example, we wanted to + access the old object value CONTRACT_OLDOF(this) + (as the object was before the function body execution) in the postconditions. + Also any function argument type can be tagged copyable if the old value of + the related argument is needed in the postconditions. In this example, (const T&)(element) could have been tagged copyable and specified + in signature-sequence as (copyable)(const T&)(element) if the old value of the argument CONTRACT_OLDOF(element) + (as the argument was before the body execution) was needed in the postconditions. +

+

+ Completing the example presented in the previous section, with the addition + of subcontracting myvector::push_back() from pushable::push_back(), we have: +

+
template<typename T>
+class myvector: public pushable<T> {
+    
+    CONTRACT_INVARIANT( ({
+        CONTRACT_ASSERT( (size() == 0) == empty() );
+    }) )
+
+public:
+    void push_back(const T& element)
+    CONTRACT_FUNCTION( (class) (copyable)(myvector)
+            (inherit)(pushable<T>)
+            (public) (void) (push_back)( (const T&)(element) )
+    (precondition) ({
+        CONTRACT_ASSERT( size() < max_size() );
+    })
+    (postcondition) ({
+        CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) );
+    })
+    (body) ({
+        vector_.push_back(element);
+    }) )
+
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_;        
+};
+
+

+ This is a fully working example assuming that: +

+
    +
  1. +pushable::push_back() + also has a contract specified using this library since it is used for subcontracting + (this library allows to specify contracts also for pure virtual functions, + see below). +
  2. +
  3. +myvector has an accessible + constant-correct + [10] + copy constructor since it was tagged (copyable) + (see contract::copy): +
  4. +
+
// Must be accessible and construct from a const& parameter.
+myvector::myvector(const myvector& source) { ... }
+
+

+ If either one of these conditions is not true, this library will generate + a compile-time errors when attempting to compile the code above. +

+
+ + Full Syntax +
+

+ Generalizing this example to include all possible syntactic + elements that can be found in a C++ function declaration, we obtain the full + syntax for signature-sequence. +

+

+ signature-sequence syntax for + CONTRACT_FUNCTION(): +

+
{(class) [(copyable)](class-type) {(inherit)(base-class-type)}*
+{(public) || (protected) || (private)}}::
+[(template)( {(function-template-parameter-type)(function-template-parameter-name)}+ )]
+[(static)] [(virtual)]
+(result-type) (function-name)( {(void) || {[(copyable)](argument-type)(argument-name)}+} ) [(const)]
+
+

+ Where we have used the following conventions: +

+
    +
  • +[item] indicates + an optional item. +
  • +
  • +item* indicates an item repeated + zero of more times. +
  • +
  • +item+ indicates an item repeated + one of more times. +
  • +
  • +{item1 operation item2 operation ...} indicates + the item resulting after evaluating the contents within the curly parenthesis. +
  • +
  • +item1|| item2 + indicates that either items can be specified. +
  • +
  • +{item}:: indicates + that item is` specified only for member functions. +
  • +
+

+ For example: +

+
    +
  • +[(copyable)] indicates that + (copyable) is optional (it will only be specified + for variables with old values in postconditions). +
  • +
  • +{(inherit)(base-class-type)}* indicates that + (inherit)(base-class-type) can be repeated zero or more times (it + can be omitted, it will only be specified when subcontracting, and when + specified it can be repeated multiple times to support subcontracting from + multiple base classes in case of multiple inheritance). +
  • +
  • +{[(copyable)](argument-type)(argument-name)}+ + indicates that the function arguments (when specified instead of (void)) + must be repeated one or more type (together with their optional (copyable) tag). +
  • +
  • +[(public)|| (protected)|| (private)] indicates that the + access level is optional but when specified it must be either (public), (protected), + or (private). +
  • +
+

+ The usual C++ syntax constraints apply. For example, (static) cannot + be specified together with (virtual) and + they can only be specified for class members so when (class) is + also specified. The library will generate compile-time errors if signature-sequence + contains tokens combinations which are C++ syntactically invalid. +

+

+ Note that within signature-sequence, multiple function + arguments (as well as function template parameters) are not + separated by commas (you can use a space or a new line instead): +

+
(function-name)( (argument-type1)(argument-name1)
+        /* no comma (a space or new line can be used instead) */
+        (argument-type2)(arguments-name2)
+        /* no comma (a space or new line can be used instead) */
+        (argument-type3)(argument-name3) ... )
+
+

+ Furthermore, if the function has no arguments, the argument list must be + specified void: +

+
(function-name)( (void) )
+
+

+ Note that (function-name)( ) cannot be used instead and it will generate a cryptic + compile-time error. +

+
+ + + + + +
[Note]Note
+

+ An empty function argument list cannot be represented simply by empty parenthesis + () as in (function-name)() because the C++ standard does not allow + to specify empty preprocessor sequence elements like () + thus (function-name)( (void) ) must + be used instead. Note that the C++ standard allows to use void to specify a function with no arguments + function-name(void) (this + is the syntax used in all the examples of this documentations to be consistent + with the relative signature-sequence syntax requirement). +

+

+ The C99 standard instead allows for empty preprocessor sequence elements + () (because it allows for + empty macro parameters, see [Nelson2004] + and Boost.Preprocessor + for details). C99 also defines deprecated the use of void + for functions with no arguments -- function-name(void) + is deprecated. Therefore, on C99 compilers (function-name)() should be used in signature-sequence + for functions with no arguments instead of (function-name)( (void) ). +

+

+ This library supports both syntaxes (function-name)( (void) ) and + (function-name)() in signature-sequence + but the later syntax will only compile for C99 (so it is not recommended). +

+

+ The same limitation applies to the CONTRACT_INVARIANT() macro when the class has no invariant. + Also in this case the library supports both syntaxes CONTRACT_INVARIANT( ({}) ) and CONTRACT_INVARIANT() bu the later syntax will only compile + for C99 (so it is not recommended). +

+
+

+ Finally, the syntaxes of signature-sequence used by + CONTRACT_CONSTRUCTOR() and CONTRACT_DESTRUCTOR() are somewhat different because C++ uses + different syntactic elements for constructor and destructor declarations + than for member functions (constructors cannot be virtual, destructors cannot + have function arguments, etc). However, the syntax for these signature-sequences + are still obtained applying the basic rule of listing the constructor and + destructor signature tokens in the exact same order as they appear in the + constructor and destructor declarations. +

+

+ signature-sequence syntax for + CONTRACT_CONSTRUCTOR(): +

+
(class) (class-type)
+{(public) || (protected) || (private)}
+[(template)( {(function-template-parameter-type)(function-template-parameter-name)}+ )]
+(class-name)( {(void) || {[(copyable)](argument-type)(argument-name)}+} )
+
+

+ Note that constructors are always class members so (class) is + not optional and it must always be specified. +

+

+ signature-sequence syntax for + CONTRACT_DESTRUCTOR(): +

+
(class) (class-type)
+{(public) || (protected) || (private)}
+(virtual) (class-name)( (void) )
+
+

+ Note that "~" is not + a valid preprocessor token so it is not used to name the destructor (just + use the class name). +

+

+ Also note that constructors and destructors do not directly subcontract (their + signature-sequences do not accept any (inherit)(base-class-type) token). This is because the C++ object construction + and destruction mechanism will automatically execute the code that checks + the base class constructor and destructor contracts if present. +

+
+ + + + + +
[Warning]Warning
+

+ Cryptic Preprocessing Errors +

+

+ There is only a limited amount of compile-time error checking which the + library can do on signature-sequence. In some cases, + and depending on the compiler used, an error in programming the signature-sequence + syntax will result in cryptic compiler errors. +

+

+ These compiler errors might involve library internal templates and macros + as well as Boost.Preprocessor + internal macros (BOOST_PP_...). Furthermore, the error line number + will only refer to the first line of code at which the contract macro appears + (because new lines within macro parameters are removed by the preprocessor). +

+

+ The best way to resolve these errors is usually to inspect the signature-sequence + by eye instead of trying to make sense of the compiler error messages. + Also, try to compile with contracts turned off to make sure that the errors + are actually in the contract code. Rarely, it might be useful to look at + the code generated by the contract macro expansion after preprocessing + using your compiler related options ("-E -P" on GCC, "/EP" + on Microsoft Visual C++, etc). +

+

+ While the C++ preprocessor imposes limits on the amount of error checking + that can be performed on signature-sequence, the current + library implementation does not implement the best + possible preprocessor error detection and reporting strategy. This is an + area of improvement for the library that is currently being worked on. +

+

+ Please report on the library help + website the criptic preprocessing errors you experience in order + to facilitate this process. +

+
+
+ + Inheritance +
+

+ The library supports subcontracting from multiple base classes in case of + multiple inheritance. +

+

+ Multiple Inheritance +

+

+ In case of multiple inheritance, it is possible to subcontract from multiple + base classes by repeating (inherit)(base-class-type) multiple times in signature-sequence. + For example, assuming myvector + is inheriting and subcontracting from both the boundable and the basic_begin + base classes: +

+
template<typename T>
+class myvector:
+        public boundable<typename std::vector<T>::const_iterator>,
+        private basic_begin<typename std::vector<T>::const_iterator> {
+    ... // Class invariants.
+
+public:
+    typedef std::vector<T>::const_iterator const_iterator;
+    
+    const_iterator begin(void) const
+    CONTRACT_FUNCTION( (class) (myvector)
+            // Multiple inheritance.
+            (inherit)(boundable<const_iterator>)
+            (inherit)(basic_begin<const_iterator>)
+            (public) (const_iterator) (begin)( (void) ) (const)
+    // No preconditions (omitted).
+    (postcondition) (result) ({ // Return value `result` in postconditions.
+        if (empty()) CONTRACT_ASSERT( result == end() );
+    })
+    (body) ({
+        // Must use CONTRACT_BODY() when calling the base function.
+        if (basic_begin<const_iterator>::CONTRACT_BODY(begin) ==
+                const_iterator()) {
+            return const_iterator();
+        }
+        return vector_.begin();
+    }) )
+
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_;        
+};
+
+

+ The subcontracted contracts are checked in the order in which their (inherit) tokens are listed in signature-sequence + and the derived class contracts are checked last. +

+
+ + + + + +
[Note]Note
+

+ The above implies that if a derived class relaxes the precondition of an + overridden function, all the base contract preconditions will have be checked + first to fails before the relaxed preconditions of the overridden function + are checked to pass. +

+

+ In this case, it would appear more efficient to check the derived class + contract first. However, the derived class invariants could be written + assuming that the base class invariants hold true (for example the base + class invariants could assert a pointer to be not null and thus the derived + class invariants could deference the pointer without checking for nullity). + In doing so, the derived class invariants assume that they are checked + last in AND with all base classes invariants. The + same argument can be made for postconditions. Therefore, if derived class + invariants (and postconditions) should be checked last in AND + with all base classes invariants (and postconditions). It is natural to + follow the same policy and check derived class function preconditions last + in the OR with all base class function preconditions + (even if this introduces the inefficiency to have to check and fail all + the base class function preconditions when a derived class function if + relaxing the base class function preconditions). +

+
+

+ Base Function Call +

+

+ When the derived class invokes the overridden function in the base class + the CONTRACT_BODY() + macro must be used: +

+
base-class::CONTRACT_BODY(function-name)(...)
+
+

+ as illustrated by the example above. The overriding function should not call the overridden function directly without + using the macro: +

+
base-class::function-name)(...)
+
+

+ because this call will cause the contracts to executed infinite recursive + calls (due to the dynamic binding of the contracted virtual base function + base-class::function-name). + [11] +

+
+ + + + + +
[Warning]Warning
+

+ Base Calls via CONTRACT_BODY() +

+

+ Overriding functions must use base-class::CONTRACT_BODY(function-name) and not just base-class::function-name when + calling the overridden functions (otherwise the contract calls will cause + infinite recursion). +

+
+
+ + Operators +
+

+ The library supports contracts for operators. +

+

+ For operators, the (function-name) token in signature-sequence + must contain both the operator symbol and the operator name + spelled out in words without using any special symbol (this is necessary + because, in general, the operator special symbols ([], + ==, <<, + etc) are not valid preprocessor tokens). For operators, (function-name) takes the following form: +

+
(operator(symbol, name))
+
+

+ Note the necessary double closing parenthesis "))" + at the end. For example: +

+
template<typename T>
+class myvector {
+    ... // Class invariants.
+    
+public:
+    typedef typename std::vector<T>::size_type size_type;
+    typedef typename std::vector<T>::const_reference const_reference;
+
+    const_reference operator[](size_type index) const
+    CONTRACT_FUNCTION( (class) (myvector)
+            (public) (const_reference) (operator([], at))(
+                    (size_type)(index) ) (const)
+    (precondition) ({
+        CONTRACT_ASSERT( index < size() );
+    })
+    // No postconditions (omitted).
+    (body) ({
+        return vector_[index];
+    }) )
+
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_; 
+};
+
+

+ The operator name, in this example "at", + is arbitrary and any name without special symbols can been used. +

+
+ + Overloaded + Functions +
+

+ The library supports contracts for overloaded functions. +

+
+ + + + + +
[Note]Note
+

+ However, the library uses the argument names + to distinguish the overloaded function signatures whereas C++ uses the + argument types (this is because, in general, the argument types, for example + const int&, are not valid preprocessor tokens). +

+

+ If two functions share the same name, the same number of arguments, and + the same const qualifier then + their argument names (and not just their types) must be different to allow + the library to distinguish these two functions from each other. (This is + usually not a significant limitation because different argument names can + be given.) +

+
+

+ For example: +

+
class number {
+public:
+    // Overloaded functions distinguished using argument names (not types) and const.
+    
+    number add(const int& n) // (1)
+    CONTRACT_FUNCTION(...)
+
+    // OK -- different from (1) because this is `const`.
+    number& add(const int& n) const
+    CONTRACT_FUNCTION(...)
+
+    // OK -- different from (1) because argument named "d" instead of "n".
+    number add(const double& d)
+    CONTRACT_FUNCTION(...)
+    
+    // Error -- same as (1) because both non-const and with argument named "n" (even if different argument type).
+    number add(const double& n)
+    CONTRACT_FUNCTION(...) // Same as (1), error!
+    
+    ...
+};
+
+
+ + Function + Templates +
+

+ The (template) token is used in signature-sequence + to specify a function template listing the relative template parameters. + The template parameters are specified using a syntax similar to the one of + the function arguments. +

+

+ For example: +

+
template<typename T>
+class myvector {
+    ... // Class invariants.
+    
+private:
+    template<class Iter>
+    static bool all_equals(Iter first, Iter last, const T& element)
+    CONTRACT_FUNCTION( (class) (myvector)
+            (private) (template)( (class)(Iter) )
+            (static) (bool) (all_equals)(
+                    (Iter)(first) (Iter)(last) (const T&)(element) )
+    (precondition) ({
+        CONTRACT_ASSERT( first < last );
+    })
+    (body) ({
+        for (Iter i = first; i < last; ++i) {
+            if (*i != element) return false;
+        }
+        return true;
+    }) )
+    
+    ... // Rest of the class.
+};
+
+

+ In this example, the function also happens to be a static member but any + function (non-member, member, static member, constructor, etc) can be be + declared a template function as usual in C++. +

+
+
+ +

+ Class invariants, preconditions, and postconditions are part of the function + specifications (indeed they assert the function specifications). + Therefore, this library requires contracts to be defined together with the + function declarations. However, the function body (i.e., the function implementation) + can be defined either together with the function declaration or separately. +

+

+ In other words, the usual C++ feature that allows to separate a function + definition from its declaration is retained by this library. +

+
+ + Separating + Declaration and Definition +
+

+ When the function body is defined separately from the function declaration: +

+
    +
  • + The (body)(;) tokens are used to define the body + in the macro parameter passed to CONTRACT_FUNCTION(). The ";" + symbol is the usual C++ symbol used to separate the function definition + from its declaration. +
  • +
  • + The CONTRACT_BODY(function-name) macro is used to name the function where + it is defined. Again, for operators function-name + must be specified as operator(symbol, name). +
  • +
  • + Similarly, it is possible to separate constructor and destructor body definitions. + In this case, the macros CONTRACT_CONSTRUCTOR_BODY(class-type, class-name) and CONTRACT_DESTRUCTOR_BODY(class-type, class-name) should be used when the constructor and + destructor are defined respectively (note again that "~" + is not specified to name destructors, just use the + class name instead). +
  • +
+

+ For example: +

+
// Declarations (usually in header files).
+
+template<typename T>
+class myvector:
+        public boundable<typename std::vector<T>::const_iterator>,
+        private basic_begin<typename std::vector<T>::const_iterator> {
+    ... // Class invariants.
+
+public:
+    typedef typename std::vector<T>::size_type size_type;
+    typedef typename std::vector<T>::const_reference const_reference;
+    typedef std::vector<T>::const_iterator const_iterator;
+
+    myvector(const myvector& right)
+    CONTRACT_CONSTRUCTOR( (class) (myvector)
+            (public) (myvector)( (const myvector&)(right) )
+    (postcondition) ({
+        CONTRACT_ASSERT( vector_ == right.vector_ );
+    })
+    (body) (;) ) // Deferres body definition.
+
+    virtual ~myvector(void)
+    CONTRACT_DESTRUCTOR(
+            (class) (myvector)
+            (public) (virtual) (myvector)( (void) )
+    (body) (;) )
+    
+    const_iterator begin(void) const
+    CONTRACT_FUNCTION( (class) (myvector)
+            (inherit)(boundable<const_iterator>)
+            (inherit)(basic_begin<const_iterator>)
+            (public) (const_iterator) (begin)( (void) ) (const)
+    (postcondition) (result) ({
+        if (empty()) CONTRACT_ASSERT( result == end() );
+    })
+    (body) (;) )
+
+    const_reference operator[](size_type index) const
+    CONTRACT_FUNCTION( (class) (myvector)
+            (public) (const_reference) (operator([], at))(
+                    (size_type)(index) ) (const)
+    (precondition) ({
+        CONTRACT_ASSERT( index < size() );
+    })
+    (body) (;) )
+
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_;        
+};
+
+// Separated definitions (eventually in a different file).
+
+template<typename T>
+CONTRACT_CONSTRUCTOR_BODY(myvector<T>, myvector)(const myvector& right) {
+    vector_ = right.vector_;
+}
+
+template<typename T>
+CONTRACT_DESTRUCTOR_BODY(myvector<T>, myvector)(void) {
+    // Do nothing in this case.
+}
+
+template<typename T>
+typename myvector<T>::iterator myvector<T>::CONTRACT_BODY(begin)(void) {
+    return vector_.begin();
+}
+
+template<typename T>
+typename myvector<T>::const_reference myvector<T>::
+        CONTRACT_BODY(operator([], at))(size_type index) const {
+    return vector_[index];
+}
+
+

+ In addition to the usual benefits of separating function definitions from + their declarations (smaller and more readable header files, less recompilation + needed, etc), this separation also improves the library compile-time error + messages. When a function is defined together with its declaration, the function + implementation code is passed as one single macro parameter (body)({ + ... }) + to the contract macros. Macro preprocessing removes all newline characters + from within the macro parameters so the implementation code is compiled as + if it were written on a single line. As a result, any compile-time error + within the function body code will be reported having the same line number + and it will be harder to track. Instead, if the body definition is separated + from the function declaration, the definition code is not wrapped within + a macro parameter and the compiler errors will indicate useful line numbers. +

+
+ + + + + +
[Note]Note

+ It is recommended to separate the body definition from the function declaration + so that line numbers in compiler errors retain their usual values. +

+

+ Finally, note how the signature-sequence unusual syntax + does not propagate to the function definitions (only + the function name is changed in the function definitions). Therefore, when + definitions are separated from declarations, the files containing the definitions + (usually the ".cpp" files) will not contain the unusual signature-sequence + syntax and they will be easier to read. +

+
+ + + + + +
[Warning]Warning
+

+ Constructor Member Initialization List +

+

+ Because of a library limitation, it is not possible to separate a constructor + definition from its declaration when the constructor uses a member initialization + list (see CONTRACT_CONSTRUCTOR_BODY() macro for details and workarounds) + [12] + . +

+
+
+ + Pure + Virtual Functions +
+

+ The library also supports contracts for pure virtual functions. +

+

+ In this case, the (body)(= 0;) + tokens are used to define the body in the macro parameter passed to CONTRACT_FUNCTION(). + The "= 0;" symbol is + the usual C++ symbol used to specify pure virtual functions. +

+

+ For example: +

+
template<typename T>
+class pushable {
+    ...
+
+public:
+    virtual void push_back(const T& element)
+    CONTRACT_FUNCTION(
+            (class) (pushable)
+            (public) (virtual) (void) (push_back)( (const T&)(element) )
+    (postcondition) ({
+        CONTRACT_ASSERT( back() == element );
+    })
+    (body) (= 0;) ) // Pure virtual body.
+};
+
+
+
+ +

+ Block invariants CONTRACT_ASSERT_BLOCK_INVARIANT() can be used to assert conditions anywhere + within a code block (not just loops). When used within a loop, block invariants + can be used to assert loop invariants. +

+

+ Loop variants can be used to check the correctness of a loop, including its + termination, as explained in detail in [Meyer1997] + (and they can only appear within loops). At each loop iteration, the specified + loop variant integer expression is automatically asserted to be positive + (> 0) and to decrease from the previous loop iteration. Loop variants + can be used to assert loop correctness. Because the variant decreases and + it cannot be zero or smaller than zero it is possible to guarantee loop termination. + A loop can only have one variant. +

+

+ When asserting loop variants using CONTRACT_ASSERT_LOOP_VARIANT() it is necessary to first call CONTRACT_INIT_LOOP_VARIANT + once (and only once) within a code block that has same of higher scope level + than the loop code block. +

+

+ For example: +

+
double abs_total(const myvector<double>& vector)
+CONTRACT_FUNCTION(
+        (double) (abs_total)( (const myvector<double>&)(vector) )
+(postcondition) (total) ({ // Result value named `total`.
+    CONTRACT_ASSERT( total >= 0.0 );
+})
+(body) ({
+    double total = 0.0;
+    // Block invariants can appear anywhere in code block.
+    CONTRACT_ASSERT_BLOCK_INVARIANT( total == 0.0 );
+
+    { // Variant initialized locally to its loop.
+        CONTRACT_INIT_LOOP_VARIANT;
+        for (size_t i = 0; i < vector.size(); ++i) {
+            // Block invariants used to assert loop invariants.
+            CONTRACT_ASSERT_BLOCK_INVARIANT( i < vector.size() );
+            // Loop variant (can only appear in loops).
+            CONTRACT_ASSERT_LOOP_VARIANT( vector.size() - i );
+
+            total += vector[i];
+        }
+    }
+    return total < 0.0 ? -total : total;
+}) )
+
+
+
+ +

+ The C++ preprocessor only recognizes the () + parenthesis. It does not recognize any other parenthesis such as <>, [], + or {}. As a consequence, any + comma passed within a macro parameter that is not wrapped by the () parenthesis will be interpreted by the + preprocessor as a parameter separation token and will generate a preprocessing + error. Also macro parameters passed as elements of Boost.Preprocessor + sequences cannot contain commas not wrapped by extra () + parenthesis (the preprocessor sequence () + parenthesis are not sufficient to wrap the commas). +

+

+ Consider the following example: +

+
template<typename K, typename T>
+std::map<K, T> fill(const std::map<K, T>& source,
+        const K& key, const T& element)
+CONTRACT_FUNCTION(
+        (template)( (typename)(K) (typename)(T) )
+        // Commas within another type expression.
+        (std::map<K, T>) (set)( 
+                // Commas within a type expression.
+                (const std::map<K, T>&)(source)
+                (const K&)(key) (const T&)(element) )
+(precondition) ({
+    // Commas within a value expression.
+    CONTRACT_ASSERT( std::map<K, T>().empty() );
+})
+(body) ({
+    ...
+}) )
+
+
+ + Value + Expressions +
+

+ The example above will not compile because the preprocessor + will interpret the expression: +

+
CONTRACT_ASSERT( std::map<K, T>().empty() );
+
+

+ as a call to the macro CONTRACT_ASSERT() passing two parameters + separated by the comma: +

+
std::map<K    // 1st macro parameter.
+T>().empty()  // 2nd macro parameter.
+
+

+ Because CONTRACT_ASSERT() takes only one parameter, the above code + will generate a preprocessing error. +

+

+ The expressions std::map<K, T>().empty() is interpreted by the compiler as a value + expression (it will be either be true + or false). Value expressions + can be wrapped by an extra set of parenthesis () + when passed as macro parameters. The following will compile: +

+
CONTRACT_ASSERT( (std::map<K, T>().empty()) );
+
+
+ + Type + Expressions +
+

+ A similar issue arises for the preprocessor sequence element: +

+
(std::map<K, T>)
+
+

+ which will be interpreted as composed of 2 parameters separated by the comma + (i.e., as a Boost.Preprocessor + 2-tuple instead than an element of a Boost.Preprocessor + sequence): +

+
std::map<T  // 1st macro parameter.
+T>          // 2nd macro parameter.
+
+

+ However, in this case the expression std::map<K, T> needs to be interpreted by the compiler + as a type expression (indeed the type std::map<K, T>) and it cannot be wrapped by the extra + parenthesis (). In fact, depending + on the context where they are used, types wrapped within parenthesis can + generate compiler-time syntactic errors. +

+

+ In order to wrap the type expression within parenthesis () + that can be parsed correctly by the preprocessor and interpreted correctly + the compiler, first we created a void-function type that contains the type + expression as the function only argument type: +

+
void(std::map<K, T>)  // Function type (wraps comma within parenthesis).
+
+

+ Then, we apply the library metafunction contract::wrap + that returns the type of the first argument of the specified void-function + type: +

+
contract::wrap<void(std::map<K, T>)>::type  // Evaluates to the type `std::map<K, T>`.
+
+

+ For convenience, the library provides the macro CONTRACT_WRAP_TYPE() which expands to the code above: +

+
CONTRACT_WRAP_TYPE( (std::macp<K, T>) )
+
+

+ Note the extra parenthesis () + similar to what it was used for value expression. +

+
+ + Body + Code Block +
+

+ Finally, both techniques are applied to eventual commas within code blocks + depending if the code is a value or type expression. +

+
+ + + + + +
[Note]Note

+ However, if the body definition is separated from the contract declaration + then the body code does not appear within a macro parameter so there is + no need to implement these workarounds in the body code. +

+

+ Applying these techniques to the example above, we obtain the following code + which compiles: +

+

+

+

+ +

+
template<typename K, typename T>
+std::map<K, T> fill(const std::map<K, T>& source,
+        const K& key, const T& element)
+CONTRACT_FUNCTION(
+        (template)( (typename)(K) (typename)(T) )
+        // Commas within type expression using the macro.
+        (typename CONTRACT_WRAP_TYPE( (std::map<K, T>) )) (set)( 
+                // Or equivalently, not using the macro.
+                (typename contract::wrap<void 
+                        (const std::map<K, T>&) >::type)(source)
+                (const K&)(key) (const T&)(element) )
+(precondition) ({
+    // Commas within value expressions must be wrapped by `()`.
+    CONTRACT_ASSERT( (std::map<K, T>().empty()) );
+})
+(body) ({
+    // Commas within code blocks use same workarounds as above
+    // wrapping differently commas within type or value expressions. 
+    // Or better, separate body definition so it is outside the macro.
+
+    // OK, commas already wrapped by function call `()`.
+    print(key, element);
+    
+    // Commas within type expression wrapped using the macro.
+    typename CONTRACT_WRAP_TYPE((std::map<K, T>)) m = source;
+    
+    // OK, commas already wrapped by if-statement `()`.
+    if (0 == std::map<K, T>().empty()) m[key] = element;
+    
+    return m;
+}) )
+
+
+

+

+

+

+
+
+ +

+ We conclude this section with a fully working example that can be compiled. + This example illustrates how to use the library contract macros to program + contracts in all the different library usages scenarios (constructor, destructors, + member functions, non-member functions, template functions, etc). +

+

+ For simplicity, this example only exposes a limited subset of the std::vector + operations and it only programs simple contracts for them (see the STL Vector + Example for complete contracts + of all std::vector operations). Furthermore, the somewhat + artificial base classes have been deliberately introduced to illustrate subcontracting + and they will probably not be part of real code. +

+

+

+

+ +

+
// Base classes for subcontracting.
+#include "pushable.hpp"
+#include "boundable.hpp"
+#include "basic_begin.hpp"
+#include <contract.hpp> // This library.
+#include <boost/utility.hpp> // For `boost::prior()`.
+#include <vector> // STL vector.
+    
+// Wrapper that adds simple (not complete) contracts to C++ STL illustrating
+// most library usages. For simplicity, assume T is comparable and copyable.
+template<typename T>
+class myvector: public pushable<T>,
+        public boundable<typename std::vector<T>::const_iterator>,
+        private basic_begin<typename std::vector<T>::const_iterator> {
+
+    // Class invariants (checked by any function with a contract).
+    CONTRACT_INVARIANT(
+    (static)({ // Static invariants (optional).
+        // Static class invariants `(static)({ ... })` are optional and they
+        // could have been omitted since they assert nothing in this example.
+        // When present, they can only access static members.
+    }) ({ // Non-static invariants (can access object).
+        CONTRACT_ASSERT( (size() == 0) == empty() );
+        // More invariants here...
+    }) )
+
+public:
+    typedef typename std::vector<T>::size_type size_type;
+    typedef typename std::vector<T>::iterator iterator;
+    typedef typename std::vector<T>::const_iterator const_iterator;
+    typedef typename std::vector<T>::const_reference const_reference;
+
+    // Contract for constructor.
+    explicit myvector(size_type count): vector_(count)
+    CONTRACT_CONSTRUCTOR( // Constructor contract macro.
+            (class) (myvector) // Constructor signature.
+            (public) (myvector)( (size_type)(count) )
+    // Never object `this` in constructor preconditions.
+    (postcondition) ({
+        // Never `CONTRACT_OLDOF(this)` in constructor postconditions.
+        CONTRACT_ASSERT( size() == count );
+    })
+    (body) ({
+        // Do nothing in this case.
+    }) )
+
+    // Contractor for overloaded member (resolved by argumnet name).
+    myvector(const myvector& right)
+    CONTRACT_CONSTRUCTOR( (class) (myvector)
+            (public) (myvector)( (const myvector&)(right) )
+    (postcondition) ({
+        CONTRACT_ASSERT( vector_ == right.vector_ );
+    })
+    (body) (;) ) // Deferres body definition.
+
+    // Contract for destructor.
+    virtual ~myvector(void)
+    CONTRACT_DESTRUCTOR( // Destructor contract macro.
+            (class) (myvector) // Destructor signature.
+            // Must use `(void)` for no arguments.
+            (public) (virtual) (myvector)( (void) )
+    // No preconditions allowed (no arguments).
+    // No postconditions allowed (no object after destructor).
+    (body) (;) )
+
+    // Contract for member function.
+    void insert(iterator where, size_type count, const T& element)
+    CONTRACT_FUNCTION( // Function contract macro.
+            (class) (copyable)(myvector) // Function signature.
+            // Old values for object `this` and argument `where`.
+            (public) (void) (insert)( (copyable)(iterator)(where)
+                    (size_type)(count) (const T&)(element) )
+    (precondition) ({ // Function preconditions (optional).
+        CONTRACT_ASSERT( (size() + count) <= max_size() );
+        // More preconditions here...
+    })
+    (postcondition) ({ // Function postconditions (optional).
+        // Any C++ code allowed in contracts (but keep it simple).
+        // Old values of types tagged copyable via `CONTRACT_OLDOF()`.
+        if (capacity() == CONTRACT_OLDOF(this)->capacity()) {
+            CONTRACT_ASSERT( all_equals(
+                    boost::prior(CONTRACT_OLDOF(where)),
+                    boost::prior(CONTRACT_OLDOF(where)) + count,
+                    element) );
+        }
+        // More postconditions here...
+    })
+    (body) ({ // Function body (mandatory).
+        vector_.insert(where, count, element);
+    }) )
+
+    // Contract for constant member.
+    const_iterator begin(void) const
+    CONTRACT_FUNCTION( (class) (myvector)
+            // Subcontracting for multiple inheritance.
+            (inherit)(boundable<const_iterator>)
+            (inherit)(basic_begin<const_iterator>)
+            (public) (const_iterator) // Non-void result type.
+            (begin)( (void) ) (const) // Constant.
+    (postcondition) (result) ({ // Named result value.
+        if (empty()) CONTRACT_ASSERT( result == end() );
+    })
+    (body) ({
+        return vector_.begin();
+    }) )
+    
+    // Contract for overloaded member (resolved because not const).
+    iterator begin(void)
+    CONTRACT_FUNCTION( (class) (myvector) (public)
+            (iterator) (begin)( (void) )
+    (postcondition) (result) ({
+        if (empty()) CONTRACT_ASSERT( result == end() );
+    })
+    (body) (
+        ;
+    ) )
+    
+    // Contract for operator.
+    const_reference operator[](size_type index) const
+    CONTRACT_FUNCTION( (class) (myvector)
+            // Must spell operator name also in words).
+            (public) (const_reference) (operator([], at))(
+                    (size_type)(index) ) (const)
+    (precondition) ({
+        CONTRACT_ASSERT( index < size() );
+    })
+    (body) (;) )
+
+    // Main function example used in documentation.
+    void push_back(const T& element)
+    CONTRACT_FUNCTION(
+            (class) (copyable)(myvector) (inherit)(pushable<T>)
+            (public) (void) (push_back)( (const T&)(element) )
+    (precondition) ({
+        CONTRACT_ASSERT( size() < max_size() );
+    })
+    (postcondition) ({
+        CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) );
+    })
+    (body) ({
+        vector_.push_back(element);
+    }) )
+    
+    // Contract for template plus static member function.
+    template<class Iter>
+    static bool all_equals(Iter first, Iter last, const T& element)
+    CONTRACT_FUNCTION( (class) (myvector)
+            (public) (template)( (class)(Iter) ) // Function template.
+            (static) (bool) (all_equals)( // Static member.
+                    (Iter)(first) (Iter)(last) (const T&)(element) )
+    (precondition) ({
+        CONTRACT_ASSERT( first < last );
+    })
+    (body) ({
+        // For simplicity, let's assume T can be compared.
+        for (Iter i = first; i < last; ++i) {
+            if (*i != element) return false;
+        }
+        return true;
+    }) )
+
+    // Similarly, complete contracts sketched here and add contracts
+    // for all other functions (see [Crowl2006] vector example).
+    bool empty(void) const { return vector_.empty(); }
+    size_type size(void) const { return vector_.size(); }
+    size_type max_size(void) const { return vector_.max_size(); }
+    size_type capacity(void) const { return vector_.capacity(); }
+    iterator end(void) { return vector_.end(); }
+    const_iterator end(void) const { return vector_.end(); }
+    const_reference back(void) const { return vector_.back(); }
+
+private:
+    std::vector<T> vector_;
+};
+
+// Deferred constructor body definition.
+template<typename T>
+CONTRACT_CONSTRUCTOR_BODY(myvector<T>, myvector)(
+        const myvector& right) {
+    vector_ = right.vector_;
+}
+
+// Deferred destructor body definition.
+template<typename T>
+CONTRACT_DESTRUCTOR_BODY(myvector<T>, myvector)(void) {
+    // Do nothing in this case.
+}
+
+// Deferred member function definition.
+template<typename T>
+typename myvector<T>::iterator myvector<T>::CONTRACT_BODY(begin)(
+        void) {
+    return vector_.begin();
+}
+
+// Deferred member operator definition.
+template<typename T>
+typename myvector<T>::const_reference myvector<T>::
+        CONTRACT_BODY(operator([], at))(
+        size_type index) const {
+    return vector_[index];
+}
+
+// Contract for non-member function.
+double abs_total(const myvector<double>& vector)
+CONTRACT_FUNCTION(
+        (double) (abs_total)( (const myvector<double>&)(vector) )
+(postcondition) (total) ({ // Result value named `total`.
+    CONTRACT_ASSERT( total >= 0.0 );
+})
+(body) ({
+    double total = 0.0;
+    // Block invariants can appear anywhere in code block.
+    CONTRACT_ASSERT_BLOCK_INVARIANT( total == 0.0 );
+
+    { // Variant initialized locally to its loop.
+        CONTRACT_INIT_LOOP_VARIANT;
+        for (size_t i = 0; i < vector.size(); ++i) {
+            // Block invariants used to assert loop invariants.
+            CONTRACT_ASSERT_BLOCK_INVARIANT( i < vector.size() );
+            // Loop variant (can only appear in loops).
+            CONTRACT_ASSERT_LOOP_VARIANT( vector.size() - i );
+
+            total += vector[i];
+        }
+    }
+    return total < 0.0 ? -total : total;
+}) )
+
+
+

+

+

+

+

+ +

+
#include <contract.hpp>
+
+template<typename T>
+class pushable {
+
+    CONTRACT_INVARIANT( ({}) )
+
+public:
+    // Contract for pure virtual function.
+    virtual void push_back(const T& element)
+    CONTRACT_FUNCTION(
+            (class) (pushable)
+            (public) (virtual) (void) (push_back)( (const T&)(element) )
+    (postcondition) ({
+        CONTRACT_ASSERT( back() == element );
+    })
+    (body) (= 0;) ) // Pure virtual body.
+
+    virtual const T& back() const = 0;
+};
+
+
+

+

+

+

+

+ +

+
#include <contract.hpp>
+
+template<class ConstIter>
+class boundable {
+
+    CONTRACT_INVARIANT( ({
+        CONTRACT_ASSERT( begin() <= end() );
+    }) )
+
+public:
+    virtual ConstIter begin(void) const
+    CONTRACT_FUNCTION( (class) (boundable)
+            (public) (virtual) (ConstIter) (begin)( (void) ) (const)
+    (body) (= 0;) )
+
+    virtual ConstIter end(void) const = 0;
+};
+
+
+

+

+

+

+

+ +

+
#include <contract.hpp>
+
+template<class ConstIter>
+class basic_begin {
+
+    CONTRACT_INVARIANT( ({}) )
+
+public:
+    virtual ConstIter begin(void) const
+    CONTRACT_FUNCTION( (class) (basic_begin)
+            (public) (virtual) (ConstIter) (begin)( (void) ) (const)
+    (body) ({
+        return ConstIter(); // Dummy implementation (for example only).
+    }) )
+};
+
+
+

+

+

+

+
+
+

+

[2] + Static member functions cannot be virtual so they cannot be overridden + and they cannot subcontract. +

+

[3] + However, the destructor body should be programmed to never + throw exceptions to comply with C++ STL exception safety requirements. +

+

[4] + As usual in C++, constant-correctness can be enforced at compile-time + only as long as programmers do not use const_cast + and mutable. +

+

[5] + To improve contract readability, it is recommended to configure your + editor C++ syntax highlighting to highlight also the macros CONTRACT_INVARIANT, CONTRACT_FUNCTION, + CONTRACT_CONSTRUCTOR, + CONTRACT_DESTRUCTOR, + CONTRACT_OLDOF, CONTRACT_BODY, CONTRACT_CONSTRUCTOR_BODY, + CONTRACT_DESTRUCTOR_BODY, + CONTRACT_ASSERT, CONTRACT_ASSERT_MSG, CONTRACT_ASSERT_BLOCK_INVARIANT, CONTRACT_ASSERT_BLOCK_INVARIANT_MSG, + CONTRACT_ASSERT_LOOP_VARIANT, + CONTRACT_ASSERT_LOOP_VARIANT_MSG, + CONTRACT_INIT_LOOP_VARIANT, + and the sequence tokens precondition, + postcondition, body, copyable, + and inherit. For example, + this can be done in the Vi IMproved (VIM) editor by adding these symbols + to the "cpp.vim" + file (usually in the VIM system configuration directory). +

+

[6] + Some text editing programs might highlight curly brackets {} within a macro parameter as a C++ + syntax error. This is incorrect as the ISO C++ standard allows for + macro parameters to contain curly brackets and the editor might offer + an option for disabling this incorrect syntax error highlighting. For + example, when C++ syntax highlighting is turned on in the Vi IMproved + (VIM) editor, curly brackets within macro parameters are highlighted + as errors but that can be disabled by adding the line let c_no_curly_error=1 in + the ".vimrc" + file (typically in your home directory). +

+

[7] + However, this is the only sensible semantics for copying pointers as + the pointer could of type void* for which it is not possible to copy + the pointed object, plus there might cases where the functions actually + changed the pointer value so CONTRACT_OLDOF() needs to the return the old pointer + value (and not the old pointed value), plus this the usual C++ pointer + copy semantic. +

+

[8] + [Meyer1997] argues preconditions + asserted using non-public members are ill written thus the Eiffel programming + language enforces this rule at compile-time. However, in C++ friend callers + could still be able to fully check preconditions via the friendship even + when non-public functions are used to assert them therefore this rule + is left as a recommended practice for programmers to follow and it is + not enforced by the library. +

+

[9] + If two Boost.Preprocessor + sequences are specified one after the other then they are automatically + concatenated into one larger sequence. For example let seq1 be (token1) (token2) and seq2 + be (token3) (token4) (token5) then seq1 + seq2 is (token1) (token2) (token3) (token4) (token5). +

+

[10] + A constant-correct copy constructor constructs + the object copying it from a constant-reference of the source object + thus it cannot alter the state of the copied object. +

+

[11] + Using the augmented object state the library could detect infinite recursion + between overriding and overridden function. However, to break the recursion + the base contract will have to call the base body function forcing static + binding (otherwise using dynamic binding the overriding function will + be called causing the infinite recursion). The contract itself cannot + perform the static binding call (e.g., using static_cast<> to the + object) because the object state is changed only if pointers or references + to the objects are used to call the body, but if pointers or reference + are used then C++ uses dynamic binding for the call. So the contract + function could call a special method of the contract class which performs + the static binding call but such a static binding call will raise a compiler + error if the body function is pure virtual. The library does not know + directly when a function is pure virtual (body is = + 0;) + or not so the library will have to define the contract class static binding + method also for pure virtual functions and in this case the static binding + call B::f() + will raise a compile time error because the function called via static + binding is pure virtual. +

+

[12] + The library could overcome this limitation if + future versions of the C++ standard were to support delegating constructors + (as proposed by [Sutter2005]). +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/contract__/without_the_macros.html b/doc/html/contract__/without_the_macros.html new file mode 100755 index 00000000..01584120 --- /dev/null +++ b/doc/html/contract__/without_the_macros.html @@ -0,0 +1,1407 @@ + + + +Without the Macros + + + + + + + + +
+PrevUpHomeNext +
+
+
+ + +

+ This section explains how to program contracts without using the library macros. + This is useful to better understand how the library actually implements Contract + Programming and to occasionally implement workarounds for compiler standard + compliance issues. However: +

+
+ + + + + +
[Important]Important
+

+ Recommended to Use Contract Macros +

+

+ In general, it is recommended to write contracts using the library macros + because they save programmers from writing a significant amount of setup + code. +

+
+

+ All the macros described in the Tutorial + section expand to code equivalent to the one explained in this section (with + the exception of block invariants and loop variants which are not covered here). + See also the Reference section for more + details. +

+
+ +

+ The following example shows how to write a contract for the vector push_back() + function without using the contract macros: +

+
#include "pushable.hpp" // Base class for subcontracting.
+#include <contract.hpp> // This library.
+#include <vector> // STL vector.
+
+template<typename T>
+class myvector: public pushable<T> {
+
+#if defined CONTRACT_CHECK_CLASS_INVARIANT ||   /* Support for       */ \
+        defined CONTRACT_CHECK_PRECONDITION ||  /* optional contract */ \
+        defined CONTRACT_CHECK_POSTCONDITION    /* compilation.      */
+    // Augmented state.
+    friend class contract::state;
+    mutable contract::state contract_state_;
+#endif // contracts
+
+#if defined CONTRACT_CHECK_CLASS_INVARIANT
+    // Static class invariants
+    static void contract_static_invariant_(void) {
+        // Assert nothing in this case.
+    }
+    // Class invariants.
+    void contract_invariant_(void) const {
+        if (!((size() == 0) == empty()))
+            throw contract::failure(__FILE__, __LINE__);
+        // More invariants here...
+    }
+#endif // invariants
+
+public:
+    void push_back(const T& element)
+#if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+        defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+    // Contracted function.
+    { contract_push_back_element_<0>().call(this , element); }
+private: // Private so not to alter user call public API.
+#if defined CONTRACT_CHECK_PRECONDITION
+    void contract_precondition_push_back_element_(const T& element) const {
+        if (!(size() < max_size())) 
+            throw contract::failure(__FILE__, __LINE__);
+        // More preconditions here...
+    }
+#endif // preconditions
+#if defined CONTRACT_CHECK_POSTCONDITION
+    void contract_postcondition_push_back_element_(
+            const myvector* old_this, // Old value for object.
+            const T& element, contract::noold // No old for `element` argument.
+            ) const {
+        if (!(size() == (old_this->size() + 1)))
+            throw contract::failure(__FILE__, __LINE__);
+        // More postconditions here...
+    }
+#endif // postconditions
+protected: // Must be protected (not private) to allow subcontracting.
+    void contract_body_push_back_(const T& element)
+#endif // contracts
+    // Original function definition (the body).
+    { vector_.push_back(element); } 
+#if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+        defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+    // Contract class.
+    template<int ZERO>
+    struct contract_push_back_element_: contract::nonstatic_member_function<
+            // Function type for contracted function.
+            // Copyable class type for old object value in postconditions.
+            // For constant members use `myvector const` instead of `myvector`.
+            void (contract::copyable<myvector>*, const T&),
+            // Base contract class for subcontracting.
+            typename pushable<T>::template contract_push_back_element_<0>
+            > {
+        // Constructor specifies body, preconditions, and postconditions.
+        contract_push_back_element_(): contract::static_member_function<
+                void (contract::copyable<myvector>*, const T&),
+                typename pushable<T>::template contract_push_back_element_<0>
+                >(    &myvector::contract_body_push_back_
+#if defined CONTRACT_CHECK_PRECONDITION
+                    , &myvector::contract_precondition_push_back_element_
+#endif // preconditions
+#if defined CONTRACT_CHECK_POSTCONDITION
+                    , &myvector::contract_postcondition_push_back_element_
+#endif // postconditions
+                ) {} 
+    };
+public: // Restore original access level.
+#endif // contracts
+
+    ... // Rest of the class.
+
+private:        
+    std::vector<T> vector_;
+};
+
+

+ Let's take a close look at this code. +

+
+
+ +

+ First of all, note that when programmers completely disable contract compilation + by not #defining any of the CONTRACT_CHECK_CLASS_INVARIANT, + CONTRACT_CHECK_PRECONDITION, + and CONTRACT_CHECK_POSTCONDITION + macro symbols, the code above reduces to just the function declaration and + its definition without any contract code + overhead: +

+
template<typename T>
+class myvector {
+
+    // Augmented state and class invariants disappear!
+
+public:
+    void push_back(const T& value)
+    // Preconditions, postconditions, and body functions disappear!
+    {
+        vector_.push_back(value); // Original function implementation.
+    }
+    // Contract class disappears!
+public:
+
+    ...
+private:
+    std::vector<T> vector_;
+};
+
+

+ Note how the CONTRACT_CHECK_CLASS_INVARIANT, + CONTRACT_CHECK_PRECONDITION, + and CONTRACT_CHECK_POSTCONDITION + macros can be #defined independently to selectively turn on or off the compilation + of class invariants only, preconditions only, postconditions only, or any + combination of the above. +

+

+ The rest of this section illustrates what happens when contract compilation + is turned on. Therefore, from here on, we will assume that CONTRACT_CHECK_CLASS_INVARIANT + , CONTRACT_CHECK_PRECONDITION, + and CONTRACT_CHECK_POSTCONDITION + are all #defined. +

+
+
+ +

+ Note how class invariants, preconditions, and postconditions are asserted + using an if-statement that throws + a contract::failure exception in case the + checked boolean condition is false (note the leading "!" + within the if-condition): +

+
// Code from the non-static class invariants (but similar for
+// static class invariants, preconditions, and postconditions).
+if (!((size() == 0) == empty()))
+    throw contract::failure(__FILE__, __LINE__);
+
+

+ When an exception (any exception) is thrown from within + class invariants, preconditions, or postconditions code blocks, the library + will handle the exception invoking the relative contract::class_invariant_failed(), contract::precondition_failed(), or contract::postcondition_failed() function (but only if that is necessary + according to subcontracting rules, see below). Therefore, the fact that the + contract condition check throws contract::failure + does not necessarily imply that the program itself will + throw but only that the correct contract failure handler function will be + invoked by the library. All contract failure handler functions terminate + by default but they can be customized (see Throw + on Failure for an example). +

+

+ It is not possible to directly call contract::class_invariant_failed(), contract::precondition_failed(), or contract::postcondition_failed() instead of throwing the exception because + of subcontracting. For example, if a precondition of a derived contract fails + but the preconditions of an overridden contract hold true then the library + will not call contract::precondition_failed() even if the derived contract throws an + exception (as specified by subcontracting requirements in Member + Function Call Semantics). +

+

+ The first two arguments of the contract::failure + constructor are mandatory and they specify file name and line number of the + assertion (used the C++ macros __FILE__ + and __LINE__). The third + argument of the constructor is an optional human readable description of + the asserted condition. For example: +

+
// More verbose error message with .
+if (!((size() == 0) == empty()))
+    throw contract::failure(__FILE__, __LINE__, "size zero iff empty");
+
+

+ All this information is simply used to provide the user with a descriptive + error message in case of a contract failure, for example: +

+
class invariant: terminate called after throwing an instance of 'contract::failure'
+  what():  contract "size zero iff empty" failed at myvector_nomacros.cpp:37
+Aborted
+
+
+
+ +

+ This library needs to declare an additional member variable for the class. + This member variable is mainly used by the library to keep track of when + contracts are being checked so to disable assertion checking in nested member + function calls that could otherwise result in infinite recursion (this a + common requirement in Contract Programming). +

+
template<typename T>
+class myvector: public pushable<T> {
+
+    // Augmented state.
+    friend class contract::state;
+    mutable contract::state contract_state_;
+
+    ...
+};
+
+

+ The state member variable must be declared of mutable + type contract::state (so the library can modify + it while still ensuring constant-correctness for the contracts), it should + be in a private section of the class (so not to alter the class public API), + and it must have the predefined name contract_state_ + (so the library knows how to access it). Furthermore, the contract::state + class type must be declared a friend so the library can internally access + the entire user class including its private and protected members. +

+

+ The details of the contract::state + type are library implementation specific. The state variable name begins + with the contract prefix + and ends with an underscore "_" + so programmers should never directly use it in user code (see Getting + Started). +

+
+
+ +

+ This library checks static and non-static class invariants invoking a static + and a constant member function with the predefined names contract_static_invariant_ + and __contract_invariant__ + respectively: +

+
template<typename T>
+class myvector: public pushable<T> {
+    ...
+    
+    // Static class invariants
+    static void contract_static_invariant_(void) {
+        // Assert nothing in this case.
+    }
+    // Class invariants.
+    void contract_invariant_(void) const {
+        if (!((size() == 0) == empty()))
+            throw contract::failure(__FILE__, __LINE__);
+        // More invariants here...
+    }
+    
+    ...
+};
+
+

+ The non-static class invariant function must a constant member so to enforce + contract checking constant-correctness. The static class invariants function + is static so it cannot change the object state because it cannot access the + object (static member functions cannot be constant). +

+

+ The class invariant function names begin with the contract + prefix and end with an underscore "_" + so programmers should never directly use it in user code (see Getting + Started). +

+
+
+ +

+ The push_back() + function is programmed to construct the contract + object and to invoke its call() member function: +

+
template<typename T>
+class myvector: public pushable<T> {
+    ...
+
+public:
+    void push_back(const T& element)
+    // Contracted function.
+    {
+        contract_push_back_element_<0>().call(this , element);
+    }
+
+    ...
+};
+
+

+ The call() function takes in input a pointer to the + object (this) and the function + arguments (just element in + this example) in the order they appear in the function declaration. +

+

+ The call() function is the one implementing the correct + Contract Programming call semantics (see Member + Function Call Semantics). In this case, call() checks class invariants and preconditions + (calling contract_static_invariant_(), contract_invariant_(), and the precondition + function, see below), then it executes the body, and lastly it checks class + invariants and postconditions (calling contract_static_invariant_(), contract_invariant_(), and the postcondition + function, see below). +

+
+
+ +

+ A member function is defined to check the preconditions: +

+
template<typename T>
+class myvector: public pushable<T> {
+    ...
+
+private:
+    void contract_precondition_push_back_element_(const T& element) const {
+        if (!(size() < max_size())) 
+            throw contract::failure(__FILE__, __LINE__);
+        // More preconditions here...
+    }
+    
+    ...
+};
+
+

+ Note the followings: +

+
    +
  • + The precondition function is private so not to alter the user class public + API. +
  • +
  • + In order to support contracts for overloaded functions, the precondition + function name must contain the contracted function name, the name of all + arguments, and a trailing const if the contracted function + is a constant member. +
  • +
  • + The precondition function must be a constant member plus all its arguments + must be constant so to enforce contract constant-correctness. +
  • +
  • + The precondition function arguments are constant references to the contracted + function arguments. +
  • +
+

+ The precondition function name begins with the contract + prefix and ends with an underscore "_" + so programmers should never directly use it in user code (see Getting + Started). +

+
+
+ +

+ A member function is defined to check the postconditions: +

+
template<typename T>
+class myvector: public pushable<T> {
+
+private:
+    ... // Preconditions.
+    void contract_postcondition_push_back_element_(
+            const myvector* old_this, // Old value for object.
+            const T& element, contract::noold // No old for `element` argument.
+            ) const {
+        if (!(size() == (old_this->size() + 1)))
+            throw contract::failure(__FILE__, __LINE__);
+        // More postconditions here...
+    }
+
+    ...
+};
+
+

+ Note the followings: +

+
    +
  • + The postcondition function is private so not to alter the user class public + API. +
  • +
  • + In order to support contracts for overloaded functions, the postcondition + function name must contain the contracted function name, the name of all + arguments, and a trailing const if the contracted function + is a constant member. +
  • +
  • + The postcondition function must be a constant member plus all its arguments + must be constant so to enforce contract constant-correctness. +
  • +
  • + The first postcondition function argument is a constant pointer to the + object old value when the class type is tagged contract::copyable + within the contract class (see below), otherwise it is of type contract::noold. +
  • +
  • + The remaining postcondition function arguments are constant references + to the contracted function argument current and old values. A function + argument old value is different from contract::nold + only if the argument type is tagged contract::copyable + within the contract class (see below). +
  • +
  • + Finally, for non-void contracted functions, there is an extra argument + at the very end of the postcondition function argument list which is a + constant reference to the function result value being returned. +
  • +
+

+ The contract::noold type is used as a "placeholder" + for an argument when its old value is not provided in + the postconditions. An contract::noold + argument cannot be mistakenly accessed or manipulated by programmers because + contract::noold is an empty class with no member + at all. Furthermore, copying contract::noold + performs no operation so contract::noold + arguments can be passed to the postcondition function by value but without + adding any run-time overhead. This ensures that programmers can only access + old values in postconditions for types that are tagged contract::copyable. +

+

+ This is an example where the old value is provided for both the object and + one of the function arguments: +

+
template<typename T>
+class myvector: public pushable<T> {
+    ...
+
+public:
+    iterator insert(iterator where, const T& element)
+    ...
+    void contract_postcondition_insert_insert_where_element_(
+            const myvector* old_this, // Old value for object.
+            const iterator& where, const iterator& old_where, // Old value for `where`.
+            
+            const T& element, contract::noold, // No old for `element` argument.
+            const iterator& result // Result value.
+            ) const {
+        ... // Assert postconditions using `old_this` and `old_where`.
+    }
+    ... // Both class type and `where` type are tagged `contract::copyable`.
+        // in the contract class (see below).
+    
+    ...
+};
+
+

+ The postcondition function name begins with the contract + prefix and ends with an underscore "_" + so programmers should never directly use it in user code (see Getting + Started). +

+
+
+

+Body +

+

+ A member function is declared as the body function and it is defined to be + the original function implementation as specified by the user: +

+
template<typename T>
+class myvector: public pushable<T> {
+    ...
+
+protected:
+    void contract_body_push_back_(const T& element)
+    // Original function definition (the body).
+    {
+        vector_.push_back(element);
+    } 
+    
+    ...
+};
+
+

+ Note the followings: +

+
    +
  • + The body function is protected to avoid changing the user's class public + API but it cannot be private to allow for subcontracting of pure virtual + functions. +
  • +
  • + The body function declaration and definition must be exactly + the ones specified by the user for the original push_back() function (only the function name is different). + For example, if the original function is declared virtual, + the body function should be declared virtual + as well. Also the body function signature (return type, argument type, + argument names, eventual constant qualifier, etc) must match exactly the + signature of the original push_back() function. +
  • +
+

+ The body function name begins with the contract + prefix and ends with an underscore "_" + so programmers should never directly use it in user code (see Getting + Started). +

+
+ + Separating + the Definition +
+

+ In this example, the body function definition { + vector_.push_back(element); } is specified together with the body function + declaration. However, following C++ usual syntax, programmers can define + the body function to be ";" + in order to separate the function definition from its declaration: +

+
// Declarations (usually in header files).
+
+template<typename T>
+class myvector: public pushable<T> {
+    ...
+
+protected:
+    void contract_body_push_back_(const T& element)
+    ; // Separating body definition using `;`.
+    
+    ...
+};
+
+// Separated definitions (eventually in a different file).
+
+template<typename T>
+void myvector<T>::
+#if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+        defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+    contract_body_push_back_ // Body function name.
+#else
+    push_back // Actual function name if contract compilation is off.
+#endif
+        (const T& element) {
+    vector_.push_back(element); // Original function definition.
+}
+
+

+ In this case, it is recommended to used the CONTRACT_BODY() macro instead of the hard to read #if around the function name. If contract + compilation is on, CONTRACT_BODY(push_back) expands to contract_body_push_back_, + otherwise it expands to push_back + (see Reference and Tutorial + sections). Using this macro, the above function definition is equivalently + written as: +

+
// Separated definitions (eventually in a different file).
+
+template<typename T>
+void myvector<T>::CONTRACT_FUNCTION_BODY(push_back)(const T& element) {
+    vector_.push_back(element); // Original function definition.
+}
+
+
+ + Pure + Virtual Functions +
+

+ Programmers can also define the body function to be pure virtual so to defer + its definition to derived classes. In this case the usual C++ syntax " + = 0;" is used: +

+
template<typename T>
+class pushable {
+    ...
+
+protected:
+    void contract_body_push_back_(const T& element)
+    = 0; // Contract for pure virtual functions.
+    
+    ...
+};
+
+
+
+ +

+ A member class is defined as the contract class: +

+
template<typename T>
+class myvector: public pushable<T> {
+    ...
+    
+protected:
+    ...
+    // Contract class.
+    template<int ZERO>
+    struct contract_push_back_element_: contract::nonstatic_member_function<
+            // Function type for contracted function.
+            // Copyable class type for old object value in postconditions.
+            // For const members, use `myvector const` instead of `myvector`.
+            void (contract::copyable<myvector>*, const T&),
+            // Base contract class for subcontracting.
+            typename pushable<T>::template contract_push_back_element_<0>
+            > {
+        // Constructor specifies body, preconditions, and postconditions.
+        contract_push_back_element_(): contract::nonstatic_member_function<
+                void (contract::copyable<myvector>*, const T&),
+                typename pushable<T>::template contract_push_back_element_<0>
+                >(    &myvector::contract_body_push_back_
+                    , &myvector::contract_precondition_push_back_element_
+                    , &myvector::contract_postcondition_push_back_element_
+                ) {} 
+    };
+public: // Restore original access level.
+
+    ...
+};
+
+

+ Note the followings: +

+
    +
  • + The contract class is protected to avoid changing the user's class public + API but it cannot be private because derived classes might need to access + it for subcontracting. +
  • +
  • + The contract class publicly inherits (it is a struct) + from contract::nonstatic_member_function. + The call() function, which implements the contract + call semantics, is inherited from this base class. +
  • +
  • + The contract::nonstatic_member_function + template takes as first parameter the a function type matching the signature + of the contracted push_back() function. +
      +
    • + For member functions (including static members, constructors, and destructors, + see contract::static_member_function, + contract::constructor, and contract::destructor respectively), + the first argument of the function type if a pointer to the class type, + followed by the contracted function argument types. Instead, for non-member + functions (see contract::nonmember_function), + there is no class pointer type and the first argument of the function + type matches the first argument type of the contract function. (This + is the same syntax used by Boost.Function[13] + .) +
    • +
    • + For constant member functions, the first argument is specified as a + constant pointer to the class type. If the function in this example + were to be a constant member function void + push_back(...) + const then the function type + would have been void (contract::copyable<myvector + const>*, + const T&). Note that when both const and contract::copyable + are used, const must be + used within contract::copyable[14] + . +
    • +
    • + In the function type, the class type (which is specified only for member + functions) and the argument types can be tagged contract::copyable + if the relative old values are needed in postconditions. Any type tagged + contract::copyable (myvector in this example) must have + an accessible constant-correct copy constructor otherwise the library + will generate a compile-time error (see contract::copy). + Note that the object contract::copyable + only wraps the class type and not the pointer (i.e., contract::copyable<myvector*> + is invalid) but for all the contracted function argument types contract::copyable wraps the entire + type including eventual pointers -- this is because for member functions, + the first argument of the function type must always be a pointer to + the class type (even when the class type is tagged contract::copyable + and/or it is qualified const). +
    • +
    +
  • +
  • + When subcontracting, the base contract classes are specified as the optional + template parameters following the function type for contract::nonstatic_member_function + (one base contract is specified in this case pushable<T>::contract_push_back_element<0>). + All these template parameters are optional and multiple base contract classes + can be specified to support subcontracting for multiple inheritance. +
  • +
  • + The contract class must define a public default constructor (i.e., with + no arguments) which constructs the base class contract::nonstatic_member_function + passing function pointers to the body, precondition, and postcondition + (so the contract knows which function to invoke to execute the body, check + preconditions, and check postconditions). +
  • +
+
+ + + + + +
[Note]Note
+

+ The contract class is declared as a template using the artificial + template parameter int ZERO + to support an internal library workaround. This allows the library to internally + use the typename and template keywords freely to explicitly characterize + types even without knowing if the contracted class is a template or not. + The artificial template parameter int + ZERO is not needed if the contracted + function is already a template (in which case int + ZERO is replaced by the actual + function template parameters). +

+

+ The value of artificial template parameter int + ZERO is not used so any value + can be specified. However, it is recommended to always specify the value + 0 for consistency (this is + practice followed by this documentation). +

+
+
+ + Contract + Class Name +
+

+ Note how, similarly to the precondition and postcondition function names, + the contract class name repeats the function name and the argument names. + Furthermore, for constant member functions, the contract class name should + end with const. This is necessary to support contracts + for overloaded functions (with the limitation that overloaded functions, + with the same number of arguments and same constant qualifier, must have + different argument names and not just different argument types otherwise + contract names will clash). In summary, the contract class name should be + as follow: +

+
contract_function-name_argument-name1_argument-name2_...argument-nameN_[const_]
+
+

+ In order to allow the contract macros to subcontract from hand-written contracts, + you must follow the above convention in naming the contract class at all + times (because this is the convention that the contract macros assume). +

+

+ The contract class name begins with the contract + prefix and ends with an underscore "_" + thus programmers should never directly use this class in user code (see + Getting Started). +

+
+
+ +

+ Contracts can also be programmed for static member functions (see the example + at the end of this section). However, compared with non-static member function + contracts the following differences apply: +

+
    +
  • + The contract::static_member_function + class template is used instead of contract::nonstatic_member_function. +
  • +
  • + The class type cannot be tagged contract::copyable + or qualified const (because + there is no object to copy or to not modify). +
  • +
  • + The precondition, postcondition, and body functions must be static members (and therefore they cannot + be const). +
  • +
  • + No base contract class can be specified because static + members cannot be virtual + so they cannot subcontract. +
  • +
+

+ All these constraints are enforced by the library at compile-time. +

+
+
+ +

+ Contracts can also be programmed for constructors (see the example at the + end of this section). However, compared with non-static member function contracts + the following differences apply: +

+
    +
  • + The contract::constructor class template + is used instead of contract::nonstatic_member_function. +
  • +
  • + The class type cannot be tagged contract::copyable + or qualified const (because + there is no object before body execution to copy and the object is always + modified by the body as it is constructed). +
  • +
  • + The contract::constructor function type + template parameter must always specify a void + return type (because constructors return no value). +
  • +
  • + The precondition function must be static + because constructor preconditions cannot access the object (as there is + no object before constructor body execution). +
  • +
  • + The postcondition function always specifies contract::noold + for the object old value because constructor postconditions can never access + the object old value (as there was no object before constructor body execution). + Furthermore, the function type passed to contract::constructor + cannot tag the class type contract::copyable. +
  • +
  • + No base contract class can be specified because constructors do not directly + subcontract (the C++ object construction mechanism will automatically invoke + the base class constructor contracts if present). +
  • +
+

+ All these constraints are enforced by the library at compile-time. +

+
+
+ +

+ Contracts can also be programmed for destructors (see the example at the + end of this section). However, compared with non-static member function contracts + the following differences apply: +

+
    +
  • + The contract::destructor class template + is used instead of contract::nonstatic_member_function. +
  • +
  • + The class type cannot be tagged contract::copyable + or qualified const (because + there are no postconditions to accessed to copied object and the object + is always modified by the body as it is destructed). +
  • +
  • + The contract::destructor function type + template parameter must always specify a void + return type and have no argument (because destructors return no value and + have no argument). Furthermore, the function pointer cannot tag the class + type contract::copyable. +
  • +
  • + The contract::destructor constructor only + takes the body function pointer and it does not take the precondition and + postcondition function pointers (because destructors have no preconditions + and no postconditions as they have no arguments and there is no object + after destructor body execution). +
  • +
  • + No base contract class can be specified because destructors do not directly + subcontract (the C++ object destruction mechanism will automatically invoke + the base class destructor contracts if present). +
  • +
+

+ All these constraints are enforced by the library at compile-time. +

+
+
+ +

+ Contracts can also be programmed for non-member functions (see the example + at the end of this section). However, compared with non-static member function + contracts the following differences apply: +

+
    +
  • + The contract::nonmember_function + class template is used instead of contract::nonstatic_member_function. +
  • +
  • + The function type passed as the first template parameter to contract::nonmember_function + does not specify the class type (i.e., result-type + (argument-type1, ...) is + used instead of result-type (class-type*,argument-type1, ...)). +
  • +
  • + The precondition, postcondition, body functions, and the contract class + are not members. +
  • +
  • + The contracted function definition must be inline + and it must appear at the very end of the contract after the precondition, + postcondition, body functions, and the contract class (to avoid duplicate + definitions and missing definitions compile-time errors). +
  • +
+

+ All these constraints are enforced by the library at compile-time. +

+
+
+ +

+ We conclude this section with a fully working example that can be compiled. + This example illustrates how to use the library to program contracts without + the macros. +

+

+ For simplicity, this example only exposes a limited subset of the std::vector + operations and it only programs simple contracts for them (see the STL Vector + Example for std::vector + complete contracts). Furthermore, the somewhat artificial base classes have + been deliberately introduced to illustrate subcontracting and they will probably + not be part of real code. +

+

+ Comparing this example with the one presented in the Tutorial + section, it is easy to note how much more setup code around the contract + assertions is required when the contract macros are not used. Therefore, + the use of the contract macros is always recommended. +

+

+

+

+ +

+
#include "pushable.hpp" // Base class for subcontracting.
+#include <contract.hpp> // This library.
+#include <vector> // STL vector.
+
+// Wrapper that adds simple (not complete) contracts to C++ STL
+// without using the library contract macros.
+template<typename T>
+class myvector: public pushable<T> {
+
+#if defined CONTRACT_CHECK_CLASS_INVARIANT ||  /* Allow for         */ \
+        defined CONTRACT_CHECK_PRECONDITION || /* optional contract */ \
+        defined CONTRACT_CHECK_POSTCONDITION   /* compilation.      */
+    // Augmented state.
+    friend class contract::state;
+    mutable contract::state contract_state_;
+#endif // contracts
+
+#if defined CONTRACT_CHECK_CLASS_INVARIANT
+    // Static class invariants
+    static void contract_static_invariant_(void) {
+        // Assert nothing in this case.
+    }
+    // Class invariants.
+    void contract_invariant_(void) const {
+        if (!((size() == 0) == empty()))
+            throw contract::failure(__FILE__, __LINE__);
+        // More invariants here...
+    }
+#endif // invariants
+
+public:
+    typedef typename std::vector<T>::size_type size_type;
+    typedef typename std::vector<T>::const_reference const_reference;
+    typedef typename std::vector<T>::const_iterator const_iterator;
+    
+    // Contract for constructor.
+    explicit myvector(size_type count): vector_(count)
+#if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+        defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+    {
+        contract_contract_constructor_count_<0>().call(this, count);
+    }
+private:
+#if defined CONTRACT_CHECK_PRECONDITION
+    // Static preconditions (i.e., no object).
+    static void contract_precondition_contract_constructor_count_(
+            const size_type& count) /* no `const` (it is `static`) */ { 
+    }
+#endif // preconditions
+#if defined CONTRACT_CHECK_POSTCONDITION
+    void contract_postcondition_contract_constructor_count_(
+            contract::noold, // Always `noold` for old object.
+            const size_type& count, contract::noold) const {
+        if (!(size() == count))
+            throw contract::failure(__FILE__, __LINE__);
+    }
+#endif // postconditions
+protected:
+    void contract_body_contract_constructor_(size_type count)
+#endif // contracts
+    {
+        // Do nothing in this case
+    }
+#if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+        defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+    template<int ZERO>
+    struct contract_contract_constructor_count_:
+            contract::constructor< // Use `constructor` (not `function`).
+            // Class type can never be tagged `copyable`.
+            void (myvector*, size_type)> {
+        contract_contract_constructor_count_(): contract::constructor <
+                void (myvector*, size_type)
+                >(    &myvector::contract_body_contract_constructor_
+                    , &myvector::contract_precondition_contract_constructor_count_
+                    , &myvector::contract_postcondition_contract_constructor_count_
+                ) {}
+    };
+public:
+#endif // contracts
+    
+    // Contract for destructor.
+    virtual ~myvector(void)
+    // Destructors only check invariants.
+#if defined CONTRACT_CHECK_CLASS_INVARIANT
+    {
+        contract_contract_destructor_<0>().call(this);
+    }
+protected:
+    // No precondition and no postcondition functions.
+    virtual void contract_body_contract_destructor_(void)
+#endif // invariant
+    {
+        // Do nothing in this case.
+    }
+#if defined CONTRACT_CHECK_CLASS_INVARIANT
+    template<int ZERO>
+    struct contract_contract_destructor_:
+            contract::destructor< // Use `destructor` (not `function`).
+            // Class type can never be tagged `copyable`.
+            void (myvector*)> {
+        contract_contract_destructor_(): contract::destructor<
+                void (myvector*)
+                >(&myvector::contract_body_contract_destructor_ ) {}
+        };
+public: 
+#endif // invariant
+
+    // Contract for non-static member functions.
+    void push_back(const T& element)
+#if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+        defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+    // Contracted function.
+    {
+        contract_push_back_element_<0>().call(this , element);
+    }
+private: // Private so not to alter user call public API.
+#if defined CONTRACT_CHECK_PRECONDITION
+    void contract_precondition_push_back_element_(const T& element) const {
+        if (!(size() < max_size())) 
+            throw contract::failure(__FILE__, __LINE__);
+        // More preconditions here...
+    }
+#endif // preconditions
+#if defined CONTRACT_CHECK_POSTCONDITION
+    void contract_postcondition_push_back_element_(
+            const myvector* contract_old_this_, // Old value for object.
+            const T& element, contract::noold   // No old for element argument.
+            ) const {
+        if (!(size() == (contract_old_this_->size() + 1)))
+            throw contract::failure(__FILE__, __LINE__);
+        // More postconditions here...
+    }
+#endif // postconditions
+protected: // Must be protected (not private) to allow subcontracting.
+    void contract_body_push_back_(const T& element)
+#endif // contracts
+    // Original function definition (the body).
+    {
+        vector_.push_back(element);
+    } 
+#if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+        defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+    // Contract class.
+    template<int ZERO>
+    struct contract_push_back_element_: contract::nonstatic_member_function<
+            // Function type for contracted function.
+            // Copyable class type for old object value in postconditions.
+            // For constant members, change `myvector` to `myvector const`.
+            void (contract::copyable<myvector>*, const T&),
+            // Base contract class for subcontracting.
+            typename pushable<T>::template contract_push_back_element_<0>
+            > {
+        // Constructor specifies body, preconditions, and postconditions.
+        contract_push_back_element_(): contract::nonstatic_member_function<
+                void (contract::copyable<myvector>*, const T&),
+                typename pushable<T>::template contract_push_back_element_<0>
+                >(    &myvector::contract_body_push_back_
+#if defined CONTRACT_CHECK_PRECONDITION
+                    , &myvector::contract_precondition_push_back_element_
+#endif // preconditions
+#if defined CONTRACT_CHECK_POSTCONDITION
+                    , &myvector::contract_postcondition_push_back_element_
+#endif // postconditions
+                ) {} 
+    };
+public: // Restore original access level.
+#endif // contracts
+
+    // Contract for template plus static member function.
+    template<class Iter>
+    static bool all_equals(Iter first, Iter last, const T& element)
+    // Static members also check (static) class invariants.
+#if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+        defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+    {
+        return contract_all_equals_first_last_element_<Iter>().call(
+                first, last, element);
+    }
+private:
+    // Static template precondition and postcondition functions.
+#if defined CONTRACT_CHECK_PRECONDITION
+    template<class Iter>
+    static void contract_precondition_all_equals_first_last_element_(
+            const Iter& first, const Iter& last, const T& element)
+            /* no `const` */ {
+        if (!(first < last))
+            throw contract::failure(__FILE__, __LINE__);
+    }
+#endif // preconditions
+#if defined CONTRACT_CHECK_POSTCONDITION
+    template<class Iter>
+    static void contract_postcondition_all_equals_first_last_element_(
+            const Iter& first, contract::noold,
+            const Iter& last, contract::noold,
+            const T& element, contract::noold,
+            const bool& result ) // Result value.
+            /* no `const` */ {
+    }
+#endif // postconditions
+protected:
+    template<class Iter>
+    static bool contract_body_all_equals_(
+            Iter first, Iter last, const T& element)
+#endif // contracts
+    {
+        for (Iter i = first; i < last; ++i) {
+            if (*i != element) return false;
+        } 
+        return true;
+    }
+#if defined CONTRACT_CHECK_CLASS_INVARIANT || \
+        defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+    // Function template parameter `class Iter` already present so
+    // no artificial `int ZERO` parameter.
+    template<class Iter>
+    struct contract_all_equals_first_last_element_: contract::static_member_function<
+            bool (myvector*, Iter, Iter, const T&)
+            > {
+        contract_all_equals_first_last_element_(): contract:: static_member_function<
+                bool (myvector*, Iter, Iter, const T&)
+                >(    &myvector::template contract_body_all_equals_<Iter>
+#if defined CONTRACT_CHECK_PRECONDITION
+                    , &myvector::template contract_precondition_all_equals_first_last_element_<Iter>
+#endif // preconditions
+#if defined CONTRACT_CHECK_POSTCONDITION
+                    , &myvector::template contract_postcondition_all_equals_first_last_element_<Iter>
+#endif // postconditions
+                ) {}
+    };
+public:
+#endif // contracts
+
+    // Similarly, complete contracts sketched here and add contracts
+    // for all other functions (see [Crowl2006] vector example).
+    size_type size(void) const { return vector_.size(); }
+    size_type max_size(void) const { return vector_.max_size(); }
+    bool empty(void) const { return vector_.empty(); }
+    const_reference back(void) const { return vector_.back(); }
+    const_iterator begin(void) const { return vector_.begin(); }
+    const_iterator end(void) const { return vector_.end(); }
+    const_reference operator[](size_type index) const
+        { return vector_[index]; }
+    
+private:
+    std::vector<T> vector_;
+};
+
+// Contract for non-member function.
+double abs_total(const myvector<double>& vector)
+// Non-member members do not check invariants.
+#if defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+;
+void contract_precondition_abs_total_vector_(
+        const myvector<double>& vector ) {
+}
+void contract_postcondition_abs_total_vector_(
+        const myvector<double>& vector, contract::noold,
+        const double& total) {
+    if (!(total >= 0.0))
+        throw contract::failure(__FILE__, __LINE__);
+}
+double contract_body_abs_total_(const myvector<double>& vector)
+#endif // preconditions or postconditions
+{
+    double total = 0.0;
+    CONTRACT_ASSERT_BLOCK_INVARIANT( total == 0.0 );
+    {
+        CONTRACT_INIT_LOOP_VARIANT;
+        for (size_t i = 0; i < vector.size(); ++i) {
+            CONTRACT_ASSERT_BLOCK_INVARIANT( i < vector.size() );
+            CONTRACT_ASSERT_LOOP_VARIANT( vector.size() - i );
+
+            total += vector[i];
+        } 
+    }
+    return total < 0.0 ? -total : total;
+}
+#if defined CONTRACT_CHECK_PRECONDITION || \
+        defined CONTRACT_CHECK_POSTCONDITION
+template<int ZERO>
+struct contract_abs_total_vector_: contract::nonmember_function<
+        // Still use `function` but no class type, just use `(*)`.
+        double (const myvector<double>&)
+        > {
+    contract_abs_total_vector_(): contract::nonmember_function<
+            double (const myvector<double>&)>
+            (     &contract_body_abs_total_
+                , &contract_precondition_abs_total_vector_
+                , &contract_postcondition_abs_total_vector_
+            ) {}
+};
+// Contracted function defined last and `inline`.
+inline double abs_total(const myvector<double>& vector) {
+    return contract_abs_total_vector_<0>().call(vector);
+}
+#endif // preconditions or postconditions
+
+
+

+

+

+

+
+
+

+

[13] + A more natural syntax would have been to use C++ function pointer + types because they already provide a syntax for non-member functions + result-type (*)(argument-type1, ...) + and a different syntax for member function result-type + (class-type::*)(argument-type1, + ...). However, the use of + function pointer types to resolve partial template specializations + (as needed by this library) it not fully supported by all compilers + (notably MVSC 8.0 has issues in resolving template specializations + between void constant and non-void constant member functions using + function pointer types). Therefore, the Boost.Function + preferred syntax was adopted for this library (also this harmonizes + this library more with the Boost + libraries). The Boost.Function + portable syntax was not used because it is maintained by Boost.Function + for backward compatibility only and it is not recommended (even + if that would have been the most portable syntax across the different + compilers, see Boost.Function + for more information). +

+

[14] + However, if the member function is constant it cannot modify the + object so there is in principle no need to copy the object value + before body execution because the body cannot modify the object + in the first place +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/doc/html/boostbook.css b/doc/html/doc/html/boostbook.css new file mode 100755 index 00000000..a428546c --- /dev/null +++ b/doc/html/doc/html/boostbook.css @@ -0,0 +1,594 @@ +/*============================================================================= + Copyright (c) 2004 Joel de Guzman + http://spirit.sourceforge.net/ + + Distributed under the Boost Software License, Version 1.0. (See accompany- + ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= + Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= + Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= + Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 90%; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= + Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font: 140% } + h2 { font: bold 140% } + h3 { font: bold 130% } + h4 { font: bold 120% } + h5 { font: italic 110% } + h6 { font: italic 100% } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 120% } + h5 tt.computeroutput { font-size: 110% } + h6 tt.computeroutput { font-size: 100% } + +/*============================================================================= + Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= + Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= + Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= + Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= + Copyright footer +=============================================================================*/ + .copyright-footer + { + text-align: right; + font-size: 70%; + } + + .copyright-footer p + { + text-align: right; + font-size: 80%; + } + +/*============================================================================= + Table of contents +=============================================================================*/ + + .toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + +/*============================================================================= + Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + table.simplelist + { + width: auto !important; + margin: 0em !important; + padding: 0em !important; + border: none !important; + } + table.simplelist td + { + margin: 0em !important; + padding: 0em !important; + text-align: left !important; + font-size: 9pt !important; + border: none !important; + } + +/*============================================================================= + Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= + Variable Lists +=============================================================================*/ + + div.variablelist + { + margin: 1em 0; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= + Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= + Colors +=============================================================================*/ + + @media screen + { + body { + background-color: #FFFFFF; + color: #000000; + } + + /* Links */ + a + { + color: #005a9c; + } + + a:visited + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + .toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + .copyright-footer + { + color: #8F8F8F; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + .toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + table.simplelist tr td + { + border: none !important; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } + +/*============================================================================= + Images +=============================================================================*/ + + span.inlinemediaobject img + { + vertical-align: middle; + } + +/*============================================================================== + Super and Subscript: style so that line spacing isn't effected, see + http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 +==============================================================================*/ + +sup, +sub { + height: 0; + line-height: 1; + vertical-align: baseline; + _vertical-align: bottom; + position: relative; + +} + +sup { + bottom: 1ex; +} + +sub { + top: .5ex; +} + diff --git a/doc/html/doc/html/images/alert.png b/doc/html/doc/html/images/alert.png new file mode 100755 index 0000000000000000000000000000000000000000..b4645bc7e7cd81f2818bf22aa898e95f89f7b154 GIT binary patch literal 603 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoR!3-ps5|6h4Ddu7)&kzm{j@u9Y9{{=Y1AIbU zf%JpT46~{k9zA+AbLPwdAIsS2PzO_vNDmfMEtWH9&ip^auzMPVqn%}CB7>9&!}iGx z-;Xhv8px)lrL9@BCcs5vO&5cqu9T{h?38MTlmG^xxVH_1kB|46nGCkpmetkOTpSE4 zavV>eK0UdRp(B^!=?;d>5QYoO7|ac%0{lFz^%?x_8RR7yVthEP3>A&_q|CG#WW*RW zl{o(Y|IZtA$qVR2(~=;+U?7)dz)-XG0w_#43p^r=85p=efH0%e8j~47LDdr1h?3y^ zw370~qErUo#N?v<+|-oJLS?-v|XG0|S%xvNh*{8XkJOIEGZr$-Qt} zs7XP9Ey3he(pHrYspZRf78PH9`FH+W)~#!9NQ>E(|7f+bS8dIEdt&+3)9k$5zE@_n zwwz6h>zL57n052?|A&@wF+B45-}O%P&a!K2U&3G9nvuNo>8jg5#pWKJFg+#ZM_3KF z@0!U*M+MgC=JZ@&d`GA4#mi|OP1Q3WUuyYq=o{O;ODgJig+1&Ot|jSj5iH+p{qlah z-+>>`onNNZu_SEo{1c_>E?8^dWc*|KzHYTkoV#ab9htMb`jx;F%~$-4S3IxI_4a$B t(zNWy?!(WO+m-mQI!w5#7{UFM>Ew3T@2Uk;6oH;)@O1TaS?83{1OOIu3ZVc1 literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/blank.png b/doc/html/doc/html/images/blank.png new file mode 100755 index 0000000000000000000000000000000000000000..764bf4f0c3bb4a09960b04b6fa9c9024bca703bc GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1SEZ8zRdwrEa{HEjtmSN`?>!lvNA9*>Uz33 zhE&XXd(lylL4oIh!GZnHecj|txT>yO8>^qY%(y?B;Tppl#t7yOYze#vq#8^aMzDZb YLK^d5CO(feU_df>y85}Sb4q9e0BevqT-$&hMpcE*)wGd!;~q-Q>IkUnZqz=PVt;M zK*p3gbLK2v%CK~4^3tV1#?q}@8MbbX+PXD)>(;G%_cH9=n|$sZ!?|yxmE{-7;w@N47?rU=3X_NkV zU|o{PnRTZ;lXp4>+)hZU_|Lw%*va*6=<@jI@BP^`_OsZ?pZg-2AaGf|;i2L0<>du@ zeRrO4er03}pLSxdREd>pap^;~&E+}=JYKy#vHnLI=Z$}pPyA_`zG;G~<$`Br2do;7 z$Heivv0AeyJYVI({@6?X6r+V~XS2Cs!|bddDqJz@2lKf$~4dA1c%lfOT+5KMUSWi#X5(9ePxx_W1Bsf2+N)z4*}Q$iB}K{RAP literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/draft.png b/doc/html/doc/html/images/draft.png new file mode 100755 index 0000000000000000000000000000000000000000..0084708c9b8287c51efa6b40b8d492854191455e GIT binary patch literal 17454 zcmXwh2{_c>_y1e^C}m43S&}RzTQstU#!g0*n6YJ1aTS}>RLe1z8LVo z`rtm$Vp5JW1|R$HTrs@@LGR)Z?>PPkL8l=j-77Z&G8Tsi{RV4sPaGi)BBI`)`R~Q` z*=O$N8oBahuA1ujq=ONsH^Z$;Z@?A2zPOR;+t7%GvNscPQvtyu^ z^(He{(TNfAz{D>S76#pNt`V=aFm{t&tF)Lut!iq>3RU|!!{xbB|2@69Az7({KpgFX zBHUL)|7ydZKc0k%azcGA&PuCQV*kD$bT{P;b?=`M@6C_|b6!~s9j#tuU~e9n-MCHj zfV5S(js_`kv|ivaLE*6pY!G%r11u^qOVBw|g29`m16#D?@yi>zc0bwz%G@ za2kvxn$XS7{2WQ_ju!==VTs+`V&L;sVz(Pl4+J?F&ZZv3KoKW2c?bBtGq5)oRM?*)usx_-H@47Cu#_qL+2eow%ZDy0=bsNsUP&ms8wSUp@nG86W_bQDmNMRgINC`_}NgC zCcqF_Ta|ScVvPu;|0KG{NIio~DaGYcHYq4AEiIzkxEPqs@0$Z$*)*@J$yP3ObX$%T zzRS=t%7(g3t{Q*^ zEyTxT$*5+N*(plL90Bl6`Nb^WdKn_Pvpb{prO$Iu<5}~-EnXK7fy@_2c89d+ZhJ|)%qTOcbj#K2|l1B!3n*4em>_| zs0+)H9*C!kU%yVP5l({XnQMeRu}L5Sj@SNhX<@4AzfhMZW{P&$t(3w4cF;s3a!PkRM$$6I_u>8qK3>fr(_ zv-Y*v{SjgTfq|+BcyYvbM!vF^@bCsN)N`rpJ$><_Gs5*qVfQ0@761Os;NFEBr2V@4l75H}1u*H-x1FzIyrv zX4-neRxZt~y^&-x>*hYlIJHqt-rL&^c9<9eB-5QN-kNin&S^e!8s9rIjX$~r#FHSZ zPPGHSJ7NH?>J1WXHMp6{3_m_JHFb(pJM-&G@!UzwMZ19kYDMv8^_@35=1Qp*GU^C$ znS!nuvPQ5{W^@`l=K{0vn9d5B4sd@GNsqwYt13N;s_n$M5sF(Y{Gu{$f)Pqq6>`4( zoK6ZojptUz?t{2OQ@f4d24!GwYi6y465k8gmK^#vxd{Il-lBt^R7pE@jfteJwgkQ(YBxT%22tXdci&(7P>~Iov zlAF+-uyinD*mU_C1!Z!%vFE`wQx$H0WX*IMeKiv()c!!|Br&A#iWksE5wy*|X}DYF zOkmbb)NtBhwAgAQQ)W7>BzBj)^ec8BETv8dt~1Wtd}pfRmKnoYyMymV`fvW*bjTy@ zNFqchp{S-_%)XBfUmWyYYl$xVgQtxEVn358@gKtpQuu~+-Kl-33E21oa-Fi&oBI&`1N%T=`T3uD7xjR z1Q5DaVd-rOkkqXdK@Yti1APh3TN{S1DknOaE4Vdk=o-MQ!`zf#3^vm0RTp!s>(8+I z(BKlybb>#^&dE#xTWKkB5>RG$`5m60nzI~B_{R+DtsN)(K1(tUpuVHL0)mIKnUfCR zGE=xGXN@3g`N9QSG|T0c&wxuu*Qg<*+`PlfSfJAKfkWnRsVJ$bx1$Z`o)r~6%k4&i z<9I5}9(ypb2w!#-r7*;K+DjakI~Af;0mNtDxBc4R3|&8W^=h6KIf?>|@$@)*tlfRZ zrCkhM8ZMxnVd%Q>wKHQ6h;cwwxcI6738osp@h30JoAC1Si}3tS%4m{iuKSkF9xsrA%;wLv z8A#j|uifcVGx>ptY|-u;nJ$&yw-19u5smA=3C-sC-n~XzIV= z*~{{V0<$*x$DP?_zs?b?-Dsw+U(_(rI4}YY;n`g??R&MWiSNSHJ{;g>QuE+91GpRE zd9DfqUKVfdeAUwO7il>!iH(N~Y+WTTbX3b$$01o$aei(SD8PN9Ig|tehF6`&rMrwH z6C(}UhO7r4V(nXd&uyraV5X$iUUKSF7E#U?bu;$RHwXn03D2wdZR{}kbxlVH%&8F=8tR+X zZ7kKlMpt29EK0Mnb~Bm{1y*D227__FT~$T7>%Bs>RxQrlgI55^$os$sc`ic?+hwHQ zy%C%qRZZ?xjTT>R%HJvzYPmTbNJa&lc4N}*?d^eJ+TgWWrby|-X?$RL63$ocD0=1z zq>bD(K@l*w5V0aAqv-^DtQq(*B!;KK;S)?XERW0Z8_eB7>{FG!W0Tmu$$a@l#~e@t zb7eAjZ0Z_IN~+HjldvP|xLYiL+|mn)Q;HmqDMG^&^)mW(%Xyb~AG4Jkd@~F091U{i zRg(Zi(!S357h;^+d50bWLHO{(l58O+_d192vyD-Oh|kx|qkk|71w!Jdg*R ze=X`e#>jQ1n83%L37gJmxi{uYC;jRU__qGnk430EXC8CcRU^h&pyhVlHM8x(ce}=L+^|Pv zi|35MNQw6wsl4bw0P{NiUo&-{is+V{iXV*G{_L^ONZ@`H!#JZ@}t;bpd`Z>sx8;y zHg4#YSJ*anpi2Do=jWPejhaoGWKx!&jJeOVaku|#u8?8fCKc>EQ4j zn#0h@X_`cW22kHot+mSQz%;tAI|=i92)Mglsf!Nu*>=_g&(G0d>km#k&)3TllY#^u z02UV-NFuEUi@}-x=ETTTKA`X~EX5jv8~B<}HTK+*9&OvU2dkm`_BX*1VwV7Ij{pg= zxZNaUqPlcVYHAyHFof?m;I-ZD4bN%(@@2Td(VgI3 z{*lWmv$RZ|smov=_kGDznn+>_uX{A6;y}7pk@d`(Lh6{gFvrA5pAdMmu#G*QM1tQg z2^Fb6c;#}e`;nd&oQKh@*-zW!9ICOL;OFgA2-lpdOKmA=Bp;B_eB?c_df>veT)HW_ zs^sQQf+2B6j;5$>ZG`htEUcU*ioNkd+t(slRq00x_hk@N@P79aTAmlqe^(+dfnlOAm^WQavYofR?D70kyE!Q*mr z=MN`!PH<&(t6*5^bfSkgq80c+f6zkhX=!PVf1h^9o$GPX_wJAXim3%oV$)U9uWEOS zFZ=#iF~Q2FVvon!cVc(IvVedI_~ko1I5_AWe$&m4Pfz2dCm|J!YrHng`j<_W)9N6m zB@dJSV}^c#gL?<*=59v;JS=y@jX-JNZOq4)l)5={d`D-W!H@43<=pJ8Cgd+PhIgZ0 z&1}v2D7JC5c5m#$OqX|BP;TfUn_N`fm(NOG0@Nct5f0=5t?)gK>f*TZCP8 zE~vAz*f8;aNltIEzGmjk2?*gK)Xp4zr=6}59u!nRQiIH`r`BWA&&b%MJ+5|@JL))( z@lrFw!p1WBNbZB0IBSb692ygY3^VVnsCLI=p1DJ|9{R_viTo;ObrMJc9HN|9uopn6 zRxJ;a=NLyqW+8?@vXq*8_pkle?wWh-VSoPI3KIY*(nFq-Do;;Op#DRi6cuGIH zS7vFz0{w!T_jHtX9_!if-#4x3C9rYkU+2(KU|U3m|Bg{GCEc)G`)=}$uCcQ=o5}DE z4Qf|tZ$U3T&S;B0h&i3`PkyvL2&sK4L#)80)82naNsAnG!T4hTE7tIKfou;^sdejO z2^s6dG*bi~@XEf#g^+->YY)^i=j)rM{NpB6Os``bQrQDn`1IcCuH_tZo5u_RDCH9} z{A(qdv9-0;w%911g+6sdttId7K8LSzQx$iqDz9QJ%qEV5yOmP%C1^8VJ~&}mU03FL z5oO`+?_NbVx$89Jw_-65lS!LLL^<~>akOrQ*k8YT2f4npv!ne5LrBe1G zio4QV3V(pOPhsqCE2}mF#DXWKYCS~L->zo*5E`io01;dT5!%$~no!XU5w!2{HcD?P z$hkcJN$uNC-y%aa0(KSOy?hfCDA$n{jchN?d(tgsICQ1t%qbWQv5cv{T zBj3*W2{Wy5d$(v$@2djHMZWKG0-|MBp}dhVgo z`Vtvp{;P+IYGFXmo{Vm!Z+%cSOfN(pk`H&G(lF_arZgk!S9%x!bxKv`i?_8}mLXr- zfr-&54|LC~#MV?wRQm-EFSRGh4UA`d#pe!1bE-N?4{$Ro_JUO#b#A&ZN*AR84Q}u< zvAY2P2=^9%#QQFnV=U#iNT(o73@pmXuFN9 zR?J5~@ZQvv3RK1HlYa(JZ^_%8l~?wwv#lhDjuMeJDC(xS8@gFpX*CRJe8FTVfJFLE z`L1aE-QBK9wh8Lf=pv(3olJVvrY$Ug*U6Z?{29OF(VGVhgGPXNls7&Qa&U0KV+QnI zZN%rly6U%&wr&4qxD-ujjGO;@!kTH7t&RXS%qN%jTu85~jgj|mC`qh(pxU=LV<8nb z2*g-&X|S0`7pDK6F8O&>ow7=M28`!FRi!}mwg<&m&wRfJeJ}DJr|iWg3+r~FUb+VH z+^&Un8v5io|7I+;!f+OL&4~5g{fgrz&*uKPkBlbI#PEevl|9*Y;=ZITUOO{Xx3C?Q zjzzGgf??gQ$0$6k$=bjrn_FR?Ye1m&Alpp zIR2qAum=_rBrlX|_n?Z@`qf(Z0Kxll;~uBw&`7z9Rouxf&+){$ zT5l^SU3Q)C3!P4v<8`92?@GD3FQ>)aS@lWl&S_BItaudFE*~l)`|-f4TB#FImiY-_6&9CJ9!>+TEFxeaHO)c zvYblCdx~?kBnWI3y61_CZ7mPPn2!+y?I{+aqiJZV?FagXcV{P$qIQQ}eE8YeF~}-C z?~`EwR@Cieg6$PyJheqdg_twn9zXuoot>29+0UEtNnjKl>TgTSUIvF?r06FMW=5%U zVd7m{^kQJvRLT(~FbI!5QPR|t;QS06HwuN4s*dj5LYaTRDxc}ZbrgWm^`&@BlD%v{ z@k_@S)~9!76hB8Mu>D387Pt4nO+z=`W~vOK4w3_J5I>vM30q#&d2?0jd#W0;VqxAg z{*lOi191%V8^8z#kba|g@ zf4GgGK?gk~`S@>iRci6!kr&;RW(POG$iTAEX&_W3#)}zCBeQ12R}+C0SYWFB65117 zYx=X?gFD^+O{W+m*yAfTKmH~iyJk_ORwrFE`7|!~oOPP-{gCa4!U@A4tRgdFHX_Yj zXQ(+MhO_<^GRY)^`TEi#V?93xP#4UrcMTTD68zJ5m{DboqT=!RTMbx!3!QK?HvU2k za26tqP;3Z8*MmUwL{1I(@xTcd(1T(ot# zQ8@|QB&oA%VI6gn^=!_v)SeO)d`3{ewC>T3XM2ZqXV?iJKc$ft~<<46c!aV(J1mq1tLFMB0Q_){R1qliEw)EIh?S*NbRo*>YaPx z2D-q!@M}X!8+eqQe9(&`vcyr9*&Oc9DxIi1?hcoq6i$Ah{XCaH^2(3TA1)Kpu+!qk zA@V)hERaLu1FN%*CTT?U)U3}+-q2_=P0!NO%*+f=0%Wimi9$O7C`K!{L9kB*slT?q zUcI7*#C3?0;`R1E9%YCjZ^&A%sl;VB6)!NN8!ilSF2s{jaYk8%7*iwJVYB!}O?`NH z3i_o?`Ay@F!YSHq7T_a4Hx}qC1`Ys?_byXR)+^(UW^H6<{Jzm;NPkU97r0{^fT(G3 zA;><1llKwo;%)@{#|9*KE2Dmt;(B|5Xn)(d7V2nr5OXUnA1y_!SW`EtahHzmtl7EE z%djW%*H&HXZ5G=Zciw~l@@5<9~SRg`>1sdv54 zxFT-jCM&GG@`Q{Ed)0jXg#Q(;FzY%A{D;AwhdaxE884#bo;|{{h3OhPo0zbfk;Dak z&K2NDkc8^wVPB=SuB`+^8?cY^RCi~h^*4EmEc?J58r@|g3@t=ykaw*U{ z7v;3}@P2CDd|+0TV}fa|3wl21cs|OFu95chX_S0!)zbD}eUfC(!|&!sVnQ$17U~i3 z0k=jQ+>~NKF!oc>Kff(i>j!z@pZJbZ5Qp)A$c?DsJ8AAv!O6p8|34Q%YV*_nJIhup zmQ_{jUUf_x$nzc!4cNy^2`mY?*);JNgVn<>CsVJYluh4fgd_lF1||t597+ld|`Ww&*4Hb;}rzPmefkY`>P)eSO9!dk2T9lx>3Nj5=Mz z>r&3-+b)2!U(?WAgFX*rf@W9Zs)AS~lgtt0D77}&rQM~)i0CR!i>JVNn(;mN6vgZBRDJTdsnC?L>2H3nvZSp}#S z6*9#|of{57Sm7ktIRid*9b3ZPg&%fX92~R}5M69&e`W5`q8wIvKfBufD8f~ti%ujG zOKrw=EiJwBQ@H^*Kw5USk7cR`7;^B0t+_@D3FT&XdE}c8tK%QmNSn;A8RAsMn%(|0 z_}jjAHPj3;YFouX*X_FojE7Cjxz=b5i*s)&Yd&bUzA+NKT|Zgbdbmf54f|QjdK38q zi<5!1eI+@#xyQUC|DfNCc{vl9E=gF^==yjQil0#7c-)K`hM1O%+v4rCu<4wKEeA0> zEp7n)lZbgQlME&N{V?)eCoEp(d6K!Ss;kAyp#QBJcej|g)B$R7KOOkifc9VnF zpKF%Ab3TXaX3pJr!NN3W-J#nLcKyGkvKH+HgbCYH}OT?)qCnEf9AXZkAVH3MBfRj~6fiIx9-31EklLu#&A>uM1w2k;x{p z6SI?Q5Rg<8S^)#s7ktzJn2#%93?7_*{LTCC-tM45qH{l**RpP#OJ?_o|&r9_@2w=JQ0!~pTA3FNiUVF zjRt1OxG5gVaVzD&sIKBRWsLqX)%Dkp^<7D*ZZlOm3zvdK^caRuw0>+%#d)V}r&k&S9MyDr!%#@BU!SxwyIS8y<#pz4TMM)V&d^NaNs%w$r@xK#Z3m-2Z*B z!#C;VD$dR|<3`KMGMYA6xX-+QD(`rW%C9UZWiLh9%$D1dG#BLbF0BPZF6E_5rP3E_PtxKxwhc&v~_AC^KGDil_tZ4XGnVb_$U_s<> zm8kOFv>8SO#Z#<$=3;#hN0AoE1Eo}p(7cFS7Qu%^IP-@56DRm6;s!W0R~nyzVbeB3 zPAN{zeWb;hUGr&tp1Tb%L(Z#nGF@88afdvP=TZ9_k=he-T;vK+PJ?P6ZmqD(qF2)s za2N9|Lc_5Nh35`gW$V?KI?Em}*YAvfg$3DWNG(QvSZl?m(ctUi;Jj>c8s=iGQ_8IM5DCuHH6)h}yp2H=v=D>3DC$o5 zULiAntcT_b0+|=uYSp|RU-2AMnA6H6X~WBacfvSg6(!cva9ZpD*PX&B$NOGVW7m4Z zwa-Ri?VbD4_e>?M_?{Gp5;i_LZoeQ02^su&$#yDX?_v;bcFNw!ZP<6Xv&q9brr24? z|MPgFAc|V;-ru*smLhtJwEd+tn+gNbYoIlb_Kua^3mizF_sOpaD<1}%2z%fRbie!kaalVI{ zp@PyqhIH`4Lsqp;dXPhYq~D8f_H6FmSVw-c0o;ya;C8Y>viOHkmc!hn^U?c42ZCH^ zPvXs&ZghbhD2ne4J#b17FiS1I9RZ}k{S#@9{3>3owZjjy1{zN14ROf_w3vGo{JOw_ z5LgnbR;Hy3#ZJxN6{=$yTGHlT+Ef*p(!2*(M=pwq@gO`fH0Dr=&t+`4T`zSS&3H_CR^wcr&oGobo(9^R&aR88N zpw8q{)!yFVT7gxPn;IJlWjTZ@;6^gu0o~Co*Y0Z@emdc=ZP)|VUtU{c#1q@-m_(_F zc1`xg?iSXAbKiaJX8bOLsLi6+@?>^2T?51nOC5Th3E$~E6NxFrub(x#dXlO?;HtC3wTw{sEq|t|$syXv8Tfi8aLLm->hWZycx7?T zJAi@9^p4)TX$*q+{W7YJe2KLA=_$$-H9nhPJihFrO_S8hL+vnyy}LF)%0Bq3`+#x! z9*bF7ccIkdCZ@bjMt&SE&fg93dDU%csbne!aFMjR)C1<>dSOfAuTm{~rfOo&wrBMJ zi&P9Lc>oaIV)w+sO?^X8sjG-$-RvZfqbMm$3ez1Ue{7OHR`>b6Zq=_PrYSjFxJ0op{4-*e>HCa+ltbeRL&8rk zOpJhZ9$>74+^4>aDY$y1{+F~p?}C)d=kkO*yn}m+Ajw3dOKVp@e;LX1bbqRk?i+lw z|D*uJfF@Z)tVkhWM8?V&E# zyTmdhV1UEb^kae@-je}deN9LG-8T#3h1#ojCe(gby>*zW``~(Lb6U7b%MwpdqEq(K zEAS{$i7H)RbG~^`>SjFQj+Y?^Ft_1`?au+^$%R3VO1zaZ&?NS4Ry^!zZ^1c#NF#h@ z0TD8T#jmQSaL?JG8@5uub}qy}n+?f&XZkDn47o*x8=R+CS@9|@+5Sc{deuI{#-k@8 zGwVmk8dyt-NdoEExb}uMJCH}0UCrJi0uMR>5}ISY3=oBH&_hoY1^&b)i~yE}u?si% z-PVt&T)q;ZjLX0sQ_TA3bY0+hmGSl}+yLQsMKtH(tvC4_;^TC@vXLuNNTcgL$DnOmGiLhtBsMO^AN`&cRypL?h%J zBiGYxSf4}dsU(n)My$~2GQ(fLVZL#U{ho7-j1j?+)IK2=G zzXCkvL!y~{frb8dl#NEpiJ)7iad@m8(PH3p4?x|-%d5zWr95 z{rZdqX#)sbTEuODXWBnoDA=^8YbJDSV-L>lfASXZ8D5y&t!Z16)p2XHLUQ||$XzhY z(ZNTOhU=WEWxG?AOmpj8K~s1|a(9*t@!RB$%7U*=_M=t5`sWAFyuz~O>Pcjl@Xup- zgO1W}S3KEY&FGc`(1n6n{`G2ikZF>bki9HXRA3j<&l!tlbJ90F>rt$!$g75+5bn&= zjyM80QWmZjI!*;6oH#S|oUcV47FQsDUj%8+H$#7kjT51X^Jtx)%R6|}%#Dzl{ml^0 zsv`Nn-|Bz+48SiLI79mr$g&j&34dbw@n{EdZCF)Q;Eel#;Nmcdr^kRV94rNTeQ>Vz znJP$)fOxR055Bx)K9o5)r}JEv*;cD>C^DQx@@g87^oPS)Thwn;1zXm|@zi=;a?}5h8y* z6>(bt{|;@&f#h3nUIC~HE_8P)0gPfgF)Iz@RlCu`TI%(q~$n4sNz_?{|9BnSz}B&7{#_ zK1qBPIgO|{V&NqKX{rq+Kghb{e3jx$f^oK<{_owdP6x{tVp%vtu+-oKp~{XTyKKwM zX$Z`c@2!q%PLTgNKUeKOH3e?Z#(AjRAjfx2O^o-wLC-f~kXBCsjG2SB4k!3w&_%ssqiht1fi`gwthS zZRJxsc=Hc02T0kCbeye6=v`L}H=CcUFBS95I`opHXTIPR!vcLUKAVpo{skf;5|%cj zKZYwozQ@0;jmm7Ewzi zo<*oL>r^0lz>yz>?Cy#9!RQ(wwu(u2d3jTu6aCREon8S6b$ev_gGij5MEh0OwVHeY z3JMHR>*HK->0zGG9~TkshQO@B>eP?{hJE$f;3N>uRLhJ}P~ZraSC!2Z-m?eb14#V` z%Wf}!yyU^lkZyZXi204#!G+O?Q@ceB{!4N<(Xh3BuOxshEnNU26-F#`#RIs>N}(pBW@Si2rp;jR0tbkkeB?zr zS^vJtRoNXb>y}tW?zt}O@HIPqMztv8X1Mb1o1(k)Qcp6Pr6uU+Wr|!Hv7+$?#M_2O z8ozNt-UfLk4P2gUH6A!~G!t9m9h^|<)O4k5$cNw60eE=UoqqjQ71i%yE>IF5MMw53 zoVZpnlyb}7VoR-eL}JL|uKeGZGj%Bhl-tR>S%pT0QE3%}REJ4vlQXBz;^otxhg?Ch z8XD=ERaU!$Uo=nzVP$E_ymK_%iP6+MG{s;{Y7rF$-fQvmr}-!7R+5kFfp=OE?phks zAIRMnzl_f-n|fdFUx?=;*-?y8#j=PGKPpOOOfX}Ic6w;#a)+T)JYU|+Xv2w$zY|)U zEeeU^HM+hO--oSU>4i-+iF%MO_+IX?wo`R@!WLpS_grU1%73579~%ph(hCzw#gqKS z33(@oiGv3~@~gXqf5#i|_#YMm|B*Feu_oGLserI4H_P&w_AZb(3Isb~x3Ld2CgpT^#omehU$@8! zZ37~|Sa6Xc;y@q!+6z@#hh!4ucXrj8>Qxso@J<)u1I)@I5I^A46Xis^4@P!i0{?O+ zk)CZ~poU|sFD2L)#iE|&ssJ3xPipy!K=bolV9l|2Z(i}*43Z1Wl>m~3P4rKR z;{jYf=VLJmi^x2<{AMKuKw`P)#B;8nQBOIhHy->XNo^z$xthq*cY@X>W!5<4<@4FX zNAk9jj2q$VscrAdjGHmRtbN?guU-Ze<)BHW%*jo5k{5v?@U7yU_yhoD$uz_q-~545jZuxv;JUQ*eFqk?xfP@lh~jP(N?2I0NIZ-q zDGD#GS$Z5%#81&o5Ufv=)9xJ28~UMS`u^V4={bp#DxfwlU7@e?)*KGps|+y(T@tnr z9A#fLvb5wqpXG&eyWHhX@kN1}iO>(98#j(F*qUrT%3$LWY&VnO9gyxolrhty?u8%M zar#N)92>LMOfsB>_D%XweB1a5z8o_t7nV53zGhsGH=Ml{GE->_3^aZ?i1k+KH{Bi* zY{{urjeCUUx{4awMMqbyudOM4lcFe}f0kQxel&TCX;q8#ItaBSss?l>cfYcppL667 zS>TiWKH{ZWLw~L%seSo-t#ZVhl2DGsZb6V3qms|C<$Uq?0!WD znTe>ujm8kZr!xr(ULadh!(KEI*eP2e8ztmktEMSwD&hN43ddd7xbRW-tc40~ z19$nWlggKs>s;Od2Iq;+HaSzqE~nHmhvFSvxIn|naZo8v~4WofUl z>!4oJlcv$-(Hu&G#ZJ_w5Z)n~Rwk6YVkfc4?7^k&H4vyEOMEwEPa;GC(@sG9UK0l< zym3g}=fXdvShWk}JWOfm_hXjhW6NC8L44=y9MCIOFwlD^9541durm zIjxI`e%J5;RSEZ-PK64!Z$8JYxg)OYus$7X)=3YXtpuw8`FEZoHX-T27L3^3mCkP{ z&5K05BG=29L~TDoxs)Ze8YnCtB6r6s5%IM>J{E>lKnexjk zF8wpQnq>*y(C;*VyBSQLL0w@L?tQ?-PuO>uDOcCX?6xMc;$ZyH<_&W`uj1gXTP$N^ zG4Xa31VfrYj;M^;f(-Tw`<_7wa3DmU;dQiQf z7NxutM)uz=k#Ko!M0*iv^qY@@ibmclp2|7Ykd5wdL5{;9N3m~n4g=tUwe;P zI25w!A{9r;$eMW>q{hpo19Bk1pe=P>6r$o%=>7_cjN&Tm5M|IJuUvH+AK${CJX4oU zgO6^=eBKAuGz|tm+nSrK8|c$@b06AJVIe41Kb6p*)`8SjV>XRLlD=n zxmF_SZPNO?HOkAGmreqZP`zhDat0zvL6TUJs#jj+mv!eE2D(4H^wQ8v?J{{F_uNf{ z3Guwlmr_Y+?1xwv+DlCV!Qxf3`85lI9<3MYLPv#eKnDUu^wHQ zc>gm5549XSAWHZ;ccVn65dF5Y_!SFO%Z|}Q(6SZUI=Dtc;z5Ty%nrLYb#L*-Yh(x- zSIj@A+IWZB(0~zQg=&PNK%${P5hZ>29oZHuVGWHXY$x1YFsQbXHgN={wk@*qqJ+Nq zd)egXY~a_ZOiJe;TU+HKlsyJTMfblt8%od5*(H)*Q$D;z+^%AQ4mXPuX2k}%-4;79 zmQ1FAba2Ra`Bcxdj1l&?kFD%K^S3JRgKXK4^qjwecz_P2uJ-l zC)Qvqm+~M!v43_gwKDlR1nJf$++0o6yE@XCdZL3q)UgB#ypJ#vJ8S*1wxK1+=6B}+ zXR*cqf>giPZZtBQvI{Zak5z&s<%W6@C}Kc7|Jd$GBC>hYST1Qs6_hTGb>DuR924B0 zN83(4+CxS$>H&|*-r;Fo4NfL83)iN!YZ&TeJH98$Hv6Ebv4bJ|{_ja0c;iH3BS>3^ zpqgshmx8R31o2gdvH`OqjyW=UU6imxAx*C0^Zy99KL{oAvkpUJI(*CnkaZUKS|miv7yJG9ATWhm{X zmhwPou-YzMm|1!Q!U)jjx%z~gla=8UD)w?G&Zaq~DL{YDwlSN`Dnf>gnqOEH6`e=5 zK`qGvB4v}6phVXVBt;`Goq9`6$1(ekF#8@rQR!O?lVvgou3PA{Mrgg$a_qp=fEaM+ zd)RS3^IyJ;lNL~f*%#*d`QhDdtk^TrNIS|sGACrecpC80;-?Fs23-ZoFWU}~?O7@t zRJMKubhf|4AK65+^Yw8fyef3O1aA8v$s3mu7PHe^U+V4qu@K`r&lUl#^MSr$PX__o zkc4H6xZrmj{B9ymd8uZ1l@104i9rzScjn&(C@ri42@jd|ET?03nMCrOz62_&EiK<& zSBCb#CxX4Kax$9yU;Qik2A;XS4l0o}3esA}H7YGS`LFZ+Cp-+Ao3iV`;Y2#t+RBw4 zx0Nc0Q9y%mXU8X3P%JXaJSA=%)~{Chg+d_{`+@cih8jx$RRzetz1P5XI7rt8+K9*g zkSIZ8rn1WK#9AdD3qWOXE$*F3Ot={(vVp^%iu~vZN~NYgy8_O?l!!1aW}T^|BNP&6 z0?qjrcZN zmjmPbA_FH7lrCAL1d^70)DpX)@;aCfO87MXaxB1q=%jAw{{D`eJ!d-BNT7BMlMWP}{ZZ&o`DY!}ep;HhTV*iZR2Rod;vAPt=MM&iugW*ReqJUt5Qt_q8>ioMMBX>R9!hDFUD-8$eYs z1-TtSGqXUHgLC2i8u*t{Y|w|+jMebIyJ4s^A?cD}pz_yAd)%*nkt{$;7Zl-taBgGY z3@mR5iYU7aF`|s8$6+Otgv24;=D;){kh=%;5zgNp{HcTraHisq6ZRfb zGW_De>QlN^)>%P;wg-4IfgjGe)9@8oA5f2u;i&iuD70ZYZG>GVyG?KsVh7^@q^+_&<9k|1f{n8Ys}&4 zar=)5U>;^OAAH~;qzbCyEiJ*~gbv|vsZP*7fI2Zi@i+OI%Qu*&(tT@erO6Mb(Z$59 zguP#oe4eqid_2;#q}qW|`vO7O$`jJe$IvZwKK6c?Xzh#3XO?(!b^2k4;!# zYGW=JqVe>I?z~`PT4Q2xwFFNu6ey9UCv31nPenw9f8bRc#Vg5bJF+YgK;aIo$ualP wqI_@;Bx5sQADwv9=?)5}0VhV#cC~Kt`tEf9DgFWeNC#x3htMsB-+J`_0Fi|iga7~l literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/home.png b/doc/html/doc/html/images/home.png new file mode 100755 index 0000000000000000000000000000000000000000..5584aacb097a80e66a5320312b6e4eb017af1a06 GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7T3?v)swEqJs=3*z$5DpHG+YkL80J$mwJ|V8+ zB7)tW9nKDRM~@s%h>KBER+u?+=H<(mwr$-K=fo0^iDsNj}a zlvGdz_qOoSb{LwMwNgp7=gl$4aErG%}mjHRWNrKOy`y@b8JoTa6ut*xc4t*y1SwY|N)#>U3Z&d%1> z*52OU=jZ3|@9+2b_y7O@tTMkk%M`~Kg@u8&dg_P^_0l3yQb639!jLZt^Lx<-O17UeeJ z-|=!77W(jGx&e#?FOku-gKofoU0$~4M+dhLFueEauP`}l7LV=;lsOdn%WHure=x;k`m0(bF&MU#) z-qv#^n8(MjB|ykioqII#+`g4no-MU=BK|Sahu_3M_-d*=7hq=~t?^}A)G7 zbairN0An*{V`DL9V>K}|HDobmIW;*pIW=W9HaTQ6F*7kTGI9=S@Bjb+07*qoM6N<$ Ef=i}M4FCWD literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/next.png b/doc/html/doc/html/images/next.png new file mode 100755 index 0000000000000000000000000000000000000000..59800b4e87f60c0e3383ede2b384b9be0f5ffe8d GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7T3?v)swEqJs=3*z$5DpHG+YkL80J$mwJ|V8+ zB7)tW9mdAS+qP~A^!HU$R#>ro>7z#vFJHct5EtX@VE6z3e?1}lM4)<}k|4ieAQuK0 zgzld^2NdTl@Q5sCVBi)4Va7{$>;3=*RZCnWN`mv#O3D+9QW<;`lZ*0mQ&Tb%72Gn5 zQp@v;vWpdbBNU7b3{2X~)|>}w5Cds&E=o--$;{7F2+7P%WiT|*H!#*WFgd=yhZCqG z!qdeuq+(9;4PKV1Hyx6gnJ3)X*T8%1&d~!CcvGht8EkNzY0cztDB;<=un7h&oMQJ5 zOnAh^!sYOgmxqZbU_wKJkwW(@g)2%k8?y8!<$B~f6iH61Ubv5eVdat_!+^S!9H1Qx Mp00i_>zopr0Jz|Gn*aa+ literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/next_disabled.png b/doc/html/doc/html/images/next_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..10a8c59d7b3741260b7bfe918b62d0670cad8433 GIT binary patch literal 1110 zcmY+@U1(Ba7zgmjDRvTtQ&L$$oM7uF2)$_$L2619oS2=UZrYjBy6mRGh`_UtKA{mr z&7hmQ>n7-KH(k`l3W_tgna$01TCHhYnyqEo%+oU}@c)DNeRv<Aw4@Ln z93k3vZsg(J43U|lVL3RF9xoOO*=)8_spRvsnW@QgsZ^`gs@1Bl&*gH{hGA%$HjdJ0 z0!^YRltHf%-=x_aG>vj-2F;>8dW+_ej^3ep^d5ac3+N+SL}4$&L!O*Z;pbcwggWI6Ht znSIeG^MqH2daRdq_j=NKWUEDx?&yZ{K(t0hNp-olr%gM()V(P|g0v^Rdp~d9J+QaF z!E^J*7D+vMK=CJy#-QLKKFMEfm#>;6HRZnKq86dtH6)t7^tAr+x)|r>qo?RMm@+$*>08dLHng9R* literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/note.png b/doc/html/doc/html/images/note.png new file mode 100755 index 0000000000000000000000000000000000000000..d0c3c645ab9af6318035b026dd86944b9ddc9114 GIT binary patch literal 490 zcmeAS@N?(olHy`uVBq!ia0vp^5+KY0Bp8m$B&h%?rX+877Y2q^y~;)m42&$EE{-7; zw^Ao5PC9JB<666~wbh%Oo7tJ0_rGWfi({a(qjR96>_P4H$tJl=Pxd^1p6`8M?=jE( z!hchf6<8Mi`NHe6`iia69>!lxe4C2-S>+Wvj;l63k!MNSb9|1+f-i>irDi|a^uLl% z^#-f2#pQ2lC%m~9m9JWJZL3|T8FRX>A78<>cU{Z6XGFG336=OLGkw25|29|RG_k%U z>j|M}Ih2i#-w+9_3T~N2 zspa`a*~JRJ5eh~I1}5!gYt92Th=DXX7o{eaWaj57gkwm>gfq&(JZLf6ZeXy%aV8%R&r1O{j}20XTDX{IIykaj z4Nx#hVBm6cU}k1+>Qw1kB6gA`rFdeFa~bob(-ZFQzAc!;#K4>y+$E64`2%PJgQu&X J%Q~loCIAR&aHIeL literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/prev_disabled.png b/doc/html/doc/html/images/prev_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..ab3c17e02d156e7494dbab2f9cd66af46af2358c GIT binary patch literal 1109 zcmY+@QAkr^6bJBgcW-U!1{X&)qK7M_5M*o=8THWJ+-L(GYZ=trG_;qf9*iP{hOHkvdvc6%2vA_iD3U9-0yJDcRs#*KhAd};6H4s z+g3+J7N6H0vA^EQ+H!#9vbD6`Ds$w15^-3cW^4D2@1tYP~^k(L0ny@6iX8LwWQOEu&AU zfQo1ZeMa02wZ5RQ=o?x^-x0S~tsm$oT0_531^q^UP!(}k|Km7w>=EA^b6?PZ^nZ>c zHKa9-^N)RQXXnMy?rd*3eEalZV2h}d<7uSYUol!mlhPcO#b+0y%6jsu%~o|iC&Tqk zjZ&+ugrhej$H%%!n2hY4Bw5`RXuNjl<&!a&&LzU`dgFGUS~a!}3S4TRbC4w09~9k9 z);;a{R+T2~>V^|?*&xZWmO@B-pr0ES45n;vpEFE`ily1KnYZ`aRH^GBuiSf29T*)S kmrP2ur(nL^B6b$eQ zaTOO4T)k@LniZub1%Y8f*1x{4x_4{3i<3oNO~t)?cMWybC-tSAKHfEHLVsF{-%ks|7 zjDPxIwu_^_r<>iTb(LLhafxxBUq39{v3=XjnKLh+@6Sy0Xlrc@39wrE41I-`%@*_H`vT)Rk40g{7sX z`FNVTJ6okB1!txP#zY2wc(d5s)2XE)>ihSl4mQR?K~7U9WB`>-?C(j83rmc1F39y? zzq)+;=Gy(c8ka3y($mw@(UR0yUs+Qb`ct-`85ma4B|(0{|49c7L~4o1Q3?TC!&%@F zSTaI#9`SV_9+c( zW;eO@wl|k#YcHt%5b*DNxDw|SUx{9YOXh`gE=j?bXD{#?S~XQQJ?8HZ6@8!dXRi6f zFs(-mE_w-be$Bq$tZlXB;`6;hFXYS9RpKXpuq=q{RQb~W-D%-&g`@1Dljl5NzBeuH zd3B|Jc-c9=PwD+{`aRe5YtcxAH&Vh)Vt}-<~+7jfdx*(to}? W^F^#dfhRDm89ZJ6T-G@yGywo=2(Kal literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/tip.png b/doc/html/doc/html/images/tip.png new file mode 100755 index 0000000000000000000000000000000000000000..5c4aab3bb3543191c360387c4af9a3cbaa051345 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoM0VEi-?r};1DW)WEcNYeRRlUkaK;CUn7srr_ zTcwkB3m#VBagbEhuIO1a$!w|j^feEHv@=+|woj32oF*6|l<3XH$!T}Lao)e6jJhoQ z_vr?OZVprC|7iZ8xaicUR0b&zR-JdP408=+?zC0Rn8IN&QLTWhMIcU0X8P7uUN4WB zR_?a_;&p>ll{>(OzfJ4N{OX={Q&zNgO}j31DC;|ya^r9Fjd348&p+!^cT+^sws+=& zCu*T*mRNK3PE;$BNx$Fa_9(Y=&DoXLMFRd#U31O)<`W^F&-o=xbIqK-c?mr!bmn>! zky6TW;ML~4nXw$T{yra=OteL6G!=B;0=?;6;u=vBoS#-wo>-L1;Gm(b>6x3Dp6Z*J zo|&AjV4`QFXQ5zesc&GRZ(yj9T$EW{Qt6OeSzMBtte0A>mr`1gpI4%noS!>!m*Ngk zP=bxiOwUU!DFvFBnrfM1VQy}0X_lO7WM-b2nq**TZkb|inr2~`WR#dJWc*7VsEZGz hD*$LMgOO>4k%_i}w!yxSoa=!y44$rjF6*2UngF(YpwIvS literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/toc-blank.png b/doc/html/doc/html/images/toc-blank.png new file mode 100755 index 0000000000000000000000000000000000000000..6ffad17a0c7a78deaae58716e8071cc40cb0b8e0 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngf!VDzk7iOmbDT4r?5LY1G0LBeqssYGrXgF}- zKtn^rf1vn(hW}s+NCR0w;4iG^2^42c@^*J&=wOxg0CMC!T^vIyZYBTtzyH6zKuy9A zentg0F+qV0g#~P97#OBpaJrNsxA6f`rE`gEL`iUdT1k0gQ7VIjhO(w-Zen_>Z(@38 za<+nro{^q~f~BRtfrY+-p+a&|W^qZSLvCepNoKNMYO!8QX+eHoiC%Jk?!;Y+JAlS% zfsM;d&r2*R1)7&;o@#7ik&>8{Vv?F>U|?x(ZfKHZYGz`bmXczeoR*Z-Hs=yh7cWRx f0MJ?nL(>XNZ3Ars^Rf>h;}|?${an^LB{Ts5OHX0g literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/toc-minus.png b/doc/html/doc/html/images/toc-minus.png new file mode 100755 index 0000000000000000000000000000000000000000..abbb020c8e2d6705ebc2f0fc17deed30f2977a46 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngf0VEhsJkjh1QcOwS?k)@rt9q4-G!sMP)HD-wQzH`-1CumMgJctv6pLi@6hos# qqtv?{|7HPo@q%;(0Ig*(G_A1IHqbUOFZ%#8j=|H_&t;ucLK6V~f=xvL literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/toc-plus.png b/doc/html/doc/html/images/toc-plus.png new file mode 100755 index 0000000000000000000000000000000000000000..941312ce0dab168e0efcc5b572e387259880e541 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngf0VEhsJkjh1QcOwS?k)@rt9q49T#T`K7w7|w?rspM=lmg95OfodLFfd9rOi4*hH8wIdOfpPPHA_l1 vPBO4aOiebg{S^Z=hXV#3jn*#4_ x=vj5p^wF)?xpx*Du6ddKc=uuXxWffq{6A*KyDFWJxdXJF!PC{xWt~$(69DY=mmvTE literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/up_disabled.png b/doc/html/doc/html/images/up_disabled.png new file mode 100755 index 0000000000000000000000000000000000000000..e22bc8712192df3a8faa3264b0ec71ff3aaaa96c GIT binary patch literal 1115 zcmY+@Z)^*37zgl2dzmw~oK$GMafp#cWXs;jyt!6uYtl7UeZec8`SV6X{7De9Dw2(4 zm>26}32(gcW*OddFPdfV_NT?wYHgXdTAfl#H+r5D$$dY`-IIHMf0Ezb_xin_j)wY; z^+eR*>U8+HT56YQ=DTxXyvjv5Ve7IHJsG&Xy#F3Q%RQaGE}~1@h=SLMDmvFJ(fJml zT!5&3h-ky9p~u59A~Sj2e&_VmWGa=4$F*XyxL7D;GnsO^oJh>ZqBHq?zEmnDlXI0y zMc4I7gDEtPW>6Hx&`b0Ry+#^}qc><4CD2?%a47s&%&rYXwnm@^2oK6>2RiC(}ybQxc@;;j!lN7xJKGXK5u*58HCq zi)yn~zbYIeQ(ynxTdSHPs@k~jXquO=uiH1eY2@@XO+VY(#*4k%x7x*t?&AUCt?S$* rDO!X~;(e<^-4?Sb9}HJ}I(CrQLYik+oARjr0iT6jPLE^M9tiybIrJyp literal 0 HcmV?d00001 diff --git a/doc/html/doc/html/images/warning.png b/doc/html/doc/html/images/warning.png new file mode 100755 index 0000000000000000000000000000000000000000..1c33db8f34a8b42b373179b46a2d8d8a10e061a9 GIT binary patch literal 1241 zcmeHH+e?!H6#vDtmgHCxG{Q}12(7`~)|MMe^RnTlY0JD#q1sIwW1DTCqzzwWg@Q=t zBC2Iceu@w4LHM97Gb5%*E%9MN*%m}jvs!{N@Pd8$H}vS?TsRzlzr#5kPPe|YG%fXL zDu6VdR$WC$&Oc)^X#ZjK-7LU>{!F!o39xr+d_Vw5fMTEwpb-s#9q<5Nzz6gIepyU?Lctpr{ZK zVzWaWPAC)#17S8h%;AIuf(Q_yeIybEqS0s^i1YdJcsv0ln9M{Xkpz;-I_^=P))~D~!!Hvpq{Dl8O{rN@cECkt>#DncX%I(O&3i_YgL-$m$VU zT3cLBLS%M1`o{TBX}S|Tbhc)vk!Yp)%rdDd&my(RPsxl%lU$)tC?(1~WuEwClUQn! n$Q8O{Mxt@ukkcT{K0> literal 0 HcmV?d00001 diff --git a/doc/html/doc/src/images/callouts/1.png b/doc/html/doc/src/images/callouts/1.png new file mode 100755 index 0000000000000000000000000000000000000000..6003ad3af44ecde89a963d5af6a4180217319dfb GIT binary patch literal 391 zcmV;20eJq2P)b;@5Jms&t_+qirbvUVh|&#BatJPvqeMAG3eJI2P~{ToLa~KgB*G#^M#2_a3)VYn zVgvz1M%rd}-qW9r=_zaNV-N&yold8HOHftSx7PZF znWv3J5s?VPuss+I+C&6q#(KSmloGvO?*KD1ilVq*tyW{LH5!R%28alCU1K(zVKSM( zIR_#-JRt<)I7YwUPn1$)t@RT#D|H;v7=y)Pfubl7MbX&`M1*d)3jm2RW~{Zwi6BW5 z + + + +]> + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/10.png b/doc/html/doc/src/images/callouts/10.png new file mode 100755 index 0000000000000000000000000000000000000000..0426f516a497db7f9a989ae412c381123c882a59 GIT binary patch literal 485 zcmVye?*7-J8XwLb#oWGHAsf2pa!fFY62Q0 z;mh~sbZC{ErT1M9yl|fLa(G!7hF#A2`>Lu`ydhOplks@`lQAalo|fnN2VK{{wcG9H zTY#b{eg{GDnTTHQ5REaWv|6p^U@&Mh#y~_!(-f+z!m=!!&u45l8;nLH*tY%dbUHl; zL4Z3%xzibAkW#|;eavPv2qBOp2^Nb5%CdaSUa#k9n)Vz7!4nZ_%Ik=69OG~};Cj8n zFbsrYh;Fxw$z*~~r-Su+4bwDh5bZUt3;;luWw0y@oOA5=dklv|0Duqzx7$qs_)$wxRTZ)pymR;BV1>g5SZnxW9 zN=Z^m;+&I|lB%jADJ2y}K}Asz=bWM_DwoUU*VSs}Jc>j_Ri5WX6h;3nk(9E^^Zfhc b@<06n&dl<{Ml4d|00000NkvXXu0mjfA|==h literal 0 HcmV?d00001 diff --git a/doc/html/doc/src/images/callouts/10.svg b/doc/html/doc/src/images/callouts/10.svg new file mode 100755 index 00000000..4740f587 --- /dev/null +++ b/doc/html/doc/src/images/callouts/10.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/11.png b/doc/html/doc/src/images/callouts/11.png new file mode 100755 index 0000000000000000000000000000000000000000..821afc4fa84787cc97485b71e9f2078f45c93dca GIT binary patch literal 410 zcmV;L0cHM)P)M+td|6n+lpimUPx=_1S)c4H7YUPG|K7G}+Q zXD3BY$LW0J{_Y!?Z)RXbkxz7K`tz)v9=YBoPVL+Dl#6|9v864%XTq&y%0>7v#V81+C6pQ~&?~07*qoM6N<$ Ef)+u)Bme*a literal 0 HcmV?d00001 diff --git a/doc/html/doc/src/images/callouts/11.svg b/doc/html/doc/src/images/callouts/11.svg new file mode 100755 index 00000000..09a0b2cf --- /dev/null +++ b/doc/html/doc/src/images/callouts/11.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/12.png b/doc/html/doc/src/images/callouts/12.png new file mode 100755 index 0000000000000000000000000000000000000000..7cec72720fa9bb6f49fc4b405f7e36f20abe7fbd GIT binary patch literal 488 zcmVP)PuxtyZYjYA&U;&lvlvl%n)GViZMKE|)kS zkFYEYm&*m+ZWonG1>^A;S(d@JZ2)kiDC#rD@FH+s7fF(UQVPQ`V4DBV62~#pG)1S= z0U-poZG&^}uGi}y+Ot5@G-O!@%d((p+5?_Wr)am^s8*{00M0p1rxOP-eGy10k!2Yi z#{mFrHXDpaBeYsAl*?rR!0mQJ6h-`SIJ_4Mg>Nq_2qB=9g75nfLSQ%?Vm_ZEj$&j0IHOdd7hsai^YGRNC+YG eJpcU+1HfO$s^?_o4trMs0000 + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/13.png b/doc/html/doc/src/images/callouts/13.png new file mode 100755 index 0000000000000000000000000000000000000000..5b41e02a670f020ae62b7854482c4ba1980d73cf GIT binary patch literal 509 zcmV4)gxr*N=Me5VesZgwj%cYwtNqcZr1 zC_xao_jajoUYEXSJjwZ;bCQPyLGYn0%a1|`74MX)s;6GB_lFQtKYCi8=bv<4|7n`0 z@g7hV#ep&QO-lLlKr}*#(rh-3ZntX?LLjBY`Fw_|s<3Sv$Kw%U7{anFbUK~R;cyr; z#_&LthfW9q=N!K8V>+Fpu4^Pog5`1vAq0XTz;3rgtJQKfO&c@DzDOxG?d^$i9AmrP z;(EQpvMk*1cl7&xn5K!vVgUf4lmdVo$MKjkh9|&vU7SuQXqpCH*I^h2Hk%D*vl$%6 z!C)`|Aq13C)OGFd_xtb4TR>41q-hGvvY;pmIOk}$+Zc^TNRk9X2mnA`*T}N02Jrg{ z5JDhLQ`okRs;V%b&yi&rvMd9o6pEstsw%{BTwgAimqw%U_2~u9Ii!^EJP)d>!f_l- zCKFIfF&qv-2zeUzJZ}fz_dl=K>zs2gIp?x0OUXHxLI_z^mAu_ + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/14.png b/doc/html/doc/src/images/callouts/14.png new file mode 100755 index 0000000000000000000000000000000000000000..de5bdbd3eb8be01d27b6f1a345d586d0c4d61b2a GIT binary patch literal 499 zcmVt^dUO<1U`T*_)UESUECTZgDyfaHIPO@ zV~8gA-qWSZ=hE+t2hQ)D1An$&uiuqr`9UeA;f>NX?a=G>elfjW3O+&NU1ON~b(liBt_qW?^90URG z2*2x$F-R%l`#z@ADTEMUjDazRG)*y?Ot9PS&~CR~UDwA!5PT*gU4MOI9LI>F2*8=YK-YB`hJhqWuv{)N7z~gk2^_}( zV+^)!LkQvS_xo@BHNZJXmSwOk3sOqVW;0Y(g~eil%jJSR&jA2J2;_M#04$#Xr4+I( zgX1{RG!4Vy5Uo}VQ52!m>40;Ns;Usju{fPhFQ#dJd3r%g2_k~$dElI*-|wTUD&%>N z(P#wD`O~oHdB5TN{-^DBTSzHMN=ao|l9ZB^Qlyl6^vbfNFbu2JYW01y*|?7&5s@m2 p;u?nGe?ugtR7Fwzd~E(#e*x=4{y$G>PWJ!+002ovPDHLkV1hgS;QRmp literal 0 HcmV?d00001 diff --git a/doc/html/doc/src/images/callouts/14.svg b/doc/html/doc/src/images/callouts/14.svg new file mode 100755 index 00000000..469aa974 --- /dev/null +++ b/doc/html/doc/src/images/callouts/14.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/15.png b/doc/html/doc/src/images/callouts/15.png new file mode 100755 index 0000000000000000000000000000000000000000..3fd6ac38603390bf6f9bbfdb85ddb203e2edc421 GIT binary patch literal 507 zcmVBYKkWd<`JW7;@NWpWE6kA22-~|X(5OQHtARz%p zgo})YY|I%?ny^`#?35$THzUn2T-SYK6o$hgE|&|GQZNhy)oRs}QuZCk`NYgpzCO|SeXLe1 zoX=5sUIS^G zA`C+qh5;hNcs#~#x5IY3#p!fHqtU?ac7yNxDhPt-d_MpA;Q}H8Go#sTBAd;k)9GL| z8UX;h-7cPGb1bv51I>iHMUVVItx*O__)|j$@AFn3E*o<#KtO&1T;` x&$C{F#LQ_FMe%aE{BMYeD2<}%$IIrw^#|YO0JIScbaVg!002ovPDHLkV1ffM + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/16.svg b/doc/html/doc/src/images/callouts/16.svg new file mode 100755 index 00000000..01d6bf81 --- /dev/null +++ b/doc/html/doc/src/images/callouts/16.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/17.svg b/doc/html/doc/src/images/callouts/17.svg new file mode 100755 index 00000000..0a04c556 --- /dev/null +++ b/doc/html/doc/src/images/callouts/17.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/18.svg b/doc/html/doc/src/images/callouts/18.svg new file mode 100755 index 00000000..1cb891b3 --- /dev/null +++ b/doc/html/doc/src/images/callouts/18.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/19.svg b/doc/html/doc/src/images/callouts/19.svg new file mode 100755 index 00000000..e6fbb179 --- /dev/null +++ b/doc/html/doc/src/images/callouts/19.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/2.png b/doc/html/doc/src/images/callouts/2.png new file mode 100755 index 0000000000000000000000000000000000000000..f7c1578846cd7e67f148e7bbe3178ec170050e48 GIT binary patch literal 446 zcmV;v0YUzWP)g%HYe&5tuzq8hs@J33d((l1w@Pmj<(Q}ki?_Jk@sMTtf zw*YCH{*qFDX6DBN;t-LjR;!hMzhBAo9NX;{Ns_?#eKea*5D@@?nUN$(_k2Fjq?9Ni zqM$P~*6TG+rxT1Zn9t`h#(;=GL=Zxt(P*I6YIPjPnMo->GPC16S8TW27>~!$T4T4{ z!CL#`3q*u^y$%4KIF4shO56>E5a@Qh0DvF}FdB{Ey6&qx6cEqzI?Vj#g@G{!tJMlb zgvn$AA;c>{@$P!P8UWwL^X787M4F};4u}67&aw<~9GlDK@>njHKiv(YD8gc~faiG# z!w}Qy6un;Wzr()o|3nZ39}b6u(pvNFcDq-WWo)gzm)4q($78nHY`%tJ*eRe6Gh3xp o8b#4xm5bzgZk1Bs?wkMQ38E9=PG^kAEC2ui07*qoM6N<$g4YPrD*ylh literal 0 HcmV?d00001 diff --git a/doc/html/doc/src/images/callouts/2.svg b/doc/html/doc/src/images/callouts/2.svg new file mode 100755 index 00000000..07d03395 --- /dev/null +++ b/doc/html/doc/src/images/callouts/2.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/20.svg b/doc/html/doc/src/images/callouts/20.svg new file mode 100755 index 00000000..ccbfd403 --- /dev/null +++ b/doc/html/doc/src/images/callouts/20.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/21.svg b/doc/html/doc/src/images/callouts/21.svg new file mode 100755 index 00000000..93ec53fd --- /dev/null +++ b/doc/html/doc/src/images/callouts/21.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/22.svg b/doc/html/doc/src/images/callouts/22.svg new file mode 100755 index 00000000..f48c5f3f --- /dev/null +++ b/doc/html/doc/src/images/callouts/22.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/23.svg b/doc/html/doc/src/images/callouts/23.svg new file mode 100755 index 00000000..66242129 --- /dev/null +++ b/doc/html/doc/src/images/callouts/23.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/24.svg b/doc/html/doc/src/images/callouts/24.svg new file mode 100755 index 00000000..a3d55253 --- /dev/null +++ b/doc/html/doc/src/images/callouts/24.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/25.svg b/doc/html/doc/src/images/callouts/25.svg new file mode 100755 index 00000000..56614a97 --- /dev/null +++ b/doc/html/doc/src/images/callouts/25.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/26.svg b/doc/html/doc/src/images/callouts/26.svg new file mode 100755 index 00000000..56faeaca --- /dev/null +++ b/doc/html/doc/src/images/callouts/26.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/27.svg b/doc/html/doc/src/images/callouts/27.svg new file mode 100755 index 00000000..a75c8121 --- /dev/null +++ b/doc/html/doc/src/images/callouts/27.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/28.svg b/doc/html/doc/src/images/callouts/28.svg new file mode 100755 index 00000000..7f8cf1a3 --- /dev/null +++ b/doc/html/doc/src/images/callouts/28.svg @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/29.svg b/doc/html/doc/src/images/callouts/29.svg new file mode 100755 index 00000000..cb63adf1 --- /dev/null +++ b/doc/html/doc/src/images/callouts/29.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/3.png b/doc/html/doc/src/images/callouts/3.png new file mode 100755 index 0000000000000000000000000000000000000000..3ff0a93931515bb97a045dfa61a8530d87e458fd GIT binary patch literal 431 zcmV;g0Z{&lP)?w-3fw;Fb-ls zDri;RUK#8kv6dIk;e17_)v9tnpMMx*Y&>|jZU1k#+kc5jU2l$*@~7*%uccC{@JNuR z=|3UFGc%8`5{HPaVzF3gG#Ul1H5Q8nk|aSGhNx63AR+(&Gb2for`>Kh6hh!Cv95Mz z#%wl26h%- + + + +]> + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/30.svg b/doc/html/doc/src/images/callouts/30.svg new file mode 100755 index 00000000..dc43ba1e --- /dev/null +++ b/doc/html/doc/src/images/callouts/30.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/4.png b/doc/html/doc/src/images/callouts/4.png new file mode 100755 index 0000000000000000000000000000000000000000..6aa29fc0b48c17aa6ce5540e1af5c00510c33ff7 GIT binary patch literal 441 zcmV;q0Y?6bP)1BH{J6*Ukh&=Hmk zRECzB?yd`#@n#QU|E!Aozxu0ay*5o+uKTCg>-{Doo%e)N>T9`N{#mQl zDxU$a*Xx^<@&_}&`kN4wpI>%IqLW}MIG_VIWeN-2>; zoSaTXAR-uJFqup+8jWC#x%C~#L8H+?tJU&_5JM^DcV-r%7*T7D*=&aGc8h+$k5Z}h z;RGT=y2!)DNiZId zk)|oEwRfMXwMLR88o;j`!1sL&1_N9!7XU!B*}QAcvJ7z?>(lA<;(6X97K_EV-EOC> zwam=CTrN2bL%ydpO*x99EDXcv&1T~R`1b>51^@&>@S!foE^ZEjU=IL-nXOXl8b#6F j$hnL$Rw?ybGy}k2rA_2 + + + +]> + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/5.png b/doc/html/doc/src/images/callouts/5.png new file mode 100755 index 0000000000000000000000000000000000000000..36e785867ad9b06bb5da296fee61b67cd8159ded GIT binary patch literal 423 zcmV;Y0a*TtP)s#AqNWNL+{%m!bruZt@^q`VMYNAEFDN!c`Zp`V!qpMaG}43yDw*Mu`(* zCbz2uThU&a&4u&vojYu`S~+nXKc;Ca@XrV#zFpV-WQ--*&QMDAOw)X`ZM*azAc~?d zDdh_hjWdYB7~_^@m72|FNo$S8VuAgBk7~7wPNxITIRJo&a5x+uw%hGcN{I}@Gdg1o z%jFWY*$iQ?@7|P`` z05p8xA4(~a8)&V;ImciyK)>J5O>RMIwOWISUUP#W2;jOd9LK@wbh>-YBuNm4VFKVI zH`r`8m`o-J!w}Qy6y0tYrfFV<&*w9I-%o-d7#EAh=N!;(w_)2hMxzmk2%hKVKX5DD zYPB|b1tA1H&qJ@*L!nTB5CTN>OZ#sa01P5Zl~U1qy}sL9Yn>{k-Y>%d@B>ihzNus- RRfYfn002ovPDHLkV1oUuv|0cF literal 0 HcmV?d00001 diff --git a/doc/html/doc/src/images/callouts/5.svg b/doc/html/doc/src/images/callouts/5.svg new file mode 100755 index 00000000..ca7a9f22 --- /dev/null +++ b/doc/html/doc/src/images/callouts/5.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/6.png b/doc/html/doc/src/images/callouts/6.png new file mode 100755 index 0000000000000000000000000000000000000000..c943676beafa0562916b058c169951febcd3cddb GIT binary patch literal 431 zcmV;g0Z{&lP)2x}6wAN@OL1SlT zq-l!d@d)P}cDo(C_aGt=5rQCqQVQeoIFeFswANpkS;|ImKA(}MDdzJz27>|OIED~! zYat?pVF&fG5i@@eULRJg71rxDq9{V1 z=O32ooI_Pr4#2O6Kq&=lEvl+QS(Z>r{TII9@5r*u<$32$t61k>phVHje&-69M_ zOeT}3aFQf{9wiDPuv{*&SS-+LwIGB5Grx)b9tHr(%(b=ldN>?D{22he_qDb5=W7@M Z{sBv`yEO&CdT0Ou002ovPDHLkV1o2ux|09^ literal 0 HcmV?d00001 diff --git a/doc/html/doc/src/images/callouts/6.svg b/doc/html/doc/src/images/callouts/6.svg new file mode 100755 index 00000000..783a0b9d --- /dev/null +++ b/doc/html/doc/src/images/callouts/6.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/7.png b/doc/html/doc/src/images/callouts/7.png new file mode 100755 index 0000000000000000000000000000000000000000..20940de30d2146b73118a08905955162fe985f68 GIT binary patch literal 397 zcmV;80doF{P)^QMQBulp-}gU=C{Aa}81s!lqHiS0W-t%ynn-<=Y3{Rlv1MG?LtZkX1=)gZx{d+ rGh1U!IGfG>ygNw}Ym9k2g#q9P_H(VTcF&$q00000NkvXXu0mjfg$Ay% literal 0 HcmV?d00001 diff --git a/doc/html/doc/src/images/callouts/7.svg b/doc/html/doc/src/images/callouts/7.svg new file mode 100755 index 00000000..59b3714b --- /dev/null +++ b/doc/html/doc/src/images/callouts/7.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/8.png b/doc/html/doc/src/images/callouts/8.png new file mode 100755 index 0000000000000000000000000000000000000000..d8e34d4a09f6dca4f9c22e626d9f9d82b969b02c GIT binary patch literal 434 zcmV;j0ZsmiP)2AuM{XfkN9S(EO_B7zVCVHjdQpD(18TdnnH=bV%s&@>J9`#qv4f)D~(mcd&4 zVg({X5Cj0QD2igMwT8TJhGB>}jsXCZ$prGB|9~*_BG2=u+m9^EFdmPw*=$hPHR3o1 zGrx*3Gped$06%UwxLhvqeIG=Gs;UqK0fZ0_;ihR&6a}Bp=jXv-@a4uUrH~{E(lkXF zhFGuH@I3F$uu|&R4VX@+h@uGAS_mP~@Au)HdolL^VE~ZMIcto$9*@U|aqp{bTWgH@ cejf&azhINZs#OUR!~g&Q07*qoM6N<$f@$x%rT_o{ literal 0 HcmV?d00001 diff --git a/doc/html/doc/src/images/callouts/8.svg b/doc/html/doc/src/images/callouts/8.svg new file mode 100755 index 00000000..c1803a3c --- /dev/null +++ b/doc/html/doc/src/images/callouts/8.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/doc/src/images/callouts/9.png b/doc/html/doc/src/images/callouts/9.png new file mode 100755 index 0000000000000000000000000000000000000000..abe636072b61306fbcd6157b95dfdf7e86a77e5d GIT binary patch literal 420 zcmV;V0bBlwP)J?lRHzhELZiNz|1T-iU zCV!@@1hs;1In4LXdqeB>`avo6nCH2PJ26c& + + + +]> + + + + + + + + diff --git a/doc/html/example/Crowl2006/README.txt b/doc/html/example/Crowl2006/README.txt new file mode 100755 index 00000000..2aafb1bc --- /dev/null +++ b/doc/html/example/Crowl2006/README.txt @@ -0,0 +1,2 @@ +Examples taken from Crowl, Ottosen, "Proposal to add Contract +Programming to C++", 2006. diff --git a/doc/html/example/Crowl2006/block/main.cpp b/doc/html/example/Crowl2006/block/main.cpp new file mode 100755 index 00000000..a55d9bd4 --- /dev/null +++ b/doc/html/example/Crowl2006/block/main.cpp @@ -0,0 +1,21 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Block invariant example. + +#include +#include + +int main() { + for (int i = 0; i < 100; ++i) { + // Invariant will intentionally fail. + CONTRACT_ASSERT_BLOCK_INVARIANT( i < 10 ); + + std::cout << i << std::endl; + } + + return 0; +} + diff --git a/doc/html/example/Crowl2006/circle/main.cpp b/doc/html/example/Crowl2006/circle/main.cpp new file mode 100755 index 00000000..094312d5 --- /dev/null +++ b/doc/html/example/Crowl2006/circle/main.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Subcontracting (from pure virtual) example. + +#include +#include + +class shape { + + CONTRACT_INVARIANT( ({}) ) // Specify invariants even if `{}`. + +public: + virtual ~shape(void) {} + + virtual int compute_area(void) const + CONTRACT_FUNCTION( (class) (shape) + (public) (virtual) (int) (compute_area)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result > 0 ); + }) + (body) ( + = 0; // Contract for pure virtual function. + ) ) +}; + +class circle: public shape { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Hard-coded radius for simplicity of this example. + int radius(void) const { return 2; } + + virtual int compute_area(void) const + CONTRACT_FUNCTION( (class) (circle) + (inherit)(shape) // Subcontracting. + (public) (virtual) (int) (compute_area)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == PI * radius() * radius() ); + }) + (body) ({ + return PI * radius() * radius(); + }) ) + +private: + static const int PI = 3; // Truncated int of 3.14... +}; + +int main() { + circle c; + + std::cout << std::endl << "compute_area()" << std::endl; + std::cout << c.compute_area() << std::endl; + + return 0; +} + diff --git a/doc/html/example/Crowl2006/factorial/main.cpp b/doc/html/example/Crowl2006/factorial/main.cpp new file mode 100755 index 00000000..7e76e021 --- /dev/null +++ b/doc/html/example/Crowl2006/factorial/main.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include +#include + +// Recursion example. +int factorial(int n) +CONTRACT_FUNCTION( + (int) (factorial)( (int)(n) ) +(precondition) ({ + CONTRACT_ASSERT( n >= 0 ); + CONTRACT_ASSERT( n <= 12 ); +}) +(postcondition) (result) ({ + CONTRACT_ASSERT( result >= 1 ); + + // Assertions disabled within assertions so factorial() can be + // recursively called also from the contract (not just the body). + // (Of course, this adds a lot of overhead...) + if (n < 2) { CONTRACT_ASSERT( result == 1 ); } + else { CONTRACT_ASSERT( result == n * factorial(n - 1) ); } +}) +(body) ({ + if (n < 2) return 1; + else return n * factorial(n - 1); +}) ) + +int main() { + std::cout << factorial(4) << std::endl; + return 0; +} + diff --git a/doc/html/example/Crowl2006/operator_equal/equal.hpp b/doc/html/example/Crowl2006/operator_equal/equal.hpp new file mode 100755 index 00000000..d0090aec --- /dev/null +++ b/doc/html/example/Crowl2006/operator_equal/equal.hpp @@ -0,0 +1,27 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef EQUAL_HPP_ +#define EQUAL_HPP_ + +#include "not_equal.hpp" +#include +#include + +template +bool operator==(T l, T r) +CONTRACT_FUNCTION( + (template)( (typename)(T) ) + (bool) (operator(==, equal)) ( (T)(l) (T)(r) ) +(postcondition) (result) ({ + CONTRACT_ASSERT( result == !(l != r) ); +}) +(body) ({ + std::clog << "checking for equality" << std::endl; + return l.value == r.value; +}) ) + +#endif // #include guard + diff --git a/doc/html/example/Crowl2006/operator_equal/main.cpp b/doc/html/example/Crowl2006/operator_equal/main.cpp new file mode 100755 index 00000000..5df0a3ca --- /dev/null +++ b/doc/html/example/Crowl2006/operator_equal/main.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Recursion example (works thanks to "assertions disabled within +// assertions" policy). + +#include "equal.hpp" +#include "not_equal.hpp" +#include + +struct number { double value; }; + +int main() { + number n; + n.value = 1.23; + + std::cout << (n == n) << std::endl; + std::cout << (n != n) << std::endl; + + return 0; +} + diff --git a/doc/html/example/Crowl2006/operator_equal/not_equal.hpp b/doc/html/example/Crowl2006/operator_equal/not_equal.hpp new file mode 100755 index 00000000..71bc79ea --- /dev/null +++ b/doc/html/example/Crowl2006/operator_equal/not_equal.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef NOT_EQUAL_HPP_ +#define NOT_EQUAL_HPP_ + +#include "equal.hpp" +#include + +template +bool operator!=(T l, T r) +CONTRACT_FUNCTION( + (template)( (typename)(T) ) + (bool) (operator(!=, not_equal))( (T)(l) (T)(r) ) +(postcondition) (result) ({ + CONTRACT_ASSERT( result == !(l == r) ); +}) +(body) ({ + std::clog << "checking for inequality" << std::endl; + return l.value != r.value; +}) ) + +#endif // #include guard + diff --git a/doc/html/example/Crowl2006/sqrt/main.cpp b/doc/html/example/Crowl2006/sqrt/main.cpp new file mode 100755 index 00000000..591c1278 --- /dev/null +++ b/doc/html/example/Crowl2006/sqrt/main.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include +#include +#include + +bool equal_within_precision(const double& x, const double& y, + const double& precision = 1e-6) { + return fabs(x - y) <= precision; +} + +// Non-member function example. +double mysqrt(double x) +CONTRACT_FUNCTION( + (double) (mysqrt)( (double)(x) ) +(precondition) ({ + CONTRACT_ASSERT( x >= 0.0 ); +}) +(postcondition) (root) ({ + CONTRACT_ASSERT( equal_within_precision(root * root, x) ); +}) +(body) ({ + return sqrt(x); +}) ) + +int main() { + std::cout << mysqrt(4.0) << std::endl; + std::cout << std::endl; + std::cout << mysqrt(-1.0) << std::endl; + return 0; +} + diff --git a/doc/html/example/Crowl2006/sum/main.cpp b/doc/html/example/Crowl2006/sum/main.cpp new file mode 100755 index 00000000..f7e2b0d1 --- /dev/null +++ b/doc/html/example/Crowl2006/sum/main.cpp @@ -0,0 +1,16 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "sum.hpp" +#include + +int main() { + double a[8] = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1}; + + std::cout << sum(8, a) << std::endl; + + return 0; +} + diff --git a/doc/html/example/Crowl2006/sum/sum.cpp b/doc/html/example/Crowl2006/sum/sum.cpp new file mode 100755 index 00000000..99f7f800 --- /dev/null +++ b/doc/html/example/Crowl2006/sum/sum.cpp @@ -0,0 +1,13 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "sum.hpp" + +double CONTRACT_BODY(sum)(int count, double* array) { + double accum = 0.0; + for (int i = 0; i < count; ++i) accum += array[i]; + return accum; +} + diff --git a/doc/html/example/Crowl2006/sum/sum.hpp b/doc/html/example/Crowl2006/sum/sum.hpp new file mode 100755 index 00000000..4417afa7 --- /dev/null +++ b/doc/html/example/Crowl2006/sum/sum.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Non-member function with separate definition. + +#ifndef SUM_HPP_ +#define SUM_HPP_ + +#include + +double sum(int count, double* array) +CONTRACT_FUNCTION( (double) (sum)( (int)(count) (double*)(array) ) +(precondition) ({ + CONTRACT_ASSERT( count % 4 == 0 ); +}) +(body) ( + ; +) ) + +#endif // #include guard + diff --git a/doc/html/example/Crowl2006/vector/main.cpp b/doc/html/example/Crowl2006/vector/main.cpp new file mode 100755 index 00000000..e13c7f55 --- /dev/null +++ b/doc/html/example/Crowl2006/vector/main.cpp @@ -0,0 +1,617 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Add complete contracts to STL C++ vector. + +#include +#include // For boost::prior(). +#include + +// Tools to write the contracts (for convenience). + +template +bool all_equals(Iter first, Iter last, const T& val) +CONTRACT_FUNCTION( + (template)( (class)(Iter) (class)(T) ) + (bool) (all_equals)( + (Iter)(first) (Iter)(last) (const T&)(val) ) +(body) ({ + // For simplicity, let's assume T can be compared. + for (Iter i = first; i < last; ++i) { + if (*i != val) return false; + } + return true; +}) ) + +template +bool equal_distance(Iter first, Iter last, Size size) +CONTRACT_FUNCTION( + (template)( (class)(Iter) (class)(Size) ) + (bool) (equal_distance)( + (Iter)(first) (Iter)(last) (Size)(size) ) +(body) ({ + // Could implement internal tagging to support input iterators. + return int(size) == std::distance(first, last); +}) ) + +// New vector interface. + +template > +class vector { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( (size() == 0) == empty() ); + CONTRACT_ASSERT( int(size()) == std::distance(begin(), end()) ); + CONTRACT_ASSERT( int(size()) == std::distance(rbegin(), rend()) ); + CONTRACT_ASSERT( size() <= capacity() ); + CONTRACT_ASSERT( capacity() <= max_size() ); + }) ) + +public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator + const_iterator; + typedef typename std::vector::reverse_iterator + reverse_iterator; + typedef typename std::vector::const_reverse_iterator + const_reverse_iterator; + typedef typename std::vector::reference reference; + typedef typename std::vector::const_reference + const_reference; + + vector(void): vector_() + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( empty() ); + }) + (body) ({ + }) ) + + explicit vector(const Alloc& al): vector_(al) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (const Alloc&)(al) ) + (postcondition) ({ + CONTRACT_ASSERT( empty() ); + CONTRACT_ASSERT( al == get_allocator() ); + }) + (body) ({ + }) ) + + explicit vector(size_type count): vector_(count) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (size_type)(count) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == count ); + CONTRACT_ASSERT( all_equals(begin(), end(), T()) ); + }) + (body) ({ + }) ) + + vector(size_type count, const T& val): vector_(count, val) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (size_type)(count) (const T&)(val) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == count ); + CONTRACT_ASSERT( all_equals(begin(), end(), val) ); + }) + (body) ({ + }) ) + + vector(size_type count, const T& val, const Alloc& al): + vector_(count, val, al) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (size_type)(count) (const T&)(val) + (const Alloc&)(al) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == count ); + CONTRACT_ASSERT( all_equals(begin(), end(), val) ); + CONTRACT_ASSERT( al == get_allocator() ); + }) + (body) ({ + }) ) + + vector(const vector& right): vector_(right.vector_) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (const vector&)(right) ) + (postcondition) ({ + CONTRACT_ASSERT( right == *this ); + }) + (body) ({ + }) ) + + template + vector(InIt first, InIt last): vector_(first, last) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (template)( (class)(InIt) ) + (vector)( (InIt)(first) (InIt)(last) ) + (postcondition) ({ + CONTRACT_ASSERT( equal_distance(first, last, size()) ); + }) + (body) ({ + }) ) + + template + vector(InIt first, InIt last, const Alloc& al): + vector_(first, last, al) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (template)( (class)(InIt) ) + (vector)( (InIt)(first) (InIt)(last) (const Alloc&)(al) ) + (postcondition) ({ + CONTRACT_ASSERT( equal_distance(first, last, size()) ); + CONTRACT_ASSERT( al == get_allocator() ); + }) + (body) ({ + }) ) + + ~vector(void) // Contracted so destructor checks invariants. + CONTRACT_DESTRUCTOR( (class) (vector) + (public) (vector)( (void) ) + (body) ({ + }) ) + + void reserve(size_type count) + CONTRACT_FUNCTION( (class) (vector) + (public) (void) (reserve)( (size_type)(count) ) + (precondition) ({ + CONTRACT_ASSERT( count < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( capacity() >= count ); + }) + (body) ({ + vector_.reserve(count); + }) ) + + size_type capacity(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (size_type) (capacity)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result >= size() ); + }) + (body) ({ + return vector_.capacity(); + }) ) + + iterator begin(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (iterator) (begin)( (void) ) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ({ + return vector_.begin(); + }) ) + + const_iterator begin(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_iterator) (begin)( (void) ) (const) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ({ + return vector_.begin(); + }) ) + + iterator end(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (iterator) (end)( (void) ) + // Contracted even if no pre/post condition so check invariants. + (body) ({ + return vector_.end(); + }) ) + + const_iterator end(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_iterator) (end)( (void) ) (const) + (body) ({ + return vector_.end(); + }) ) + + reverse_iterator rbegin(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (reverse_iterator) (rbegin)( (void) ) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == rend() ); + }) + (body) ({ + return vector_.rbegin(); + }) ) + + const_reverse_iterator rbegin(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reverse_iterator) (rbegin)( (void) ) (const) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == rend() ); + }) + (body) ({ + return vector_.rbegin(); + }) ) + + reverse_iterator rend(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (reverse_iterator) (rend)( (void) ) + (body) ({ + return vector_.rend(); + }) ) + + const_reverse_iterator rend(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reverse_iterator) (rend)( (void) ) (const) + (body) ({ + return vector_.rend(); + }) ) + + void resize(size_type newsize) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (resize)( (size_type)(newsize) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == newsize ); + // Version 1: with an if. + if (newsize > CONTRACT_OLDOF(this)->size()) CONTRACT_ASSERT( + all_equals(begin() + CONTRACT_OLDOF(this)->size(), + end(), T()) ); + }) + (body) ({ + vector_.resize(newsize); + }) ) + + void resize(size_type newsize, T val) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (resize)( (size_type)(newsize) (T)(val) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == newsize ); + // Version 2: with a ternary operator. + CONTRACT_ASSERT( newsize > CONTRACT_OLDOF(this)->size() ? + all_equals(begin() + CONTRACT_OLDOF(this)->size(), + end(), val) : true ); + }) + (body) ({ + vector_.resize(newsize, val); + }) ) + + size_type size(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (size_type) (size)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result <= capacity() ); + }) + (body) ({ + return vector_.size(); + }) ) + + size_type max_size(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (size_type) (max_size)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result >= capacity() ); + }) + (body) ({ + return vector_.max_size(); + }) ) + + bool empty(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (bool) (empty)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (size() == 0) ); + }) + (body) ({ + return vector_.empty(); + }) ) + + Alloc get_allocator(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (Alloc) (get_allocator)( (void) ) (const) + (body) ({ + return vector_.get_allocator(); + }) ) + + reference at(size_type off) + CONTRACT_FUNCTION( (class) (vector) + (public) (reference) (at)( (size_type)(off) ) + (precondition) ({ + CONTRACT_ASSERT( off < size() ); + }) + (body) ({ + return at(off); + }) ) + + const_reference at(size_type off) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reference) (at)( (size_type)(off) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( off < size() ); + }) + (body) ({ + return at(off); + }) ) + + reference operator[](size_type off) + CONTRACT_FUNCTION( (class) (vector) + (public) (reference) (operator_at)( (size_type)(off) ) + (precondition) ({ + CONTRACT_ASSERT( off < size() ); + }) + (body) ({ + return operator[](off); + }) ) + + const_reference operator[](size_type off) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reference) (operator_at)( + (size_type)(off) ) (const) + (precondition) ({ + CONTRACT_ASSERT( off < size() ); + }) + (body) ({ + return operator[](off); + }) ) + + reference front(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (reference) (front)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (body) ({ + return vector_.front(); + }) ) + + const_reference front(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reference) (front)( (void) ) (const) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (body) ({ + return vector_.front(); + }) ) + + reference back(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (reference) (back)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (body) ({ + return vector_.back(); + }) ) + + const_reference back(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reference) (back)( (void) ) (const) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (body) ({ + return vector_.back(); + }) ) + + void push_back(const T& val) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (push_back)( (const T&)(val) ) + (precondition) ({ + CONTRACT_ASSERT( size() < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( back() == val ); + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + CONTRACT_ASSERT( capacity() >= CONTRACT_OLDOF(this)->capacity() ); + }) + (body) ({ + vector_.push_back(val); + }) ) + + void pop_back(void) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (pop_back)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() - 1) ); + }) + (body) ({ + vector_.pop_back(); + }) ) + + template + void assign(InIt first, InIt last) + CONTRACT_FUNCTION( (class) (vector) + (public) (template)( (class)(InIt) ) + (void) (assign)( (InIt)(first) (InIt)(last) ) + (precondition) ({ + /** @pre [first, last) not sub-range of [begin(), end()). */ + }) + (postcondition) ({ + CONTRACT_ASSERT( equal_distance(first, last, size()) ); + }) + (body) ({ + vector_.assign(first, last); + }) ) + + void assign(size_type count, const T& val) + CONTRACT_FUNCTION( (class) (vector) + (public) (void) (assign)( + (size_type)(count) (const T&)(val) ) + (precondition) ({ + CONTRACT_ASSERT( count <= max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( all_equals(begin(), end(), val) ); + }) + (body) ({ + vector_.assign(count, val); + }) ) + + iterator insert(iterator where, const T& val) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (iterator) (insert)( + (iterator)(where) (const T&)(val) ) + (precondition) ({ + CONTRACT_ASSERT( size() < max_size() ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( *result == val ); + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + CONTRACT_ASSERT( capacity() >= CONTRACT_OLDOF(this)->capacity() ); + /** @post + * if capacity() > oldof capacity(): + * all iterators invalidated + * else: + * all iterators in [where, end()) invalidated + */ + }) + (body) ({ + return vector_.insert(where, val); + }) ) + + void insert(iterator where, size_type count, const T& val) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (insert)( (copyable)(iterator)(where) + (size_type)(count) (const T&)(val) ) + (precondition) ({ + CONTRACT_ASSERT( (size() + count) < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( size() == + (CONTRACT_OLDOF(this)->size() + count) ); + CONTRACT_ASSERT( capacity() >= CONTRACT_OLDOF(this)->capacity() ); + if (capacity() == CONTRACT_OLDOF(this)->capacity()) { + CONTRACT_ASSERT( all_equals( + boost::prior(CONTRACT_OLDOF(where)), + boost::prior(CONTRACT_OLDOF(where)) + count, + val) ); + /** @post All iterators in [where, end()) invalidated. */ + } + else { + /** @post All iterators invalidated. */ + } + }) + (body) ({ + vector_.insert(where, val); + }) ) + + template + void insert(iterator where, InIt first, InIt last) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (template)( (class)(InIt) ) + (void) (insert)( (copyable)(iterator)(where) + (InIt)(first) (InIt)(last) ) + (precondition) ({ + /** @pre [first, last) not a sub-range or [begin(), end()). */ + int count = std::distance(first, last); + CONTRACT_ASSERT( (size() + count) < max_size() ); + }) + (postcondition) ({ + int count = std::distance(first, last); + CONTRACT_ASSERT( size() == + (CONTRACT_OLDOF(this)->size() + count) ); + CONTRACT_ASSERT( capacity() >= CONTRACT_OLDOF(this)->capacity() ); + }) + (body) ({ + return vector_.insert(where, first, last); + }) ) + + iterator erase(iterator where) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (iterator) (erase)( (iterator)(where) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + CONTRACT_ASSERT( where != end() ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() - 1) ); + if (empty()) CONTRACT_ASSERT( result == end() ); + /** @post Iterators in [where, end()) invalidated. */ + }) + (body) ({ + return vector_.erase(where); + }) ) + + iterator erase(iterator first, iterator last) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (iterator) (erase)( (iterator)(first) + (iterator)(last) ) + (precondition) ({ + CONTRACT_ASSERT( size() >= std::distance(first, last) ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() - + std::distance(first, last)) ); + if (empty()) CONTRACT_ASSERT( result == end() ); + /** @post Iterators in [first, end()) invalidated. */ + }) + (body) ({ + return vector_.erase(first, last); + }) ) + + void clear(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (void) (clear)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( empty() ); + }) + (body) ({ + vector_.clear(); + }) ) + + void swap(vector& right) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (swap)( (copyable)(vector&)(right) ) + (postcondition) ({ + CONTRACT_ASSERT( *CONTRACT_OLDOF(this) == right ); + CONTRACT_ASSERT( CONTRACT_OLDOF(right) == *this ); + }) + (body) ({ + vector_.swap(right); + }) ) + + bool operator==(const vector& right) const + CONTRACT_FUNCTION( (class) (vector) + (public) (bool) (operator_equal)( + (const vector&)(right) ) (const) + (body) ({ + return vector_ == right.vector_; + }) ) + +private: + std::vector vector_; +}; + +int main() { + // Run a few of the operations (could test more of them...). + std::cout << std::endl << "constructor()" << std::endl; + vector v(3); + const vector& cv = v; // A reference, no copy. + + std::cout << std::endl << "copy constructor()" << std::endl; + vector w(v); + + std::cout << std::endl << "begin()" << std::endl; + vector::iterator b = v.begin(); + std::cout << *b << std::endl; + + std::cout << std::endl << "begin() const" << std::endl; + vector::const_iterator cb = cv.begin(); + std::cout << *cb << std::endl; + + std::cout << std::endl << "insert()" << std::endl; + v.insert(b, 2, -3.21); + + std::cout << std::endl << "operator[]" << std::endl; + double v0 = v[0]; + std::cout << v0 << std::endl; + + std::cout << std::endl << "push_back()" << std::endl; + v.push_back(1.23); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/Makefile b/doc/html/example/Makefile new file mode 100755 index 00000000..501361b4 --- /dev/null +++ b/doc/html/example/Makefile @@ -0,0 +1,135 @@ +# Copyright (C) 2009-2010 Lorenzo Caminiti. +# Use, modification, and distribution is subject to the +# Contract++ Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt.) + +# Supported C++ compliers `make CXX=compiler ...', where compiler is: +# GCC GNU g++ (e.g., on Linux) (default) +# MSVC Microsoft Visual C++ (e.g., on Cygwin) +CXX=GCC + +bin:=./bin +ifeq ($(CXX), GCC) + cpp_nodef:=g++ -Wall -Werror -I./src + def:=-D + out:=-o +endif +ifeq ($(CXX), MSVC) + # Don't use /Wall for MSVC has very verbose warnings (even in Boost?!). + cpp_nodef:=source $(bin)/env-MSVC8.sh && cl.exe /EHsc /I./src + def:=/D + out:=/Fe +endif +cpp:=$(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION +ifeq ($(debug), 1) + cpp:=$(cpp) $(def)CONTRACT_CONFIG_DEBUG_=1 +endif + +src:=./example +build:=./build/example +codedoc:=./codedoc/example + +all: myvector myvector_checks commas throw Crowl2006 Mitchell2002 Meyer1997 Stroustrup1997 + +clean: + rm -rf $(build) + +mkdir_: + mkdir -p $(build) + +myvector: mkdir_ + $(cpp) $(src)/myvector/main.cpp $(out)$(build)/myvector +myvector_checks: mkdir_ + # Compile with all different contract checking combinations. + $(cpp_nodef) $(src)/myvector/main.cpp $(out)$(build)/myvector-check_none + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(src)/myvector/main.cpp $(out)$(build)/myvector-check_inv + $(cpp_nodef) $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_inv + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_post + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_inv_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_inv_post + $(cpp_nodef) $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_inv_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_inv_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_inv_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_inv_pre_post + +myvector_nomacros: mkdir_ + $(cpp) $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros +myvector_nomacros_checks: mkdir_ + # Compile with all different contract checking combinations. + $(cpp_nodef) $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_none + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_inv + $(cpp_nodef) $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_inv + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_post + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_inv_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_inv_post + $(cpp_nodef) $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_inv_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_inv_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_inv_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_inv_pre_post + +commas: mkdir_ + $(cpp) $(src)/commas/main.cpp $(out)$(build)/commas + +throw: mkdir_ + $(cpp) $(src)/throw/main.cpp $(out)$(build)/throw + +Crowl2006: sqrt block sum factorial circle operator_equal vector +sqrt: mkdir_ + $(cpp) $(src)/Crowl2006/sqrt/main.cpp $(out)$(build)/sqrt +block: mkdir_ + $(cpp) $(src)/Crowl2006/block/main.cpp $(out)$(build)/block +sum: mkdir_ + $(cpp) $(src)/Crowl2006/sum/sum.cpp $(src)/Crowl2006/sum/main.cpp $(out)$(build)/sum +factorial: mkdir_ + $(cpp) $(src)/Crowl2006/factorial/main.cpp $(out)$(build)/factorial +circle: mkdir_ + $(cpp) $(src)/Crowl2006/circle/main.cpp $(out)$(build)/circle +operator_equal: mkdir_ + $(cpp) $(src)/Crowl2006/operator_equal/main.cpp $(out)$(build)/operator_equal +vector: mkdir_ + $(cpp) $(src)/Crowl2006/vector/main.cpp $(out)$(build)/vector + +Mitchell2002: name_list stack simple_queue dictionary courier customer_manager observe counter +name_list: mkdir_ + $(cpp) $(src)/Mitchell2002/name_list/names.cpp $(src)/Mitchell2002/name_list/main.cpp $(out)$(build)/name_list +stack: mkdir_ + $(cpp) $(src)/Mitchell2002/stack/main.cpp $(out)$(build)/stack +simple_queue: mkdir_ + $(cpp) $(src)/Mitchell2002/simple_queue/main.cpp $(out)$(build)/simple_queue +dictionary: mkdir_ + $(cpp) $(src)/Mitchell2002/dictionary/main.cpp $(out)$(build)/dictionary +courier: mkdir_ + $(cpp) $(src)/Mitchell2002/courier/couriers.cpp $(src)/Mitchell2002/courier/main.cpp $(out)$(build)/courier +customer_manager: mkdir_ + $(cpp) $(src)/Mitchell2002/customer_manager/customer_manager.cpp $(src)/Mitchell2002/customer_manager/main.cpp $(out)$(build)/customer_manager +observe: mkdir_ + $(cpp) $(src)/Mitchell2002/observe/main.cpp $(out)$(build)/observe +counter: mkdir_ + $(cpp) $(src)/Mitchell2002/counter/main.cpp $(out)$(build)/counter + +Meyer1997: stack4 stack3 gcd maxarray +stack4: mkdir_ + $(cpp) $(src)/Meyer1997/stack4/main.cpp $(out)$(build)/stack4 +stack3: mkdir_ + $(cpp) $(src)/Meyer1997/stack3/main.cpp $(out)$(build)/stack3 +gcd: mkdir_ + $(cpp) $(src)/Meyer1997/gcd/main.cpp $(out)$(build)/gcd +maxarray: mkdir_ + $(cpp) $(src)/Meyer1997/maxarray/main.cpp $(out)$(build)/maxarray + +Stroustrup1997: string +string: mkdir_ + $(cpp) $(src)/Stroustrup1997/string/string.cpp $(src)/Stroustrup1997/string/main.cpp $(out)$(build)/string + diff --git a/doc/html/example/Meyer1997/README.txt b/doc/html/example/Meyer1997/README.txt new file mode 100755 index 00000000..cc8e3ad6 --- /dev/null +++ b/doc/html/example/Meyer1997/README.txt @@ -0,0 +1,2 @@ +Examples taken from Meyer, "Object Oriented Software Construction", +1997. diff --git a/doc/html/example/Meyer1997/gcd/main.cpp b/doc/html/example/Meyer1997/gcd/main.cpp new file mode 100755 index 00000000..5f831c78 --- /dev/null +++ b/doc/html/example/Meyer1997/gcd/main.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Loop variants and invariants (ported from Eiffel code). + +#include +#include +#include + +/** Calculate greater common divisor of given positive integers. */ +int gcd(const int& a, const int& b) +CONTRACT_FUNCTION( (int)(gcd)( (const int&)(a) (const int&)(b) ) +(precondition) ({ + CONTRACT_ASSERT( a > 0 ); + CONTRACT_ASSERT( b > 0 ); +}) +(postcondition) (result) ({ + /** @post result is greatest common divisor of a and b */ +}) +(body) ({ + int x = a; + int y = b; + // Block invariants can apper in any code block (not just loop). + CONTRACT_ASSERT_BLOCK_INVARIANT( x == a ); + CONTRACT_ASSERT_BLOCK_INVARIANT( y == b ); + + // Loop variant and invariants. + for (CONTRACT_INIT_LOOP_VARIANT; x != y; ) { + CONTRACT_ASSERT_BLOCK_INVARIANT( x > 0 ); + CONTRACT_ASSERT_BLOCK_INVARIANT( y > 0 ); + /** @inv gcd(x, y) == gcd(a, b) */ + CONTRACT_ASSERT_LOOP_VARIANT( std::max(x, y) ); + + if (x > y) x = x - y; + else y = y - x; + } + + return x; +}) ) + +int main() { + int a = 12, b = 18; + std::cout << "gcd(" << a << ", " << b << ") = " + << gcd(a, b) << std::endl; + + a = 4; b = 14; + std::cout << "gcd(" << a << ", " << b << ") = " + << gcd(a, b) << std::endl; + + return 0; +} + diff --git a/doc/html/example/Meyer1997/maxarray/main.cpp b/doc/html/example/Meyer1997/maxarray/main.cpp new file mode 100755 index 00000000..1ddd686e --- /dev/null +++ b/doc/html/example/Meyer1997/maxarray/main.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Loop variants and invariants (ported from Eiffel code). + +#include +#include +#include + +int maxarray(const int* array, const size_t& size) +CONTRACT_FUNCTION( (int) (maxarray)( (const int*)(array) + (const size_t&)(size) ) +(precondition) ({ + CONTRACT_ASSERT( size >= 1 ); +}) +(body) ({ + size_t i = 0; + int result = array[i]; + + CONTRACT_INIT_LOOP_VARIANT; + while (i < (size - 1)) { + for (size_t j = 0; j < i; ++j) + CONTRACT_ASSERT_BLOCK_INVARIANT( result >= array[j] ); + // -2 because start from 0 and already done element at 0. + CONTRACT_ASSERT_LOOP_VARIANT( size - i - 2 ); + + ++i; + result = std::max(result, array[i]); + } + + return result; +}) ) + +int main() { + int a[] = {1, 5, 3}; + std::cout << maxarray(a, 3) << std::endl; + return 0; +} + diff --git a/doc/html/example/Meyer1997/stack3/main.cpp b/doc/html/example/Meyer1997/stack3/main.cpp new file mode 100755 index 00000000..96482970 --- /dev/null +++ b/doc/html/example/Meyer1997/stack3/main.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "stack3.hpp" +#include +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + stack3 s(3); + + std::cout << std::endl << "count()" << std::endl; + std::cout << s.count() << std::endl; + + std::cout << std::endl << "empty()" << std::endl; + std::cout << s.empty() << std::endl; + + std::cout << std::endl << "full()" << std::endl; + std::cout << s.full() << std::endl; + + std::cout << std::endl << "put()" << std::endl; + s.put("Galileo"); + + std::cout << std::endl << "capacity()" << std::endl; + std::cout << s.capacity() << std::endl; + + std::cout << std::endl << "item()" << std::endl; + std::cout << s.item() << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + s.remove(); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/Meyer1997/stack3/stack3.hpp b/doc/html/example/Meyer1997/stack3/stack3.hpp new file mode 100755 index 00000000..3d1fc971 --- /dev/null +++ b/doc/html/example/Meyer1997/stack3/stack3.hpp @@ -0,0 +1,186 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for a stack reporting errors using error codes instead +// of asserting preconditions or invariants (ported from Eiffel code). + +#ifndef STACK3_HPP_ +#define STACK3_HPP_ + +#include "../stack4/stack4.hpp" +#include + +/** Dispenser structures with a Last-In, First-Out access policy, and + * a fixed maximum capacity. Tolerant version setting an error code + * in case of impossible operations. */ +template +class stack3 { + + CONTRACT_INVARIANT( ({}) ) + +public: + static const T DEFAULT_ITEM; + + /** Error codes. */ + enum Error { + NO_ERROR = 0, + OVERFLOW_ERROR, + UNDERFLOW_ERROR, + SIZE_ERROR, + }; + + // Initialization // + + /** Create stack for a maximum of n elements. If n < 0, set error + * to SIZE_ERROR (but no precondition). */ + stack3(const int& n): representation_(0), error_(NO_ERROR) + CONTRACT_CONSTRUCTOR( (class) (stack3) + (public) (stack3)( (const int&)(n) ) + (postcondition) ({ + CONTRACT_ASSERT( (n < 0) == (error() == SIZE_ERROR) ); + CONTRACT_ASSERT( (n >= 0) == !error() ); + if (!error()) CONTRACT_ASSERT( capacity() == n ); + }) + (body) ({ + if (n >= 0) { + representation_ = stack4(n); + } else { + error_ = SIZE_ERROR; + } + }) ) + + /** Destroy stack. */ + virtual ~stack3(void) + CONTRACT_DESTRUCTOR( (class) (stack3) + (public) (virtual) (stack3)( (void) ) + (body) ({ + }) ) + + // Access // + + /** Maximum number of stack elements. */ + int capacity(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (int) (capacity)( (void) ) (const) + (body) ({ + return representation_.capacity(); + }) ) + + /** Number of stack elements. */ + int count(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (int) (count)( (void) ) (const) + (body) ({ + return representation_.count(); + }) ) + + /** Top element if present. Otherwise, return type's default + * value and set error to UNDERFLOW_ERROR (but no precondition). */ + const T& item(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (const T&) (item)( (void) ) (const) + (postcondition) (result) ({ + // Const function so no need to user ODLOF(this)->empty(). + CONTRACT_ASSERT( empty() == (error() == UNDERFLOW_ERROR) ); + CONTRACT_ASSERT( !empty() == !error() ); + }) + (body) ({ + if (!empty()) { + error_ = NO_ERROR; + return representation_.item(); + } else { + error_ = UNDERFLOW_ERROR; + return DEFAULT_ITEM; + } + }) ) + + // Status Report // + + /** Error indicator, set by various operators to a non-zero (not + * NO_ERROR) value if they cannot perform their job. */ + Error error(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (Error) (error)( (void) ) (const) + (body) ({ + return error_; + }) ) + + /** Is stack has not item. */ + bool empty(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (bool) (empty)( (void) ) (const) + (body) ({ + return representation_.empty(); + }) ) + + /** If stack cannot accept any more item. */ + bool full(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (bool) (full)( (void) ) (const) + (body) ({ + return representation_.full(); + }) ) + + // Element Change // + + /** Add x to top if there is capacity left. Otherwise, set error + * to OVERFLOW_ERROR (but no precondition). */ + void put(const T& x) + CONTRACT_FUNCTION( (class) (copyable)(stack3) + (public) (void) (put)( (const T&)(x) ) + (postcondition) ({ + CONTRACT_ASSERT( CONTRACT_OLDOF(this)->full() == + (error() == OVERFLOW_ERROR) ); + CONTRACT_ASSERT( !CONTRACT_OLDOF(this)->full() == + !error() ); + if (!error()) CONTRACT_ASSERT( !empty() ); + if (!error()) CONTRACT_ASSERT( item() == x ); + if (!error()) CONTRACT_ASSERT( + count() == (CONTRACT_OLDOF(this)->count() + 1) ); + }) + (body) ({ + if (full()) { + error_ = OVERFLOW_ERROR; + } else { + representation_.put(x); + error_ = NO_ERROR; + } + }) ) + + /** Remove element if present. Otherwise, set error to + * UNDERFLOW_ERROR (but no precondition) */ + void remove(void) + CONTRACT_FUNCTION( (class) (copyable)(stack3) + (public) (void) (remove)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( CONTRACT_OLDOF(this)->empty() == + (error() == UNDERFLOW_ERROR) ); + CONTRACT_ASSERT( !CONTRACT_OLDOF(this)->empty() == + !error() ); + if (!error()) CONTRACT_ASSERT( !full() ); + if (!error()) CONTRACT_ASSERT( + count() == (CONTRACT_OLDOF(this)->count() - 1) ); + }) + (body) ({ + if (empty()) { + error_ = UNDERFLOW_ERROR; + } else { + representation_.remove(); + error_ = NO_ERROR; + } + }) ) + +private: + stack4 representation_; + // Mutable, changed by logically const members to report error. + mutable Error error_; +}; + +// For simplicity, T must have default constructor. +template +const T stack3::DEFAULT_ITEM = T(); + +#endif // #include guard + diff --git a/doc/html/example/Meyer1997/stack4/main.cpp b/doc/html/example/Meyer1997/stack4/main.cpp new file mode 100755 index 00000000..65c8fe0a --- /dev/null +++ b/doc/html/example/Meyer1997/stack4/main.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "stack4.hpp" +#include +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + stack4 s(3); + + std::cout << std::endl << "capacity()" << std::endl; + std::cout << s.capacity() << std::endl; + + std::cout << std::endl << "count()" << std::endl; + std::cout << s.count() << std::endl; + + std::cout << std::endl << "put()" << std::endl; + s.put("Galileo"); + + std::cout << std::endl << "empty()" << std::endl; + std::cout << s.empty() << std::endl; + + std::cout << std::endl << "full()" << std::endl; + std::cout << s.full() << std::endl; + + std::cout << std::endl << "item()" << std::endl; + std::cout << s.item() << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + s.remove(); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/Meyer1997/stack4/stack4.hpp b/doc/html/example/Meyer1997/stack4/stack4.hpp new file mode 100755 index 00000000..13e8e518 --- /dev/null +++ b/doc/html/example/Meyer1997/stack4/stack4.hpp @@ -0,0 +1,227 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for a stack (ported from Eiffel code). + +#ifndef STACK4_HPP_ +#define STACK4_HPP_ + +#include + +// Specification // + +/** Dispenser structures with a Last-In, First-Out access policy, + * and a fixed maximum capacity. */ +template +class stack4 { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT_MSG( representation_, "array allocated" ); + CONTRACT_ASSERT( count() >= 0 ); + CONTRACT_ASSERT( count() <= capacity() ); + CONTRACT_ASSERT( empty() == (count() == 0) ); + if (count() > 0) CONTRACT_ASSERT_MSG( + representation_[count() - 1] == item(), + "if positive, item at top" ); + }) ) + +public: + // Initialization // + + /** Create stack for a maximum of n elements. */ + stack4(const int& n): capacity_(0), count_(0), representation_() + CONTRACT_CONSTRUCTOR( (class) (stack4) + (public) (stack4)( (const int&)(n) ) + (precondition) ({ + CONTRACT_ASSERT( n >= 0 ); + }) + (postcondition) ({ + CONTRACT_ASSERT( capacity() == n ); + CONTRACT_ASSERT( empty() ); + }) + (body) ( + ; + ) ) + + /** Deep copy. */ + stack4(const stack4& other): capacity_(other.capacity_), + count_(other.count_), + representation_(new T[other.capacity_]) + CONTRACT_CONSTRUCTOR( (class) (stack4) + (public) (stack4)( (const stack4&)(other) ) + (body) ( + ; + ) ) + + /** Deep assignment. */ + stack4& operator=(const stack4& other) + CONTRACT_FUNCTION( (class) (stack4) + (public) (stack4&) (operator(=, assign))( + (const stack4&)(other) ) + (body) ( + ; + ) ) + + /** Destroy this stack. */ + virtual ~stack4(void) + CONTRACT_DESTRUCTOR( (class) (stack4) + (public) (virtual) (stack4)( (void) ) + (body) ( + ; + ) ) + + // Access // + + /** Maximum number of stack elements. */ + int capacity(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (int) (capacity)( (void) ) (const) + (body) ( + ; + ) ) + + /** Number of stack elements. */ + int count(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (int) (count)( (void) ) (const) + (body) ( + ; + ) ) + + /** Top element. */ + const T& item(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (const T&) (item)( (void) ) (const) + (body) ( + ; + ) ) + + // Status Report // + + /** If stack is empty. */ + bool empty(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (bool) (empty)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (count() == 0) ); + }) + (body) ( + ; + ) ) + + /** If stack is full. */ + bool full(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (bool) (full)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (count() == capacity()) ); + }) + (body) ( + ; + ) ) + + // Element Change // + + /** Add x on top. */ + void put(const T& x) + CONTRACT_FUNCTION( (class) (copyable)(stack4) + (public) (void) (put)( (const T&)(x) ) + (precondition) ({ + CONTRACT_ASSERT( !full() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( !empty() ); + CONTRACT_ASSERT_MSG( item() == x, "added to top" ); + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT_MSG( representation_[count() - 1] == x, + "at top array entry" ); + }) + (body) ( + ; + ) ) + + /** Remove top item. */ + void remove(void) + CONTRACT_FUNCTION( (class) (copyable)(stack4) + (public) (void) (remove)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( !full() ); + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() - 1) ); + }) + (body) ( + ; + ) ) + +private: + int capacity_; + int count_; + T* representation_; // C-style array. +}; + +// Implementation // + +template +CONTRACT_CONSTRUCTOR_BODY(stack4, stack4)(const int& n) { + capacity_ = n; + representation_ = new T[n]; +} + +template +CONTRACT_CONSTRUCTOR_BODY(stack4, stack4)(const stack4& other) { + for (int i = 0; i < other.count_; ++i) { + representation_[i] = other.representation_[i]; + } +} + +template +stack4& stack4::CONTRACT_BODY(operator(=, assign))( + const stack4& other) { + delete[] representation_; + capacity_ = other.capacity_; + count_ = other.count_; + representation_ = new T[other.capacity_]; + for (int i = 0; i < other.count_; ++i) { + representation_[i] = other.representation_[i]; + } + return *this; +} + +template +CONTRACT_DESTRUCTOR_BODY(stack4, ~stack4)(void) + { delete[] representation_; } + +template +int stack4::CONTRACT_BODY(capacity)(void) const + { return capacity_; } + +template +int stack4::CONTRACT_BODY(count)(void) const { return count_; } + +template +const T& stack4::CONTRACT_BODY(item)(void) const + { return representation_[count() - 1]; } + +template +bool stack4::CONTRACT_BODY(empty)(void) const + { return count() == 0; } + +template +bool stack4::CONTRACT_BODY(full)(void) const + { return count() == capacity(); } + +template +void stack4::CONTRACT_BODY(put)(const T& x) + { representation_[count_++] = x; } + +template +void stack4::CONTRACT_BODY(remove)(void) { --count_; } + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/README.txt b/doc/html/example/Mitchell2002/README.txt new file mode 100755 index 00000000..7a5fa9aa --- /dev/null +++ b/doc/html/example/Mitchell2002/README.txt @@ -0,0 +1,2 @@ +Examples taken from Mitchell, McKim, "Design by Contract, +by Example", 2002. diff --git a/doc/html/example/Mitchell2002/counter/counter.hpp b/doc/html/example/Mitchell2002/counter/counter.hpp new file mode 100755 index 00000000..dcbcb505 --- /dev/null +++ b/doc/html/example/Mitchell2002/counter/counter.hpp @@ -0,0 +1,69 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// A somewhat more complex example using the observer design pattern +// (ported from Eiffel code). Also shows how to make the library +// access a private copy constructor to support old value for +// `decrement_button` objects. + +#ifndef COUNTER_HPP_ +#define COUNTER_HPP_ + +#include "../observe/observe.hpp" +#include + +/** Positive integer counter. */ +class counter: public subject { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Construct counter. */ + counter(const int& value = 10): value_(value) + CONTRACT_CONSTRUCTOR( (class) (counter) + (public) (counter)( (const int&)(value) ) + (body) ({ + }) ) + + /** Destroy counter. */ + virtual ~counter(void) + CONTRACT_DESTRUCTOR( (class) (counter) + (public) (counter)( (void) ) + (body) ({ + }) ) + + // Queries // + + /** Counter current value. */ + int value(void) const + CONTRACT_FUNCTION( (class) (counter) + (public) (int) (value)( (void) ) (const) + (body) ({ + return value_; + }) ) + + // Commands // + + /** Decrement counter value. */ + void decrement(void) + CONTRACT_FUNCTION( (class) (copyable)(counter) + (public) (void) (decrement)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( value() == + (CONTRACT_OLDOF(this)->value() - 1) ); + }) + (body) ({ + --value_; + notify(); // Notifies all attached observers. + }) ) + +private: + int value_; +}; + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/counter/decrement_button.hpp b/doc/html/example/Mitchell2002/counter/decrement_button.hpp new file mode 100755 index 00000000..6c454528 --- /dev/null +++ b/doc/html/example/Mitchell2002/counter/decrement_button.hpp @@ -0,0 +1,123 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Use `contract:copy` to relax the library copyable requirements. + +#ifndef DECREMENT_BUTTON_HPP_ +#define DECREMENT_BUTTON_HPP_ + +#include "push_button.hpp" +#include "counter.hpp" +#include "../observe/observe.hpp" +#include +#include + +class decrement_button: public push_button, protected observer, + // This class is non-copyable but postconditions can still + // access its old values (see below). + boost::noncopyable { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create button associated with given counter. */ + decrement_button(counter& the_counter): counter_ref_(the_counter) + CONTRACT_CONSTRUCTOR( (class) (decrement_button) + (public) (decrement_button)( (counter&)(the_counter) ) + (postcondition) ({ + CONTRACT_ASSERT( enabled() == (the_counter.value() > 0) ); + }) + (body) ({ + counter_ref_.attach(this); + }) ) + + /** Destroy button. */ + virtual ~decrement_button(void) + CONTRACT_DESTRUCTOR( (class) (decrement_button) + (public) (virtual) (decrement_button)( (void) ) + (body) ({ + }) ) + + // Commands // + + void on_bn_clicked(void) + CONTRACT_FUNCTION( (class) (copyable)(decrement_button) + (inherit)(push_button) + (public) (void) (on_bn_clicked)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( enabled() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( counter_ref_.value() == + (CONTRACT_OLDOF(this)->counter_ref_.value() - 1) ); + }) + (body) ({ + counter_ref_.decrement(); + }) ) + +private: + decrement_button& operator=(const decrement_button&); + + bool up_to_date_with_subject(void) const + CONTRACT_FUNCTION( (class) (decrement_button) (inherit)(observer) + (private) (bool) (up_to_date_with_subject)( (void) ) + (const) + (body) ({ + return true; // For simplicity, always return true. + }) ) + + void update(void) + CONTRACT_FUNCTION( (class) (decrement_button) (inherit)(observer) + (private) (void) (update)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( enabled() == (counter_ref_.value() > 0) ); + }) + (body) ({ + if (0 == counter_ref_.value()) disable(); + else enable(); + }) ) + + counter& counter_ref_; + + // Allow access to contracts to implement special "copy". + friend class contract::copy; +}; + +// WARNING: Specialize `contract::copy` with care and only if really +// necessary (as a wrongly implemented specialization could brake +// contract constant-correctness guarantees). +// +// The decrement_button class has a reference member. The referenced +// counter (and not the counter reference!) are copied here to support +// object old value semantics in contract preconditions. This special +// "copy" is for contracts only -- in fact, decrement_button is +// `boost::noncopyable` and cannot be copied for general purposes. +// +// Similar techniques can be used to handle copy of objects with +// member pointers, in which case the `contract::copy` constructor +// allocates and copies the pointed objects (and not the pointers!) +// and the destructor deallocates them. +namespace contract { + template<> + class copy { + private: + // Not a reference type so it is copied. + counter counter_; // Non-const but local to this class. + public: + const decrement_button value; + + copy(const decrement_button& source): + // Copy the referenced counter (not the reference). + counter_(source.counter_ref_), + // "Copy" decrement_button constructing one from + // the copied counter. + value(counter_) {} + }; +} + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/counter/main.cpp b/doc/html/example/Mitchell2002/counter/main.cpp new file mode 100755 index 00000000..675193ee --- /dev/null +++ b/doc/html/example/Mitchell2002/counter/main.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "counter.hpp" +#include "decrement_button.hpp" +#include "view_of_counter.hpp" +#include + +int main() { + counter cnt(3); + view_of_counter view(cnt); + decrement_button dec(cnt); + + // Simple text-based menu selection. + char ch = '\0'; + while (ch != 'q') { + if (dec.enabled()) { + std::cout << "(-) Decrement counter" << std::endl; + } + std::cout << "(q) Quit" << std::endl; + std::cout << "Select: "; + + std::cin >> ch; + if ('q' == ch) { + return 0; + } else if ('-' == ch && dec.enabled()) { + dec.on_bn_clicked(); + } else { + std::cout << "Invalid selection '" << ch << "'" + << std::endl; + } + } + + return 0; +} + diff --git a/doc/html/example/Mitchell2002/counter/push_button.hpp b/doc/html/example/Mitchell2002/counter/push_button.hpp new file mode 100755 index 00000000..d3a6bb7a --- /dev/null +++ b/doc/html/example/Mitchell2002/counter/push_button.hpp @@ -0,0 +1,79 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef PUSH_BUTTON_HPP_ +#define PUSH_BUTTON_HPP_ + +#include + +/** Basic button. */ +class push_button { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create button. */ + push_button(void): enabled_(true) + CONTRACT_CONSTRUCTOR( (class) (push_button) + (public) (push_button)( (void) ) + (body) ({ + }) ) + + virtual ~push_button(void) + CONTRACT_DESTRUCTOR( (class) (push_button) + (public) (virtual) (push_button)( (void) ) + (body) ({ + }) ) + + // Queries // + + /** If button enabled. */ + bool enabled(void) const + CONTRACT_FUNCTION( (class) (push_button) + (public) (bool) (enabled)( (void) ) (const) + (body) ({ + return enabled_; + }) ) + + // Commands // + + /** Enable this button. */ + void enable(void) + CONTRACT_FUNCTION( (class) (push_button) + (public) (void) (enable)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( enabled() ); + }) + (body) ({ + enabled_ = true; + }) ) + + /** Disable this button. */ + void disable(void) + CONTRACT_FUNCTION( (class) (push_button) + (public) (void) (disable)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( !enabled() ); + }) + (body) ({ + enabled_ = false; + }) ) + + /** Invoked externally when this button is clicked. */ + virtual void on_bn_clicked(void) + CONTRACT_FUNCTION( (class) (push_button) + (public) (virtual) (void) (on_bn_clicked)( (void) ) + (body) ( + = 0; + ) ) + +private: + bool enabled_; +}; + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/counter/view_of_counter.hpp b/doc/html/example/Mitchell2002/counter/view_of_counter.hpp new file mode 100755 index 00000000..cfb79116 --- /dev/null +++ b/doc/html/example/Mitchell2002/counter/view_of_counter.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef VIEW_OF_COUNT_HPP_ +#define VIEW_OF_COUNT_HPP_ + +#include "../observe/observe.hpp" +#include "counter.hpp" +#include +#include // To view counter value on console. + +/** Show current value of associated counter. */ +class view_of_counter: private observer { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create viewer associated with given counter. */ + view_of_counter(counter& the_counter): counter_ref_(the_counter) + CONTRACT_CONSTRUCTOR( (class) (view_of_counter) + (public) (view_of_counter)( (counter&)(the_counter) ) + (body) ({ + counter_ref_.attach(this); + std::cout << std::endl << ">> Counter started at " + << counter_ref_.value() << std::endl << std::endl; + }) ) + +private: + bool up_to_date_with_subject(void) const + CONTRACT_FUNCTION( (class) (view_of_counter) (inherit)(observer) + (private) (bool) (up_to_date_with_subject)( (void) ) (const) + (body) ({ + return true; // For simplicity, always return true. + }) ) + + void update(void) + CONTRACT_FUNCTION( (class) (view_of_counter) (inherit)(observer) + (private) (void) (update)( (void) ) + (body) ({ + std::cout << std::endl << ">> Counter changed to " + << counter_ref_.value() << std::endl << std::endl; + }) ) + + counter& counter_ref_; +}; + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/courier/couriers.cpp b/doc/html/example/Mitchell2002/courier/couriers.cpp new file mode 100755 index 00000000..4ca28df3 --- /dev/null +++ b/doc/html/example/Mitchell2002/courier/couriers.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "couriers.hpp" + +// Courier // + +double courier::min_insurance_dollar = 10.0e+6; + +CONTRACT_CONSTRUCTOR_BODY(courier, courier)( + const double& insurance_cover_dollar) {} + +CONTRACT_DESTRUCTOR_BODY(courier, ~courier)(void) {} + +double courier::CONTRACT_BODY(insurance_cover_dollar)(void) const { + return insurance_cover_dollar_; +} + +void courier::CONTRACT_BODY(deliver)(package& the_package, + const std::string& 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_CONSTRUCTOR_BODY(different_courier, different_courier)( + const double& insurance_cover_dollar) {} + +CONTRACT_DESTRUCTOR_BODY(different_courier, ~different_courier)( + void) {} + +void different_courier::CONTRACT_BODY(deliver)(package& the_package, + const std::string& destination) { + the_package.location = destination; + // Delivery takes only 0.5 hours. + the_package.delivered_hour = the_package.accepted_hour + 0.5; +} + diff --git a/doc/html/example/Mitchell2002/courier/couriers.hpp b/doc/html/example/Mitchell2002/courier/couriers.hpp new file mode 100755 index 00000000..b369c59f --- /dev/null +++ b/doc/html/example/Mitchell2002/courier/couriers.hpp @@ -0,0 +1,175 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Subcontracting and static invariant example (ported from Eiffel code). + +#ifndef COURIERS_HPP_ +#define COURIERS_HPP_ + +#include +#include + +/** Basic package information. */ +struct package { + /** Weight in kilograms. */ + double weight_kg; + /** Current location. */ + std::string location; + /** Hour when it was accepted for delivery (from some 0-hour). */ + double accepted_hour; + /** Hour when was delivered (from some 0-hour). */ + double delivered_hour; + + package(const double& the_weight_kg, + const std::string the_location = "", + const double& the_accepted_hour = 0.0, + const double& the_delivered_hour = 0.0): + weight_kg(the_weight_kg), + location(the_location), + accepted_hour(the_accepted_hour), + delivered_hour(the_delivered_hour) + {} +}; + +/** Basic courier for package delivery. */ +class courier { + + CONTRACT_INVARIANT( (static) ({ + CONTRACT_ASSERT( min_insurance_dollar > 0.0 ); + }) ({ + CONTRACT_ASSERT( insurance_cover_dollar() >= + min_insurance_dollar ); + }) ) + +public: + static double min_insurance_dollar; + + // Creation // + + /** Create courier with specified insurance value. */ + courier(const double& insurance_cover_dollar = + min_insurance_dollar): + insurance_cover_dollar_(insurance_cover_dollar) + CONTRACT_CONSTRUCTOR( (class) (courier) + (public) (courier)( + (const double&)(insurance_cover_dollar) ) + (precondition) ({ + CONTRACT_ASSERT( insurance_cover_dollar > 0.0 ); + }) + (body) ( + ; + ) ) + + /** Destroy courier. */ + virtual ~courier(void) + CONTRACT_DESTRUCTOR( (class) (courier) + (public) (courier)( (void) ) + (body) ( + ; + ) ) + + // Queries // + + /** Return insurance cover. */ + double insurance_cover_dollar(void) const + CONTRACT_FUNCTION( (class) (courier) + (public) (double) (insurance_cover_dollar)( (void) ) + (const) + (body) ( + ; + ) ) + + // Commands // + + /** Deliver package to destination. */ + virtual void deliver(package& the_package, + const std::string& destination) + CONTRACT_FUNCTION( (class) (courier) + (public) (virtual) (void) (deliver)( + (package&)(the_package) + (const std::string&)(destination) ) + (precondition) ({ + CONTRACT_ASSERT_MSG( the_package.weight_kg <= 5.0, + "max weight" ); + }) + (postcondition) ({ + CONTRACT_ASSERT_MSG( (the_package.delivered_hour - + the_package.accepted_hour) <= 3.0, + "max delivery time" ); + CONTRACT_ASSERT_MSG( the_package.location == destination, + "delivered at destination" ); + }) + (body) ( + ; + ) ) + +private: + double insurance_cover_dollar_; +}; + +/** Different courier for package delivery. */ +class different_courier: public courier { + + CONTRACT_INVARIANT( (static) ({ + // Stronger invariant on insurance value (higher amount). + CONTRACT_ASSERT( different_insurance_dollar >= + courier::min_insurance_dollar ); + }) ({ + CONTRACT_ASSERT( insurance_cover_dollar() >= + different_insurance_dollar ); + }) ) + +public: + static double different_insurance_dollar; + + // Creation // + + /** Create courier with specified insurance value. */ + different_courier(const double& insurance_cover_dollar = + different_insurance_dollar): + courier(insurance_cover_dollar) + CONTRACT_CONSTRUCTOR( (class) (different_courier) + (public) (different_courier)( + (const double&)(insurance_cover_dollar) ) + (precondition) ({ + CONTRACT_ASSERT( insurance_cover_dollar >= 0.0 ); + }) + (body) ( + ; + ) ) + + /** Destroy courier. */ + virtual ~different_courier(void) + CONTRACT_DESTRUCTOR( (class) (different_courier) + (public) (virtual) (different_courier)( (void) ) + (body) ( + ; + ) ) + + // Commands // + + virtual void deliver(package& the_package, + const std::string& destination) + CONTRACT_FUNCTION( (class) (different_courier) (inherit)(courier) + (public) (virtual) (void) (deliver)( + (package&)(the_package) + (const std::string&)(destination) ) + (precondition) ({ + // Weaker precondition on weight (can weight more). + CONTRACT_ASSERT( the_package.weight_kg <= 8.0 ); + }) + (postcondition) ({ + // Stronger postcondition on deliver time (faster deliver). + CONTRACT_ASSERT( (the_package.delivered_hour - + the_package.accepted_hour) <= 2.0 ); + // Inherits "delivered at destination" postcondition. + }) + (body) ( + ; + ) ) +}; + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/courier/main.cpp b/doc/html/example/Mitchell2002/courier/main.cpp new file mode 100755 index 00000000..49462899 --- /dev/null +++ b/doc/html/example/Mitchell2002/courier/main.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "couriers.hpp" +#include + +int main() { + std::cout << std::endl << "courier constructor" << std::endl; + courier c; + { + std::cout << std::endl << "different courier constructor" + << std::endl; + different_courier dc; + + package cups(3.6, "store"); + package desk(7.2, "store"); + + std::cout << std::endl << "courier delivers cups home" + << std::endl; + c.deliver(cups, "home"); + + std::cout << std::endl << "different courier delivers desk " + << "to office" << std::endl; + dc.deliver(desk, "office"); + + std::cout << std::endl << "different courier destructor" + << std::endl; + } + std::cout << std::endl << "courier destructor" << std::endl; + return 0; +} + diff --git a/doc/html/example/Mitchell2002/customer_manager/customer_manager.cpp b/doc/html/example/Mitchell2002/customer_manager/customer_manager.cpp new file mode 100755 index 00000000..15e34212 --- /dev/null +++ b/doc/html/example/Mitchell2002/customer_manager/customer_manager.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "customer_manager.hpp" + +CONTRACT_CONSTRUCTOR_BODY(customer_manager, customer_manager)(void) {} + +CONTRACT_DESTRUCTOR_BODY(customer_manager, ~customer_manager)(void) {} + +int customer_manager::CONTRACT_BODY(count)(void) const { + return customers_.size(); +} + +bool customer_manager::CONTRACT_BODY(id_active)( + const basic_customer_details::identifier& id) const { + return customers_.find(id) != customers_.end(); +} + +const std::string& customer_manager::CONTRACT_BODY(name_for)( + const basic_customer_details::identifier& id) const { + // Find != end() because of id_active() precondition. + return customers_.find(id)->second.name; +} + +void customer_manager::CONTRACT_BODY(add)( + const basic_customer_details& details) { + customers_.insert(std::pair(details.id, customer(details))); +} + +void customer_manager::CONTRACT_BODY(set_name)( + const basic_customer_details::identifier& id, + const std::string& name) { + // Find != end() because of id_active() precondition. + customers_.find(id)->second.name = name; +} + diff --git a/doc/html/example/Mitchell2002/customer_manager/customer_manager.hpp b/doc/html/example/Mitchell2002/customer_manager/customer_manager.hpp new file mode 100755 index 00000000..13f70b7c --- /dev/null +++ b/doc/html/example/Mitchell2002/customer_manager/customer_manager.hpp @@ -0,0 +1,159 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contract example (ported from Eiffel code). + +#ifndef CUSTOMER_MANAGE_HPP_ +#define CUSTOMER_MANAGE_HPP_ + +#include +#include +#include + +/** Basic customer information. */ +class basic_customer_details { + friend class customer_manager; + +public: + /** Identifier type. */ + typedef std::string identifier; + + /** Construct basic customer information. */ + explicit basic_customer_details(const identifier& the_id): + id(the_id), name(), address(), birthday() {} + +protected: + /** Customer identifier. */ + identifier id; + /** Customer name. */ + std::string name; + /** Customer address. */ + std::string address; + /** Customer date of birth. */ + std::string birthday; +}; + +/** Manage customers. */ +class customer_manager { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( count() >= 0 ); + }) ) + +public: + // Construction // + + customer_manager(void): customers_() + CONTRACT_CONSTRUCTOR( (class) (customer_manager) + (public) (customer_manager)( (void) ) + (body) ( + ; + ) ) + + virtual ~customer_manager(void) + CONTRACT_DESTRUCTOR( (class) (customer_manager) + (public) (customer_manager)( (void) ) + (body) ( + ; + ) ) + + // Basic Queries // + + /** Number of customers. */ + int count(void) const + CONTRACT_FUNCTION( (class) (customer_manager) + (public) (int) (count)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result >= 0 ); + }) + (body) ( + ; + ) ) + + /** There is a customer with given identifier. */ + bool id_active(const basic_customer_details::identifier& id) + const + CONTRACT_FUNCTION( (class) (customer_manager) + (public) (bool) (id_active)( + (const basic_customer_details::identifier&)(id) ) + (const) + (body) ( + ; + ) ) + + // Derived Queries // + + /** Name of customer with given identifier. */ + const std::string& name_for( + const basic_customer_details::identifier& id) const + CONTRACT_FUNCTION( (class) (customer_manager) + (public) (const std::string&) (name_for)( + (const basic_customer_details::identifier&)(id) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( id_active(id) ); + }) + (body) ( + ; + ) ) + + // Commands // + + /** Add given customer. */ + void add(const basic_customer_details& details) + CONTRACT_FUNCTION( (class) (copyable)(customer_manager) + (public) (void) (add)( + (const basic_customer_details&)(details) ) + (precondition) ({ + CONTRACT_ASSERT( !id_active(details.id) ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT( id_active(details.id) ); + }) + (body) ( + ; + ) ) + + /** Set name of customer with given identifier. */ + void set_name(const basic_customer_details::identifier& id, + const std::string& name) + CONTRACT_FUNCTION( (class) (customer_manager) + (public) (void) (set_name)( + (const basic_customer_details::identifier&)(id) + (const std::string&)(name) ) + (precondition) ({ + CONTRACT_ASSERT( id_active(id) ); + }) + (postcondition) ({ + CONTRACT_ASSERT( name_for(id) == name ); + }) + (body) ( + ; + ) ) + +private: + /** Customer agent. */ + class agent {}; + + /** Basic customer. */ + class customer: public basic_customer_details { + public: + /** Customer agent/ */ + agent managing_agent; + /** Customer last contacted. */ + std::string last_contact; + + explicit customer(const basic_customer_details& details): + basic_customer_details(details), managing_agent(), + last_contact() {} + }; + + std::map customers_; +}; + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/customer_manager/main.cpp b/doc/html/example/Mitchell2002/customer_manager/main.cpp new file mode 100755 index 00000000..c440c10c --- /dev/null +++ b/doc/html/example/Mitchell2002/customer_manager/main.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "customer_manager.hpp" +#include + +int main() { + std::cout << "constructor()" << std::endl; + customer_manager mgr; + + basic_customer_details d("sci"); + std::cout << std::endl << "add()" << std::endl; + mgr.add(d); + + std::cout << std::endl << "set_name()" << std::endl; + mgr.set_name("sci", "Galileo"); + + std::cout << std::endl << "name_for()" << std::endl; + std::cout << mgr.name_for("sci"); + + std::cout << std::endl << "count()" << std::endl; + std::cout << mgr.count() << std::endl; + + std::cout << std::endl << "id_active()" << std::endl; + std::cout << mgr.id_active("sci") << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/Mitchell2002/dictionary/dictionary.hpp b/doc/html/example/Mitchell2002/dictionary/dictionary.hpp new file mode 100755 index 00000000..9651dfc9 --- /dev/null +++ b/doc/html/example/Mitchell2002/dictionary/dictionary.hpp @@ -0,0 +1,117 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for an Eiffel-like dictionary (ported from Eiffel code). + +#ifndef DICTINARY_HPP_ +#define DICTINARY_HPP_ + +#include +#include + +/** Simple dictionary. */ +template +class dictionary { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( count() >= 0 ); + }) ) + +public: + // Creation // + + /** Create empty dictionary. */ + dictionary(void) + CONTRACT_CONSTRUCTOR( (class) (dictionary) + (public) (dictionary)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( 0 == count() ); + }) + (body) ({ + }) ) + + /** Destroy dictionary. */ + virtual ~dictionary(void) + CONTRACT_DESTRUCTOR( (class) (dictionary) + (public) (dictionary)( (void) ) + (body) ({ + }) ) + + // Basic Queries // + + /** Number of key entries. */ + int count(void) const + CONTRACT_FUNCTION( (class) (dictionary) + (public) (int) (count)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result >= 0 ); + }) + (body) ({ + return items_.size(); + }) ) + + /** If there is an entry for specified key. */ + bool has(const Key& key) const + CONTRACT_FUNCTION( (class) (dictionary) + (public) (bool) (has)( (const Key&)(key) ) (const) + (postcondition) (result) ({ + if (count() == 0) CONTRACT_ASSERT( result == false ); + }) + (body) ({ + return items_.find(key) != items_.end(); + + }) ) + + /** Value for given key. */ + const Value& value_for(const Key& key) const + CONTRACT_FUNCTION( (class) (dictionary) + (public) (const Value&) (value_for)( (const Key&)(key) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( has(key) ); + }) + (body) ({ + return items_.find(key)->second; + }) ) + + // Commands // + + /** Put value for given key. */ + void put(const Key& key, const Value& value) + CONTRACT_FUNCTION( (class) (copyable)(dictionary) + (public) (void) (put)( (const Key&)(key) + (const Value&)(value) ) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT( has(key) ); + CONTRACT_ASSERT( value_for(key) == value ); + }) + (body) ({ + items_.insert(std::pair(key, value)); + }) ) + + /** Remove value for given key. */ + void remove(const Key& key) + CONTRACT_FUNCTION( (class) (copyable)(dictionary) + (public) (void) (remove)( (const Key&)(key) ) + (precondition) ({ + CONTRACT_ASSERT( has(key) ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() - 1) ); + CONTRACT_ASSERT( !has(key) ); + }) + (body) ({ + items_.erase(key); + }) ) + +private: + std::map items_; +}; + +#endif // #inlcude guard + diff --git a/doc/html/example/Mitchell2002/dictionary/main.cpp b/doc/html/example/Mitchell2002/dictionary/main.cpp new file mode 100755 index 00000000..48754aad --- /dev/null +++ b/doc/html/example/Mitchell2002/dictionary/main.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "dictionary.hpp" +#include +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + dictionary ages; + + std::cout << std::endl << "has()" << std::endl; + std::cout << ages.has("Galileo") << std::endl; + + std::cout << std::endl << "put()" << std::endl; + ages.put("Galileo", 78); + + std::cout << std::endl << "value_for()" << std::endl; + std::cout << ages.value_for("Galileo") << std::endl; + + std::cout << std::endl << "count()" << std::endl; + std::cout << ages.count() << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + ages.remove("Galileo"); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/Mitchell2002/name_list/main.cpp b/doc/html/example/Mitchell2002/name_list/main.cpp new file mode 100755 index 00000000..ad7e8e14 --- /dev/null +++ b/doc/html/example/Mitchell2002/name_list/main.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "names.hpp" + +int main() { + std::string n = "Galileo"; + + std::cout << std::endl << "constructor()" << std::endl; + name_list nl; + relaxed_name_list rl; + + std::cout << std::endl << "put()" << std::endl; + rl.put(n); + std::cout << std::endl << "put() again (allowed)" << std::endl; + rl.put(n); + + std::cout << std::endl << "put()" << std::endl; + nl.put(n); + std::cout << std::endl << "put() again (not allowed)" << std::endl; + nl.put(n); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/Mitchell2002/name_list/names.cpp b/doc/html/example/Mitchell2002/name_list/names.cpp new file mode 100755 index 00000000..3a7ecd42 --- /dev/null +++ b/doc/html/example/Mitchell2002/name_list/names.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "names.hpp" +#include + +// name_list // + +CONTRACT_CONSTRUCTOR_BODY(name_list, name_list)(void) {} + +CONTRACT_DESTRUCTOR_BODY(name_list, ~name_list)(void) {} + +bool name_list::CONTRACT_BODY(has)(const std::string& name) const { + std::clog << "base has\n"; + return names_.end() != std::find(names_.begin(), names_.end(), + name); +} + +unsigned int name_list::CONTRACT_BODY(count)(void) const { + std::clog << "base count\n"; + return names_.size(); +} + +void name_list::CONTRACT_BODY(put)(const std::string& name) { + std::clog << "base put\n"; + 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_BODY(put)(const std::string& name) { + std::clog << "dervied put\n"; + if (!has(name)) { + // Base class operations must be called via BODY macro. + name_list::CONTRACT_BODY(put)(name); + // name_list::put(name); // ERROR: causes infinite recursion. + } +} + diff --git a/doc/html/example/Mitchell2002/name_list/names.hpp b/doc/html/example/Mitchell2002/name_list/names.hpp new file mode 100755 index 00000000..86a25245 --- /dev/null +++ b/doc/html/example/Mitchell2002/name_list/names.hpp @@ -0,0 +1,127 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Subcontracting example (ported from Eiffel code). + +#ifndef NAMES_HPP_ +#define NAMES_HPP_ + +#include +#include +#include + +/** List of names. */ +class name_list { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create object. */ + name_list(void): names_() + CONTRACT_CONSTRUCTOR( (class) (name_list) + (public) (name_list)( (void) ) + (body) ( + ; + ) ) + + /** Destroy object. */ + virtual ~name_list(void) + CONTRACT_DESTRUCTOR( (class) (name_list) + (public) (virtual) (name_list)( (void) ) + (body) ( + ; + ) ) + + // Queries // + + /** If specified names is in list. */ + bool has(const std::string& name) const + CONTRACT_FUNCTION( (class) (name_list) + (public) (bool) (has)( (const std::string&)(name) ) + (const) + (body) ( + ; + ) ) + + /** Number of names in list. */ + unsigned int count(void) const + CONTRACT_FUNCTION( (class) (name_list) + (public) (unsigned int) (count)( (void) ) (const) + (body) ( + ; + ) ) + + // Commands // + + /** Add name to list. */ + virtual void put(const std::string& name) + CONTRACT_FUNCTION( (class) (copyable)(name_list) + (public) (virtual) (void) (put)( + (const std::string&)(name) ) + (precondition) ({ + CONTRACT_ASSERT( !has(name) ); + }) + (postcondition) ({ + // If-guard to allow subcontracts to relax postconditions. + if (!CONTRACT_OLDOF(this)->has(name)) { + CONTRACT_ASSERT( has(name) ); + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + } + }) + (body) ( + ; + ) ) + +private: + std::list names_; +}; + +/** List of names that allows for duplicates. */ +class relaxed_name_list: public name_list { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + relaxed_name_list(void): name_list() + CONTRACT_CONSTRUCTOR( (class) (relaxed_name_list) + (public) (relaxed_name_list)( (void) ) + (body) ( + ; + ) ) + + virtual ~relaxed_name_list(void) + CONTRACT_DESTRUCTOR( (class) (relaxed_name_list) + (public) (virtual) (relaxed_name_list)( (void) ) + (body) ( + ; + ) ) + + // Commands // + + void put(const std::string& name) + CONTRACT_FUNCTION( (class) (copyable)(relaxed_name_list) + (inherit)(name_list) + (public) (void) (put)( (const std::string&)(name) ) + (precondition) ({ + // Relax inherited precondition `!has(name)`. + CONTRACT_ASSERT( has(name) ); + }) + (postcondition) ({ + // Inherited postcondition not checked because of its if-guard. + if (CONTRACT_OLDOF(this)->has(name)) CONTRACT_ASSERT( + count() == CONTRACT_OLDOF(this)->count() ); + }) + (body) ( + ; + ) ) +}; + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/observe/main.cpp b/doc/html/example/Mitchell2002/observe/main.cpp new file mode 100755 index 00000000..d98564a7 --- /dev/null +++ b/doc/html/example/Mitchell2002/observe/main.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "observe.hpp" +#include +#include + +/** Implement an actual subject. */ +class concrete_subject: public subject { +public: + /** State being observed. */ + typedef int state; + + concrete_subject(): state_() {} + + /** Set state being observed. */ + void set_state(const state& the_state) { + std::cout << "Changing state to " << the_state << std::endl; + state_ = the_state; + notify(); // Notify observers. + } + + /** Get state being observed. */ + state get_state() const { return state_; } + +private: + state state_; +}; + +/** Implement of actual observer. */ +class concrete_observer: public observer { +public: + /** Create concrete observer. */ + concrete_observer(const concrete_subject& the_subject): + subject_(the_subject), observed_state_() {} + +private: + bool up_to_date_with_subject(void) const + CONTRACT_FUNCTION( (class) (concrete_observer) (inherit)(observer) + (private) (bool) (up_to_date_with_subject)( (void) ) + (const) + (body) ({ + return true; // For simplicity, always true. + }) ) + + void update(void) + CONTRACT_FUNCTION( (class) (concrete_observer) (inherit)(observer) + (private) (void) (update)( (void) ) + (body) ({ + observed_state_ = subject_.get_state(); + std::cout << "Observed state " << observed_state_ + << std::endl; + }) ) + + const concrete_subject& subject_; + concrete_subject::state observed_state_; +}; + +int main() { + std::cout << std::endl << "Constructing objects" << std::endl; + concrete_subject sbj; + concrete_observer ob(sbj); + + std::cout << std::endl << "Attaching observer " << &ob + << std::endl; + sbj.attach(&ob); + + concrete_subject::state st = -10; + std::cout << std::endl << "Setting state to " << st << std::endl; + sbj.set_state(st); + + st = +10; + std::cout << std::endl << "Re-setting state to " << st << std::endl; + sbj.set_state(st); + + std::cout << std::endl << "Destructing objects" << std::endl; + return 0; +} + diff --git a/doc/html/example/Mitchell2002/observe/observe.hpp b/doc/html/example/Mitchell2002/observe/observe.hpp new file mode 100755 index 00000000..c1fbfba1 --- /dev/null +++ b/doc/html/example/Mitchell2002/observe/observe.hpp @@ -0,0 +1,184 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// A frame rule for observer design pattern (ported from Eiffel code). + +#ifndef OBSERVE_HPP_ +#define OBSERVE_HPP_ + +#include +#include +#include + +/** Observer. */ +class observer { + friend class subject; + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create observer. */ + observer(void) + CONTRACT_CONSTRUCTOR( (class) (observer) + (public) (observer)( (void) ) + (body) ({ + }) ) + + /** Destroy observer. */ + virtual ~observer(void) + CONTRACT_DESTRUCTOR( (class) (observer) + (public) (virtual) (observer)( (void) ) + (body) ({ + }) ) + +protected: + // Commands // + + /** If up to date with its subject. */ + virtual bool up_to_date_with_subject(void) const + CONTRACT_FUNCTION( (class) (observer) + (protected) (virtual) (bool) (up_to_date_with_subject)( + (void) ) (const) + (body) ( + = 0; + ) ) + + virtual void update(void) + CONTRACT_FUNCTION( (class) (observer) + (protected) (virtual) (void) (update)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( up_to_date_with_subject() ); + }) + (body) ( + = 0; + ) ) +}; + +/** Subject for observer design pattern. */ +class subject { + + CONTRACT_INVARIANT( ({ + for (std::list::const_iterator + i = observers_.begin(); i != observers_.end(); ++i) + CONTRACT_ASSERT( *i ); + }) ) + +public: + // Creation // + + /** Construct subject. */ + subject(void): observers_() + CONTRACT_CONSTRUCTOR( (class) (subject) + (public) (subject)( (void) ) + (body) ({ + }) ) + + /** Destroy subject. */ + virtual ~subject(void) + CONTRACT_DESTRUCTOR( (class) (subject) + (public) (virtual) (subject)( (void) ) + (body) ({ + }) ) + + // Queries // + + /** If given observer is attached. */ + bool attached(const observer* const ob) const + CONTRACT_FUNCTION( (class) (subject) + (public) (bool) (attached)( (const observer* const)(ob) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( ob ); + }) + (postcondition) (result) ({ + const std::list obs = observers(); + CONTRACT_ASSERT( result == (std::find(obs.begin(), obs.end(), + ob) != obs.end()) ); + }) + (body) ({ + return std::find(observers_.begin(), observers_.end(), + ob) != observers_.end(); + }) ) + + // Commands // + + /** Remember given objects as on of the subject observers. */ + void attach(observer* const ob) + CONTRACT_FUNCTION( (class) (copyable)(subject) + (public) (void) (attach)( (observer* const)(ob) ) + (precondition) ({ + CONTRACT_ASSERT( ob ); + CONTRACT_ASSERT( !attached(ob) ); + }) + (postcondition) ({ + CONTRACT_ASSERT( attached(ob) ); + + // Frame rule. + const std::list& old = + CONTRACT_OLDOF(this)->observers(); + std::list now = observers(); + std::remove(now.begin(), now.end(), ob); + std::list::const_iterator nowi = now.begin(); + std::list::const_iterator oldi = old.begin(); + while (now.end() != nowi && old.end() != oldi) { + CONTRACT_ASSERT_MSG( *nowi == *oldi, + "all other observers unchanged" ); + ++nowi; + ++oldi; + } + }) + (body) ({ + observers_.push_back(ob); + }) ) + +protected: + // Queries // + + /** All observers attached to this subject. + * This is protected because it is intended to support contract + * specification only (including contracts of derived classes). + * See related discussion in [Mitchell2002] Section 9.9. */ + std::list observers(void) const + CONTRACT_FUNCTION( (class) (subject) + (protected) (std::list) + (observers)( (void) ) (const) + (body) ({ + // 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 // + + /** Update all attached observers. */ + void notify(void) + CONTRACT_FUNCTION( (class) (subject) + (protected) (void) (notify)( (void) ) + (postcondition) ({ + const std::list obs = observers(); + for (std::list::const_iterator + i = obs.begin(); i != obs.end(); ++i) { + CONTRACT_ASSERT( *i ); + CONTRACT_ASSERT( (*i)->up_to_date_with_subject() ); + } + }) + (body) ({ + for (std::list::iterator + i = observers_.begin(); i != observers_.end(); ++i) + // Invariant ensures no null pointers in observers. + (*i)->update(); + }) ) + +private: + std::list observers_; +}; + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/simple_queue/main.cpp b/doc/html/example/Mitchell2002/simple_queue/main.cpp new file mode 100755 index 00000000..bd2f0854 --- /dev/null +++ b/doc/html/example/Mitchell2002/simple_queue/main.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "simple_queue.hpp" +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + simple_queue q(10); + + std::cout << std::endl << "count()" << std::endl; + std::cout << q.count() << std::endl; + + std::cout << std::endl << "put()" << std::endl; + q.put('a'); + std::cout << std::endl << "put() (again)" << std::endl; + q.put('b'); + + std::cout << std::endl << "items()" << std::endl; + const std::vector& items = q.items(); + for (std::vector::const_iterator i = items.begin(); + items.end() != i; ++i) { + std::cout << *i << std::endl; + } + + std::cout << std::endl << "capacity()" << std::endl; + std::cout << q.capacity() << std::endl; + + std::cout << std::endl << "head()" << std::endl; + std::cout << q.head() << std::endl; + + std::cout << std::endl << "is_empty()" << std::endl; + std::cout << q.is_empty() << std::endl; + + std::cout << std::endl << "is_full()" << std::endl; + std::cout << q.is_full() << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + q.remove(); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/Mitchell2002/simple_queue/simple_queue.hpp b/doc/html/example/Mitchell2002/simple_queue/simple_queue.hpp new file mode 100755 index 00000000..971c6148 --- /dev/null +++ b/doc/html/example/Mitchell2002/simple_queue/simple_queue.hpp @@ -0,0 +1,164 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for an Eiffel-like simple queue (ported from Eiffel code). + +#ifndef SIMPLE_QUEUE_HPP_ +#define SIMPLE_QUEUE_HPP_ + +#include +#include + +/** Simple queue. */ +template +class simple_queue { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( count() >= 0 ); + }) ) + +public: + // Creation // + + /** Create empty queue. */ + simple_queue(const int& the_capacity): items_() + CONTRACT_CONSTRUCTOR( (class) (simple_queue) + (public) (simple_queue)( (const int&)(the_capacity) ) + (precondition) ({ + CONTRACT_ASSERT( the_capacity >= 1 ); + }) + (postcondition) ({ + CONTRACT_ASSERT( capacity() == the_capacity ); + CONTRACT_ASSERT( is_empty() ); + }) + (body) ({ + items_.reserve(the_capacity); + }) ) + + /** Destroy queue. */ + virtual ~simple_queue(void) + CONTRACT_DESTRUCTOR( (class) (simple_queue) + (public) (virtual) (simple_queue)( (void) ) + (body) ({ + }) ) + + // Basic Queries // + + /** Items in the queue (in their order). */ + const std::vector& items(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (const std::vector&) (items)( (void) ) (const) + (body) ({ + return items_; + }) ) + + /** Maximum number of items queue can hold. */ + int capacity(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (int) (capacity)( (void) ) (const) + (body) ({ + return items_.capacity(); + }) ) + + // Derived Queries // + + /** Number of items. */ + int count(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (int) (count)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == int(items().size()) ); + }) + (body) ({ + return items_.size(); + }) ) + + /** Item at head. */ + const T& head(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (const T&) (head)( (void) ) (const) + (precondition) ({ + CONTRACT_ASSERT( !is_empty() ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == items().at(0) ); + }) + (body) ({ + return items_.at(0); + }) ) + + /** If queue contains no items. */ + bool is_empty(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (bool) (is_empty)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (0 == count()) ); + }) + (body) ({ + return 0 == items_.size(); + }) ) + + /** If queue has no room for another item. */ + bool is_full(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (bool) (is_full)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == + (int(items().size()) == capacity()) ); + }) + (body) ({ + return items_.size() == items_.capacity(); + }) ) + + // Commands // + + /** Remove head item shifting all other items accordingly. */ + void remove(void) + CONTRACT_FUNCTION( (class) (copyable)(simple_queue) + (public) (void) (remove)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !is_empty() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() - 1) ); + + for (size_t i = 1; i < CONTRACT_OLDOF(this)->items().size(); + ++i) + CONTRACT_ASSERT( items().at(i - 1) == + CONTRACT_OLDOF(this)->items().at(i) ); + }) + (body) ({ + items_.erase(items_.begin()); + }) ) + + /** Add item to tail. */ + void put(const T& item) + CONTRACT_FUNCTION( (class) (copyable)(simple_queue) + (public) (void) (put)( (const T&)(item) ) + (precondition) ({ + CONTRACT_ASSERT( count() < capacity() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT( items().at(count() - 1) == item ); + if (count() >= 2) { + for (int i = 0; i < CONTRACT_OLDOF(this)->count(); ++i) { + CONTRACT_ASSERT( items().at(i) == + CONTRACT_OLDOF(this)->items().at(i) ); + } + } + }) + (body) ({ + items_.push_back(item); + }) ) + +private: + std::vector items_; +}; + +#endif // #include guard + diff --git a/doc/html/example/Mitchell2002/stack/main.cpp b/doc/html/example/Mitchell2002/stack/main.cpp new file mode 100755 index 00000000..613592ad --- /dev/null +++ b/doc/html/example/Mitchell2002/stack/main.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "stack.hpp" +#include +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + stack s; + + std::cout << std::endl << "count()" << std::endl; + std::cout << s.count() << std::endl; + + std::cout << std::endl << "put()" << std::endl; + s.put("Galileo"); + + std::cout << std::endl << "item_at()" << std::endl; + std::cout << s.item_at(1) << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + s.remove(); + + std::cout << std::endl << "is_empty()" << std::endl; + std::cout << s.is_empty() << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/Mitchell2002/stack/stack.hpp b/doc/html/example/Mitchell2002/stack/stack.hpp new file mode 100755 index 00000000..68f86fe4 --- /dev/null +++ b/doc/html/example/Mitchell2002/stack/stack.hpp @@ -0,0 +1,127 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for an Eiffel-like stack (ported from Eiffel code). + +#ifndef STACK_HPP_ +#define STACK_HPP_ + +#include +#include + +/** Simple stack. */ +template +class stack { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( count() >= 0 ); + }) ) + +public: + // Creation // + + /** Create empty stack. */ + stack(void): items_() + CONTRACT_CONSTRUCTOR( (class) (stack) + (public) (stack)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( count() == 0 ); + }) + (body) ({ + }) ) + + /** Destroy stack. */ + ~stack(void) + CONTRACT_DESTRUCTOR( (class) (stack) + (public) (stack)( (void) ) + (body) ({ + }) ) + + // Basic Queries // + + /** Number of items. */ + int count(void) const + CONTRACT_FUNCTION( (class) (stack) + (public) (int) (count)( (void) ) (const) + (body) ({ + return items_.size(); + }) ) + + /** Item at index in [1, count()] (Eiffel index starts at 1). */ + const T& item_at(const int& index) const + CONTRACT_FUNCTION( (class) (stack) + (public) (const T&) (item_at)( (const int&)(index) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( index >= 1 ); + CONTRACT_ASSERT( index <= count() ); + }) + (body) ({ + return items_.at(index - 1); + }) ) + + // Derived Queries // + + /** If no items. */ + bool is_empty(void) const + CONTRACT_FUNCTION( (class) (stack) + (public) (bool) (is_empty)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (count() == 0) ); + }) + (body) ({ + return items_.size() == 0; + }) ) + + /** Top item. */ + const T& item(void) const + CONTRACT_FUNCTION( (class) (stack) + (public) (const T&) (item)( (void) ) (const) + (precondition) ({ + CONTRACT_ASSERT( count() > 0 ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == item_at(count()) ); + }) + (body) ({ + return items_.at(items_.size() - 1); + }) ) + + // Commands // + + /** Push new item to the top. */ + void put(const T& new_item) + CONTRACT_FUNCTION( (class) (copyable)(stack) + (public) (void) (put)( (const T&)(new_item) ) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT( item() == new_item ); + }) + (body) ({ + items_.push_back(new_item); + }) ) + + /** Pop top item. */ + void remove(void) + CONTRACT_FUNCTION( (class) (copyable)(stack) + (public) (void) (remove)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( count() > 0 ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() - 1) ); + }) + (body) ({ + items_.resize(items_.size() - 1); + }) ) + +private: + std::vector items_; +}; + +#endif // #include guard + diff --git a/doc/html/example/README.txt b/doc/html/example/README.txt new file mode 100755 index 00000000..2827ee21 --- /dev/null +++ b/doc/html/example/README.txt @@ -0,0 +1,6 @@ +Examples that illustrate how to use the library to write contracts. + +Many of these examples are taken from books and articles. The +directory names reflect the example source -- see the library +documentation for a complete reference list. + diff --git a/doc/html/example/Stroustrup1997/README.txt b/doc/html/example/Stroustrup1997/README.txt new file mode 100755 index 00000000..5c6c6564 --- /dev/null +++ b/doc/html/example/Stroustrup1997/README.txt @@ -0,0 +1 @@ +Examples taken from B. Stroustrup. "The C++ Programming Language", 1997. diff --git a/doc/html/example/Stroustrup1997/string/main.cpp b/doc/html/example/Stroustrup1997/string/main.cpp new file mode 100755 index 00000000..8b2cd33a --- /dev/null +++ b/doc/html/example/Stroustrup1997/string/main.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "string.hpp" +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + String s("Galileo"); + + std::cout << std::endl << "operator[]" << std::endl; + std::cout << s[0] << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/Stroustrup1997/string/string.cpp b/doc/html/example/Stroustrup1997/string/string.cpp new file mode 100755 index 00000000..f919ec16 --- /dev/null +++ b/doc/html/example/Stroustrup1997/string/string.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "string.hpp" + +CONTRACT_CONSTRUCTOR_BODY(String, String)(const char* q) { + sz = strlen(q); + p = new char[sz + 1]; + for (int i = 0; i < sz; ++i) p[i] = q[i]; + p[sz] = '\0'; +} + +CONTRACT_DESTRUCTOR_BODY(String, ~String)(void) { delete[] p; } + +char& String::CONTRACT_BODY(operator([], at))(int i) { + // check invariant and preconditions on entry + return p[i]; // do work + // check invariant on exit +} + +int String::CONTRACT_BODY(size)(void) { return sz; } + diff --git a/doc/html/example/Stroustrup1997/string/string.hpp b/doc/html/example/Stroustrup1997/string/string.hpp new file mode 100755 index 00000000..fb6e24b6 --- /dev/null +++ b/doc/html/example/Stroustrup1997/string/string.hpp @@ -0,0 +1,70 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Example of invariant and simple preconditions that throw user +// defined exception on contract failure. + +#include + +// Adapted from an example presented in [Stroustrup1997] to illustrate +// importance of invariants. Simple preconditions were added where it +// made sense. This should be compiled with CHECK_POSTCONDITION off +// because postconditions are deliberately not used. +// See [Stroustrup1997] for a discussion on the importance of +// invariants, and on pros and cons of using pre and post conditions. +class String { + + CONTRACT_INVARIANT( ({ + if (p == 0 || sz < 0 || TOO_LARGE <= sz || p[sz]) + throw Invariant(); + }) ) + + int sz; + char* p; + +public: + class Range {}; // exception classes + class Invariant {}; + class Null {}; + class Too_large {}; + + enum { TOO_LARGE = 16000 }; // length limit + + String(const char* q) + CONTRACT_CONSTRUCTOR( (class) (String) + (public) (String)( (const char*)(q) ) + (precondition) ({ + if (!q) throw Null(); + if (strlen(q) > TOO_LARGE) throw Too_large(); + }) + (body) ( + ; + ) ) + + ~String(void) + CONTRACT_DESTRUCTOR( (class) (String) + (public) (String)( (void) ) + (body) ( + ; + ) ) + + char& operator[](int i) + CONTRACT_FUNCTION( (class) (String) + (public) (char&) (operator([], at))( (int)(i) ) + (precondition) ({ + if (i < 0 || sz <= i) throw Range(); + }) + (body) ( + ; + ) ) + + int size(void) + CONTRACT_FUNCTION( (class) (String) + (public) (int) (size)( (void) ) + (body) ( + ; + ) ) +}; + diff --git a/doc/html/example/commas/README.txt b/doc/html/example/commas/README.txt new file mode 100755 index 00000000..848068a8 --- /dev/null +++ b/doc/html/example/commas/README.txt @@ -0,0 +1 @@ +Show how to pass commas within macro parameters (used by documentation). diff --git a/doc/html/example/commas/main.cpp b/doc/html/example/commas/main.cpp new file mode 100755 index 00000000..2838ec77 --- /dev/null +++ b/doc/html/example/commas/main.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Show workarounds to pass commas within macro parameters. + +#include +#include +#include + +template +void print(const K& key, const T& element) { + std::cout << key << " -> " << element << std::endl; +} + +//[ commas_cpp + +template +std::map fill(const std::map& source, + const K& key, const T& element) +CONTRACT_FUNCTION( + (template)( (typename)(K) (typename)(T) ) + // Commas within type expression using the macro. + (typename CONTRACT_WRAP_TYPE( (std::map) )) (set)( + // Or equivalently, not using the macro. + (typename contract::wrap&) >::type)(source) + (const K&)(key) (const T&)(element) ) +(precondition) ({ + // Commas within value expressions must be wrapped by `()`. + CONTRACT_ASSERT( (std::map().empty()) ); +}) +(body) ({ + // Commas within code blocks use same workarounds as above + // wrapping differently commas within type or value expressions. + // Or better, separate body definition so it is outside the macro. + + // OK, commas already wrapped by function call `()`. + print(key, element); + + // Commas within type expression wrapped using the macro. + typename CONTRACT_WRAP_TYPE((std::map)) m = source; + + // OK, commas already wrapped by if-statement `()`. + if (0 == std::map().empty()) m[key] = element; + + return m; +}) ) + +//] + +int main() { + std::map m1; + std::map m2 = set(m1, 1, 2.3); + return 0; +} + diff --git a/doc/html/example/myvector/README.txt b/doc/html/example/myvector/README.txt new file mode 100755 index 00000000..d01ffc60 --- /dev/null +++ b/doc/html/example/myvector/README.txt @@ -0,0 +1 @@ +This is the main example used in the library documentation. diff --git a/doc/html/example/myvector/basic_begin.hpp b/doc/html/example/myvector/basic_begin.hpp new file mode 100755 index 00000000..4291ffe2 --- /dev/null +++ b/doc/html/example/myvector/basic_begin.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Base class for a myvector subcontracting example. + +#ifndef BASIC_BEGIN_HPP_ +#define BASIC_BEGIN_HPP_ + +//[ basic_begin_cpp + +#include + +template +class basic_begin { + + CONTRACT_INVARIANT( ({}) ) + +public: + virtual ConstIter begin(void) const + CONTRACT_FUNCTION( (class) (basic_begin) + (public) (virtual) (ConstIter) (begin)( (void) ) (const) + (body) ({ + return ConstIter(); // Dummy implementation (for example only). + }) ) +}; + +//] + +#endif // #include guard + diff --git a/doc/html/example/myvector/boundable.hpp b/doc/html/example/myvector/boundable.hpp new file mode 100755 index 00000000..bc8ce4d0 --- /dev/null +++ b/doc/html/example/myvector/boundable.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Base class for a myvector subcontracting example. + +#ifndef BOUNDABLE_HPP_ +#define BOUNDABLE_HPP_ + +//[ boundable_cpp + +#include + +template +class boundable { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( begin() <= end() ); + }) ) + +public: + virtual ConstIter begin(void) const + CONTRACT_FUNCTION( (class) (boundable) + (public) (virtual) (ConstIter) (begin)( (void) ) (const) + (body) (= 0;) ) + + virtual ConstIter end(void) const = 0; +}; + +//] + +#endif // #include guard + diff --git a/doc/html/example/myvector/main.cpp b/doc/html/example/myvector/main.cpp new file mode 100755 index 00000000..85b5b343 --- /dev/null +++ b/doc/html/example/myvector/main.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "myvector.hpp" +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + myvector v(3); + const myvector& cv = v; // A reference, no copy. + + std::cout << std::endl << "copy constructor()" << std::endl; + myvector w(v); + + std::cout << std::endl << "begin()" << std::endl; + myvector::iterator b = v.begin(); + std::cout << *b << std::endl; + + std::cout << std::endl << "begin() const" << std::endl; + myvector::const_iterator cb = cv.begin(); + std::cout << *cb << std::endl; + + std::cout << std::endl << "insert()" << std::endl; + v.insert(b, 2, -3.21); + + std::cout << std::endl << "operator[]" << std::endl; + double v0 = v[0]; + std::cout << v0 << std::endl; + + std::cout << std::endl << "push_back()" << std::endl; + v.push_back(1.23); + + std::cout << std::endl << "all_equals()" << std::endl; + bool eq = myvector::all_equals(v.begin(), v.end(), 1.23); + std::cout << eq << std::endl; // It will be false. + + std::cout << std::endl << "abs_total()" << std::endl; + double tot = abs_total(v); + std::cout << tot << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/myvector/main_nomacros.cpp b/doc/html/example/myvector/main_nomacros.cpp new file mode 100755 index 00000000..d2667bff --- /dev/null +++ b/doc/html/example/myvector/main_nomacros.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "myvector_nomacros.hpp" +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + myvector v(3); + + std::cout << std::endl << "push_back()" << std::endl; + v.push_back(1.23); + + std::cout << std::endl << "all_equals()" << std::endl; + bool eq = myvector::all_equals(v.begin(), v.end(), 1.23); + std::cout << eq << std::endl; // It will be false. + + std::cout << std::endl << "abs_total()" << std::endl; + double tot = abs_total(v); + std::cout << tot << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/doc/html/example/myvector/myvector.hpp b/doc/html/example/myvector/myvector.hpp new file mode 100755 index 00000000..31b56fb4 --- /dev/null +++ b/doc/html/example/myvector/myvector.hpp @@ -0,0 +1,245 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Main documentation example that illustrates most library uses. + +#ifndef MYVECTOR_HPP_ +#define MYVECTOR_HPP_ + +//[ myvector_cpp + +// Base classes for subcontracting. +#include "pushable.hpp" +#include "boundable.hpp" +#include "basic_begin.hpp" +#include // This library. +#include // For `boost::prior()`. +#include // STL vector. + +// Wrapper that adds simple (not complete) contracts to C++ STL illustrating +// most library usages. For simplicity, assume T is comparable and copyable. +template +class myvector: public pushable, + public boundable::const_iterator>, + private basic_begin::const_iterator> { + + // Class invariants (checked by any function with a contract). + CONTRACT_INVARIANT( + (static)({ // Static invariants (optional). + // Static class invariants `(static)({ ... })` are optional and they + // could have been omitted since they assert nothing in this example. + // When present, they can only access static members. + }) ({ // Non-static invariants (can access object). + CONTRACT_ASSERT( (size() == 0) == empty() ); + // More invariants here... + }) ) + +public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::const_reference const_reference; + + // Contract for constructor. + explicit myvector(size_type count): vector_(count) + CONTRACT_CONSTRUCTOR( // Constructor contract macro. + (class) (myvector) // Constructor signature. + (public) (myvector)( (size_type)(count) ) + // Never object `this` in constructor preconditions. + (postcondition) ({ + // Never `CONTRACT_OLDOF(this)` in constructor postconditions. + CONTRACT_ASSERT( size() == count ); + }) + (body) ({ + // Do nothing in this case. + }) ) + + // Contractor for overloaded member (resolved by argumnet name). + myvector(const myvector& right) + CONTRACT_CONSTRUCTOR( (class) (myvector) + (public) (myvector)( (const myvector&)(right) ) + (postcondition) ({ + CONTRACT_ASSERT( vector_ == right.vector_ ); + }) + (body) (;) ) // Deferres body definition. + + // Contract for destructor. + virtual ~myvector(void) + CONTRACT_DESTRUCTOR( // Destructor contract macro. + (class) (myvector) // Destructor signature. + // Must use `(void)` for no arguments. + (public) (virtual) (myvector)( (void) ) + // No preconditions allowed (no arguments). + // No postconditions allowed (no object after destructor). + (body) (;) ) + + // Contract for member function. + void insert(iterator where, size_type count, const T& element) + CONTRACT_FUNCTION( // Function contract macro. + (class) (copyable)(myvector) // Function signature. + // Old values for object `this` and argument `where`. + (public) (void) (insert)( (copyable)(iterator)(where) + (size_type)(count) (const T&)(element) ) + (precondition) ({ // Function preconditions (optional). + CONTRACT_ASSERT( (size() + count) <= max_size() ); + // More preconditions here... + }) + (postcondition) ({ // Function postconditions (optional). + // Any C++ code allowed in contracts (but keep it simple). + // Old values of types tagged copyable via `CONTRACT_OLDOF()`. + if (capacity() == CONTRACT_OLDOF(this)->capacity()) { + CONTRACT_ASSERT( all_equals( + boost::prior(CONTRACT_OLDOF(where)), + boost::prior(CONTRACT_OLDOF(where)) + count, + element) ); + } + // More postconditions here... + }) + (body) ({ // Function body (mandatory). + vector_.insert(where, count, element); + }) ) + + // Contract for constant member. + const_iterator begin(void) const + CONTRACT_FUNCTION( (class) (myvector) + // Subcontracting for multiple inheritance. + (inherit)(boundable) + (inherit)(basic_begin) + (public) (const_iterator) // Non-void result type. + (begin)( (void) ) (const) // Constant. + (postcondition) (result) ({ // Named result value. + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ({ + return vector_.begin(); + }) ) + + // Contract for overloaded member (resolved because not const). + iterator begin(void) + CONTRACT_FUNCTION( (class) (myvector) (public) + (iterator) (begin)( (void) ) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ( + ; + ) ) + + // Contract for operator. + const_reference operator[](size_type index) const + CONTRACT_FUNCTION( (class) (myvector) + // Must spell operator name also in words). + (public) (const_reference) (operator([], at))( + (size_type)(index) ) (const) + (precondition) ({ + CONTRACT_ASSERT( index < size() ); + }) + (body) (;) ) + + // Main function example used in documentation. + void push_back(const T& element) + CONTRACT_FUNCTION( + (class) (copyable)(myvector) (inherit)(pushable) + (public) (void) (push_back)( (const T&)(element) ) + (precondition) ({ + CONTRACT_ASSERT( size() < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + }) + (body) ({ + vector_.push_back(element); + }) ) + + // Contract for template plus static member function. + template + static bool all_equals(Iter first, Iter last, const T& element) + CONTRACT_FUNCTION( (class) (myvector) + (public) (template)( (class)(Iter) ) // Function template. + (static) (bool) (all_equals)( // Static member. + (Iter)(first) (Iter)(last) (const T&)(element) ) + (precondition) ({ + CONTRACT_ASSERT( first < last ); + }) + (body) ({ + // For simplicity, let's assume T can be compared. + for (Iter i = first; i < last; ++i) { + if (*i != element) return false; + } + return true; + }) ) + + // Similarly, complete contracts sketched here and add contracts + // for all other functions (see [Crowl2006] vector example). + bool empty(void) const { return vector_.empty(); } + size_type size(void) const { return vector_.size(); } + size_type max_size(void) const { return vector_.max_size(); } + size_type capacity(void) const { return vector_.capacity(); } + iterator end(void) { return vector_.end(); } + const_iterator end(void) const { return vector_.end(); } + const_reference back(void) const { return vector_.back(); } + +private: + std::vector vector_; +}; + +// Deferred constructor body definition. +template +CONTRACT_CONSTRUCTOR_BODY(myvector, myvector)( + const myvector& right) { + vector_ = right.vector_; +} + +// Deferred destructor body definition. +template +CONTRACT_DESTRUCTOR_BODY(myvector, myvector)(void) { + // Do nothing in this case. +} + +// Deferred member function definition. +template +typename myvector::iterator myvector::CONTRACT_BODY(begin)( + void) { + return vector_.begin(); +} + +// Deferred member operator definition. +template +typename myvector::const_reference myvector:: + CONTRACT_BODY(operator([], at))( + size_type index) const { + return vector_[index]; +} + +// Contract for non-member function. +double abs_total(const myvector& vector) +CONTRACT_FUNCTION( + (double) (abs_total)( (const myvector&)(vector) ) +(postcondition) (total) ({ // Result value named `total`. + CONTRACT_ASSERT( total >= 0.0 ); +}) +(body) ({ + double total = 0.0; + // Block invariants can appear anywhere in code block. + CONTRACT_ASSERT_BLOCK_INVARIANT( total == 0.0 ); + + { // Variant initialized locally to its loop. + CONTRACT_INIT_LOOP_VARIANT; + for (size_t i = 0; i < vector.size(); ++i) { + // Block invariants used to assert loop invariants. + CONTRACT_ASSERT_BLOCK_INVARIANT( i < vector.size() ); + // Loop variant (can only appear in loops). + CONTRACT_ASSERT_LOOP_VARIANT( vector.size() - i ); + + total += vector[i]; + } + } + return total < 0.0 ? -total : total; +}) ) + +//] + +#endif // #include guard + diff --git a/doc/html/example/myvector/myvector_nomacros.hpp b/doc/html/example/myvector/myvector_nomacros.hpp new file mode 100755 index 00000000..e9b01728 --- /dev/null +++ b/doc/html/example/myvector/myvector_nomacros.hpp @@ -0,0 +1,320 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Main documentation example that illustrates contracts without the macros. + +#ifndef MYVECTOR_NOMACROS_HPP_ +#define MYVECTOR_NOMACROS_HPP_ + +//[ myvector_nomacros_cpp + +#include "pushable.hpp" // Base class for subcontracting. +#include // This library. +#include // STL vector. + +// Wrapper that adds simple (not complete) contracts to C++ STL +// without using the library contract macros. +template +class myvector: public pushable { + +#if defined CONTRACT_CHECK_CLASS_INVARIANT || /* Allow for */ \ + defined CONTRACT_CHECK_PRECONDITION || /* optional contract */ \ + defined CONTRACT_CHECK_POSTCONDITION /* compilation. */ + // Augmented state. + friend class contract::state; + mutable contract::state contract_state_; +#endif // contracts + +#if defined CONTRACT_CHECK_CLASS_INVARIANT + // Static class invariants + static void contract_static_invariant_(void) { + // Assert nothing in this case. + } + // Class invariants. + void contract_invariant_(void) const { + if (!((size() == 0) == empty())) + throw contract::failure(__FILE__, __LINE__); + // More invariants here... + } +#endif // invariants + +public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::const_reference const_reference; + typedef typename std::vector::const_iterator const_iterator; + + // Contract for constructor. + explicit myvector(size_type count): vector_(count) +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + { + contract_contract_constructor_count_<0>().call(this, count); + } +private: +#if defined CONTRACT_CHECK_PRECONDITION + // Static preconditions (i.e., no object). + static void contract_precondition_contract_constructor_count_( + const size_type& count) /* no `const` (it is `static`) */ { + } +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + void contract_postcondition_contract_constructor_count_( + contract::noold, // Always `noold` for old object. + const size_type& count, contract::noold) const { + if (!(size() == count)) + throw contract::failure(__FILE__, __LINE__); + } +#endif // postconditions +protected: + void contract_body_contract_constructor_(size_type count) +#endif // contracts + { + // Do nothing in this case + } +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + template + struct contract_contract_constructor_count_: + contract::constructor< // Use `constructor` (not `function`). + // Class type can never be tagged `copyable`. + void (myvector*, size_type)> { + contract_contract_constructor_count_(): contract::constructor < + void (myvector*, size_type) + >( &myvector::contract_body_contract_constructor_ + , &myvector::contract_precondition_contract_constructor_count_ + , &myvector::contract_postcondition_contract_constructor_count_ + ) {} + }; +public: +#endif // contracts + + // Contract for destructor. + virtual ~myvector(void) + // Destructors only check invariants. +#if defined CONTRACT_CHECK_CLASS_INVARIANT + { + contract_contract_destructor_<0>().call(this); + } +protected: + // No precondition and no postcondition functions. + virtual void contract_body_contract_destructor_(void) +#endif // invariant + { + // Do nothing in this case. + } +#if defined CONTRACT_CHECK_CLASS_INVARIANT + template + struct contract_contract_destructor_: + contract::destructor< // Use `destructor` (not `function`). + // Class type can never be tagged `copyable`. + void (myvector*)> { + contract_contract_destructor_(): contract::destructor< + void (myvector*) + >(&myvector::contract_body_contract_destructor_ ) {} + }; +public: +#endif // invariant + + // Contract for non-static member functions. + void push_back(const T& element) +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + // Contracted function. + { + contract_push_back_element_<0>().call(this , element); + } +private: // Private so not to alter user call public API. +#if defined CONTRACT_CHECK_PRECONDITION + void contract_precondition_push_back_element_(const T& element) const { + if (!(size() < max_size())) + throw contract::failure(__FILE__, __LINE__); + // More preconditions here... + } +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + void contract_postcondition_push_back_element_( + const myvector* contract_old_this_, // Old value for object. + const T& element, contract::noold // No old for element argument. + ) const { + if (!(size() == (contract_old_this_->size() + 1))) + throw contract::failure(__FILE__, __LINE__); + // More postconditions here... + } +#endif // postconditions +protected: // Must be protected (not private) to allow subcontracting. + void contract_body_push_back_(const T& element) +#endif // contracts + // Original function definition (the body). + { + vector_.push_back(element); + } +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + // Contract class. + template + struct contract_push_back_element_: contract::nonstatic_member_function< + // Function type for contracted function. + // Copyable class type for old object value in postconditions. + // For constant members, change `myvector` to `myvector const`. + void (contract::copyable*, const T&), + // Base contract class for subcontracting. + typename pushable::template contract_push_back_element_<0> + > { + // Constructor specifies body, preconditions, and postconditions. + contract_push_back_element_(): contract::nonstatic_member_function< + void (contract::copyable*, const T&), + typename pushable::template contract_push_back_element_<0> + >( &myvector::contract_body_push_back_ +#if defined CONTRACT_CHECK_PRECONDITION + , &myvector::contract_precondition_push_back_element_ +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + , &myvector::contract_postcondition_push_back_element_ +#endif // postconditions + ) {} + }; +public: // Restore original access level. +#endif // contracts + + // Contract for template plus static member function. + template + static bool all_equals(Iter first, Iter last, const T& element) + // Static members also check (static) class invariants. +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + { + return contract_all_equals_first_last_element_().call( + first, last, element); + } +private: + // Static template precondition and postcondition functions. +#if defined CONTRACT_CHECK_PRECONDITION + template + static void contract_precondition_all_equals_first_last_element_( + const Iter& first, const Iter& last, const T& element) + /* no `const` */ { + if (!(first < last)) + throw contract::failure(__FILE__, __LINE__); + } +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + template + static void contract_postcondition_all_equals_first_last_element_( + const Iter& first, contract::noold, + const Iter& last, contract::noold, + const T& element, contract::noold, + const bool& result ) // Result value. + /* no `const` */ { + } +#endif // postconditions +protected: + template + static bool contract_body_all_equals_( + Iter first, Iter last, const T& element) +#endif // contracts + { + for (Iter i = first; i < last; ++i) { + if (*i != element) return false; + } + return true; + } +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + // Function template parameter `class Iter` already present so + // no artificial `int ZERO` parameter. + template + struct contract_all_equals_first_last_element_: contract::static_member_function< + bool (myvector*, Iter, Iter, const T&) + > { + contract_all_equals_first_last_element_(): contract:: static_member_function< + bool (myvector*, Iter, Iter, const T&) + >( &myvector::template contract_body_all_equals_ +#if defined CONTRACT_CHECK_PRECONDITION + , &myvector::template contract_precondition_all_equals_first_last_element_ +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + , &myvector::template contract_postcondition_all_equals_first_last_element_ +#endif // postconditions + ) {} + }; +public: +#endif // contracts + + // Similarly, complete contracts sketched here and add contracts + // for all other functions (see [Crowl2006] vector example). + size_type size(void) const { return vector_.size(); } + size_type max_size(void) const { return vector_.max_size(); } + bool empty(void) const { return vector_.empty(); } + const_reference back(void) const { return vector_.back(); } + const_iterator begin(void) const { return vector_.begin(); } + const_iterator end(void) const { return vector_.end(); } + const_reference operator[](size_type index) const + { return vector_[index]; } + +private: + std::vector vector_; +}; + +// Contract for non-member function. +double abs_total(const myvector& vector) +// Non-member members do not check invariants. +#if defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION +; +void contract_precondition_abs_total_vector_( + const myvector& vector ) { +} +void contract_postcondition_abs_total_vector_( + const myvector& vector, contract::noold, + const double& total) { + if (!(total >= 0.0)) + throw contract::failure(__FILE__, __LINE__); +} +double contract_body_abs_total_(const myvector& vector) +#endif // preconditions or postconditions +{ + double total = 0.0; + CONTRACT_ASSERT_BLOCK_INVARIANT( total == 0.0 ); + { + CONTRACT_INIT_LOOP_VARIANT; + for (size_t i = 0; i < vector.size(); ++i) { + CONTRACT_ASSERT_BLOCK_INVARIANT( i < vector.size() ); + CONTRACT_ASSERT_LOOP_VARIANT( vector.size() - i ); + + total += vector[i]; + } + } + return total < 0.0 ? -total : total; +} +#if defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION +template +struct contract_abs_total_vector_: contract::nonmember_function< + // Still use `function` but no class type, just use `(*)`. + double (const myvector&) + > { + contract_abs_total_vector_(): contract::nonmember_function< + double (const myvector&)> + ( &contract_body_abs_total_ + , &contract_precondition_abs_total_vector_ + , &contract_postcondition_abs_total_vector_ + ) {} +}; +// Contracted function defined last and `inline`. +inline double abs_total(const myvector& vector) { + return contract_abs_total_vector_<0>().call(vector); +} +#endif // preconditions or postconditions + +//] + +#endif // #include guard + diff --git a/doc/html/example/myvector/pushable.hpp b/doc/html/example/myvector/pushable.hpp new file mode 100755 index 00000000..5fd2e0f5 --- /dev/null +++ b/doc/html/example/myvector/pushable.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Base class for a myvector subcontracting example. + +#ifndef PUSHABLE_HPP_ +#define PUSHABLE_HPP_ + +//[ pushable_cpp + +#include + +template +class pushable { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Contract for pure virtual function. + virtual void push_back(const T& element) + CONTRACT_FUNCTION( + (class) (pushable) + (public) (virtual) (void) (push_back)( (const T&)(element) ) + (postcondition) ({ + CONTRACT_ASSERT( back() == element ); + }) + (body) (= 0;) ) // Pure virtual body. + + virtual const T& back() const = 0; +}; + +//] + +#endif // #include guard + + diff --git a/doc/html/example/throw/README.txt b/doc/html/example/throw/README.txt new file mode 100755 index 00000000..71cd705a --- /dev/null +++ b/doc/html/example/throw/README.txt @@ -0,0 +1,2 @@ +Show how to configure the library to throw on contract failure +instead of terminating (used by documentation). diff --git a/doc/html/example/throw/main.cpp b/doc/html/example/throw/main.cpp new file mode 100755 index 00000000..32247701 --- /dev/null +++ b/doc/html/example/throw/main.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Configure the library to throw on contract failure. + +//[ throw_on_failure_cpp + +#include +#include + +// User defined exception (not even derived from `std::exception`). +class not_a_number {}; + +double sqrt(double x) +CONTRACT_FUNCTION( (double) (sqrt)( (double)(x) ) +(precondition) ({ + // Eventually throws user-defined exception. + if (!( x >= 0.0 )) throw not_a_number(); +}) +(postcondition) (root) ({ + // Eventually throw library defined exception `contract::failure`. + CONTRACT_ASSERT( (root * root) == x ); +}) +(body) ({ + return 0.0; // Intentionally incorrect to fail postcondition. +}) ) + +void throwing_handler(const contract::from& where) { + if (where == contract::FROM_DESTRUCTOR) { + // Cannot throw from within destructor for STL exception safety. + 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. + } +} + +void postcondition_throwing_handler(const contract::from& where) { + // try/catch/re-throw to get active exception (for logging, etc.). + try { + throw; // Re-throw active exception thrown by precondition. + } catch (std::exception& error) { // Get exception object. + std::clog << "Throwing '" << error.what() << "'" << std::endl; + + throw; // Re-throw. + } // Non standard exception also thrown. +} + +int main() { + // Setup contract failure handlers that throw (instead of terminate). + contract::set_precondition_failed(&throwing_handler); + contract::set_postcondition_failed(&postcondition_throwing_handler); + // Invariants not used by this examples but set anyway... + contract::set_class_invariant_failed(&throwing_handler); + contract::set_block_invariant_failed(&throwing_handler); + + try { + std::cout << sqrt(-1.0) << std::endl; + } catch (not_a_number&) { + std::clog << "Ignored not a number exception" << std::endl; + } + + try { + std::cout << sqrt(4.0) << std::endl; + } catch (...) { + std::clog << "Unable to calculate square root" << std::endl; + } + + return 0; +} + +//] + diff --git a/doc/html/index.html b/doc/html/index.html new file mode 100755 index 00000000..f6772fe9 --- /dev/null +++ b/doc/html/index.html @@ -0,0 +1,377 @@ + + + +Contract++ 0.3.469 + + + + + + +
Next
+
+
+
+

+Contract++ 0.3.469

+

+Lorenzo Caminiti +

+
+
+

+ Distributed under the Contract++ Software License, Version 1.0 (see accompanying + file LICENSE_1_0.txt) +

+
+
+ +

+ The Contract++ library implements Contract Programming for the C++ programming + language. +

+
++++ + + + + + + + + + + + + + + + + + + + + + + +
+

+ What +

+
+

+ Where +

+
+

+ Download +

+
+

+ http://sourceforge.net/projects/dbcpp/ +

+
+

+ Help +

+
+

+ http://sourceforge.net/projects/dbcpp/forums/forum/920163 +

+
+

+ Comments +

+
+

+ http://sourceforge.net/projects/dbcpp/forums/forum/920162 +

+
+

+ Contact the author +

+
+

+ Email lorcaminiti@gmail.com + (with [contract] in the subject) +

+
+

+

+
+ +

+ Contract Programming (CP) is also known as Design + by Contract + [1] + (DbC) and it was first introduced by the Eiffel programming language (see + [Meyer1997]). All Contract Programming + features of the Eiffel programming language are supported by this library, + among others (see Features): +

+
    +
  • + Optional compilation and checking of invariants, preconditions, and postconditions. +
  • +
  • + Customizable actions on contract failure (terminate by default but it can + throw, exit, etc). +
  • +
  • + Subcontracting for derived classes (with support for pure virtual functions + and multiple inheritance). +
  • +
  • + Access to "old" variable values (before body execution) and return + value "result" in postconditions. +
  • +
  • + Support block invariants and loop variants. +
  • +
+

+ In brief, Contract Programming allows to specify invariants, preconditions, + and postconditions that are automatically checked when functions are called + at run-time. These conditions are used to assert the function specifications + within the source code itself allowing to find bugs more quickly during testing + and improving software quality. +

+
+ + An Example +
+

+ This example shows how to write a contract for the C++ STL vector push_back() + function using this library. It also shows how to subcontract assuming that + the vector class inherits from some pushable + base class. +

+

+

+

+ +

+
#include "pushable.hpp" // Some base class (for subcontracting).
+#include <contract.hpp> // This library.
+#include <vector>       // C++ STL vector.
+
+// Wrapper class that adds contracts to std::vector.
+template<typename T>
+class myvector: public pushable<T> {
+
+    CONTRACT_INVARIANT( ({
+        CONTRACT_ASSERT( ((size() == 0) == empty() );
+        ... // More invariants.
+    }) ) 1
+    
+public:
+    void push_back(const T& element)
+    CONTRACT_FUNCTION( (class) (copyable)(myvector) 2 // Function signature.
+            (inherit)(pushable<T>) 3
+            (public) (void) (push_back)( (const T&)(element) )
+    (precondition)({ 4
+        CONTRACT_ASSERT( size() < max_size() );
+        ... // More preconditions.
+    })
+    (postcondition)({
+        CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); 5
+        ... // More postconditions.
+    })
+    (body)({ 6
+        vector_.push_back(element); // Original implementation.
+    }) ) 7
+    
+    ... // Rest of the class.
+private:
+    std::vector<T> vector_;
+};
+
+
+

+

+

+

+

+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

1

No need for ";" after + the macro closing parenthesis ")". +

2

The function signature tokens are passed to the CONTRACT_FUNCTION() + macro in the exact same order as they appear in the function declaration. + The parenthesis () around the + tokens are mandatory (they create a Boost.Preprocessor + sequence).

3

(inherit)(pushable<T>) + subcontracts from the base contract of pushable<T>::push_back(). +

4

The precondition section (precondition) ({...}) + and the postcondition section (postcondition) + ({...}) can both be omitted, the body + section (body) ({...}) + is mandatory instead.

5

CONTRACT_OLDOF(this) + is a copy to the object before the body is executed. For it to be available + in postconditions, the class type had to be tagged copyable using (copyable)(myvector) in the function signature sequence.

6

The + body specifies the original function definition. Instead of { vector_.push_back(element); }, ";" can be used to separate the function + definition from its declaration, or " = + 0;" can be used to write contracts for pure virtual + functions.

7

Again, no need for ";" + after macro closing parenthesis ")". +

+

+

+

+

+

+ When the push_back() + function is called: +

+
    +
  1. + First, the class invariants and the function preconditions are checked. +
  2. +
  3. + Then, the function body is executed. +
  4. +
  5. + Lastly, the class invariants and function postconditions are checked. +
  6. +
+

+ For example, if there is a bug in the function caller for which push_back() + is called when myvector size + is equal to max_size() + then the execution 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: +

+
precondition: terminate called after throwing an instance of 'contract::failure'
+  what():  contract "size() < max_size()" failed at myvector.cpp:20
+Aborted
+
+

+ Instead, if there is a bug in the push_back() implementation for which myvector + size is not increased by 1 after element + has been added to the 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 the push_back() function implementation: +

+
postcondition: terminate called after throwing an instance of 'contract::failure'
+  what():  contract "size() == (CONTRACT_OLDOF(this)->size() + 1)" failed at myvector.cpp:20
+Aborted
+
+

+ Note how the library error messages contain enough information to uniquely + identify the failure point: contract type (precondition, postcondition, etc), + assertion text, file name, and line number. +

+
+ + Compilers and + Platforms +
+

+ This library is implemented using both preprocessor (Boost.Preprocessor) + and template (Boost.MPL) + metaprogramming. The library also uses templates with partial specializations + and function pointer types (to implement an interface similar to the one of + Boost.Function). + As a consequence, this library is fairly demanding on compilers compliance + with the ISO C++ standard. At present, this library has been successfully compiled + and tested on the following compilers and platforms: +

+
    +
  1. + GCC 4.2.4 on Ubuntu Linux. +
  2. +
  3. + Microsoft Visual C++ 8.0 (MSVC 14) on Windows XP. +
  4. +
  5. + GCC 3.4.4 on Cygwin. +
  6. +
+

+ (No other compiler was tried thus far.) +

+
+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+
+

+

[1] + Design by Contract is a registered trademark of Eiffel Software. +

+
+
+ + + +

Last revised: February 21, 2010 at 23:08:31 GMT

+
+
Next
+ + diff --git a/doc/html/reference.html b/doc/html/reference.html new file mode 100755 index 00000000..51ab1072 --- /dev/null +++ b/doc/html/reference.html @@ -0,0 +1,233 @@ + + + +Reference + + + + + + + + +
+PrevUpHomeNext +
+
+
+

+Reference

+ +
+ +

Facilities to assert contract conditions and specify actions to take in case of contract failure.

+
+
+CONTRACT_ASSERT(boolean_condition)
+CONTRACT_ASSERT_MSG(boolean_condition, string_description)
+
namespace contract {
+  class failure;
+  typedef __ContractFailedHandler__ contract_failed_handler;
+  contract_failed_handler set_block_invariant_failed(contract_failed_handler);
+  void block_invariant_failed(const from &);
+  contract_failed_handler set_class_invariant_failed(contract_failed_handler);
+  void class_invariant_failed(const from &);
+  contract_failed_handler set_precondition_failed(contract_failed_handler);
+  void precondition_failed(const from &);
+  contract_failed_handler set_postcondition_failed(contract_failed_handler);
+  void postcondition_failed(const from &);
+}
+
+
+ +

Assert block (and loop) invariants and loop variants.

+
+
+CONTRACT_ASSERT_BLOCK_INVARIANT(boolen_condition)
+CONTRACT_ASSERT_BLOCK_INVARIANT_MSG(boolean_condition, string_description)
+CONTRACT_ASSERT_LOOP_VARIANT(integer_expression)
+CONTRACT_ASSERT_LOOP_VARIANT_MSG(integer_expression, string_description)
+CONTRACT_INIT_LOOP_VARIANT
+
namespace contract {
+  typedef __Integer__ loop_variant_type;
+}
+
+
+ +

Macros used to name the body function when separating its definition from the contract declaration.

+

For example, these macros are used when function body definitions are implemented in a source file ".cpp" while the function and contract declarations are given in separate header file ".hpp".

+

See: Examples and more information in the Tutorial section.

+
+
+CONTRACT_CONSTRUCTOR_BODY(class_type, class_name)
+CONTRACT_DESTRUCTOR_BODY(class_type, class_name)
+CONTRACT_BODY(function_name)
+
+
+ +

Macros to change some of the library compile-time configuration.

+

Configuration macros can be #defined by the user to change some of the library behaviour. If the user does not #define these macros, the library uses proper default values:

+
    #ifndef CONTRACT_CONFIG_SOMETHING
+    #   define CONTRACT_CONFIG_SOMETHING some-default-value
+    #endif
+
+

Note: It is strongly recommended not to changed the configuration macro default values unless strictly necessary.

+
+
+CONTRACT_CONFIG_MAX_FUNCTION_ARITY
+CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE
+
+
+ +

Class template used to write contracts for constructors.

+
namespace contract {
+  template<typename F> class constructor;
+}
+
+
+

+Header <contract.hpp>

+

Include the entire library.

+
    #include <contract.hpp>
+
+

It is recommended to include the library this way instead of including the single header files from the "contract/" directory.

+

Metaprogramming Symbols

+

This documentation source code indicates some metaprogramming constructs using special mixed-case symbols prefixed and postfixed by double underscores "__". These symbols are then expanded to actual code in the documentation text. For example:

+
    // Metaprogramming conventions for this documentation.
+    __AMetaprogrammingConstruct__
+    __AMetaprogrammingConstructWithParameters__< X, Y, Z >
+
+

In this convention, these metaporgramming constructs are not templates. They are internally implemented by the library using both preprocessor and template metaprogramming (in a way that is intentionally not documented here because it is library implementation specific).

+

See: Getting Started section.

+
+
+CONTRACT_CHECK_BLOCK_INVARIANT
+CONTRACT_CHECK_CLASS_INVARIANT
+CONTRACT_CHECK_PRECONDITION
+CONTRACT_CHECK_POSTCONDITION
+
+
+ +

Class template used to write contracts for destructors.

+
namespace contract {
+  template<typename F> class destructor;
+}
+
+
+ +

Context from which the contract failure was generated.

+
namespace contract {
+  enum from;
+}
+
+
+ +

Contract macros.

+

These macros are the primary tools to write contracts.

+

See: See the Tutorial section for examples.

+
+
+CONTRACT_INVARIANT(sequence)
+CONTRACT_CONSTRUCTOR(sequence)
+CONTRACT_DESTRUCTOR(sequence)
+CONTRACT_FUNCTION(sequence)
+
+
+ +

Class template used to write contracts non-member functions.

+
namespace contract {
+  template<typename F> class nonmember_function;
+}
+
+
+ +

Class template used to write contracts for non-static member functions.

+
namespace contract {
+  template<typename F, typename BaseContractClass1 = void, ... , 
+           typename BaseContractClassM = void> 
+    class nonstatic_member_function;
+}
+
+
+

+Header <contract/old.hpp>

+

Facilities to support old values in postconditions.

+

Postconditions can access old variable values (before body executions) for types tagged contract::copyable.

+
+
+CONTRACT_OLDOF(variable_name)
+
namespace contract {
+  template<typename T> class copyable;
+  template<typename T> class copy;
+}
+
+
+ +

Augmented object state internally used by the library.

+
namespace contract {
+  class state;
+}
+
+
+ +

Class template used to write contracts for static member functions.

+
namespace contract {
+  template<typename F> class static_member_function;
+}
+
+
+ +

Utilities to pass commas within macro parameters.

+
+
+CONTRACT_WRAP_TYPE(parenthesized_type)
+
namespace contract {
+  template<typename T> struct wrap;
+
+  template<typename T> struct wrap<void(T)>;
+}
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/standalone_HTML.manifest b/doc/html/standalone_HTML.manifest new file mode 100755 index 00000000..9c49e9b3 --- /dev/null +++ b/doc/html/standalone_HTML.manifest @@ -0,0 +1,56 @@ +index.html +contract__/getting_started.html +contract__/tutorial.html +contract__/without_the_macros.html +contract__/throw_on_failure.html +contract__/contract_programming.html +contract__/examples.html +reference.html +contract/failure.html +contract/contract_failed_handler.html +contract/set_block_invariant_failed.html +contract/block_invariant_failed.html +contract/set_class_invariant_failed.html +contract/class_invariant_failed.html +contract/set_precondition_failed.html +contract/precondition_failed.html +contract/set_postcondition_failed.html +contract/postcondition_failed.html +CONTRACT_ASSERT.html +CONTRACT_ASSERT_MSG.html +contract/loop_variant_type.html +CONTRACT_ASSERT_BLOCK_INVARIANT.html +CONTRACT_ASSERT_BLOCK_INVARIANT_MSG.html +CONTRACT_ASSERT_LOOP_VARIANT.html +CONTRACT_ASSERT_LOOP_VARIANT_MSG.html +CONTRACT_INIT_LOOP_VARIANT.html +CONTRACT_CONSTRUCTOR_BODY.html +CONTRACT_DESTRUCTOR_BODY.html +CONTRACT_BODY.html +CONTRACT_CONFIG_MAX_FUNCTION_ARITY.html +CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE.html +contract/constructor.html +CONTRACT_CHECK_BLOCK_INVARIANT.html +CONTRACT_CHECK_CLASS_INVARIANT.html +CONTRACT_CHECK_PRECONDITION.html +CONTRACT_CHECK_POSTCONDITION.html +contract/destructor.html +contract/from.html +CONTRACT_INVARIANT.html +CONTRACT_CONSTRUCTOR.html +CONTRACT_DESTRUCTOR.html +CONTRACT_FUNCTION.html +contract/nonmember_function.html +contract/nonstatic_member_function.html +contract/copyable.html +contract/copy.html +CONTRACT_OLDOF.html +contract/state.html +contract/static_member_function.html +contract/wrap.html +contract/wrap_void_T__id2348632.html +CONTRACT_WRAP_TYPE.html +contract__/bibliography.html +contract__/license.html +contract__/release_history.html +contract__/todo.html diff --git a/doc/qbk/README.txt b/doc/qbk/README.txt new file mode 100755 index 00000000..ba9ea71d --- /dev/null +++ b/doc/qbk/README.txt @@ -0,0 +1 @@ +Library documentation source files (in Boost.Quickbook format). diff --git a/doc/qbk/bibliography.qbk b/doc/qbk/bibliography.qbk new file mode 100755 index 00000000..c0912b51 --- /dev/null +++ b/doc/qbk/bibliography.qbk @@ -0,0 +1,47 @@ + +[section Bibliography] + +[Abrahams2005] D. Abrahams, L. Crowl, T. Ottosen, and J. Widman. /Proposal to add Contract Programming to C++ (revision 2)./ The C++ Standards Committee, [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1773.html n1773], 2005. + +[Bright2004] W. Bright. [@http://www.digitalmars.com/d/2.0/dbc.html /Contract Programming for the D Programming Language./] 2004. + +[Bright2004b] W. Bright. [@http://www.digitalmars.com/ctg/contract.html /Contract Programming for the Digital Mars C++ Compiler./] 2004. + +[C^2] Aechmea. [@http://www.programmersheaven.com/app/news/DisplayNews.aspx?NewsID=3843 /C^2 Contract Programming add-on for C++./] 2005. + +[Chrome2002] RemObjects. [@http://blogs.remobjects.com/blogs/mh/2008/05/01/p216 /Chromes: Contract Programming for Object Pascal in .NET./] 2002. + +[Crowl2005] L. Crowl and T. Ottosen. /Proposal to add Contract Programming to C++ (revision 3)./ The C++ Standards Committee, [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1866.html n1866], 2005. + +[Crowl2006] L. Crowl and T. Ottosen. /Proposal to add Contract Programming to C++ (revision 4)./ The C++ Standards Committee, [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html n1962], 2006. + +[iContract] O. Enseling. [@http://www.javaworld.com/javaworld/jw-02-2001/jw-0216-cooltools.html /iContract: Contract Programming for Java./] 2001. + +[Jcontract] Parasoft. [@http://www.parasoft.com/jsp/products/article.jsp?label=product_info_Jcontract /Jcontract: Contract Programming for Java./] + +[Maley1999] 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. + +[Meyer1997] B. Meyer. /Object Oriented Software Construction./ Prentice-Hall, 2nd edition, 1997. + +[Mitchell2002] R. Mitchell and J. McKim. /Design by Contract, by Example./ Addison-Wesley, 2002. + +[Nelson2004] C. Nelson. /Working draft changes for C99 preprocessor synchronization./ C++ Standards Committee [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm n1653], 2004. + +[Ottosen2004] T. Ottosen. /Proposal to add Design by Contract to C++./ The C++ Standards Committee, [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1613.pdf n1613], 2004. + +[Ottosen2004b] T. Ottosen. /Proposal to add Contract Programming to C++ (revision 1)./ The C++ Standards Committee, [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1669.html n1669], 2004. + +[SPARKAda] Praxis. [@http://www.praxis-his.com/sparkada/language.asp /SPARKAda (Ada-like Language with Contract Programming)./] + +[Spec#] Microsoft. [@http:://research.microsoft.com/en-us/projects/specsharp/ /Spec# (C# Extension)./] + +[Stroustrup1997] B. Stroustrup. /The C++ Programming Language./ Prentice-Hall, 2nd Edition, 1997 + +[Sutter2005] H. Sutter and F. Glassborow. /Delegating Constructors, revision 2./ C++ Standards Committee, [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1895.pdf n1895], 2005. + +[Tandin2004] A. Tandin. [@http://www.codeproject.com/KB/macros/DbC_and_Doxygen.aspx /Design by Contract macros for C++ and link to Doxygen./] 2004. + +[Wilson2006] M. Wilson. /Contract Programming 101 -- The Nuclear Reactor and the Deep Space Probe./ [@http://www.artima.com/cppsource/deepspace.html The C++ Source], 2006. + +[endsect] + diff --git a/doc/qbk/contract.qbk b/doc/qbk/contract.qbk new file mode 100755 index 00000000..485caf24 --- /dev/null +++ b/doc/qbk/contract.qbk @@ -0,0 +1,176 @@ + +[preface Contract++ + [quickbook 1.3] + [version 0.3.469] + [id contractpp] + [copyright 2009-2010 Lorenzo Caminiti] + [purpose Implement Contract Programming for C++.] + [category Correctness and testing] + [authors [Caminiti, Lorenzo]] + [license Distributed under the Contract++ Software License, Version 1.0 (see accompanying file LICENSE_1_0.txt)] + [source-mode c++] +] + +[/ CONVENTIONS + * Contract conditions FAILURE (not violation, broken, etc). + * Object code (not object file). + * ResultType (not ReturnType). + * "Parameters:", "Returns:", "Warning:", "Note:", "See:". + * Function arguments but macro/template parameters. +] + + +[def __download__ [@http://sourceforge.net/projects/dbcpp/]] +[def __help__ [@http://sourceforge.net/projects/dbcpp/forums/forum/920163]] +[def __comments__ [@http://sourceforge.net/projects/dbcpp/forums/forum/920162]] +[def __email__ [@mailto:lorcaminiti@gmail.com lorcaminiti@gmail.com]] +[def __help_website__ [@http://sourceforge.net/projects/dbcpp/forums/forum/920163 help website]] + +[def __Abrahams2005__ [link contract__.bibliography \[Abrahams2005\]]] +[def __Bright2004__ [link contract__.bibliography \[Bright2004\]]] +[def __Bright2004b__ [link contract__.bibliography \[Bright2004b\]]] +[def __C2__ [link contract__.bibliography \[C^2\]]] +[def __Chrome2002__ [link contract__.bibliography \[Chrome2002\]]] +[def __Crowl2005__ [link contract__.bibliography \[Crowl2005\]]] +[def __Crowl2006__ [link contract__.bibliography \[Crowl2006\]]] +[def __Crowl2006_etc__ [link contract__.bibliography \[Crowl2006, etc\]]] +[def __iContract__ [link contract__.bibliography \[iContract\]]] +[def __Jcontract__ [link contract__.bibliography \[Jcontract\]]] +[def __Maley1999__ [link contract__.bibliography \[Maley1999\]]] +[def __Meyer1997__ [link contract__.bibliography \[Meyer1997\]]] +[def __Mitchell2002__ [link contract__.bibliography \[Mitchell2002\]]] +[def __Nelson2004__ [link contract__.bibliography \[Nelson2004\]]] +[def __Ottosen2004__ [link contract__.bibliography \[Ottosen2004\]]] +[def __Ottosen2004b__ [link contract__.bibliography \[Ottosen2004b\]]] +[def __SPARKAda__ [link contract__.bibliography \[SPARKAda\]]] +[def __SpecSharp__ [link contract__.bibliography \[Spec#\]]] +[def __Sutter2005__ [link contract__.bibliography \[Sutter2005\]]] +[def __Stroustrup1997__ [link contract__.bibliography \[Stroustrup1997\]]] +[def __Tandin2004__ [link contract__.bibliography \[Tandin2004\]]] +[def __Wilson2006__ [link contract__.bibliography \[Wilson2006\]]] + +[def __Design_by_Contract__ [@http://en.wikipedia.org/wiki/Design_by_contract Design by Contract]] +[def __Eiffel_Software__ [@http://en.wikipedia.org/wiki/Eiffel_Software Eiffel Software]] +[def __Doxygen__ [@http://www.doxygen.org Doxygen]] +[def __Boost__ [@http://www.boost.org/ Boost]] +[def __Boost_Preprocessor__ [@http://www.boost.org/libs/preprocessor/doc/index.html Boost.Preprocessor]] +[def __Boost_MPL__ [@http://www.boost.org/libs/mpl/doc/index.html Boost.MPL]] +[def __Boost_Function__ [@http://www.boost.org/doc/libs/1_42_0/doc/html/function.html Boost.Function]] + + +[def __CONTRACT_CHECK_BLOCK_INVARIANT__ [@CONTRACT_CHECK_BLOCK_INVARIANT.html CONTRACT_CHECK_BLOCK_INVARIANT]] +[def __CONTRACT_CHECK_CLASS_INVARIANT__ [@CONTRACT_CHECK_CLASS_INVARIANT.html CONTRACT_CHECK_CLASS_INVARIANT]] +[def __CONTRACT_CHECK_PRECONDITION__ [@CONTRACT_CHECK_PRECONDITION.html CONTRACT_CHECK_PRECONDITION]] +[def __CONTRACT_CHECK_POSTCONDITION__ [@CONTRACT_CHECK_POSTCONDITION.html CONTRACT_CHECK_POSTCONDITION]] + +[def __CONTRACT_INVARIANT__ [@CONTRACT_INVARIANT.html CONTRACT_INVARIANT]] +[def __CONTRACT_CONSTRUCTOR__ [@CONTRACT_CONSTRUCTOR.html CONTRACT_CONSTRUCTOR]] +[def __CONTRACT_DESTRUCTOR__ [@CONTRACT_DESTRUCTOR.html CONTRACT_DESTRUCTOR]] +[def __CONTRACT_FUNCTION__ [@CONTRACT_FUNCTION.html CONTRACT_FUNCTION]] + +[def __CONTRACT_BODY__ [@CONTRACT_BODY.html CONTRACT_BODY]] +[def __CONTRACT_CONSTRUCTOR_BODY__ [@CONTRACT_CONSTRUCTOR_BODY.html CONTRACT_CONSTRUCTOR_BODY]] +[def __CONTRACT_DESTRUCTOR_BODY__ [@CONTRACT_DESTRUCTOR_BODY.html CONTRACT_DESTRUCTOR_BODY]] + +[def __call__ [@contract/nonstatic_member_function.html call]] +[def __precondition__ [@contract/nonstatic_member_function.html precondition]] +[def __postcondition__ [@contract/nonstatic_member_function.html postcondition]] +[def __result__ [@contract/nonstatic_member_function.html result]] + +[def __nonmember_function__ [@contract/nonmember_function.html nonmember_function]] +[def __nonstatic_member_function__ [@contract/nonstatic_member_function.html nonstatic_member_function]] +[def __static_member_function__ [@contract/static_member_function.html static_member_function]] +[def __constructor__ [@contract/constructor.html constructor]] +[def __destructor__ [@contract/destructor.html destructor]] + +[def __contract_static_invariant___ [@contract/nonstatic_member_function.html '''contract_static_invariant_''']] +[def __contract_invariant___ [@contract/nonstatic_member_function.html '''contract_invariant_''']] + +[def __state__ [@contract/state.html state]] +[def __contract_state___ [@contract/nonstatic_member_function.html '''contract_state_''']] + +[def __CONTRACT_OLDOF__ [@CONTRACT_OLDOF.html CONTRACT_OLDOF]] +[def __copyable__ [@contract/copyable.html copyable]] +[def __copy__ [@contract/copy.html copy]] +[def __noold__ [@contract/oldof.html noold]] + +[def __failure__ [@contract/failure.html failure]] +[def __from__ [@contract/from.html from]] +[def __contract_failed_handler__ [@contract/contract_failed_handler.html contract_failed_handler]] + +[def __block_invariant_failed__ [@contract/block_invariant_failed.html block_invariant_failed]] +[def __set_block_invariant_failed__ [@contract/set_block_invariant_failed.html set_block_invariant_failed]] + +[def __class_invariant_failed__ [@contract/class_invariant_failed.html class_invariant_failed]] +[def __set_class_invariant_failed__ [@contract/set_class_invariant_failed.html set_class_invariant_failed]] + +[def __precondition_failed__ [@contract/precondition_failed.html precondition_failed]] +[def __set_precondition_failed__ [@contract/set_precondition_failed.html set_precondition_failed]] + +[def __postcondition_failed__ [@contract/postcondition_failed.html postcondition_failed]] +[def __set_postcondition_failed__ [@contract/set_postcondition_failed.html set_postcondition_failed]] + +[def __CONTRACT_ASSERT__ [@CONTRACT_ASSERT.html CONTRACT_ASSERT]] +[def __CONTRACT_ASSERT_MSG__ [@CONTRACT_ASSERT_MSG.html CONTRACT_ASSERT_MSG]] + +[def __CONTRACT_ASSERT_BLOCK_INVARIANT__ [@CONTRACT_ASSERT_BLOCK_INVARIANT.html CONTRACT_ASSERT_BLOCK_INVARIANT]] +[def __CONTRACT_ASSERT_BLOCK_INVARIANT_MSG__ [@CONTRACT_ASSERT_BLOCK_INVARIANT_MSG.html CONTRACT_ASSERT_BLOCK_INVARIANT_MSG]] + +[def __CONTRACT_ASSERT_LOOP_VARIANT__ [@CONTRACT_ASSERT_LOOP_VARIANT.html CONTRACT_ASSERT_LOOP_VARIANT]] +[def __CONTRACT_ASSERT_LOOP_VARIANT_MSG__ [@CONTRACT_ASSERT_LOOP_VARIANT_MSG.html CONTRACT_ASSERT_LOOP_VARIANT_MSG]] +[def __CONTRACT_INIT_LOOP_VARIANT__ [@CONTRACT_INIT_LOOP_VARIANT.html CONTRACT_INIT_LOOP_VARIANT]] + +[def __wrap__ [@contract/wrap.html wrap]] +[def __CONTRACT_WRAP_TYPE__ [@CONTRACT_WRAP_TYPE.html CONTRACT_WRAP_TYPE]] + +[def __CONTRACT_CONFIG_MAX_FUNCTION_ARITY__ [@CONTRACT_CONFIG_MAX_FUNCTION_ARITY.html CONTRACT_CONFIG_MAX_FUNCTION_ARITY]] +[def __CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE__ [@CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE.html CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE]] + + +[def __Getting_Started__ [link contract__.getting_started Getting Started]] +[def __Tutorial__ [link contract__.tutorial Tutorial]] +[def __Contract_Programming_Overview__ [link contract__.tutorial.contract_programming_overview Contract Programming Overview]] +[def __Member_Function_Call_Semantics__ [link contract__.tutorial.contract_programming_overview.member_function_call_semantics Member Function Call Semantics]] +[def __Constructor_Call_Semantics__ [link contract__.tutorial.contract_programming_overview.constructor_call_semantics Constructor Call Semantics]] +[def __Destructor_Call_Semantics__ [link contract__.tutorial.contract_programming_overview.destructor_call_semantics Destructor Call Semantics]] +[def __Without_the_Macros__ [link contract__.without_the_macros Without the Macros]] +[def __Throw_on_Failure__ [link contract__.throw_on_failure Throw on Failure]] +[def __Features__ [link contract__.contract_programming.features Features]] +[def __Examples__ [link contract__.examples Examples]] +[def __Example__ [link contract__.examples Example]] +[def __Reference__ [@reference.html Reference]] + + +[import stubs/myvector_stub.cpp] +[import ../../example/myvector/pushable.hpp] +[import ../../example/myvector/boundable.hpp] +[import ../../example/myvector/basic_begin.hpp] +[import ../../example/myvector/myvector.hpp] +[import ../../example/myvector/myvector_nomacros.hpp] +[import ../../example/commas/main.cpp] +[import ../../example/throw/main.cpp] + + +The Contract++ library implements Contract Programming for the C++ programming language. + +[table +[ [ What ] [ Where ] ] +[ [ Download ] [ __download__ ] ] +[ [ Help ] [ __help__ ] ] +[ [ Comments ] [ __comments__ ] ] +[ [ Contact the author ] [ Email __email__ (with '''[contract]''' in the subject) ] ] +] + +[include introduction.qbk] +[include getting_started.qbk] +[include tutorial.qbk] +[include without_the_macros.qbk] +[include throw_on_failure.qbk] +[include contract_programming.qbk] +[include examples.qbk] +[xinclude ../reference.xml] +[include bibliography.qbk] +[include license.qbk] +[include release_history.qbk] +[include todo.qbk] + diff --git a/doc/qbk/contract_programming.qbk b/doc/qbk/contract_programming.qbk new file mode 100755 index 00000000..1bf2b9d4 --- /dev/null +++ b/doc/qbk/contract_programming.qbk @@ -0,0 +1,236 @@ + +[section:contract_programming Annex: Contract Programming] + +This section continues the discussion on Contract Programming started in __Contract_Programming_Overview__. + +[section Features] + +The following table compares features between this library, the proposal for adding Contract Programming to the C++ standard __Crowl2006__ (see also __Crowl2005__, __Abrahams2005__, __Ottosen2004b__, and __Ottosen2004__) +[footnote These are all revisions of the same proposal for adding Contract Programming to the C++ standard.] +, the Eiffel programming language __Meyer1997__, and the D programming language __Bright2004__. + +[table Contract Programming Feature Comparison +[ + [ Feature ] + [ This Library ] + [ C++ Standard Proposal ] + [ ISE Eiffel 5.4 ] + [ D ] +][ + [ /Keywords/ ] + [ In contract macros preprocessor sequence: =(precondition)=, =(postcondition)=, =(body)=, =(copyable)=, =(inherit)= ] + [ =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 (might throw) ] + [ Default to `std::terminate()` but can be customized (might throw) ] + [ Throw exception ] + [ Throw exception ] +][ + [ /Return value in postconditions/ ] + [ Yes, =(postcondition)(=/result-name/=)= ] + [ Yes, =postcondition (=/result-name/=)= ] + [ Yes, =result= keyword ] + [ No ] +][ + [ /Old values in postconditions/ ] + [ Yes, =CONTRACT_OLDOF(=/name/=)= (but only for class and argument types tagged `contract::copyable`) ] + [ Yes, =oldof= keyword ] + [ Yes, =old= keyword ] + [ No ] +][ + [ /Subcontracting/ ] + [ Yes, also support multiple base contracts for multiple inheritance ] + [ Yes, also support multiple base contracts but only base classes can specify preconditions ] + [ Yes ] + [ Yes ] +][ + [ /Contracts for abstract functions/ ] + [ Yes ] + [ Yes ] + [ Yes ] + [ No (planned) ] +][ + [ /Arbitrary code in contracts/ ] + [ Yes (but recommended to limit contracts to a list of assertions =CONTRACT_ASSERT()= and to use only public members in preconditions)] + [ No, assertions only ] + [ No, assertions only plus preconditions can only access public members ] + [ Yes ] +][ + [ /Constant-correct/ ] + [ Yes ] + [ Yes ] + [ Yes ] + [ No ] +][ + [ /Function code ordering/ ] + [ In contract macros preprocessor sequence: Preconditions -> postconditions -> body ] + [ Preconditions, postconditions, body ] + [ Preconditions, body, postconditions ] + [ Preconditions, postconditions, body ] +][ + [ /Static assertions/ ] + [ No (but __Boost_MPL__ can be used within contracts) ] + [ No ] + [ No ] + [ Yes ] +][ + [ /Block invariants/ ] + [ Yes, =CONTRACT_ASSERT_BLOCK_INVARIANT()= ] + [ Yes, =invariant= ] + [ No, but support loop invariants (loops are special code blocks that iterate) ] + [ No ] +][ + [ /Loop variants/ ] + [ Yes, =CONTRACT_ASSERT_LOOP_VARIANT()= and =CONTRACT_INIT_LOOP_VARIANT= ] + [ No ] + [ Yes ] + [ No ] +][ + [ /Disable assertion checking within assertions checking (policy)/ ] + [ Yes (to prevent infinite recursion) ] + [ Yes, but not in preconditions ] + [ Yes ] + [ No ] +][ + [ /Nested function calls (policy)/ ] + [ Disable checking of class invariants (static and non) ] + [ Disable nothing ] + [ Disable all checks ] + [ Disable nothing ] +][ + [ /Non-static class invariants checking (policy)/ ] + [ At constructor exit, around any non-static function, at destructor entry, and at function exit due to exception -- but only if programmers specifies contracts for those (e.g., if no contract specified for a private function then no class invariant and no contract is checked for that function) ] + [ At constructor exit, around public functions, at destructor entry, and at function exit due to exception ] + [ At constructor exit, and around public functions ] + [ At constructor exit, around public functions, and at destructor entry ] +][ + [ /Static class invariants checking (policy)/ ] + [ At entry and exit of any (also static) member function, constructor, and destructor ] + [ No static class invariants ] + [ No static class invariants ] + [ No static class invariants ] +][ + [ /Removable from object code/ ] + [ Yes, any combinations of `CONTRACT_CHECK_BLOCK_INVARIANT`, `CONTRACT_CHECK_CLASS_INVARIANT`, `CONTRACT_CHECK_PRECONDITION`, and `CONTRACT_CHECK_POSTCONDITION` ] + [ Yes ] + [ Yes (but predefined combinations only) ] + [ Yes ] +] +] + +[endsect] +[section Requirements] + +The design of this library was largely based on the requirements identified by the different revisions of the proposal for adding Contract Programming to the C++ standard __Crowl2006_etc__ and by the Eiffel programming language __Meyer1997__. + +This is a list of some of the specific requirements considered for the library design: + +# Implement Contract Programming within ISO standard C++ (without using external preprcessing tools, etc). +# Support optional contract compilation and checking. +Programmers can select any combination among invariants, preconditions, and postconditions to be compiled and checked (e.g., compile and check invariants and postconditions only). +# Programmers can decide the action to take on contract failure. +# Programmers can completely remove contract code for compilation. +In other words, if no invariants, no preconditions, and no postconditions are compiled and checked then the user code should remain unchanged (for object size, execution time, compilation-time, etc). +# Support old values in postconditions for copyable types. +Plus allow programmers to remove the extra copy overhead even for copyable types if the old value is not needed in postconditions (e.g., by not specifying the type copyable). +# Support result value in postconditions. +# Support subcontracting with multiple inheritance. +# Enforce contract constant-correctness at compile-time. +# Do not alter the user code public API. +# Support contract for all C++ constructs (operators, template class, template functions, static members, non-members, non-static members, constructors, destructors, pure virtual members, etc). +# Program contracts together with function and class declarations (not definitions) because contracts are part of the specifications. +# Support contract when function (body) definition is separated from (contract) declaration. +# Support block invariants. +# Support loop variants and invariants. + +In addition, library early implementations were somewhat inspired by the work of __Maley1999__. + +[endsect] +[section Benefits] + +The main use of Contract Programming is to improve software quality. +__Meyer1997__ discusses how Contract Programming can be used as the basic tool to write "correct" software. +The following is a short summary of the benefits associated with Contract Programming mainly taken from __Ottosen2004__. +See also __Wilson2006__ for a discussion of Contract Programming applied to the C++ programming language. +Furhtermore, __Stroustrup1997__ discusses the key importance of class invariants plus advantages and disadvantages of using preconditions and postconditions. + +# 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 object life-cycle checking the class invariants one last time before destroying the object. +# 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 the old value in postconditions, Contract Programming provides a mechanism that allows programmers to compare values of an expression before and after the executions of the function body. +This mechanism is powerful enough to enable programmers to express many constraints within the code -- constraints that would otherwise have to be captured at the best only informally by the code documentation. +# Because contracts are embedded directly into 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 source code itself. +# 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 that in some later stage of the program in an apparently unrelated manner. +In general, 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 they 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 they make a mistake twice (in the body /and/ in the contract) is lower than the probability that the mistake is made just once (in the body).] +# 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 inputs cause it to exit normally. +# 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. +# Contract Programming formalizes the virtual function overriding mechanism via the concept of subcontracting. +This keeps the base class programmers in control as overriding functions still have to fully satisfy the base class contracts. +# Contract Programming assertions can replace /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 __Stroustrup1997__ and __Meyer1997__. + +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 class invariants, preconditions, and postconditions). +# The extra processing required to copy object and function arguments when their old values are accessed in postconditions. + +To alleviate some of these run-time performance impacts, you can selectively turn off some of the contract compilation and the related run-time checking. +In reality, you will have to decide based on the performance trade-offs required by your system but a reasonable approach might be to +[footnote This approach is generally reasonable because in well tested production code, validating the function body implementation via postconditions and class invariants is rarely needed since the function has shown itself to be "correct" during testing. +On the other hand, checking arguments has continuing need because of the evolution of the callers.]: + +* Always write contracts to clarify the semantics of your design embedding them directly into the code and its documentation. +* Turn on class invariants, preconditions, and postconditions compilation and checking during early testing. +* Turn on only preconditions (and possibly class invariants) during release testing and for the final release. +(Postconditions are usually more expensive to check.) + +Compile-time performances are also impacted by this library as compilation time and compiler memory usage increase mainly because: + +# The contracts appear in the class declaration (usually header files) so they have to be re-compiled for each translation unit. +# The library implementation extensively uses C++ preprocessor and template metaprogramming which can significantly stress some compilers. + +In addition, Contract Programming might induce a false sense of security on the correctness of the software. +However, Contract Programming is proposed here as a tool to complement (and not to substitute) testing. + +In general, Contract Programming is an essential approach to improve software quality even if it comes at a performance cost. +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 a system that quickly and efficiently provides the incorrect output. + +[endsect] +[section Other Tools] + +Contract Programming is also supported by the following tools (this is /not/ a complete list): + +* __Bright2004b__ is the Digital Mars C++ compiler with added Contract Programming support. +* __C2__ implements Contract Programming for C++ using an external preprocessing tool. +* __SpecSharp__ extends C# with Contract Programming. +* __iContract__ and __Jcontract__ are external preprocessing tools that implement Contract Programming for Java. +* __Chrome2002__ is Object Pascal in .NET with Contract Programming support. +* __SPARKAda__ 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. + +[endsect] +[endsect] + diff --git a/doc/qbk/examples.qbk b/doc/qbk/examples.qbk new file mode 100755 index 00000000..7eb9f001 --- /dev/null +++ b/doc/qbk/examples.qbk @@ -0,0 +1,180 @@ + +[section Examples] + +This section provides source code of fully working examples that can all be compiled and executed using this library. +The most interesting examples (from the authors' prospective) have highlighted keywords in their purpose descriptions. + +All examples presented in the Contract Programming proposal for the C++ standard __Crowl2006__ are programmed here using the library. +Most of the other examples have been ported to C++ from Eiffel code using this library and they were originally presented in __Meyer1997__ and __Mitchell2002__. + +[table +[ [ Source ] + [ Name ] + [ Purpose ] + [ Files ]] + +[ [ __Crowl2006__ ] + [ STL Vector ] + [ *Complete contracts* for STL vector. ] + [ + [@example/Crowl2006/vector/main.cpp main.cpp] + ]] + +[ [ __Crowl2006__ ] + [ Block ] + [ Block invariants. ] + [ + [@example/Crowl2006/block/main.cpp main.cpp] + ]] + +[ [ __Crowl2006__ ] + [ Circle ] + [ Subcontracting. ] + [ + [@example/Crowl2006/circle/main.cpp main.cpp] + ]] + +[ [ __Crowl2006__ ] + [ Factorial ] + [ Contracts with recursion. ] + [ + [@example/Crowl2006/factorial/main.cpp main.cpp] + ]] + +[ [ __Crowl2006__ ] + [ Operator Equal ] + [ Contracts for operators. ] + [ + [@example/Crowl2006/operator_equal/main.cpp main.cpp] + ]] + +[ [ __Crowl2006__ ] + [ Square Root ] + [ Contracts for non-member functions. ] + [ + [@example/Crowl2006/sqrt/main.cpp main.cpp] + ]] + +[ [ __Crowl2006__ ] + [ Sum ] + [ Contracts for non-member functions (with separated definition). ] + [ + [@example/Crowl2006/sum/sum.hpp sum.hpp] + [@example/Crowl2006/sum/sum.cpp sum.cpp] + [@example/Crowl2006/sum/main.cpp main.cpp] + ]] + +[ [ __Mitchell2002__ ] + [ Name List ] + [ Relax base class preconditions using *subcontracting*. ] + [ + [@example/Mitchell2002/name_list/names.hpp names.hpp] + [@example/Mitchell2002/name_list/names.hpp names.cpp] + [@example/Mitchell2002/name_list/main.cpp main.cpp] + ]] + +[ [ __Mitchell2002__ ] + [ Courier ] + [ Relax base class preconditions using subcontracting. ] + [ + [@example/Mitchell2002/courier/couriers.hpp couriers.hpp] + [@example/Mitchell2002/courier/couriers.hpp couriers.cpp] + [@example/Mitchell2002/courier/main.cpp main.cpp] + ]] + + +[ [ __Mitchell2002__ ] + [ Dictionary ] + [ Contracts for a dictionary (map-like) data-type. ] + [ + [@example/Mitchell2002/dictionary/dictionary.hpp dictionary.hpp] + [@example/Mitchell2002/dictionary/main.cpp main.cpp] + ]] + +[ [ __Mitchell2002__ ] + [ Stack ] + [ Contracts for a stack. ] + [ + [@example/Mitchell2002/stack/stack.hpp stack.hpp] + [@example/Mitchell2002/stack/main.cpp main.cpp] + ]] + +[ [ __Mitchell2002__ ] + [ Simple Queue ] + [ Contracts for a queue. ] + [ + [@example/Mitchell2002/simple_queue/simple_queue.hpp simple_queue.hpp] + [@example/Mitchell2002/simple_queue/main.cpp main.cpp] + ]] + +[ [ __Mitchell2002__ ] + [ Customer Manager ] + [ Contracts for a class manging customers. ] + [ + [@example/Mitchell2002/customer_manager/customer_manager.hpp customer_manager.hpp] + [@example/Mitchell2002/customer_manager/customer_manager.cpp customer_manager.cpp] + [@example/Mitchell2002/customer_manager/main.cpp main.cpp] + ]] + +[ [ __Mitchell2002__ ] + [ Observe ] + [ Contracts for the observer design pattern. ] + [ + [@example/Mitchell2002/observe/observe.hpp observe.hpp] + [@example/Mitchell2002/observer/main.cpp main.cpp] + ]] + +[ [ __Mitchell2002__ ] + [ Counter ] + [ *Relaxe the accessible copy constructor requirement* for old `decrement_button` objects in postconditions. ] + [ + [@example/Mitchell2002/counter/counter.hpp counter.hpp] + [@example/Mitchell2002/counter/view_of_counter.hpp view_of_counter.hpp] + [@example/Mitchell2002/counter/push_button.hpp push_button.hpp] + [@example/Mitchell2002/counter/decrement_button.hpp decrement_button.hpp] + [@example/Mitchell2002/counter/main.cpp main.cpp] + ]] + +[ [ __Meyer1997__ ] + [ Stack3] + [ Contracts for functions returning *error codes*. ] + [ + [@example/Meyer1997/stack3/stack3.hpp stack3.hpp] + [@example/Meyer1997/stack3/main.cpp main.cpp] + ]] + +[ [ __Meyer1997__ ] + [ Stack4 ] + [ Contracts for stack. ] + [ + [@example/Meyer1997/stack4/stack4.hpp stack4.hpp] + [@example/Meyer1997/stack4/main.cpp main.cpp] + ]] + +[ [ __Meyer1997__ ] + [ Greatest Common Divisor ] + [ *Block invariants and loop variants.* ] + [ + [@example/Meyer1997/gcd/main.cpp main.cpp] + ]] + +[ [ __Meyer1997__ ] + [ Max Array ] + [ Block invariants and loop variants. ] + [ + [@example/Meyer1997/maxarray/main.cpp main.cpp] + ]] + +[ [ __Stroustrup1997__ ] + [ String ] + [ Precondition and invariants (no postconditions). ] + [ + [@example/Stroustrup1997/string/string.hpp string.hpp] + [@example/Stroustrup1997/string/string.cpp string.cpp] + [@example/Stroustrup1997/string/main.cpp main.cpp] + ]] + +] + +[endsect] + diff --git a/doc/qbk/getting_started.qbk b/doc/qbk/getting_started.qbk new file mode 100755 index 00000000..ecd07587 --- /dev/null +++ b/doc/qbk/getting_started.qbk @@ -0,0 +1,86 @@ + +[section Getting Started] + +This section illustrates how to setup your system to use this library. + +[section Installation] + +This library requires the __Boost_MPL__ and __Boost_Preprocessor__ libraries. +The __Boost__ library is a collection of highly portable C++ libraries. +You should be able to download, compile, and install __Boost__ for your operating system from the __Boost__ website. +Precompiled __Boost__ installation packages are also available for most common operating systems and they might already be installed on your system. + +This library is composed of header files only. +Therefore there are no library precompiled object files which need to be installed. +Just instruct your C++ compiler where to find the library header files (e.g., using the '-I' option for GCC or '/I' for MSVC). +For example, if you have uncompressed the library files in a directory named `"$HOME/libs/contractpp/"` then you can compile with GCC using: + +[pre +'''$ g++ -I$HOME/libs/contractpp/src/ ...''' +] + +Note that the path of the library source files (contained in the `"src/"` subdirectory) is specified. + +[endsect] +[section Header Files] + +The library headers are simply included in your C++ source code as follow: + + #include + +In general, there is no need to include the header files from the ="contract/"= directory separately and the one include above is enough. +In this documentation, the `#include ` will occasionally be assumed and omitted from the example code. + +[endsect] +[section Control Contract Compilation] + +This library provides the following macro symbols to selectively turn on or off contract compilation and run-time checking: + +* *Block invariants* and *loop variants* are compiled and checked only if the `__CONTRACT_CHECK_BLOCK_INVARIANT__` is #defined. By default, this macro symbol is /not/ #defined. +* *Class invariants* are compiled and checked only if the `__CONTRACT_CHECK_CLASS_INVARIANT__` is #defined. By default, this macro symbol is /not/ #defined. +* *Preconditions* are compiled and checked only if the `__CONTRACT_CHECK_PRECONDITION__` is #defined. By default, this macro symbol is /not/ #defined. +* *Postconditions* are compiled and checked only if the `__CONTRACT_CHECK_POSTCONDITION__` is #defined. By default, this macro symbol is /not/ #defined. In addition, the library copies variables to support old values in postconditions only when `__CONTRACT_CHECK_POSTCONDITION__` is #defined (in this case, these extra copy operations will introduce some run-time overhead). + +[important *Contracts Off by Default* + +All these symbols are #undefined by default so you must define them when compiling otherwise the library will do nothing.] + +In Contract Programming, it is usually important to be able to selectively turn off compilation of invariants, preconditions, and/or postconditions for the sake of run-time efficiency and to reduce the size of the compiled object code. + +These macros must be #defined before the library /first/ #include. +Your compiler options to #define macros can be used to this purpose ("-D" and "-U" for GCC, "/D" and "/U" for Microsoft Visual C++, etc). + +For example, let's assume we only want to check class invariants and preconditions but no postconditions and block invariants. +Then we have to #define `__CONTRACT_CHECK_CLASS_INVARIANT__` and `__CONTRACT_CHECK_PRECONDITION__` but leave `__CONTRACT_CHECK_POSTCONDITION__` and `__CONTRACT_CHECK_BLOCK_INVARIANT__` #undefined. +If we are using the GCC compiler, we can do this using the following command line options: + +[pre +$ g++ -DCONTRACT_CHECK_CLASS_INVARIANT -DCONTRACT_CHECK_PRECONDITION + -UCONTRACT_CHECK_POSTCONDITION -UCONTRACT_CHECK_BLOCK_INVARIANT ... +] + +[endsect] +[section Names and Symbols] + +All library names are defined within the `contract` namespace. +All library macros start with the `CONTRACT` prefix. +Any library names, macros, files, directories, etc that end with an underscore "`_`" are library implementation specific and should /not/ be used directly in user code by programmers. + +This library needs to /augment/ the user code with special symbols to implement the contracts. +These symbols need to be defined within the user code namespace. +All these symbols start with the `contract` prefix and end with an underscore "`_`" to prevent name clashes with user code. Again, these symbols end with an underscore "`_`" so they are library implementation specific and should /not/ be used directly in user code by programmers. + +Finally, all library names in the `contract::aux` namespace and symbols starting with `CONTRACT_AUX` are also library implementation specific and should /not/ be used directly in user code by programmers. + +[endsect] +[section Compile-Time Configuration] + +Some of the library behaviour can be changed at compile-time #defining special /configuration macros/ (`__CONTRACT_CONFIG_MAX_FUNCTION_ARITY__`, `__CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE__`, etc). +If configuration macros are not #defined, the library will use appropriate default values for them. + +The library configuration macros can be #defined using your compiler options similarly to what discussed above. +However, it is strongly recommended /not/ to change the library compile-time configuration unless strictly necessary. + +[endsect] +[endsect] + diff --git a/doc/qbk/introduction.qbk b/doc/qbk/introduction.qbk new file mode 100755 index 00000000..683715cd --- /dev/null +++ b/doc/qbk/introduction.qbk @@ -0,0 +1,61 @@ + +[section Introduction] + +Contract Programming (CP) is also known as __Design_by_Contract__ [footnote /Design by Contract/ is a registered trademark of __Eiffel_Software__.] (DbC) and it was first introduced by the Eiffel programming language (see __Meyer1997__). +All Contract Programming features of the Eiffel programming language are supported by this library, among others (see __Features__): + +* Optional compilation and checking of invariants, preconditions, and postconditions. +* Customizable actions on contract failure (terminate by default but it can throw, exit, etc). +* Subcontracting for derived classes (with support for pure virtual functions and multiple inheritance). +* Access to "old" variable values (before body execution) and return value "result" in postconditions. +* Support block invariants and loop variants. + +In brief, Contract Programming allows to specify invariants, preconditions, and postconditions that are automatically checked when functions are called at run-time. +These conditions are used to assert the function specifications within the source code itself allowing to find bugs more quickly during testing and improving software quality. + +[h5 An Example] + +This example shows how to write a contract for the C++ STL vector `push_back()` function using this library. +It also shows how to subcontract assuming that the vector class inherits from some `pushable` base class. + +[myvector_stub_cpp] + +When the `push_back()` function is called: + +# First, the class invariants and the function preconditions are checked. +# Then, the function body is executed. +# Lastly, the class invariants and function postconditions are checked. + +For example, if there is a bug in the function caller for which `push_back()` is called when `myvector` size is equal to `max_size()` then the execution 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: terminate called after throwing an instance of 'contract::failure' + what(): contract "size() < max_size()" failed at myvector.cpp:20 +Aborted +] + +Instead, if there is a bug in the `push_back()` implementation for which `myvector` size is not increased by 1 after `element` has been added to the 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 the `push_back()` function implementation: + +[pre +postcondition: terminate called after throwing an instance of 'contract::failure' + what(): contract "size() == (CONTRACT_OLDOF(this)->size() + 1)" failed at myvector.cpp:20 +Aborted +] + +Note how the library error messages contain enough information to uniquely identify the failure point: contract type (precondition, postcondition, etc), assertion text, file name, and line number. + +[h5 Compilers and Platforms] + +This library is implemented using both preprocessor (__Boost_Preprocessor__) and template (__Boost_MPL__) metaprogramming. +The library also uses templates with partial specializations and function pointer types (to implement an interface similar to the one of __Boost_Function__). +As a consequence, this library is fairly demanding on compilers compliance with the ISO C++ standard. +At present, this library has been successfully compiled and tested on the following compilers and platforms: + +# GCC 4.2.4 on Ubuntu Linux. +# Microsoft Visual C++ 8.0 (MSVC 14) on Windows XP. +# GCC 3.4.4 on Cygwin. + +(No other compiler was tried thus far.) + +[endsect] + diff --git a/doc/qbk/license.qbk b/doc/qbk/license.qbk new file mode 100755 index 00000000..dc1280ba --- /dev/null +++ b/doc/qbk/license.qbk @@ -0,0 +1,41 @@ + +[section License] + +[pre +Copyright (C) 2009-2010 Lorenzo Caminiti. +Use, modification, and distribution is subject to the +Contract++ Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt.) +] + +[pre +(File: LICENSE_1_0.txt) + +Contract Programming for C++ (Contract++) Software License, Version 1.0 +April 19th, 2009 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +] + +[endsect] + diff --git a/doc/qbk/navbar.xsl b/doc/qbk/navbar.xsl new file mode 100755 index 00000000..af8ce46d --- /dev/null +++ b/doc/qbk/navbar.xsl @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Home + Libraries + People + FAQ + More + + Home + Libraries + People + FAQ + More + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + boost-toc + + + + + + +
+
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + | + + + + + + -toc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/doc/qbk/release_history.qbk b/doc/qbk/release_history.qbk new file mode 100755 index 00000000..4f00dc68 --- /dev/null +++ b/doc/qbk/release_history.qbk @@ -0,0 +1,50 @@ + +[section Release History] + +List of releases from the newest to the oldest. + + ``/release-number/ := /major/./minor/./subversion-revision/`` + +[section Release 0.3.469 (2010-02-21)] + +# 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 `sequence` (same for postconditions, body is mandatory instead). +For non-void functions, user 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 non-member and static 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 functions 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 intended to handle Boost.Preprocessor sequences). +# Rewritten entire documentation (now using Boost.Quickbook instead of Doxygen). + +[endsect] +[section Release 0.2.190 (2009-11-21)] + +# Compiled on both GCC (Linux and Cygwin) and Microsoft Visual C++ (Windows XP). +# Required to use `void` to specify empty function argument list. +This is to comply with C++ ISO standard that does not allow to pass empty macro parameters so it does not support empty preprocessor sequence elements `()`. + +[endsect] +[section Release 0.1.26 (2009-06-17)] + +# Completed first documentation draft. + +[endsect] +[section Release 0.1.55 (2009-04-19)] + +# Reorganized files to cleanup root directory. +# Added installation program. + +[endsect] +[section Release 0.1.50 (2009-04-19)] + +# First public release. + +[endsect] +[endsect] + diff --git a/doc/qbk/src/README.txt b/doc/qbk/src/README.txt new file mode 100755 index 00000000..adf2171c --- /dev/null +++ b/doc/qbk/src/README.txt @@ -0,0 +1 @@ +Library source code documentation (Doxygen integrating in Boost.QuickBook). diff --git a/doc/qbk/src/contract.hpp b/doc/qbk/src/contract.hpp new file mode 100755 index 00000000..e420b7ec --- /dev/null +++ b/doc/qbk/src/contract.hpp @@ -0,0 +1,76 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// CONFIGURE DOXYGEN +// The following Doxygen user defined command must be added to the Doxyfile +// ALIASES configuration parameter. This is done because Boost Doxygen disables +// some of the Doxygen native similar commands (template/macro parameters, +// @return, @see, @note, etc). +// For example, put following in Boost Jamfile: +// +// ALIASES=" Params=\"Parameters: \" Param{2}=\"\" EndParams=\"
\\1\\2
\" Returns=\"Returns:\" Note=\"Note:\" Warning=\"Warning:\" See=\"See:\" " + +/** +@file +Include the entire library. + +@code + #include +@endcode + +It is recommended to include the library this way instead of including the single header files from the "contract/" directory. + +Metaprogramming Symbols + +This documentation source code indicates some metaprogramming constructs using special mixed-case symbols prefixed and postfixed by double underscores "__". +These symbols are then expanded to actual code in the documentation text. +For example: +@code + // Metaprogramming conventions for this documentation. + __AMetaprogrammingConstruct__ + __AMetaprogrammingConstructWithParameters__< X, Y, Z > +@endcode +In this convention, these metaporgramming constructs are @b not templates. +They are internally implemented by the library using both preprocessor and template metaprogramming (in a way that is intentionally @e not documented here because it is library implementation specific). + +@See Getting Started section. +*/ + +/** +Block invariants (and therefore also loop variants) are compiled and checked at run-time @b only when this macro is \#defined (\#undefined by default). + +When this macro is \#undefined, block invariants (and loop variants) are not compiled in the object code and no block invariant (and loop variants) contract overhead is added. + +@See Getting Started section for more information. +*/ +#define CONTRACT_CHECK_BLOCK_INVARIANT + +/** +Class invariants are compiled and checked at run-time @b only when this macro is \#defined (\#undefined by default). + +When this macro is \#undefined, class invariants are not compiled in the object code and no class invariant contract overhead is added. + +@See Getting Started section for more information. +*/ +#define CONTRACT_CHECK_CLASS_INVARIANT + +/** +Preconditions are compiled and checked at run-time @b only when this macro is \#defined (\#undefined by default). + +When this macro is \#undefined, preconditions are not compiled in the object code and no precondition contract overhead is added. + +@See Getting Started section for more information. +*/ +#define CONTRACT_CHECK_PRECONDITION + +/** +Postconditions are compiled and checked at run-time @b only when this macro is \#defined (\#undefined by default). + +When this macro is \#undefined, postconditions are not compiled in the object code and no postcondition contract overhead is added. + +@See Getting Started section for more information. +*/ +#define CONTRACT_CHECK_POSTCONDITION + diff --git a/doc/qbk/src/contract/README.txt b/doc/qbk/src/contract/README.txt new file mode 100755 index 00000000..c1335bf0 --- /dev/null +++ b/doc/qbk/src/contract/README.txt @@ -0,0 +1 @@ +Documentation of library public API source code. diff --git a/doc/qbk/src/contract/assert.hpp b/doc/qbk/src/contract/assert.hpp new file mode 100755 index 00000000..fe0d8f7b --- /dev/null +++ b/doc/qbk/src/contract/assert.hpp @@ -0,0 +1,265 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** @file +Facilities to assert contract conditions and specify actions to take in case of contract failure. +*/ + +/** +Macro used to assert contract conditions for class invariants, preconditions, and postconditions. + +Whenever possible, it is recommended to use this macro instead of throwing @c contract::failure directly. +For example (see the Tutorial section for more information): +@code + CONTRACT_ASSERT( true ); +@endcode + +The code asserting the specified boolean condition is used as the description of the assertion (otherwise use @c CONTRACT_ASSERT_MSG()). + +@Params +@Param{boolean_condition, The boolean contract condition being asserted.} +@EndParams + +@Returns This macro expands to code equivalent to the following (see the Without the Macros section): +@code + if (!(boolean_condition)) + throw contract::failure(__FILE__, __LINE__, # boolean_condition); +@endcode +Note how @c __FILE__ and @c __LINE__ are automatically used by the macro to improve error reporting. +(The preprocessor operator @c # makes a string from the specified token.) + +@See @c CONTRACT_ASSERT_MSG(), @c contract::failure +*/ +#define CONTRACT_ASSERT(boolean_condition) + +/** +Macro used to assert contract conditions for class invariants, preconditions, and postconditions specifying also a human readable message. + +When possible, it is recommended to use this macro instead of throwing @c contract::failure directly. +For example (see the Tutorial section for more information): +@code + CONTRACT_ASSERT_MSG( true, "always true" ); +@endcode + +@Params +@Param{boolean_condition, The boolean contract condition being asserted.} +@Param{string_description, + A string providing a human readable description of the condition being (used for error reporting).} +@EndParams + +@Returns This macro expands to code equivalent to the following (see the Without the Macros section): +@code + if (!(boolean_condition)) + throw contract::failure(__FILE__, __LINE__, string_description); +@endcode +Note how @c __FILE__ and @c __LINE__ are automatically used by the macro to improve error reporting. + +@See @c CONTRACT_ASSERT(), @c contract::failure +*/ +#define CONTRACT_ASSERT_MSG(boolean_condition, string_description) + +namespace contract { + +/** +Default exception thrown when a contract condition is found to be false. + +It is recommended to assert contract conditions using the @c CONTRACT_ASSERT() macro instead of throwing this exception directly. + +The library handles exceptions (any exception, not just this one) when thrown from within block invariants (plus loop variants), class invariants, preconditions, and postconditions invoking @c contract::block_invariant_failed(), @c contract::class_invariant_failed(), @c contract::precondition_failed(), and @c contract::postcondition_failed() respectively (see the Without the Macros section). + +Therefore, throwing this exception on a contract condition failure does @b not imply that an exception will be thrown overall to handle the failure. +It only implies that the correct contract failure handler function will be automatically invoked by the library (after checking eventual overridden contracts for subcontracting, etc). +It is not possible to call the failure handler functions directly instead of throwing the exception because that will not allow the library to check overridden contracts when subcontracting. +The failure handler functions will then decide the action to take (the default handlers provided by the library invoke @c std::terminate() but programmers can redefine this behaviour using @c contract::set_block_invariant_failed(), @c contract::set_class_invariant_failed(), @c contract::set_precondition_failed(), and @c contract::set_postcondition_failed()). + +The member functions of this class do not throw (their exception specification is @c thow()) so they can be safely used when checking contracts in compliance with STL C++ exception safety requirements at all times. + +@See Without the Macros section. +*/ +class failure: public std::logic_error { +public: + /** + Create a condition failure object. + + All the constructor parameters are used to provide more descriptive error messages in case of contract condition failure. + At least the file and line number must be specified so to uniquely identify the point of the contract condition failure. + + @Params + @Param{file, The source code file containing the failed contract condition (use @c __FILE__).} + @Param{line, The source code line number containing the failed contract condition (use @c __LINE__).} + @Param{description, An optional human readable description of the contract condition failure (@c "" if not specified).} + @EndParams + */ + explicit failure(const char* file, const unsigned long& line, + const char* description = "") throw(); + + /** Create a condition failure object copying it from the specified one. */ + failure(const failure& source) throw(); + + /** Copy a condition failure from the specified one. */ + virtual failure& operator=(const failure& source) throw(); + + /** Destroy the condition failure object. */ + virtual ~failure() throw(); + + /** + Return a human readable message explaining the nature of the condition failure. + + @Returns The actual message text is library implementation specific but it will contain the condition description, the file name, and the line number (when specified). + For example, the returned message could look like this: + @code + contract "size increased by 1" failed at myvector.cpp:40 + @endcode + */ + virtual const char* what() const throw(); + + /** Return the condition failure source file. */ + virtual const char* file() const throw(); + + /** Return the condition failure source line number. */ + virtual unsigned long line() const throw(); + + /** Return the condition failure description (@c "" if not specified).*/ + virtual const char* description() const throw(); +}; + +/** +Function pointer type of the contract condition failure handler functions. + +Where the function pointer type __ContractFailedHandler__ is defined as follows: +@code + typedef void (* contract_failed_handler)(const from& where); +@endcode + +@Params +@Param{where, The source that found the condition failure. This is useful for example to program failure handlers that throw exceptions in general but never from within destructors.} +@EndParams + +@See Throw on Failure annex for an example. +*/ +typedef __ContractFailedHandler__ contract_failed_handler; + +/** +Set the specified user defined handler function to call on block invariant failure. + +This function can be used by programmers to specify an action to take in case of block invariant failure different from the default to terminate the program. + +@Params +@Param{handler, + A pointer to the new handler function. + Passing an invalid pointer\, including 0\, has undefined behaviour and it will likely result in a segmentation fault.} +@EndParams + +@Returns The previously set handler function pointer. + +@See Throw on Failure annex for an example. +*/ +inline contract_failed_handler set_block_invariant_failed( + contract_failed_handler handler) throw(); + +/** +Automatically invoked by this library when a block invariant condition fails. + +It calls @c std::terminate() by default but it can be redefined using @c contract::set_block_invariant_failed(). +When this function is called, the exception raised by the contract failure is the active unhandled exception (which can be re-thrown using throw and then caught, see Throw on Failure annex). + +@Params +@Param{where, The source that found the the block invariant failure.} +@EndParams +*/ +inline void block_invariant_failed(const from& where); + +/** +Set the specified user defined handler function to call on class invariant failure. + +This function can be used by programmers to specify an action to take in case of class invariant failure different from the default to terminate the program. + +@Params +@Param{handler, + A pointer to the new handler function. + Passing an invalid pointer\, including 0\, has undefined behaviour and it will likely result in a segmentation fault.} +@EndParams + +@Returns The previously set handler function pointer. + +@See Throw on Failure annex for an example. +*/ +inline contract_failed_handler set_class_invariant_failed( + contract_failed_handler handler) throw(); + +/** +Automatically invoked by this library when a class invariant condition fails. + +It calls @c std::terminate() by default but it can be redefined using @c contract::set_class_invariant_failed(). +When this function is called, the exception raised by the contract failure is the active unhandled exception (which can be re-thrown using throw and then caught, see Throw on Failure annex). + +@Params +@Param{where, The source that found the the invariant failure.} +@EndParams +*/ +inline void class_invariant_failed(const from& where); + +/** +Set the specified user defined handler function to call on precondition failure. + +This function can be used by programmers to specify an action to take in case of precondition failure different from the default to terminate the program. + +@Params +@Param{handler, + A pointer to the new handler function. + Passing an invalid pointer\, including 0\, has undefined behaviour and it will likely result in a segmentation fault.} +@EndParams + +@Returns The previously set handler function pointer. + +@See Throw on Failure annex for an example. +*/ +inline contract_failed_handler set_precondition_failed( + contract_failed_handler handler) throw(); + +/** +Automatically invoked by this library when a precondition fails. + +It calls @c std::terminate() by default but it can be redefined using @c contract::set_precondition_failed(). +When this function is called, the exception raised by the contract failure is the active unhandled exception (which can be re-thrown using throw and then caught, see Throw on Failure annex). + +@Params +@Param{where, The source that found the the invariant failure.} +@EndParams +*/ +inline void precondition_failed(const from& where); + +/** +Set the specified user defined handler function to call on postcondition failure. + +This function can be used by programmers to specify an action to take in case of postcondition failure different from the default to terminate the program. + +@Params +@Param{handler, + A pointer to the new handler function. + Passing an invalid pointer\, including 0\, has undefined behaviour and it will likely result in a segmentation fault.} +@EndParams + +@Returns The previously set handler function pointer. + +@See Throw on Failure annex for an example. +*/ +inline contract_failed_handler set_postcondition_failed( + contract_failed_handler handler) throw(); + +/** +Automatically invoked by this library when a postcondition fails. + +It calls @c std::terminate() by default but it can be redefined using @c contract::set_postcondition_failed(). +When this function is called, the exception raised by the contract failure is the active unhandled exception (which can be re-thrown using throw and then caught, see Throw on Failure annex). + +@Params +@Param{where, The source that found the the invariant failure.} +@EndParams +*/ +inline void postcondition_failed(const from& where); + +} // namespace + diff --git a/doc/qbk/src/contract/block.hpp b/doc/qbk/src/contract/block.hpp new file mode 100755 index 00000000..48db6e26 --- /dev/null +++ b/doc/qbk/src/contract/block.hpp @@ -0,0 +1,237 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** @file +Assert block (and loop) invariants and loop variants. +*/ + + + + + + + + + + +/** +Macro used to assert invariant contract conditions from within a code block. + +To assert class invariants, preconditions, and postcondition use @c CONTRACT_ASSERT() instead. + +The code asserting the boolean condition is also used as the description of the condition. +For example (see the Tutorial section for more information): +@code + ... + { // From within this code block. + int x = 0; + CONTRACT_ASSERT_BLOCK_INVARIANT( x == 0 ); + } + ... +@endcode + +@Params +@Param{boolean_condition, The boolean contract condition being asserted.} +@EndParams + +@Returns This macro expands to code that will automatically invoke @c contract::block_invariant_failed() if the specified condition is evaluated to be @c false. +The macro expands to code equivalent to the following: +@code + try { + CONTRACT_ASSERT( boolean_condition ); + } catch (...) { + contract::block_invariant_failed(contract::FROM_BLOCK); + } +@endcode + +@See @c CONTRACT_ASSERT_BLOCK_INVARIANT_MSG() +*/ +#define CONTRACT_ASSERT_BLOCK_INVARIANT(boolen_condition) + + + + + + + + + + +/** +Macro used to assert invariant contract conditions from within a code block specifying also a human readable message. + +To assert class invariants, preconditions, and postcondition use @c CONTRACT_ASSERT_MSG() instead. + +For example (see the Tutorial section for more information): +@code + ... + { // From within this code block. + int x = 0; + CONTRACT_ASSERT_BLOCK_INVARIANT_MSG( x == 0, "x is zero" ); + } + ... +@endcode + +@Params +@Param{boolean_condition, The boolean contract condition being asserted.} +@Param{string_description, + A string providing a human readable description of the condition being asserted. (used for error reporting).} +@EndParams + +@Returns This macro expands to code that will automatically invoke @c contract::block_invariant_failed() if the specified condition is evaluated to be @c false. +The macro expands to code equivalent to the following: +@code + try { + CONTRACT_ASSERT_MSG( boolean_condition, string_description ); + } catch (...) { + contract::block_invariant_failed(contract::FROM_BLOCK); + } +@endcode + +@See @c CONTRACT_ASSERT_BLOCK_INVARIANT() +*/ +#define CONTRACT_ASSERT_BLOCK_INVARIANT_MSG(boolean_condition, string_description) + + + + + + + + + + + +/** +Macro used to assert loop variant. + +At each loop iteration, the value of the specified loop variant expression is automatically evaluated and asserted to be positive (> 0) and to decrease (<) from the variant value at previous loop iteration. +A loop can only have one variant. + +@Note Loop variants can be used to check loop correctness (see the Tutorial section and related references): +Because the loop variant decreases monotonically at each loop iteration and it cannot be zero or smaller than zero, it is possible to guarantee loop termination. + +The macro @c CONTRACT_INIT_LOOP_VARIANT must be used (once and only once) before asserting the loop variant and within the same or higher scope of the block containing @c CONTRACT_ASSERT_LOOP_VARIANT(). + +Loops are code blocks that repeat themselves in iteration. Therefore, it is possible to use @c CONTRACT_ASSERT_BLOCK_INVARIANT() (or @c CONTRACT_ASSERT_BLOCK_INVARIANT_MSG()) to assert loop invariants together with loop variants. +A loop can have multiple invariants. + +For example (see the Tutorial section for more information): +@code + ... + { + CONTRACT_INIT_LOOP_VARIANT; // Declare variant within scope. + for (i = 0; i < v.size(); ++i) { + // Loop invariants. + CONTRACT_ASSERT_BLOCK_INVARIANT( i >= 0 ); + CONTRACT_ASSERT_BLOCK_INVARIANT( i < v.size() ); + // Loop variant (assert always positive and decreasing). + CONTRACT_ASSERT_LOOP_VARIANT( v.size() - i ); + + std::cout << v[i] << std::endl; + } + ... +@endcode + +The variant expression code is used as a human readable description of the variant (see @c CONTRACT_ASSERT_LOOP_VARIANT_MSG()). + +@Params +@Param{integer_expression, The integer expression which is evaluated at each loop iteration and asserted to be positive and decreasing from one iteration to the next one.} +@EndParams + +@Returns This macro expands to code that will automatically invoke @c contract::block_invariant_failed() if the specified variant is not positive or it does not decrease. + +@See @c CONTRACT_INIT_LOOP_VARIANT, @c CONTRACT_ASSERT_LOOP_VARIANT_MSG() +*/ +#define CONTRACT_ASSERT_LOOP_VARIANT(integer_expression) + + + + + + + + + + +/** +Macro used to assert loop variant specifying also a human readable description. + +See @c CONTRACT_ASSERT_LOOP_VARIANT() explanations and examples. + +@Params +@Param{integer_expression, The integer expression which is evaluated at each loop iteration and asserted to be positive and decreasing from one iteration to the next one.} +@Param{string_description, A human readable description of the loop variant expression (used for error reporting).} +@EndParams + +@Returns This macro expands to code that will automatically invoke @c contract::block_invariant_failed() if the specified variant is not positive or it does not decrease. + +@See @c CONTRACT_INIT_LOOP_VARIANT(), @c CONTRACT_ASSERT_LOOP_VARIANT() +*/ +#define CONTRACT_ASSERT_LOOP_VARIANT_MSG(integer_expression, string_description) + + + + + + + + + + + +/** +Initialize the evaluation of the loop variant expression of type @c contract::loop_variant_type. + +It must be used once, and only once, in a given code block. +It must be used before using @c CONTRACT_ASSERT_LOOP_VARIANT() (or @c CONTRACT_ASSERT_LOOP_VARIANT_MSG()) at same of higher scope level. + +It can also be used within a @c for loop initialization argument, for example: +@code + void offset(int& i) { + ... + for (CONTRACT_INIT_LOOP_VARIANT; i < MAX; ) { + CONTRACT_ASSERT_LOOP_VARIANT( MAX - i ); + ... + i += DELTA; + } + } +@endcode + +@See @c contract::loop_variant_type, @c CONTRACT_ASSERT_LOOP_VARIANT(), @c CONTRACT_ASSERT_LOOP_VARIANT_MSG() +*/ +#define CONTRACT_INIT_LOOP_VARIANT + + + + + + + + + +namespace contract { + +/** +The type of the loop variant expression. + +The @c __Integer__ type is a signed integer type but its actual type is library implementation specific. + +@Note While the loop variant expression type is signed, the loop variant value is asserted to be always positive (> 0). + +For example, you can use this type to convert (not cast) the variant expression into the variant type: +@code + CONTRACT_INIT_LOOP_VARIANT; + for (size_t i = 0; i < v.size(); ++i) { + CONTRACT_ASSERT_LOOP_VARIANT( loop_variant_type(v.size() - i) ); + ... + } +@endcode +Note this is @b not a type cast so it will generate a compile-time error if the type conversion if not possible. +*/ +typedef __Integer__ loop_variant_type; + +} // namespace + diff --git a/doc/qbk/src/contract/body.hpp b/doc/qbk/src/contract/body.hpp new file mode 100755 index 00000000..3c5c71ad --- /dev/null +++ b/doc/qbk/src/contract/body.hpp @@ -0,0 +1,179 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** @file +Macros used to name the body function when separating its definition from the contract declaration. + +For example, these macros are used when function body definitions are implemented in a source file ".cpp" while the function and contract declarations are given in separate header file ".hpp". + +@See Examples and more information in the Tutorial section. +*/ + +/** +Macro used to name the constructor body when separating constructor definition from its declaration. + +This macro is used when the constructor is defined outside the class declaration (for example in a separate ".cpp" file) to name the constructor body function: +@code + BOOST_CONTRACT_CONSTRUCTOR_BODY(class_type, class_name) + (...) { // Constructor arguments. + ... // Constructor implementation. + } +@endcode + +@Params +@Param{class_type, The type of the class. For class templates this must also list the template parameters.} +@Param{class_name, The constructor name which is the class type name. For class templates this shall not list the template parameters.} +@EndParams + +@Returns This macro expands to code equivalent to the following: +@code + #if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + void class_type::contract_body_constructor_ // Constructor body function name. + #else + class_type::class_name // Constructor function (contracts off). + #endif + (...) { // Constructor arguments. + ... // Constructor implementation. + } +@endcode + +Member Initialization List + +A limitation of this mechanism is that it does not directly support constructor member initialization list. +If a member initialization list is specified then the constructor definition must be provided together with its declaration (for example in the header file). +(This library could overcome this limitation in the future if upcoming C++ standard revisions were to support delegating constructors.) + +If the constructor implementation must be separated from its declaration, a possible workaround is to: +-# Delegate the construction job to a special initialization function which must be named "constructor" (and it should be private to avoid other code from messing with the object construction). +-# Program the real constructor to just invoke the initialization function. +-# Write the contract for the initialization function instead that for the real constructor (but using CONTRACT_CONSTRUCTOR() instead of CONTRACT_FUNCTION()). + +If this is done then both the constructor and the initialization function body definitions can be separated from the contract declaration. +For example: +@code + // Declaration. + + template + class myvector { + ... // Invariants. + + public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::const_reference const_reference; + + explicit myvector(size_type count); // Separated definition. + + ... // Rest of the class. + + private: + // The initialization function is private and must be named "constructor +". + void constructor(size_type count) + // Specify the contract for the initialization function instead of the real constructor. + CONTRACT_CONSTRUCTOR( (class) (myvector) + (private) (myvector)( (size_type)(count) ), { + // Constructor preconditions (none in this case). + }, { + // Constructor postconditions. + CONTRACT_ASSERT(self.now.size() == count.now, + "size set to count"); + }, ;) // Now we can separate the body definition using ";". + + std::vector vector_; + }; + + // Separated definition (possibly in a different file). + + template + myvector::myvector(size_type count): + vector_(count) { // Member initialization list. + constructor(count); // Just invoke the initialization function. + } + + template + void myvector::CONTRACT_BODY(constructor)(size_type count) { + // Actual constructor implementation (do nothing in this case). + } +@endcode + +To allow for this workaround, the @c CONTRACT_CONSTRUCTOR() macro can follow a member function but @b only when the member function is named "constructor", it has a @c void return type, and it is not @c const (essentially, only when its signature matches the one of a constructor). +Be aware that for this special "constructor" member function, class invariants will @b not be checked before body execution (because the @c CONTRACT_CONSTRUCTOR() macro implements the Constructor Call Semantics and not the Member Function Call Semantics as explained in the Tutorial section). + +@See Tutorial section, @c CONTRACT_CONSTRUCTOR() +*/ +#define CONTRACT_CONSTRUCTOR_BODY(class_type, class_name) + +/** +Macro used to name the destructor body when separating destructor definition from its declaration. + +This macro is used when the destructor is defined outside the class declaration (for example in a separate ".cpp" file) to name the destructor body function: +@code + CONTRACT_DESTRUCTOR_BODY(class_type, class_name) + (void) { // Destructors have no argument. + ... // Destructor implementation. + } +@endcode + +@Params +@Param{class_type, The type of the class. For class templates this must also list the template parameters.} +@Param{class_name, The constructor name which is the class type name -- do @b not prefixed the class name with "~" (this is the class name and not the destructor name). For class templates this shall not list the template parameters.} +@EndParams + +@Returns This macro expands to code equivalent to the following: +@code + #if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + void class_type::contract_body_destructor_ // Destructor body function name. + #else + class_type::~class_name // Destructor function (contracts off). + #endif + (void) { // Destructor have no argument. + ... // Destructor implementation. + } +@endcode + +@See Tutorial section, @c CONTRACT_DESTRUCTOR() +*/ +#define CONTRACT_DESTRUCTOR_BODY(class_type, class_name) + +/** +Macro used to name the function body when separating the function definition from its declaration. + +This macro is used when the function is defined separately from its declaration (for example in a separate ".cpp" file) to name the body function: +@code + ... // Function return type, class-type:: prefix, etc. + CONTRACT_BODY(function_name) + (...) { // Function arguments. + ... // Function implementation. + } +@endcode + +@Params +@Param{function_name, The name of the function. For operators the name must be operator(symbol\, word) where word must contain no special operator symbol and it must match what specified in the contract declaration (see the Tutorial section).} +@EndParams + +@Returns This macro expands to code equivalent to the following: +@code + ... // Function return type, class-type:: prefix, etc. + #if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + contract_body_ ## function_name ## _ // Body function name. + #else + function_name // Function name (contracts off). + #endif + (...) { // Function arguments. + ... // Function implementation. + } +@endcode +(The preprocessor operator @c ## concatenates the specified tokens.) + +@See Tutorial section, @c CONTRACT_FUNCTION() +*/ +#define CONTRACT_BODY(function_name) + diff --git a/doc/qbk/src/contract/config.hpp b/doc/qbk/src/contract/config.hpp new file mode 100755 index 00000000..71441757 --- /dev/null +++ b/doc/qbk/src/contract/config.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** @file +Macros to change some of the library compile-time configuration. + +Configuration macros can be \#defined by the user to change some of the library behaviour. +If the user does not \#define these macros, the library uses proper default values: + +@code + #ifndef CONTRACT_CONFIG_SOMETHING + # define CONTRACT_CONFIG_SOMETHING some-default-value + #endif +@endcode + +@Note It is strongly recommended not to changed the configuration macro default values unless strictly necessary. +*/ + +/** +The maximum number of function arguments supported by this library. + +@Warning Increasing this number can @b significantly increase compilation time. +If possible, do not increase this number. + +If you need to write a contract for a function with a number of arguments larger than the one specified by this macro default value, consider alternatives like wrapping the arguments within a @c struct. +For example, consider the function: +@code + // Many arguments thus need to increase configuration macro value. + void f(int i1, int i2, int i3, int i4, int i5, int i6, int i7); +@endcode +However, this function could be rewritten as a single argument function using a @c struct: +@code + struct ints { + int i1; + int i2; + int i3; + int i4; + int i5; + int i6; + int i7; + }; + + // Just one argument and default macro value suffice. + void f(ints i); +@endcode +Now the contract for @c f only requires one argument and this macro value does not need to be increased. +*/ +#define CONTRACT_CONFIG_MAX_FUNCTION_ARITY + +/** +The maximum number of base classes supported when subcontracting with multiple inheritance. + +@Warning Increasing this number can @b significantly increase compilation time. +If possible, do not increase this number. +*/ +#define CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE + diff --git a/doc/qbk/src/contract/constructor.hpp b/doc/qbk/src/contract/constructor.hpp new file mode 100755 index 00000000..a11757ad --- /dev/null +++ b/doc/qbk/src/contract/constructor.hpp @@ -0,0 +1,116 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** +@file +Class template used to write contracts for constructors. +*/ + +namespace contract { + +/** +Class template used to write contracts for constructors. + +@Note Only the differences between this class and the @c contract::nonstatic_member_function class are documented here. +Read the @c contract::nonstatic_member_function documentation first. + +The @c CONTRACT_CONSTRUCTOR() macro expands to code that uses this class template (see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. +Rarely, it might be needed to use this class template directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard. + +@Params +@Param{F, The function type of the constructor function being contracted.} +@EndParams + +Base contract classes cannot be specified because constructors do not directly subcontract (C++ object construction mechanism will automatically invoke base class contracts when they are present). + +The function type @c F must be specified as follows: +@code + void (ClassType*, ArgumentType1, ..., ArgumentTypeN) +@endcode +Note: +@li The result type is always @c void because constructors return no value. +@li @c ClassType is never @c const because constructors can never be constant members (as they modify the object by constructing it). +@li @c ClassType cannot be tagged @c contract::copyable because there is no object before constructor body execution (it has not been constructed yet) -- the library will generate a compile-time error otherwise. + +@See Without the Macros section, @c contract::nonstatic_member_function +*/ +template +class constructor: public nonstatic_member_function { +public: + + /** + Construct this contract object using the specified body, preconditions, and postconditions functions. + + @Params + @Param{body_function, A pointer to the function executing the body.} + @Param{precondition_function, A pointer to the function asserting the preconditions.} + @Param{postcondition_function, A pointer to the function asserting the postconditions.} + @EndParams + + Refer to the @c contract::nonstatic_member_function documentation for the definition of metaprogramming constructs used below (@c __IfCopyable__, etc). + + The body function pointer type is defined as follows: + @code + typedef void (ClassType::* __BodyFunctionPointer__) + ( __RemoveCopyable__< ArgumentType1 >, + ..., + __RemoveCopyable__< ArgumentTypeN > + ); + @endcode + + The precondition function pointer type is defined as follows: + @code + typedef void (* __PreconditionFunctionPointer__) + ( boost::add_reference >::type>::type, + ..., + boost::add_reference >::type>::type + ); + @endcode + @li This is a @b static member function (because is does not specify the class type using (*) instead of (ClassType::*)). + This ensures that constructor preconditions do not access the object (as before constructor body no object has been constructed yet). + @li The precondition function is never @c const (because is must be @c static). + + The postcondition function pointer type is defined as follows: + @code + typedef void (ClassType::* __PreconditionFunctionPointer__) + ( contract::noold, + boost::add_reference >::type>::type, + __IfCopyable__< ArgumentType1, + boost::add_reference >::type>::type >, + ..., + boost::add_reference >::type>::type, + __IfCopyable__< ArgumentTypeN, + boost::add_reference >::type>::type > + ) const; + @endcode + @li The old object value is never available (it is always of type @c contract::noold). + This ensure that constructor postconditions never access the object old value (as there was no object before constructor body execution). + */ + constructor(__BodyFunctionPointer__ body_function, + __PreconditionFunctionPointer__ precondition_function, + __PostconditionFunctionPointer__ postcondition_function); + + /** Destroy this contract object. */ + virtual ~constructor(); + + /** + Check the contract and executes the member function body. + + Refer to the @c contract::nonstatic_member_function documentation. + + Accordingly with @c F, the @c call() function always returns @c void. + */ + virtual void call(__MaybeConstClassPointer__ object, + ArgumentType1 argument1, ..., ArgumetnTypeN argumentN); +}; + +} // namespace + diff --git a/doc/qbk/src/contract/destructor.hpp b/doc/qbk/src/contract/destructor.hpp new file mode 100755 index 00000000..b9825dc5 --- /dev/null +++ b/doc/qbk/src/contract/destructor.hpp @@ -0,0 +1,78 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** +@file +Class template used to write contracts for destructors. +*/ + +namespace contract { + +/** +Class template used to write contracts for destructors. + +@Note Only the differences between this class and the @c contract::nonstatic_member_function class are documented here. +Read the @c contract::nonstatic_member_function documentation first. + +The @c CONTRACT_DESTRUCTOR() macro expands to code that uses this class template (see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. +Rarely, it might be needed to use this class template directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard. + +@Params +@Param{F, The function type for the destructor being contracted.} +@EndParams + +Base contract classes cannot be specified because destructors do not directly subcontract (C++ object destruction mechanism will automatically invoke base class contracts when they are present). + +The function type @c F must be specified as follows: +@code + void (ClassType::*)() +@endcode +Note: +@li The result type is always @c void because destructors return no value. +@li @c ClassType is never @c const because destructors can never be constant members (as they modify the object by destructing it). +@li @c ClassType cannot be tagged @c contract::copyable because there is no object before destructor body execution (it has not been destructed yet) -- the library will generate a compile-time error otherwise. +@li There is no function argument type because destructors take no argument. + +@See Without the Macros section, @c contract::nonstatic_member_function +*/ +template +class destructor: public nonstatic_member_function { +public: + + /** + Construct this contract object using the specified body. + + No precondition and no postcondition function is specified (destructors only check class invariants). + This is because destructors have no arguments so there are no preconditions, in addition there is no object after destructor body execution so there are no postconditions (see Tutorial section for more information). + + @Params + @Param{body_function, A pointer to the function executing the body.} + @EndParams + + The body function pointer type is defined as follows: + @code + typedef void (ClassType::* __BodyFunctionPointer__)(); + @endcode + @li Destructor body takes no argument. + + */ + destructor(__BodyFunctionPointer__ body_function); + + + /** Destroy this contract object. */ + virtual ~destructor(); + + /** + Check the contract and executes the member function body. + + Refer to the @c contract::nonstatic_member_function documentation. + + Accordingly with @c F, the @c call() function always returns void and it takes no argument. + */ + virtual void call(__MaybeConstClassPointer__ object); +}; + +} // namespace + diff --git a/doc/qbk/src/contract/from.hpp b/doc/qbk/src/contract/from.hpp new file mode 100755 index 00000000..1aab32cb --- /dev/null +++ b/doc/qbk/src/contract/from.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** @file +Context from which the contract failure was generated. +*/ + +namespace contract { + +/** +Source that found the contract condition failure. + +For example, this is used in the Throw on Failure annex to ensure that destructors never throw to comply with C++ STL exception safety requirements. + +These failure sources are identified separately because they all have different contract checking semantics with respect to each other (see the Tutorial section). + +@Warning You must not assume any specific integer value for these enumerated values. +Only use the enumerated values because the integer values they map to are library implementation specific and they could change in future revisions of the library. + +@See @c contract::contract_failed_handler +*/ +typedef enum { + /** Contract condition failed from a constructor. */ + FROM_CONSTRUCTOR, + /** Contract condition failed from a destructor. */ + FROM_DESTRUCTOR, + /** Contract condition failed from a non-static member function. */ + FROM_NON_STATIC_MEMBER_FUNCTION, + /** Contract condition failed from a static member function. */ + FORM_STATIC_MEMBER_FUNCTION, + /** Contract condition failed from a non-member function. */ + FROM_NON_MEMBER_FUNCTION, + /** Contract condition failed from a code block. */ + FROM_BLOCK, +} from; + +} // namespace + diff --git a/doc/qbk/src/contract/macros.hpp b/doc/qbk/src/contract/macros.hpp new file mode 100755 index 00000000..57f19299 --- /dev/null +++ b/doc/qbk/src/contract/macros.hpp @@ -0,0 +1,332 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** @file +Contract macros. + +These macros are the primary tools to write contracts. + +@See See the Tutorial section for examples. +*/ + + + + + + + + + + +/** +Macro used to write (static and non) class invariants. + +This macro should be used in a private section at the beginning of the class declaration. +There is no need for a trailing ";" after the macro closing parenthesis ")". + +For example (see the Tutorial section for more information): +@code + template + class myvector { + + CONTRACT_INVARIANT( (static) ({ + ... // Assert static class invariants. + }) ({ + ... // Assert non-static class invariants. + }) ) // No need for ";" after macro closing parenthesis ")". + + ... // Rest of the class. + }; +@endcode + +@Params +@Param{sequence, + A Boost.Preprocesor sequence of tokens (1st-token)(2nd-token)...(last-token) that specifies static and non-static class invariants. + - At least one of the class invariants must be specified (i.e.\, you can specify only non-static class invariants\, only static class invariants\, or both static and non-static class invariants). + - The code block ({ ... }) following (static) should assert static class invariants. The other code block should assert non-static class invariants. + - The class invariant @c sequence syntax is as follows ([] for optional tokens): + + +[(static)({ ... })] +({ ... }) + +} +@EndParams + +@Returns +See the Without the Macro section for examples of the code generated by this macro expansion. +@li If contract compilation is turned on, this macro expands to the augmented state member variable named @c contract_state_. +@li Furthermore, if invariants compilation is specifically turned on, this macro expands to the static member function @c contract_static_invariant_ and the non-static member function @c contract_invariant_ defined respectively using the two code blocks from (static)({ ... }) and ({ ... }). +@li Otherwise, if contract compilation is turned off, this macro expands to nothing (and no contract overhead is added). + +@Note Even if a class has no invariants, you must still use this macro (with an empty code block) otherwise the library will generate a compile-time error saying that it cannot find the invariant check function for your class (see the Tutorial section for more information): +@code + class myclass { + + // Assert no invariant (mandatory). + CONTRACT_INVARIANT( ({}) ) + + ... // Rest of the class. + }; +@endcode +In this case, CONTRACT_INVARIANT() cannot be used instead of CONTRACT_INVARIANT( ({}) ). +This is because ISO standard C++ does not allow for empty macro parameters (this library also supports @c CONTRACT_INVARIANT() but this will only compile on C99 so its use is not recommended -- see the Tutorial section for more information). + +@See @c CONTRACT_ASSERT(), @c CONTRACT_CONSTRUCTOR(), @c CONTRACT_DESTRUCTOR(), @c CONTRACT_FUNCTION() +*/ +#define CONTRACT_INVARIANT(sequence) + + + + + + + + + + +/** +Macro used to write contracts for constructors. + +This macro must be used right after the constructor declaration -- and after the member initialization list if such a list is specified. +There is no need for a trailing ";" after the macro closing parenthesis ")". + +For example (see the Tutorial section for more information): +@code + template + class myvector { + ... // Invariants. + + public: + explicit myvector(size_type count) // Constructor declaration. + : vector_(count) // Member initialization list. + CONTRACT_COSTRUCTOR( (class) (myvector) + (public) (myvector)( (size_type)(count) ) + (precondition) ({ + ... // Assert constructor preconditions. + }) + (postcondition) ({ + ... // Assert constructor postconditions. + }) + (body) ({ + ... // Actual constructor implementation. + }) ) // No need for ";" after macro closing parenthesis ")". + + ... // Rest of the class. + }; +@endcode + +@Params +@Param{sequence, + A Boost.Preprocessor sequence of tokens (1st-token)(2nd-token)...(last-token) that repeats the constructor signature syntactic elements and specifies the contract. + - The signature tokens are needed by the library to generate the contract code with the function name\, the argument types and names\, etc as discussed in the Without the Macros section (e.g.\, the argument names are needed to actually name the precondition and postcondition function arguments). + - The extra parenthesis () around the tokens are mandatory (they are the ones making the preprocessor sequence). + - It is recommended to use @c CONTRACT_ASSERT() to assert preconditions and postconditions within the relative code blocks. + - Within the postcondition code block\, CONTRACT_OLDOF(argument-name) is a constant reference to the related old argument value (as the value was before body execution) but only if the argument-type was tagged (copyable) in @c sequence. + - For the body block\, ";" can be used to separate the constructor definition from its declaration (see @c CONTRACT_CONSTRUCTOR_BODY()). + - As explained in the Tutorial section\, the tokens in @c sequence appear in the exact same order as they appear in the constructor declaration followed by the optional preconditions\, optional postconditions\, and mandatory body. + - The constructor @c sequence syntax is as follows ([] for optional tokens\, {} tokens resulting from parenthesis contents evaluation\, || one token or the other\, + tokens repeated 1 or more times): + + +[(class)] (class-type) +{(public) || (protected) || (private)} +[(template)( {(function-template-parameter-type)(function-template-parameter-name)}+ )] +(class-name)( {(void) || {[(copyable)](argument-type)(argument-name)}+} ) +[(precondition) ({ ... })] +[(postcondition) ({ ... })] +(body) ({ ... }) + +} +@EndParams + +@Returns +See the Without the Macro section for examples of the code generated by this macro expansion. +@li If contract compilation is turned on, this macro expands to the constructor contract. +@li Otherwise, if contract compilation is turned off, this macro expands to just the constructor function body using the given body code block (and no contract overhead is added). + +@Note For functions with no argument (class-name)( (void) ), and not just (class-name)( ), must be used to specify the empty argument list within @c sequence. +This is because ISO standard C++ does not allow for empty macro parameters (this library also supports (class-name)( ) but this will only compile on C99 so its use is not recommended -- see the Tutorial section for more information). + +@Note In comparing the @c sequence syntax of constructors with the one of member functions from @c CONTRACT_FUNCTION(), note the following differences (see also the Constructor Call Semantics in the Tutorial section): +There is no (copyable) before class-type because there is no object before construction body execution; +There is no (inherit) because constructors cannot directly subcontract; +There is no (static) or (virtual) because constructors cannot be static or virtual; +There is no (result-type) because constructors have no return value; +The function-name must be the class-name as always for constructors; +There is no trailing (const) because constructor cannot be constant members. + +@See @c CONTRACT_ASSERT(), @c CONTRACT_INVARIANT(), @c CONTRACT_DESTRUCTOR(), @c CONTRACT_FUNCTION() +*/ +#define CONTRACT_CONSTRUCTOR(sequence) + + + + + + + + + + +/** +Macro used to write contracts for destructors. + +This macro must be used right after the destructor declaration. +There is no need for a trailing ";" after the macro closing parenthesis ")". + +For example (see the Tutorial section for more information): +@code + template + class myvector { + ... // Invariants. + + public: + virtual ~myvector(void) // Destructor declaration. + BOOST_CONTRACT_DESTRUCTOR( (class) (myvector) + (public) (virtual) (myvector)( (void) ) + // Never preconditions or postconditions for destructors. + (body ({ + ... // Actual destructor implementation. + }) ) // No need for ";" after macro closing parenthesis ")". + + ... // Rest of the class. + }; +@endcode + +@Params +@Param{signature_sequence, + A Boost.Preprocessor sequence of tokens (1st-token)(2nd-token)...(last-token) that repeats the destructor signature syntactic elements. + - The signature tokens are needed by the library to generate the contract code with the function name\, the argument types and names\, etc as discussed in the Without the Macros section. + - The extra parenthesis () around the tokens are mandatory (they are the ones making the preprocessor sequence). + - For the body code block\, ";" can be specified to separate the destructor definition from its declaration (see @c CONTRACT_DESTRUCTOR_BODY()). + - As explained in the Tutorial section\, the tokens in @c sequence appear in the exact same order as they appear in the destructor declaration followed by the mandatory body code block. + - The destructor @c sequence syntax is as follows ([] for optional tokens\, {} tokens resulting from parenthesis contents evaluation\, || one token or the other): + + +[(template)] (class-type) +{(public) || (protected) || (private)} [(virtual)] +(class-name)( (void) ) +(body) ({ ... }) + +} +@EndParams + +@Returns +See the Without the Macro section for examples of the code generated by this macro expansion. +@li If contract compilation is turned on, this macro expands to the destructor contract. +@li Otherwise, if contract compilation is turned off, this macro expands to just the destructor function body using body code block (and no contract overhead is added). + +@Note Destructor have no argument so (void) must always be used in (class-name)( (void) ) to specify the empty argument list within @c sequence. +This is because ISO standard C++ does not allow for empty macro parameters (this library also supports (class-name)( ) but this will only compile on C99 so its use is not recommended -- see the Tutorial section for more information). + +@Note In comparing the @c sequence syntax of destructors with the one of member functions from @c CONTRACT_FUNCTION(), note the following differences (see also the Destructor Call Semantics in the Tutorial section): +There is no (copyable) before class-type because there are no postconditions; +There is no (inherit) because destructors cannot directly subcontract; +There is no function template keyword and arguments because destructors cannot be template functions; +There is no (static) because destructors cannot be static; +There is no (result-type) because destructors have no return value; +The function-name must be the class-name as always for destructors; +The function argument list must be (void) because destructors take no argument; +There is no trailing (const) because constructor cannot be constant members. + +@See @c CONTRACT_ASSERT(), @c CONTRACT_INVARIANT(), @c CONTRACT_CONSTRUCTOR(), @c CONTRACT_FUNCTION() +*/ +#define CONTRACT_DESTRUCTOR(sequence) + + + + + + + + + + +/** +Macro used to write contracts for functions (non-static members, static members, and non-members but not for constructors and destructors). + +This macro must be used right after the member function declaration. +There is no need for a trailing ";" after the macro closing parenthesis ")". + +For example (see the Tutorial section for more information): +@code + template + class myvector { + ... // Invariants. + + public: + void push_back(const T& element) // Function declaration. + CONTRACT_FUNCTION( (class) (copyable)(myvector) + (public) (void) (push_back)( (const T&)(element) ) + (precondition) ({ + ... // Assert function preconditions. + }) + (postcondition) ({ + ... // Assert function postconditions. + }) + (body) ({ + ... // Actual function implementation. + }) ) // No need for ";" after macro closing parenthesis ")". + + ... // Rest of the class. + }; +@endcode + +@Params +@Param{sequence, + A Boost.Preprocessor sequence of tokens (1st-token)(2nd-token)...(last-token) that repeats the function signature syntactic elements and specifies the contract. + - The signature tokens are needed by the library to generate the contract code with the function name\, the argument types and names\, etc as explained in the the Without the Macros section (e.g.\, the argument names are needed to actually name the arguments for the precondition and postcondition functions). + - The extra parenthesis () around the tokens are mandatory (they are the ones making the preprocessor sequence). + - It is recommended to use @c CONTRACT_ASSERT() to assert preconditions and postconditions within the relative code blocks. + - Within the postcondition code block\, CONTRACT_OLDOF(this) is a constant pointer to the object old value (as it was before body execution) but only if class-type was tagged (copyable) in @c sequence. + Similarly\, CONTRACT_OLDOF(argument-name) is a constant reference to the related old argument value (as is was before body execution) but only if the argument-type was tagged (copyable) in @c sequence. + - Within the postcondition code block\, result-name (with the actual name specified in @c sequence) is a constant reference to the value being returned but only when result-type is specified different from @c void in @c sequence. + - For the body block\, ";" can be used to separate the constructor definition from its declaration (see @c CONTRACT_CONSTRUCTOR_BODY()). Also\, "= 0;" can be specified when writing contracts for pure virtual member functions. + - As explained in the Tutorial section\, the tokens in @c sequence appear in the exact same order as they appear in the member function declaration followed by the optional preconditions\, optional postconditions\, and mandatory body. + - The function @c sequence syntax is as follows ([] for optional tokens\, {} tokens resulting from parenthesis contents evaluation\, || one token or the other\, * tokens repeated 0 or more times\, + tokens repeated 1 or more times\, {}:: tokens specified only for member functions\, {}? tokens specified only for non-void functions): + + +{[(template)] [(copyable)](class-type) {(inherit)(base-class-type)}* +{(public) || (protected) || (private)}}:: +[(template)( {(function-template-parameter-type)(function-template-parameter-name)}+ )] +[{(static) || (virtual)}] +(result-type) (function-name)( {(void) || {[(copyable)](argument-type)(argument-name)}+} ) [(const)] +[(precondition) ({ ... })] +[(postcondition) {(result-name)}? ({ ... })] +(body) ({ ... }) + +} +@EndParams + +@Returns +See Without the Macro section for examples of the code generated by this macro expansion. +@li If contract compilation is turned on, this macro expands to the function contract (see the Without the Macros section). +@li Otherwise, if contract compilation is turned off, this macro expands to just the function body using @c body_code_block (and no contract overhead is added). + +The usual C++ restrictions on the function signature apply. +For example, static member functions cannot be @c virtual or @c const, plus they cannot subcontract so (inherit) cannot be specified. +The library will generate compile-time errors if @c sequence violates these constraints. + +For @b operators, the operator name must also be spelled out in words and passed as (operator(symbol, word)) (this is because operator names usually contain symbols, like "[]", that are not valid preprocessor token so they cannot be used by this library). +The spelled out operator name is arbitrary but it cannot contain operator special symbols (see the Tutorial for more information). +For example, for operator[] the function name passed to @c sequence could be (operator([], at)). + +@b Overloaded functions, with same number of arguments and constant qualifier, must have different argument names (and not just different argument types). +This is necessary otherwise this library will not be able to distinguish the contract of the overloaded functions from each other and it will generate a compile-time error. +(C++ uses the argument types and not their names to distinguish overloaded functions from each other but this library cannot use the argument types because, in general, they are not valid preprocessor tokens -- see the Tutorial for more information on this topic.) + +@Note For functions with no argument (function-name)( (void) ), and not just (function-name)( ), must be used to specify the empty argument list within @c sequence. +This is because ISO standard C++ does not allow for empty macro parameters (this library also supports (function-name)( ) but this will only compile on C99 so its use is not recommended -- see the Tutorial section for more information). + +@Warning While there is only a limited amount of compile-time error checking that the library can do on @c sequence, the current library implementation does not uses the best possible error detection and reporting mechanism for missuses of the @c sequence syntax. +In some cases, and depending on the compiler used, an error in programming @c sequence might result in cryptic compiler errors (involving library internal templates and preprocessor macros, Boost.Preprocessor internal macros BOOST_PP_..., and only referring to the contract macro first line number). +The best way to resolve these errors is usually to inspect the @c sequence by eye instead of trying to make sense of the compiler error messages. +Also, try first to compile with contracts turned off so to make sure that the errors are actually in the contract code. +Rarely, it might be useful to look at the code generated by the contract macro expansion after preprocessing using your compiler related options ("-E -P" on GCC, "\EP" on Microsoft Visual C++, etc). + +@See @c CONTRACT_ASSERT(), @c CONTRACT_INVARIANT(), @c CONTRACT_CONSTRUCTOR(), @c CONTRACT_DESTRUCTOR() +*/ +#define CONTRACT_FUNCTION(sequence) + diff --git a/doc/qbk/src/contract/nonmember_function.hpp b/doc/qbk/src/contract/nonmember_function.hpp new file mode 100755 index 00000000..e7f3009b --- /dev/null +++ b/doc/qbk/src/contract/nonmember_function.hpp @@ -0,0 +1,114 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** +@file +Class template used to write contracts non-member functions. +*/ + +namespace contract { + +/** +Class template used to write contracts for non-member functions. + +@Note Only the differences between this class and the @c contract::nonstatic_member_function class are documented here. +Read the @c contract::nonstatic_member_function documentation first. + +The @c CONTRACT_FUNCTION() macro expands to code that uses this class template (when no (class) is specified in the function signature sequence, see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. +Rarely, it might be needed to use this template class directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard. + +@Params +@Param{F, The function type of the non-member function being contracted.} +@EndParams + +The function type @c F must be specified as follows: +@code + ResultType (ArgumentType1, ..., ArgumentTypeN) +@endcode + + + +@See Without the Macros section, @c contract::nonstatic_member_function +*/ +template +class nonmember_function { +public: + + /** + Construct this contract object using the specified body, preconditions, and postconditions functions. + + @Params + @Param{body_function, A pointer to the function executing the body.} + @Param{precondition_function, A pointer to the function asserting the preconditions.} + @Param{postcondition_function, A pointer to the function asserting the postconditions.} + @EndParams + + Refer to the @c contract::nonstatic_member_function documentation for the definition of metaprogramming constructs used below (@c __IfCopyable__, etc). + + Note the followings for the function pointer types defined below: + @li They are non-member functions. + @li There is no old object value in postconditions, not even @c contract::noold (because non-member functions have no object). + + The body function pointer type is defined as follows: + @code + typedef ResultType (* __BodyFunctionPointer__) + ( __RemoveCopyable__< ArgumentType1 >, + ..., + __RemoveCopyable__< ArgumentTypeN > + ); + @endcode + + The precondition function pointer type is defined as follows: + @code + typedef ResultType (* __PreconditionFunctionPointer__) + ( boost::add_reference >::type>::type, + ..., + boost::add_reference >::type>::type + ); + @endcode + + The postcondition function pointer type is defined as follows: + @code + typedef ResultType (* __PreconditionFunctionPointer__) + ( boost::add_reference >::type>::type, + __IfCopyable__< ArgumentType1, + boost::add_reference >::type>::type >, + ..., + boost::add_reference >::type>::type, + __IfCopyable__< ArgumentTypeN, + boost::add_reference >::type>::type >, + __IfNonVoid__< boost::add_reference::type>::type > + ) const; + @endcode + */ + nonmember_function(__BodyFunctionPointer__ body_function, + __PreconditionFunctionPointer__ precondition_function, + __PostconditionFunctionPointer__ postcondition_function); + + + /** Destroy this contract object. */ + virtual ~nonmember_function(); + + /** + Check the contract and executes the member function body. + + Refer to the @c contract::nonstatic_member_function documentation. + + The @c call() function takes no object (because the contracted function is not a member). + */ + virtual ResultType call( + ArgumentType1 argument1, ..., ArgumetnTypeN argumentN); + +}; + +} // namespace + diff --git a/doc/qbk/src/contract/nonstatic_member_function.hpp b/doc/qbk/src/contract/nonstatic_member_function.hpp new file mode 100755 index 00000000..3c55740c --- /dev/null +++ b/doc/qbk/src/contract/nonstatic_member_function.hpp @@ -0,0 +1,202 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** +@file +Class template used to write contracts for non-static member functions. +*/ + +namespace contract { + +/** +Class template used to write contracts for non-static member functions. + +@Note This class is used to write contracts for non-static member functions but it cannot be used for static-member functions (see @c contract::static_member), constructors (see @c contract::constructor), destructors (see @c contract::destructor), and non-m +ember functions (see @c contract::nonmember_function) because they have different contract checking semantics. + +The @c CONTRACT_FUNCTION() macro expands to code that uses this class template (see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. +Rarely, it might be needed to use this class template directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard. + +@Params +@Param{F, The function type of the function being contracted.} +@Param{BaseContractClass1\, ...\, BaseContractClassM, + These are the contracts from which the member function is subcontracting. + These are all optional\, they are only specified when the member function is subcontracting: no base contract is specified if no subcontracting\, only @c BaseContractClass1 is specified to subcontract from 1 base class only\, and more base contract classes are specified to support subcontracting with multiple inheritance. + @li Each of these types must inherit from @c contract::nonstatic_member_function (so to be a contract class) and its class type must be a base class of the contracted class (otherwise the library will generate a compile-time error). + @li When multiple base contract classes are specified\, the overridden contracts are checked following the order of the specified template parameters. + The derived class contract is checked last. + @li The maximum number of supported base class contracts @e M is specified by the @c CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE configuration macro. +} +@EndParams + +The following metaprogramming constructs (e.g., @c __AMetaprogrammingConstruct__) are used in this documentation to define the different types: +- If @c S is @c contract::copyable then __RemoveCopyable__< S > is @c T, otherwise it is @c S (i.e., this removes the eventual @c contract::copyable tag from the specified type). +- If @c F is a member function pointer then @c __UncopyableClassType__ is __RemoveCopyable__< ClassType >:: (`::` included), otherwise it is nothing. +- If @c F is a constant member then @c __ConstIfConstantMember__ is @c const, otherwise it is nothing. +- If @c S is tagged @c contract::copyable then __IfCopyable__< S, T > is the @c T, otherwise it is the @c contract::noold. +- If @c F has a non-void @c ResultType then __IfNonVoid__< C > is C, otherwise it is nothing. +- If @c F is a non-constant member functions then @c __MaybeConstClassPointer__ is boost::add_pointer< __UncopyableClassType__ >::type, otherwise is is boost::add_pointer::type>:: type. + +These metaporgramming constructs are @b not templates. +They are internally implemented by the library using both preprocessor and template metaprogramming (in a way that is intentionally @e not documented here because it is library implementation specific). + +The function type template parameter @c F must be specified as follows: +@code + // For member functions. + ResultType (ClassType __ConstIfConstantMember__*, ArgumentType1, ..., ArgumentTypeN) +@endcode +Where: +@li The @c ResultType is the function result type (use @c void for functions that have no return value). +@li The @c ClassType is the type of the class the function is member of. +@li For constant member functions @c const qualifies the class type. +@li The class type @c ClassType (together with its eventual @c const qualifier) can be tagged @c contract::copyable as in contract::copyable* if the object old value CONTRACT_OLDOF(this) is needed in the postconditions (in this case the class must have an accessible constant-correct copy constructor, see @c contract::copy). +Note that @c contract::copyable does @b not wrap the pointer operator (i.e., contract::copyable is invalid). +@li The class type must declare a (private) mutable member variable of a friend type @c contract::state with the predefined name @c contract_state_ otherwise the library will generate a compile-time error. +This member variable is mainly used by the library to keep track of when contracts are being checked so to disable assertion checking in nested member function calls that could otherwise result in infinite recursion (see the Without the Macros section). +@code + class ClassType { + + // Optional contract compilation. + #if defined BOOST_CONTRACT_CHECK_CLASS_INVARIANT || \ + defined BOOST_CONTRACT_CHECK_PRECONDITION || \ + defined BOOST_CONTRACT_CHECK_POSTCONDITION + // Augmented state. + friend contract::state; + mutable contract::state contract_state_; + #endif + + ... // Rest of the class. + }; +@endcode +Whenever possible, use the @c CONTRACT_INVARIANT() macro instead of declaring @c contract_state_ directly. +@li The function argument types @c ArgumentType1, ..., @c ArgumentTypeN are all optional (specify none for a function with no argument, only @c ArgumentType1 is specified for a function with one argument, etc). +@li Any of the argument type can be tagged @c contract::copyable if the old value CONTRACT_OLDOF(argument-name) (before body execution) of the related argument is needed in postconditions. +Types tagged @c contract::copyable must have an accessible constant-correct copy constructor (otherwise the library will generate a compile-time error, see @c contract::copy). +The eventual @c contract::copyable tag must wrap the @b entire argument type (including the pointer operator if present, this is different from the class type). +@li The maximum number of supported function arguments @e N is specified by the @c CONTRACT_CONFIG_MAX_FUNCTION_ARITY configuration macro. + +@See Without the Macros section +*/ +template +class nonstatic_member_function { +public: + + /** + Construct this contract object using the specified body, preconditions, and postconditions functions. + + @Params + @Param{body_function, A pointer to the function executing the body.} + @Param{precondition_function, A pointer to the function asserting the preconditions.} + @Param{postcondition_function, A pointer to the function asserting the postconditions.} + @EndParams + + The body function pointer type is defined as follows: + @code + typedef ResultType (__UncopyableClassType__* __BodyFunctionPointer__) + ( __RemoveCopyable__< ArgumentType1 >, + ..., + __RemoveCopyable__< ArgumentTypeN > + ) __ConstIfConstantMember__; + @endcode + @li The body function pointer type matches the signature of the contracted function. + @li The @c contract::copyable tag is removed from the class and argument types. + @li The function type is the @c const only if the contracted function is a constant member. + + The precondition function pointer type is defined as follows: + @code + typedef void (__UncopyableClassType__* __PreconditionFunctionPointer__) + ( boost::add_reference >::type>::type, + ..., + boost::add_reference >::type>::type + ) const; + @endcode + @li The precondition function pointer type always has a @c void return type. + @li The @c contract::copyable tag is removed from the class and argument types. + @li Each function argument is passed as a contract reference. + @li The function type is always @c const if the contracted function is a member. + + The postcondition function pointer type is defined as follows: + @code + typedef void (__UncopyableClassType__* __PreconditionFunctionPointer__) + ( __IfCopyable__< ClassType, + boost::add_pointer::type>::type >, + boost::add_reference >::type>::type, + __IfCopyable__< ArgumentType1, + boost::add_reference >::type>::type >, + ..., + boost::add_reference >::type>::type, + __I fCopyable__< ArgumentTypeN, + boost::add_reference >::type>::type >, + __IfNonVoid__< boost::add_reference::type>::type > + ) const; + @endcode + @li The postcondition function pointer type always has a @c void return type. + @li The @c contract::copyable tag is removed from the class and argument types. + @li The first argument is a constant pointer to the object old value if the class type was tagged @c contract::copyable, otherwise it is of type @c contract::noold (indicating that no object old value is available because the class type was not tagged @c contract::copyable). + @li Each function argument is passed as contract reference and it is followed by its old value. Each old value is a constant reference to the argument old value if the argument type was tagged @c contract::copayble, otherwise it is of type @c contract::noold (indicating that no object old value is available because the argument type was not tagged @c contract::copyable). + @li The function type is always @c const if the contracted function is a member. + */ + nonstatic_member_function(__BodyFunctionPointer__ body_function, + __PreconditionFunctionPointer__ precondition_function, + __PostconditionFunctionPointer__ postcondition_function); + + + /** Destroy this contract object. */ + virtual ~nonstatic_member_function(); + + /** + Check the contract and execute the member function body. + + This function implements the correct contract checking semantics for the function call (see the Tutorial section). + In summary: + @li It checks class invariants and preconditions (also of overridden contracts when subcontracting), it executes the member function body, then it checks class invariants and postconditions (also of overridden contracts when subcontracting). + @li If the body throws an exception, only class invariants (and not postconditions) are checked on function exit. + @li Non-member functions do not check class invariants and they do not subcontract. + + + @Params + @Param{object, A pointer to the object (present only if @c F is a member function pointer type). + The object pointer is @c const only if @c F is a constant member function pointer type (to handle constant member functions).} + @Param{argument1\, ...\, argumentN, The function arguments.} + @EndParams + + @Returns The function return value but only when @c F is a non-void function pointer type. + + @Note When @c F is a member function pointer type, the @c call() function checks class invariants by calling a constant member function with the @c contract_invariant_ predefined name and it also checks static class invariants by calling a static member function with the @c contract_static_invariant_ predefined name (see the Without the Macros section for more information): + @code + class ClassType { + + #if defined BOOST_CONTRACT_CHECK_INVARIANT + void contract_static_invariant_(void) { + ... // Assert static class invariants. + } + void contract_invariant_ (void) const { + ... // Assert class invariants. + } + #endif + + ... // Rest of the class. + }; + @endcode + Note the \#if guard to declare the function only when invariant compilation and checking is turned on. + Such function must be defined and accessible otherwise the library will generate a compile-time error. + Whenever possible, use the @c CONTRACT_INVARIANT() macro instead of programming the @c contract_invariant_ and @c contract_static_invariant_ functions directly. + */ + virtual ResultType call(__MaybeConstClassPointer__ object, + ArgumentType1 argument1, ..., ArgumetnTypeN argumentN); + +}; + +} // namespace + diff --git a/doc/qbk/src/contract/old.hpp b/doc/qbk/src/contract/old.hpp new file mode 100755 index 00000000..1ba97dad --- /dev/null +++ b/doc/qbk/src/contract/old.hpp @@ -0,0 +1,194 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** @file +Facilities to support old values in postconditions. + +Postconditions can access old variable values (before body executions) for types tagged @c contract::copyable. +*/ + +namespace contract { + +/** +Macro used to access old value for the variable with the specified name in postconditions. + +The library automatically declares variables to hold old values of types tagged @c contract::copyable and makes then accessible in the postconditions code block (and from the postconditions code block only). +This macro simply expands the specified name to the name of the old variable automatically declared by the library. + +For example, in postconditions of a member function void myvector::push_back(const T& element), if both the class type @c myvector and the @c element argument type const T& have been tagged copyable (see the @c sequence parameter of @c CONTRACT_FUNCTION() and @c contract::copy) then the following old values are available: +@code + CONTRACT_OLDOF(this)->... // Object old value. + CONTRACT_OLDOF(element)... // Old value of function argument `element`. +@endcode + +@Params +@Param{variable_name, Use @c this to access a pointer to the old object value. Use one of the function argument names to access the old value of that argument. The type of the variable with the specified name must be tagged @c contract::copyable in the signature sequence its old value to be available (otherwise the use of this macro will generate a compile-time error with @c noold in the error message).} +@EndParams + +@Returns This macro expands to code equivalent to the following: +@code + contract_old_ ## variable_name ## _ +@endcode +(The preprocessor operator @c ## concatenates the specified tokens.) + +@Note Shallow copies are performed for old values of pointer types (unless the pointed type defines a different copy constructor or @c contract::copy has been specialized for the pointed type to perform a different copy operation). +Therefore, if a pointer type is tagged @c contract::copyable, the old pointer value will be available in the postconditions and not the old pointed value -- this might not be what you intended. +The notable exception is the object which is passed by pointer (like @c this) but its old value is automatically deep copied by the library. + +@Note The library supports old values for the object and all the function argument types. +This is a subset of the old values supported by Eiffel which are old values for any expression that can be evaluated in postconditions. +However, the old values supported by the library are usually enough to program the postconditions. + +@See @c contract::copy, @c contract::copyable +*/ +#define CONTRACT_OLDOF(variable_name) + +/** +Tag the specified type @c T copyable. + +In general, you should tag a type copyable @b only when the related variable old value (before body execution) is really needed in postconditions because: + +-# The correspondent variable value will be copied before body execution adding run-time overhead. +The library performs the extra copy to support old values in postconditions only for variables of types tagged copyable and only when the @c CONTRACT_CHECK_POSTCONDITION macro is defined. +-# A type tagged copyable has the extra requirement that it must define an accessible constant-correct copy constructor (otherwise the library will generate a compile-time error). +The copy constructor is constant-correct when it accesses the copied value via a constant reference argument (this way the copied value cannot be mistakenly modified while it is being copied to check contracts): +@code + T::T(const T& source) { ... } // Must be accessible and construct from a const&. +@endcode +See @c contract::copy to relax this requirement. + +@Params +@Param{T, The type to be tagged. The @b entire type with eventual @c const\, &\, *\, etc qualifier should be tagged copyable. For example\, if the type is const int& then contract::copyable should be used (and not const contract::copyable&).} +@EndParams + +@Note When using the contract macros, (copyable)(T) is used instead of @c contract::copyable to tag the type @c T copyable in the macro @c sequence parameter. + +@See @c CONTRACT_OLDOF(), @c contract::copy +*/ +template class copyable {}; + +/** +Copy wrapper used by the library to make the actual copy of variables for which old values are needed in postconditions. + +@Params +@Param{T, Type of the object being copied.} +@EndParams + +@Note Under most circumstances programmers do @b not need to use this class which is usually just used internally by the library. + +Specifically, if the copied type @c T already has a public constant-correct copy constructor then the @c contract::copy template will use such a constructor by default and programmers do not need to define any specialization of the @c contract::copy template. +@code + class T { + public: + T(const T& source); // Public constant-correct copy constructor. + + ... + }; +@endcode +The constructor needs to be public for the library to access it and it needs to be contract-correct for the library to use it while still ensuring the contract-correctness of the contract checking code. + +However, the @c contract::copy template can be specialized by programmers to expose a non-public constant-correct copy constructor to the library via friendship: +@code + class x { + ... // User class with no public copy constructor. + + private: + // Only the library can access this copy constructor via friendship. + friend class contract::copy; + x(const x* source); // Constant-correct (private) copy constructor. + }; +@endcode + +Furthermore, programmers can specialize the @c contract::copy template for a user defined type in order to relax the library requirement of an accessible constant-correct copy constructor all together (it is recommended @b not to do this unless strictly necessary). +@code + class y: boost::noncopyable { // User class with no copy constructor at all. + // Self backup copy maintained by the class itself. + y backup_copy; // Use this as the old value. + + ... + }; + + namespace contract { + + // Specialization to handle y old value without copying it. + template<> + class copy { + public: + // It must declare a member variable named `value`. + const y& value; // Maintains constant-correctness by using const member. + + // It must defined this copy constructor. It must maintains + // constant-correctness taking a constant reference to `source`. + copy(const y& source): + // This does not copy `source` (`value` is a reference). + // Instead it uses its `source` existing backup copy. + value(source.backup_copy) {} + }; + + } // namespace +@endcode + +The @c contract::copy template can also be specialized to alter the copy semantics for a type (it is recommended @b not to do this unless strictly necessary). +For example, by default a pointer to a double number double* is copied by copying the pointer value and not by copying the pointed number (this is the usual C++ copy semantic for pointers). +The following specialization of @c contract::copy copies the pointed number instead of the pointer value for postcondition old values of argument of type double*. +@code + namespace contract { + + template<> + class copy { + private: + double number_; // Copied pointed number value. + public: + const double* value; // Pointer to number_. + + copy(const double* number_ptr): number_(), value(&number_) { + // Check pointer is valid. + if (!number_ptr) throw std::logic_error("Invalid number pointer"); + number_ = *number_ptr; // Copy the *pointed* number. + } + }; + + } // namespace +@endcode + +See also the Examples section for a concrete example that specializes @c contract::copy to relax the accessible constant-correct constructor requirement. +*/ +template +class copy { +public: + /** + The copied value (used as the old value in postconditions). + + The variable type is defined as follows: + @code + typedef typename boost::add_const::type>::type __ConstType__; + @endcode + */ + __ConstType__ value; + + /** + Constructor which copies the specified object. + + The copy is done by constructing the member variable `value` using an accessible constant-correct copy constructor for @c T (which must be available otherwise the library will generate a compile-time error). + + @Note Source is a constant reference so to ensure contract checking + constant-correctness (correctly, this constraint cannot be relaxed not + even by specializing this class template). + + The constant reference type is defined as follows: + @code + typedef typename boost::add_reference::type __ConstRef__; + @endcode + + @Params + @Param{source, The source object to be copied into the @c value member variable.} + @EndParams + */ + copy(__ConstRef__ source): value(source) {} +}; + +} // namespace + diff --git a/doc/qbk/src/contract/state.hpp b/doc/qbk/src/contract/state.hpp new file mode 100755 index 00000000..aaff93bd --- /dev/null +++ b/doc/qbk/src/contract/state.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** @file +Augmented object state internally used by the library. +*/ + +namespace contract { + +/** +Augmented object state internally used by the library. + +As illustrated by the @c contract::nonstatic_member_function documentation, the class being contracted must declare a (private) member variable named @c contract_state_ of @c mutable type @c contract::state (see @c contract::nonstatic_member_function for example code). +The type @c contract::state must be declared a friend of the class. +This member variable is automatically declared when the @c CONTRACT_INVARIANT() macro is used (recommended). + +This library will generate a compile-time error if this state variable is not declared and accessible to the contracts. + +@Note This member variable is used internally by this library mainly to track when assertions are being checked so to disable assertion checking in nested function calls that could otherwise lead to infinite recursion (this is a common requirement for Contract Programming). +The friendship is requires so the library internally has access to the entire user class including non public members. + +@See @c contract::nonstatic_member_function, Without the Macros section +*/ +class state {}; + +} // namespace + diff --git a/doc/qbk/src/contract/static_member_function.hpp b/doc/qbk/src/contract/static_member_function.hpp new file mode 100755 index 00000000..fd9c58e0 --- /dev/null +++ b/doc/qbk/src/contract/static_member_function.hpp @@ -0,0 +1,116 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** +@file +Class template used to write contracts for static member functions. +*/ + +namespace contract { + +/** +Class template used to write contracts for static member functions. + +@Note Only the differences between this class and the @c contract::nonstatic_member_function class are documented here. +Read the @c contract::nonstatic_member_function documentation first. + +The @c CONTRACT_FUNCTION() macro expands to code that uses this class template (when (static) is specified in the function signature sequence, see the Without the Macros section) -- whenever possible, use the macro instead of using this class template directly. +Rarely, it might be needed to use this template class directly to implement workarounds for compilers that do not fully comply with the ISO C++ standard. + +@Params +@Param{F, The function type of the static member function being contracted.} +@EndParams + +Base contract classes cannot be specified because static member functions cannot be virtual and they cannot override base virtual functions so they cannot subcontract. + +The function type @c F must be specified as follows: +@code + ResultType (ClassType*, ArgumentType1, ..., ArgumentTypeN) +@endcode +Note: +@li @c ClassType is never @c const because static member functions cannot be constant member functions (there is no object to not modify). +@li @c ClassType cannot be tagged @c contract::copyable because there is no object for static member functions -- the library will generate a compile-time error otherwise. + +@See Without the Macros section, @c contract::nonstatic_member_function +*/ +template +class static_member_function: public non_member_function { +public: + + /** + Construct this contract object using the specified body, preconditions, and postconditions functions. + + @Params + @Param{body_function, A pointer to the function executing the body.} + @Param{precondition_function, A pointer to the function asserting the preconditions.} + @Param{postcondition_function, A pointer to the function asserting the postconditions.} + @EndParams + + Refer to the @c contract::nonstatic_member_function documentation for the definition of metaprogramming constructs used below (@c __IfCopyable__, etc). + + Note the followings for the function pointer types defined below: + @li They are static member functions (they do not specify the class type as in (ClassType::*) but only the function pointer (*)). + @li They are never @c const member functions because they are @c static. + @li There is no old object value in postconditions, not even @c contract::noold (because static member functions have no object). + + The body function pointer type is defined as follows: + @code + typedef ResultType (* __BodyFunctionPointer__) + ( __RemoveCopyable__< ArgumentType1 >, + ..., + __RemoveCopyable__< ArgumentTypeN > + ); + @endcode + + The precondition function pointer type is defined as follows: + @code + typedef ResultType (* __PreconditionFunctionPointer__) + ( boost::add_reference >::type>::type, + ..., + boost::add_reference >::type>::type + ); + @endcode + + The postcondition function pointer type is defined as follows: + @code + typedef ResultType (* __PreconditionFunctionPointer__) + ( boost::add_reference >::type>::type, + __IfCopyable__< ArgumentType1, + boost::add_reference >::type>::type >, + ..., + boost::add_reference >::type>::type, + __IfCopyable__< ArgumentTypeN, + boost::add_reference >::type>::type >, + __IfNonVoid__< boost::add_reference::type>::type > + ) const; + @endcode + */ + static_member_function(__BodyFunctionPointer__ body_function, + __PreconditionFunctionPointer__ precondition_function, + __PostconditionFunctionPointer__ postcondition_function); + + /** Destroy this contract object. */ + virtual ~static_member_function(); + + /** + Check the contract and executes the member function body. + + Refer to the @c contract::nonstatic_member_function documentation. + + The @c call() function takes no object (because the contracted function is static). + */ + virtual ResultType call( + ArgumentType1 argument1, ..., ArgumetnTypeN argumentN); +}; + +} // namespace + diff --git a/doc/qbk/src/contract/wrap.hpp b/doc/qbk/src/contract/wrap.hpp new file mode 100755 index 00000000..fa0cb910 --- /dev/null +++ b/doc/qbk/src/contract/wrap.hpp @@ -0,0 +1,110 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +/** @file +Utilities to pass commas within macro parameters. +*/ + +/** +Macro used to pass type expressions with unwrapped commas as macro parameters. + +The C++ ISO standard preprocessor only recognizes the parenthesis @c () and it does not recognize any other parenthesis like @c <>, @c {}, @c [], etc. + +As a consequence, any comma within a macro parameter which is not wrapped by the @c () parenthesis will be interpreted by the preprocessor as a separation token (the end of the current macro parameter and the start of the next macro parameter). +See also the Tutorial section for more explanation and examples. + +Value Expressions + +Value expressions passed as macro parameters and containing unwrapped commas can be wrapped by and extra set of parenthesis @c (). + +For example, this is OK because the comma `,` is already wrapped by the parenthesis @c () of the @c add() function call: +@code + CONTRACT_ASSERT( add(1, 2) == 3 ); // OK. +@endcode +This is incorrect instead because the comma `,` is not wrapped. +It is interpreted as a call to @c CONTRACT_ASSERT() passing @b two distinct macro parameters `std::map` and `int>().empty()` separated by the comma `,`: +@code + CONTRACT_ASSERT( std::map().empty() ); // Error. +@endcode +However, it can be fixed by using and extra set of parenthesis to wrap the value expression: +@code + CONTRACT_ASSERT( (std::map().empty()) ); // OK. +@endcode + +Type Expressions + +A similar issue arises when type expressions with unwrapped commas are passed as macro parameters (including when they are passed as preprocessor sequence elements): +@code + std::map m(void) + CONTRACT_FUNCTION( (std::map) (m)( (void) ) // Error. + ... + ) +@endcode +This is interpreted as a preprocessor 2-tuple with two elements `std::map` and `int>` separated by the comma `,` instead that one single element of the preprocessor sequence. + +@Note Unfortunately, the approach followed for value expressions cannot be used for macro parameters that represent type expressions. +That is because types wrapped by an extra set of parenthesis @c () can introduce syntax or semantics errors depending on the context where they are used. +For example, with respect to std::map, the wrapped type expression (std::map) could be compiled a C-style type cast potentically introducing a semantic error, or it could generate a syntax error if it were used to declare a variable. + +The macro @c CONTRACT_WRAP_TYPE() (or equivalently the @c contract::wrap class template) is be used to overcome this limitation: +@code + std::map m(void) + CONTRACT_FUNCTION( (CONTRACT_WRAP_TYPE( (std::map) )) //OK. + (m)( (void) ) + ... + ) +@endcode +Note that the extra pair of parenthesis @c () used in invoking the macro are mandatory as they wrap the comma(s) so one parameter (not many) is passed to the macro. + +@Params +@Param{parenthesized_type, The type expression wrapped within an extra set of mandatory parenthesis @c ().} +@EndParams + +@Returns The macro in the example above expands to code equivalent to the following: +@code + std::map m(void) + CONTRACT_FUNCTION( (contract::wrap)>::type) + (m)( (void) ) + ... + ) +@endcode +@See contract::wrap, Tutorial section +*/ +#define CONTRACT_WRAP_TYPE(parenthesized_type) + +namespace contract { + +/** +Metafunction used to wrap type expressions containing commas so they can be passed as macro parameters. + +@Warning Attempting to use this template directly will generate a compile-time error. +Only the template specialization contract::wrap can be used. + +@See contract::wrap specialization, @c CONTRACT_WRAP_TYPE() +*/ +template +struct wrap {}; + + +/** +Metafunction used to wrap type expressions containing commas so they can be passed as macro parameters. + +This metafunction first wrap the specified type @c T within parenthesis @c () (so @c T can be passed as a single macro parameter even if it contains commas) forming a void-function type with one argument of type @c T. +Then the application of the metafunction via its member @c type returns the wrapped type @c T. + +@Params +@Param{T, Type to be wrapped so it can be passed within a macro parameter even if it contains commas.} +@EndParams + +@See CONTRACT_WRAP_TYPE() for more explanation and examples +*/ +template +struct wrap { + /** The type T. */ + typedef T type; +}; + +} // namespace + diff --git a/doc/qbk/stubs/README.txt b/doc/qbk/stubs/README.txt new file mode 100755 index 00000000..693cab8a --- /dev/null +++ b/doc/qbk/stubs/README.txt @@ -0,0 +1,2 @@ +Pieces of C++ code used by the documentation and that cannot be compiled. +If the code can be comipled, then put it into "example/" instead. diff --git a/doc/qbk/stubs/myvector_stub.cpp b/doc/qbk/stubs/myvector_stub.cpp new file mode 100755 index 00000000..e491595c --- /dev/null +++ b/doc/qbk/stubs/myvector_stub.cpp @@ -0,0 +1,41 @@ + +//[ myvector_stub_cpp + +#include "pushable.hpp" // Some base class (for subcontracting). +#include // This library. +#include // C++ STL vector. + +// Wrapper class that adds contracts to std::vector. +template +class myvector: public pushable { + + ``*CONTRACT_INVARIANT*``( ({ + CONTRACT_ASSERT( ((size() == 0) == empty() ); + ... // More invariants. + }) ) /*< No need for "`;`" after the macro closing parenthesis "`)`". >*/ + +public: + void push_back(const T& element) + ``*CONTRACT_FUNCTION*``( (class) (copyable)(myvector) /*< The function signature tokens are passed to the __CONTRACT_FUNCTION__() macro in the exact same order as they appear in the function declaration. + The parenthesis `()` around the tokens are mandatory (they create a __Boost_Preprocessor__ sequence). >*/ // Function signature. + (inherit)(pushable) /*< `(inherit)(pushable)` subcontracts from the base contract of `pushable::push_back()`. >*/ + (public) (void) (push_back)( (const T&)(element) ) + (``*precondition*``)({ /*< The precondition section `(precondition) ({...})` and the postcondition section `(postcondition) ({...})` can both be omitted, the body section `(body) ({...})` is mandatory instead. >*/ + CONTRACT_ASSERT( size() < max_size() ); + ... // More preconditions. + }) + (``*postcondition*``)({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); /*< `CONTRACT_OLDOF(this)` is a copy to the object before the body is executed. For it to be available in postconditions, the class type had to be tagged copyable using `(copyable)(myvector)` in the function signature sequence. >*/ + ... // More postconditions. + }) + (``*body*``)({ /*< The body specifies the original function definition. Instead of `{ vector_.push_back(element); }`, `";"` can be used to separate the function definition from its declaration, or `" = 0;"` can be used to write contracts for pure virtual functions. >*/ + vector_.push_back(element); // Original implementation. + }) ) /*< Again, no need for "`;`" after macro closing parenthesis "`)`". >*/ + + ... // Rest of the class. +private: + std::vector vector_; +}; + +//] + diff --git a/doc/qbk/throw_on_failure.qbk b/doc/qbk/throw_on_failure.qbk new file mode 100755 index 00000000..d5249793 --- /dev/null +++ b/doc/qbk/throw_on_failure.qbk @@ -0,0 +1,18 @@ + +[section:throw_on_failure Annex: Throw on Failure] + +This example shows how to setup the library to throw exceptions on contract condition failure (overriding the library default behaviour to call `std::terminate()` to handle contract failures). + +Specifically: + +# Any exception (including user defined ones) that is thrown when checking a contract condition is re-thrown by the contract failure handlers defined below. +# However, if a contract condition fails from a destructor, exceptions cannot be thrown (to comply with C++ STL exception safety requirements) so a message is logged to `std::clog` and the program execution continues. +[footnote Continuing the program in this case assumes that the destructors body will be able to somehow execute correctly even if the class invariants do not hold true. +This is usually /not/ a safe assumption and it is made here only for simplicity. +You could chose to still terminate in case class invariants fail for a destructor or to attempt to recover from such an error in some other, more sophisticated, way.] +# In addition, the postcondition failure handler catches any exception derived from `std::exception` to print the exception description `what()` on `std::clog` before re-throwing it (this is to show how the contract failure handlers can selectively catch exceptions). + +[throw_on_failure_cpp] + +[endsect] + diff --git a/doc/qbk/todo.qbk b/doc/qbk/todo.qbk new file mode 100755 index 00000000..001a9ef2 --- /dev/null +++ b/doc/qbk/todo.qbk @@ -0,0 +1,213 @@ + +[section TODO] + +This section lists open items under consideration for future development of this library. +It is mainly intended as a memorandum for the library authors. + +[/ *** PUBLIC TODs ***] + +[section Improve contract macros `sequence` error detection and reporting] + +The current implementation for syntax error detection and reporting for the `sequence` parameter of the contract macros should be improved. +For example, if I forget the sequence element for the result type `(result-type)`, the preprocessor given a ton of errors most of which are about Boost.Preprocessor internal macros and make no sense to the user. +While there are some fundamental limitations to the amount of syntax checking I can implement with the preprocessor for `sequence`, I should be able to improve the current implementation. + +[endsect] +[section Can constructor member initialization list limitation be removed?] + +Can the contract macros overcome the constructor member initialization list limitation when separating definition from declaration? +However, this would have to work for all combinations of the followings: (1) with and without contracts, (2) definition together and separated from declaration, (3) with and without member initialization list. + +[endsect] +[section Should preconditions be checked before constructor member initialization list?] + +The library checks constructor preconditions after executing the member initialization list: {Default AND Pre}Body{Post AND Inv} (Default is the member initialization list). + +This is what Eiffel does but is this what C++ should do or {Pre AND Default} is a better approach for C++? +Why does Eiffel do {Default AND Pre}? +Does any of the CP proposals for C++ mention this issue explicitly? + +If {Pre AND Default} is a better approach, {Default AND Pre} should be documented as a library limitation. +If {Default and Pre} is a better approach, I should document why. + +[endsect] +[section Can syntax of contract macros be unified with other Boost libraries?] + +Look if the contract macro `sequence` syntax can be unified with the one of other Boost libraries. + +Specifically, is this possible with Boost.ConceptCheck and how concept checking interacts with this Contract Programming library? +Same questions respect to Boost.Parameter. +Any other Boost library I should look in these regards? + +[endsect] +[section Consider allowing optional contract checking based on assertion priority and/or class name] + +# I have a template library that is well tested so I want to disable postcondition checking. +However, that is a template so it cannot be precompiled separately with postconditions off. +I must compile it together with the rest of the code. +Therefore, if the rest of the code needs to check postconditions, I must check postconditions for the well tested template library as well! +# There might be contract conditions which are very inefficient to test so I might want to turn only the inefficient condition checking off. + +If I could disable contract checking (at least at run-time) based on class name or class+function name, I could address the template issue. +And/or if I could disable contract checking (at least at run-time) based on some assertion priority (or level of inefficiency), I could address the second issue (one of the CP C++ proposal might suggest to attach a priority label to the assertions... I am not sure). + +[endsect] +[/ *** PRIVATE TODOs *** ] + +[/ !!! FOR MY RECORD ONLY -- LEAVE THESE COMMENTED OUT !!! + +[section Rename SourceForge to contractpp] + +Rename SourceForge project and SVN repository from 'dbcpp' to 'contractpp' (for Contract++). +Also indicate that the library is about "Correctness And Testing" (same as Boost category). + +[endsect] +[section Update information and links on BoostLibraryUnderConstruction] + +Update information, description, links, etc for Boost.Contract to point to latest Contract++ release and documentation on SourceForge at https://svn.boost.org/trac/boost/wiki/LibrariesUnderConstruction#Boost.Contract. + +[endsect] +[section Destructor should use CHECK_INVARIANT instead of CHECK_ANY] + +Destructor optional compilation should just use CHECK_INVARIANT and not CHECK_ANY because there is no need to add destructor contract overhead when only pre/post are checked if no inv is checked. + +Similarly, for non-member function only CHECK_PRE and CHECK_POST should be checked because they have no inv so there is no reason to add contract overhead when only inv is checked. + +(Note that is NOT the case for static-members which have pre and post bust also inv (static inv) so they must use CHECK_INV, CHECK_PRE, and CHECK_POST as usual.) + +[endsect] +[section Read MPL book chapter on compiler performances] + +Read MPL book chapter on compiler performances in the attempt to understand compile-time optimization for this library... + +[endsect] +[section Make library thread-safe if CONTRACT_THREADING is #defined] + +In this case: this library will also require Boost.Threading. +sync_<> must have mutex. +contract_global_checking_ must have a mutex. +This will add quite a bit on sync at the class level but also at a global level via dbc_global_checking_... + +Consider impl waiting pre/post conditions. + +[endsect] +[section Scoped contract macros] + +Add CONTRACT_FUNCTION_SCOPED(signature_sequence, scoped_code, preconditions_code_block, postconditions_code_block, body_code_block) and similar for CONTRACT_CONSTRUCTOR_SCOPED() and CONTRACT_DESTRUCTOR_SCOPED(). +The scoped_code is executed in the function definition before contract.call() is invoked. +This code can be used to hold scoped resources during contract checking and body execution. + +If the scoped resource is a scoped mutex lock, then this can be used to executing inv+require+body+inv+ensure atomically (sync'd by a mutex) so that effectively only 1 operation at the time for class can be exec among the operations w/ contracts. + +To deal with concurrency, I could provide a "scoped" version of the macros and let the user put the locks. + + int f(void) + CONTRACT_FUNCTION_SCOPED( (int) (f)( (void) ), + boost::recursive_mutex::scoped_lock lock(mutex_); + { + }, { + }, { + return -1; + }) + + Will exapnd to: + + void f(void) + { + boost::recursive_mutex::scoped_lock lock(mutex_); // scoped_code + contarct().call(...); + } + ... // Usual stuff. + + But even with contract compilation it must include to scoed_code so: + + void f(void) + { + boost::recursive_mutex::scoped_lock lock(mutex_); // scoped_code + { return -1; } // body_code_block + } + +Still, what about the global lock to check if asserting globally?? + +[endsect] +[section Consider value of adding contracts to all STL classes in `contract::std`] + +All std:: classes/functions can be wrapped by classes/function in contract::std declaring contracts for the STL entities. +For example a contract::std::list<> class can wrap std::list<> and add contracts to it. +Post/Inv checking here is likely not interesting given that STL code is well tested to work. +Pre checking might be interesting instead. + +Look for STL standard guarantees. +If I cannot find them on-line, consider asking Crowl and/or Ottosen. +In particular, I would like to write contract::std::map<> to exercise the library more also when there is code with commas not wrapped by (). + +[endsect] +[section Document MSVC error "warning ... not enough actual parameters for macro BOOST_PP_SEQ'] + +Document MSVC error "warning ... not enough actual parameters for macro 'BOOST_PP_SEQ...'" repeated many, many times when using "(f)( )" instead of "(f)( (void) )" to specify empty argument list. + +[endsect] +[section Shall I try to compile on MSVC with /Wall??] + +This gives a LOT of warning also in Boost... +For g++, it compiles with no warnings but the "already friend" one. + +[endsect] +[section Can I remove limitation that BODY() must be used when calling overridden function] + +If an overriding function does not use BODY() to invoke the overridden function, contracts go into infinite recursion. +Document this limitation (as a warning). + +It is not possible to work around this limitation. +Using object state the library could detect infinite recursion between overriding and overridden function (I prototyped something like this but I am not even sure if this is 100% possible). +However, to break the recursion the base contract will have to call the base body function via static binding (otherwise using dynamic binding, default C++ behaviour for the call, the overriding function will be called causing the recursion). +The contract itself cannot perform the static binding call (e.g., using static_cast<> to the object) because the object state is changed only if pointers/references to the objects are used to call the body, but if pointers/objects are used then C++ uses dynamic binding for the call. +So the contract function could call a special method of the contracted class which performs the static binding call `contract_static_binding_body_...`. +The issue is that such a static binding call will raise a compiler error if the body function is pure virtual. +The library does not know directly when a function is pure virtual or not so the library will have to define `contract_static_binding_body_...` also for pure virtual functions and in this case the static binding call `B::f()` will raise a compile time error. +*** BUT, could I use templates so the contract_static_biding_body_ is templated and it is not compiled unless called? This way I only get the error if the use calls attempts the static binding for pure virtual?? *** + + struct base { + virtual void call() { + std::cout << "base call\n"; + // body(); // This causes infinite recursion as it calls deriv::body() via dynamic binding. + static_binding_body(); + } + void static_binding_body() { + std::cout << "base static binding body\n"; + b::body(); // Compiler error for pure virtual body()... + } + virtual void body() = 0; + // { + // std::cout << "base body\n"; + // } + }; + + struct deriv: base { + virtual void call() { + std::cout << "deriv call\n"; + body(); + } + virtual void body() { + std::cout << "deri body\n"; + base::call(); // Causes infinite recursion... + // base::body(); // This is fine instead. + } + }; + + Infinite recursion: deriv::base --> deriv::body --> base::call() --> deriv::body() causing infinite recursion because base::body() is NOT called... + +So, at the moment, I did not see a way around this. +Programmers will have to pay attention and use BODY() for static binding call of the base class. + +[endsect] +[section Email all referenced authors after 1st solid release] + +After the 1st solid release of Contract++, email all cited authors (Crowl, Ottosen, Meyer, Mitchell, Abrahams, etc) to ask for feedback on the library. + +[endsect] + +] + +[endsect] + diff --git a/doc/qbk/tutorial.qbk b/doc/qbk/tutorial.qbk new file mode 100755 index 00000000..ac1b1792 --- /dev/null +++ b/doc/qbk/tutorial.qbk @@ -0,0 +1,1071 @@ + +[section Tutorial] + +This section gives an overview of Contract Programming and explains how this library can be used to write contracts. +At the end of the section there is a fully working example that can be compiled and executed. + +[section Contract Programming Overview] + +Contract Programming is characterized at least by the following assertion mechanisms (see __Meyer1997__, __Ottosen2004__, or __Crowl2006__): + +# It is possible to describe *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 member function with a contract, and before the destructor is executed (e.g., class invariants can define a valid state for all objects of a class). +It is possible to describe *static class invariants* also which are expected to be true before and after the execution of any member function with a contract (including static member functions, constructor entry, and destructor exit). +# It is possible to describe function *preconditions*. These are logical conditions that programmers except to be true when the function is called (e.g., to check constraints on input function arguments). +# It is possible to describe function *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). +# It is possible to formalize the notion of overriding a virtual member function via *subcontracting*. Subcontracting can be justified by substitution principles and it consists of the following rules that the overriding function must obey: + # Preconditions cannot be strengthen. + # Postconditions cannot be weaken. + # Class invariants cannot be weaken. +# It is possible to describe *block invariants*. +These are logical conditions that programmes 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 function like /loop invariants/ asserting conditions that are excepted to be true for every loop iteration. +# It is possible to describe a *loop variant*. +This a positive integer expression with a value that is expected to decrease at every subsequent loop iteration. + +Based on these definitions of invariants, preconditions, postconditions, and subcontracting it is possible to specify the semantics of the invocation of a function for which a contract has been specified. + +[h5 Non-Member Function Call Semantics] + +A non-member function call should execute the following steps: + +# Check preconditions. +# Execute function body. +# Check postconditions. + +[h5 Member Function Call Semantics] + +A member function call should execute the following steps: + +# Check static class invariants. +# Check non-static class invariants /AND/, when subcontracting, check the base class invariants (for non-static member functions only +[footnote Static member functions cannot be virtual so they cannot be overridden and they cannot subcontract.]). +# Check preconditions /OR/, when subcontracting, check the overridden function preconditions. +# Execute function body. +# Check static class invariants (even if body throws an exception). +# Check non-static class invariants /AND/, when subcontracting, check base class invariants (for non-static member functions only plus checked even if body throws an exception). +# Check postconditions /AND/, when subcontracting, check overridden function postconditions (only if body did not throw an exception). + +Where /AND/ and /OR/ are the logical "and" and "or" operators evaluated in short-circuit (i.e., A /AND/ B evaluates B only if A is evaluated to be true, A /OR/ B evaluates B only if A is evaluated to be false). + +When a member function overrides more than one virtual function due to multiple inheritance: + +* Class invariants are checked in /AND/ with the invariants of /all/ the base classes (following the inheritance order). +* Preconditions are checked in /OR/ with the preconditions of /all/ the overridden functions (following the inheritance order). +* Postconditions are checked in /AND/ with the postconditions of /all/ the overridden functions (following the inheritance order). + +[h5 Constructor Call Semantics] + +A constructor call should execute the following steps: + +# Initialize member variables via the constructor member initialization list (if such a list is specified). +# Check static class invariants (but not the non-static class invariants). +# Check preconditions. +# Execute constructor body. +# Check static class invariants (even if body throws an exception). +# Check class invariants (even if body throws an exception). +# Check postconditions (only if body did not throw an exception). + +Before constructor body execution, there is no object therefore: + +* Non-static class invariants do not have to hold true and they are not checked at constructor entry. +* Preconditions cannot access the object. +* Postconditions cannot access the old object value (as it was before body execution). + +[h5 Destructor Call Semantics] + +A destructor call should execute the following steps: + +# Check static class invariants. +# Check class invariants. +# Execute destructor body. +# Check static class invariants (but not the non-static class invariants plus checked even if body throws an exception +[footnote However, the destructor body should be programmed to /never/ throw exceptions to comply with C++ STL exception safety requirements.]). + +Note that: + +* Destructors have no arguments so they have no preconditions. +* After destructor body execution, there is no object anymore (because it has been destroyed) so non-static class invariants do not have to hold true and they are not checked at destructor exit. +* Destructors have no postconditions as there is no function argument and after body execution there is no object. + +[endsect] +[section Checking Contracts] + +After programmers specify contracts, this library provides a mechanism to automatically check if class invariants, preconditions, postconditions, block invariants, and loop variants hold true at run-time or not. + +If a class invariant, precondition, postcondition, block invariant, or loop variant asserted via `__CONTRACT_ASSERT__()`, `__CONTRACT_ASSERT_BLOCK_INVARIANT__()`, or `__CONTRACT_ASSERT_LOOP_VARIANT__()` is checked to be false, the library invokes the `contract::__class_invariant_failed__()`, `contract::__precondition_failed__()`, `contract::__postcondition_failed__()`, `contract::__block_invariant_failed__()` (for both block invariant and loop variant failures) function respectively. +These functions invoke `std::terminate()` by default but programmers can redefine them to take a different action using `contract::__set_class_invariant_failed__()`, `contract::__set_precondition_failed__()`, `contract::__set_postcondition_failed__()`, and `contract::__set_block_invariant_failed__()`. + +This mechanism is similarly to the one of C++ `std::set_terminate()` (see __Throw_on_Failure__ for an example). + +[h5 Exceptions] + +When an exception if thrown while checking invariants, preconditions, or postconditions then the contract condition is considered failed (because it was not possible to check it as being true) and the relative contract failure handler function is invoked. + +When an exception if thrown while executing the body then the class invariants are checked (for member functions only) and, if they hold true, the exception is passed up to the caller as usual (otherwise the class invariant failed handler function is invoked). +Therefore, exception specifications will work as usual as long as the member function body does not fail the class invariant when it throws the exception. + +[h5 Constant-Correctness] + +Contracts are only supposed to /check/ the object state in order to ensure its compliance with the software specifications. +Therefore, contract checking should not be allowed to modify the object state and exclusively "read-only" operations (or /queries/) should be used to specify contracts. + +This library enforces +[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`.] +this constraint at compile-time using the C++ `const` qualifier. +Contracts only have access to the object, function arguments, and return value via constant references thus only constant members can be accessed when checking contracts. +Furthermore, pointers are passed as `const T*` so the pointed object is constants and cannot be changed (note that the pointer value itself is not constant, because it is not passed as `const T* const`, and it could be changed by the contract but such a change will be local to the contract function therefore still ensuring the const-correctness of the contract). + +[endsect] +[section Writing Contracts] + +The following overview of the contract macros and their usages should be enough to understand the working example at the end of this section, most of the examples in the __Examples__ annex, and to start writing contracts on your own. +Consult the library __Reference__ documentation for more information. + +[h5 Contract Macros] + +This is a summary of the macros provided by this library to program contracts +[footnote To improve contract readability, it is recommended to configure your editor C++ syntax highlighting to highlight also the macros +`CONTRACT_INVARIANT`, +`CONTRACT_FUNCTION`, +`CONTRACT_CONSTRUCTOR`, +`CONTRACT_DESTRUCTOR`, +`CONTRACT_OLDOF`, +`CONTRACT_BODY`, +`CONTRACT_CONSTRUCTOR_BODY`, +`CONTRACT_DESTRUCTOR_BODY`, +`CONTRACT_ASSERT`, +`CONTRACT_ASSERT_MSG`, +`CONTRACT_ASSERT_BLOCK_INVARIANT`, +`CONTRACT_ASSERT_BLOCK_INVARIANT_MSG`, +`CONTRACT_ASSERT_LOOP_VARIANT`, +`CONTRACT_ASSERT_LOOP_VARIANT_MSG`, +`CONTRACT_INIT_LOOP_VARIANT`, +and the sequence tokens +`precondition`, `postcondition`, `body`, `copyable`, and `inherit`. +For example, this can be done in the Vi IMproved (VIM) editor by adding these symbols to the `"cpp.vim"` file (usually in the VIM system configuration directory).]. + +[*[^__CONTRACT_INVARIANT__( (static)({ ... }) ({ ... }) )]] + +This macro is used to program class invariants. +It should appear within a private section at the very beginning of the class declaration. +It takes one parameter which is a __Boost_Preprocessor__ sequence of the following elements: + +* `(static) ({ ... })`: The code block `{ ... }` +[footnote Some text editing programs might highlight curly brackets `{}` within a macro parameter as a C++ syntax error. +This is incorrect as the ISO C++ standard allows for macro parameters to contain curly brackets and the editor might offer an option for disabling this incorrect syntax error highlighting. +For example, when C++ syntax highlighting is turned on in the Vi IMproved (VIM) editor, curly brackets within macro parameters are highlighted as errors but that can be disabled by adding the line `let c_no_curly_error=1` in the `".vimrc"` file (typically in your home directory).] +asserting static class invariants. +This is optional and it can be omitted. +* `({ ... })`: A secondary code block `{ ... }` asserting non-static class invariants. +This is mandatory but an empty code block `({})` can be specified if there are no class invariants (using `__CONTRACT_INVARIANT__()` instead of `__CONTRACT_INVARIANT__( ({}) )` will generate a preprocessor error). + +If contract compilation is turned off, this macro expands to nothing (and no contract overhead is added). +Otherwise, it expands to code that checks the class invariants (see __Without_the_Macros__ for details). + +[*[^__CONTRACT_FUNCTION__( /signature-sequence/ (precondition)({ ... }) (postcondition)(/result-name/)({ ... }) (body)({ ... }) )]] + +[*[^__CONTRACT_CONSTRUCTOR__( /signature-sequence/ (precondition)({ ... }) (postcondition)({ ... }) (body)({ ... }) )]] + +These macros are used to program preconditions and postconditions for functions (members and non) and constructors respectively. +They should appear right after the function and constructor declaration, and after the constructor members initialization list when such a list is specified. +They both take the following parameters: + +* /signature-sequence/: A __Boost_Preprocessor__ sequence with the function or constructor signature tokens (see subsections below). +* `(precondition) ({ ... })`: An optional code block `{ ... }` asserting the preconditions. +* `(postcondition) (`/result-name/`) ({ ... })`: An optional code block `{ ... }` asserting the postconditions. +The `(`/result-name/`)` element is only specified for non-void functions (so never for constructors) and it names the variable used to access the return value within postconditions (e.g., `result`). +* `(body)({ ... })`: A mandatory code block `{ ... }` implementing the function or constructor body. + +If contract compilation is turned off, these macros simply expand to the body code block (and no contract overhead is added). +Otherwise, they expand to code that implements the __Member_Function_Call_Semantics__ and __Constructor_Call_Semantics__ respectively thus checking class invariants, preconditions, and postconditions (see __Without_the_Macros__ for details). + +[*[^__CONTRACT_DESTRUCTOR__( /signature-sequence/ (body)({ ... }) )]] + +This macro is used to program destructor contracts. +It should appear right after the destructor declaration. +It takes the following parameters: + +* /signature-sequence/: The destructor signature tokens (see below). +* `(body) ({ ... })`: A mandatory code block `{ ... }` implementing the destructor body. + +If contract compilation is turned off, this macro simply expands to the body code block (and no contract overhead is added). +Otherwise, it expands to code that implements the __Destructor_Call_Semantics__ checking the class invariants (see __Without_the_Macros__ for details). + +[*[^__CONTRACT_OLDOF__( variable_name )]] + +This macro is used to access the old value for the variable with the specified name in postconditions. +It takes the following parameter: + +* `name`: The name of the variable. +As usual, `this` can be used as the variable name for the object so `CONTRACT_OLDOF(this)` is used to access the object old value. +Otherwise, any of the function argument variable names can be specified. +The variable type (class or argument type) must be tagged copyable in the signature sequence for the variable old value to be available (see below). +The library generates a compile-time error (containing the text `contract::noold`) if this macro is used on a variable name of a type which was not tagged copyable. + +[note This library does not support old values for /any/ expression that can be evaluated in postcondition as supported by Eiffel and required __Crowl2006__ instead. +The library supports old values for the object and all the function argument types, and this is a subset of the old values supported by Eiffel and required by __Crowl2006__. +However, the old values supported by the library are usually enough to program the postconditions (e.g., all Eiffel examples from __Meyer1997__, __Mitchell2002__, and all C++ examples from __Crowl2006__ were successfully programmed using just these old values, see the __Examples__ section).] + +The old value variable are only declared locally within postconditions therefore they cannot be mistakenly accessed outside the related postcondition code block (see __Without_the_Macros__ for details). + +[note If pointer types are tagged copyable, then the pointer value, and /not/ the pointed value, is copied. +Therefore the old pointer value will be available in postconditions via `__CONTRACT_OLDOF__()` and /not/ the old pointed value. +In other words, as usual, shallow copies are performed for pointers (unless the pointed type defines a different copy operation). +Be careful as this might not be what you intended when using `__CONTRACT_OLDOF__()` on a pointer +[footnote However, this is the only sensible semantics for copying pointers as the pointer could of type `void*` for which it is not possible to copy the pointed object, plus there might cases where the functions actually changed the pointer value so `__CONTRACT_OLDOF__()` needs to the return the old pointer value (and not the old pointed value), plus this the usual C++ pointer copy semantic.]. + +The notable exception is the object `this` which is passed to the contract functions by pointer but its old value is automatically deep copied by the library.] + +[*[^__CONTRACT_ASSERT__( boolean_condition )]] + +This macro is used to assert conditions within the class invariant, precondition, and postcondition code blocks (see also __CONTRACT_ASSERT_MSG__()). +It takes the following parameter: + +* `boolean_condition`: The boolean condition being asserted. + +If contract compilation is turned off, this macro expands to nothing (and no contract overhead is added). +Otherwise, this macro expands to code that triggers the invocation of `contract::__class_invariant_failed__()`, `contract::__precondition_failed__()`, or `contract::__postcondition_failed__()` in case the asserted boolean condition is evaluated to be false at run-time from within invariants, preconditions, or postconditions respectively (see __Without_the_Macros__ for details). + +[*[^__CONTRACT_ASSERT_BLOCK_INVARIANT__( boolean_condition )]] + +This macro is used to assert invariant within a generic code block (see also __CONTRACT_ASSERT_BLOCK_INVARIANT_MSG__()). +This macro can also be used within loops to assert loop invariants. +It takes the following parameter: + +* `boolean_condition`: The boolean condition being asserted. + +If contract compilation is turned off, this macro expands to nothing (and no contract overhead is added). +Otherwise, this macro expands to code that triggers the invocation of `contract::__block_invariant_failed__()` in case the asserted boolean condition is evaluated to be false at run-time (see __Without_the_Macros__ for details). + +[note This macro is similar to the C `assert()` macro as it can be used at any point within a block of code. +However, in case the asserted condition either throws an exception or it is evaluated to be `false`, this macro invokes `contract::__block_invariant_failed__()` instead of calling `abort()`.] + +[*[^__CONTRACT_ASSERT_LOOP_VARIANT__( integer_expression )]] + +[*[^__CONTRACT_INIT_LOOP_VARIANT__]] + +This macro is used to assert loop variants (see also __CONTRACT_ASSERT_LOOP_VARIANT_MSG__()). It must be used /after/ `__CONTRACT_INIT_LOOP_VARIANT__` has been called once within the same code block scope (see below). + +* `integer_expression`: An integer expression which is evaluated at each loop iteration as the loop variant. +It must be always positive (not negative and not zero) and it must strictly decrease at each subsequent loop iteration (of `1` or more). + +If contract compilation is turned off, this macro expands to nothing (and no contract overhead is added). +Otherwise, this macro expands to code that triggers the invocation of `contract::__block_invariant_failed__()` at run-time in case the specified variant expression is either not positive or it does not decrease from one loop iteration to the next (see __Without_the_Macros__ for details). + +[h5 Step-by-Step Example] + +Let's assume we want to write a `myvector` class template that wraps the C++ STL vector template `std::vector` adding contracts to it. +Here we show, step-by-step, how to program a contract for the `push_back()` function. + +[*Step 1)] First, we implement `myvector::push_back()` to call `std::vector::push_back()` and we can sketch the contract using comments. + + template + class myvector { + // Invariant: (size() == 0) == empty() + + public: + // Precondition: size() < max_size() + // Postcondition: size() == (oldof size() + 1) + void push_back(const T& element) { vector_.push_back(element); } + + ... // Rest of the class. + private: + std::vector vector_; + }; + +Where "`oldof size()`" indicates the value `size()` has before the `push_back()` function is executed. + +To keep this example simple, we intentionally did not write the full contract but we only wrote one invariant, one precondition, and one postcondition (see the STL Vector __Example__ for the complete `push_back()` contract). +These contract conditions specify the followings: + +# The class invariant asserts that the vector is empty if and only if its size is zero. +# The precondition asserts that the vector size must be smaller than the maximum size when `push_back()` is called (so there is available space to add one extra vector element). +# The postcondition asserts that the vector size must increase by 1 after `push_back()` has been executed (to reflect the newly added vector element). + +[*Step 2)] The library provides the `__CONTRACT_FUNCTION__()` macro to write member function contracts. +This macro must be used /right after/ the `push_back()` function declaration. +The `push_back()` function definition `{ vector_.push_back(); }` is moved within the macro becoming the last element of the __Boost_Preprocessor__ sequence passed as the macro parameter: + + template + class myvector { + // Invariant: (size() == 0) == empty() + + public: + // Precondition: size() < max_size() + // Postcondition: size() == (old size()) + 1 + void push_back(const T& element) + ``*CONTRACT_FUNCTION*``( ``/signature-sequence/`` + ``/precondition-sequence/`` + ``/postcondition-sequence/`` + ``*(body) ({ + vector_.push_back(element); + })* )`` // No need for ";" after the macro closing parenthesis ")". + + ... // Rest of the class. + private: + std::vector vector_; + }; + +There is no need for "`;`" after the macro closing parenthesis "`)`". + +[*Step 3)] We now program the postconditions using `__CONTRACT_ASSERT__()` inside a code block `{ ... }` specifying the /postcondition-sequence/ elements: + + template + class myvector { + // Invariant: (size() == 0) == empty() + + public: + // Precondition: size() < max_size() + void push_back(const T& element) + CONTRACT_FUNCTION( ``/signature-sequence/`` + ``/precondition-sequence/`` + ``*(postcondition) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + })*`` + (body) ({ + vector_.push_back(element); + }) ) + + ... // Rest of the class. + private: + std::vector vector_; + }; + +Note how `CONTRACT_OLDOF(this)` is used to access the old object value as it was before body execution. + +[*Step 4)] Similarly, we program the preconditions in a code block `{ ... }` specifying the /precondition-sequence/ elements: + + template + class myvector { + // Invariant: (size() == 0) == empty() + + public: + void push_back(const T& element) + CONTRACT_FUNCTION( ``/signature-sequence/`` + ``*(precondition) ({ + CONTRACT_ASSERT( size() < max_size() ); + })*`` + (postcondition) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + + }) + (body) ({ + vector_.push_back(element); + }) ) + + ... // Rest of the class. + private: + std::vector vector_; + }; + +[*Step 5)] The /signature-sequence/ elements are discussed separately (see below) and for now we will leave them unresolved. + +[*Step 6)] Similarly to what we did with for preconditions and postconditions, we program the class invariants in a code block `{ ... }` specifying sequence elements passed to the `__CONTRACT_INVARIANT__()` macro: + + template + class myvector { + + ``*CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( (size() == 0) == empty() ); + }) )*`` // Again, no need for ";" after the macro closing parenthesis ")". + + public: + void push_back(const T& element) + CONTRACT_FUNCTION( ``/signature-sequence/`` + (precondition) ({ + CONTRACT_ASSERT( size() < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + + }) + (body) ({ + vector_.push_back(element); + }) ) + + ... // Rest of the class. + private: + std::vector vector_; + }; + +Again, there is no need for "`;`" after the macro closing parenthesis "`)`". + +[*Step 7)] The same step-by-step process can be applied to understand the usage of `__CONTRACT_CONSTRUCTOR__()` and `__CONTRACT_DESTRUCTOR__()` (see the example at the very end of this section). + +[h5 Contract Code Blocks] + +This library allows for arbitrary constant-correct code within the class invariant, precondition, and postcondition code blocks `({ ... })`. + +In other words, the class invariant, precondition, and postcondition code blocks can contain any legal C++ code and they can access any constant class member (private, protected, or public). +However, writing complex code in the contracts will increase the probability of introducing bugs in the contracts themselves so it is better to limit the contract code to a simple list of assertions with occasional if-statements to guard them. +Furthermore, if non-public members are used in preconditions then the callers will not be able to fully check the preconditions to make sure the contract is satisfied before calling the function so it is best to only use public members at least in preconditions +[footnote __Meyer1997__ argues preconditions asserted using non-public members are ill written thus the Eiffel programming language enforces this rule at compile-time. +However, in C++ friend callers could still be able to fully check preconditions via the friendship even when non-public functions are used to assert them therefore this rule is left as a recommended practice for programmers to follow and it is not enforced by the library.]. + +In addition, this library checks class invariants (as well as preconditions and postconditions) only for functions that have a contract. +For example, if a private member function is allowed to /temporarily/ brake the class invariants, you can omit the contract for that one private function so no invariants (as well as no preconditions and no postconditions) will be checked when that function is called. +However, it should never be the case that public member functions can brake class invariants. +It is recommended to write contracts for all functions (public and non) with the rare exceptions of a private member function that cannot be programmed without allowing for it to temporarily brake the class invariants. + +[important *Recommended Practices* + +1. Limit the contract code to a list of assertions with occasional if-statements to guard them. + +2. Only access public class members when asserting preconditions. + +3. Write contracts at least for all public member functions (even if they have no preconditions and no postconditions) so they check the class invariants. +] + +These practices are followed by all the examples of this documentation. + +[endsect] +[section Signature Sequence] + +The very first elements of the __Boost_Preprocessor__ sequence passed to the macros `__CONTRACT_CONSTRUCTOR__()`, `__CONTRACT_DESTRUCTOR__()`, and `__CONTRACT_FUNCTION__()` are the elements of the /signature-sequence/ +[footnote +If two __Boost_Preprocessor__ sequences are specified one after the other then they are automatically concatenated into one larger sequence. +For example let `seq1` be `(token1) (token2)` and `seq2` be `(token3) (token4) (token5)` then `seq1 seq2` is `(token1) (token2) (token3) (token4) (token5)`. +]. +The /signature-sequence/ repeats the syntactic elements of the function declaration. + +The syntax of /signature-sequence/ is somewhat unusual (even if it is all legal ISO standard C++). However, there is a convenient rule for remembering this syntax: + +[important *Signature Sequence Mnemonic* + +The tokens in the signature sequence appear in the exact same order as they appear in the relative function declaration.] + +[h5 An Example] + +Let's consider the following example (with respect to the `myvector` example above, we have added the base class `pushable` to show how to subcontract): + + template + ``*class myvector:*`` public ``*pushable*`` { + ``*public*``: + ``*void push_back(const T& element)*`` + CONTRACT_FUNCTION( ``/signature-sequence/`` ... ) + ... + }; + +Applying the mnemonic rule, we read the declaration of `push_back()` from top to bottom and we find the following tokens in the listed order (we have to start all the way up to the top of the `myvector` class declaration): + +# The [*[^class]] keyword for `myvector` (this indicates that `push_back` is a member function). +# The [*[^myvector]] class type (this indicates that `push_back` is a member function of `myvector`). +# The [*[^pushable]] base class which is repeated in /signature-sequence/ as `(inherit)(pushable)` but only when the function is subcontracting from the specified base class (because "`:`" is not a valid preprocessor token `(inherit)` is used instead; also the inheritance access level, the `public` keyword in this case, is not relevant and it is not repeated in /signature-sequence/). +# The [*[^public]] access level of the `push_back()` member function. +# The [*[^void]] return type. +# The [*[^push_back]] function name. +# The parenthesis "[*[^(]]" to open the function argument list. +# The [*[^const T&]] function argument type. +# The [*[^element]] function argument name. +# The parenthesis "[*[^)]]" to close the function argument list. + +Wrapping all these tokens within parenthesis `()` and listing them in the exact order as they appear in the function declaration, we obtain the /signature-sequence/ elements for this example. +The parenthesis `()` around the tokens are mandatory because they are the ones actually creating the __Boost_Preprocessor__ sequence. New lines and spaces do not matter within preprocessor sequences. + + (class) (copyable)(myvector) (inherit)(vector_interface) + (public) (void) (push_back)( (const T&)(element) ) + +The `myvector` class type is preceded by `(copyable)` because, for this example, we wanted to access the old object value `CONTRACT_OLDOF(this)` (as the object was before the function body execution) in the postconditions. +Also any function argument type can be tagged copyable if the old value of the related argument is needed in the postconditions. +In this example, `(const T&)(element)` could have been tagged copyable and specified in /signature-sequence/ as `(copyable)(const T&)(element)` if the old value of the argument `CONTRACT_OLDOF(element)` (as the argument was before the body execution) was needed in the postconditions. + +Completing the example presented in the previous section, with the addition of subcontracting `myvector::push_back()` from `pushable::push_back()`, we have: + + template + class myvector: public pushable { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( (size() == 0) == empty() ); + }) ) + + public: + void push_back(const T& element) + CONTRACT_FUNCTION( ``[*(class) (copyable)(myvector) + (inherit)(pushable) + (public) (void) (push_back)( (const T&)(element) )]`` + (precondition) ({ + CONTRACT_ASSERT( size() < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + }) + (body) ({ + vector_.push_back(element); + }) ) + + ... // Rest of the class. + private: + std::vector vector_; + }; + +This is a fully working example assuming that: + +# `pushable::push_back()` also has a contract specified using this library since it is used for subcontracting (this library allows to specify contracts also for pure virtual functions, see below). +# `myvector` has an accessible constant-correct +[footnote A /constant-correct copy constructor/ constructs the object copying it from a constant-reference of the source object thus it cannot alter the state of the copied object.] +copy constructor since it was tagged `(copyable)` (see `contract::__copy__`): + + // Must be accessible and construct from a const& parameter. + myvector::myvector(const myvector& source) { ... } + +If either one of these conditions is not true, this library will generate a compile-time errors when attempting to compile the code above. + +[h5 Full Syntax] + +Generalizing this example to include /all/ possible syntactic elements that can be found in a C++ function declaration, we obtain the full syntax for /signature-sequence/. + +[*/signature-sequence/ syntax for `__CONTRACT_FUNCTION__()`:] + + ``/{/``(class) ``/[/``(copyable)``/]/``(``/class-type/``) ``/{/``(inherit)(``/base-class-type/``)``/}*/`` + ``/{/``(public) ``/||/`` (protected) ``/||/`` (private)``/}}::/`` + ``/[/``(template)( ``/{/``(``/function-template-parameter-type/``)(``/function-template-parameter-name/``)``/}+/`` )``/]/`` + ``/[/``(static)``/]/`` ``/[/``(virtual)``/]/`` + (``/result-type/``) (``/function-name/``)( ``/{/``(void) ``/||/`` ``/{[/``(copyable)``/]/``(``/argument-type/``)(``/argument-name/``)``/}+}/`` ) ``/[/``(const)``/]/`` + +Where we have used the following conventions: + +* /[/=item=/]/ indicates an optional item. +* =item=/*/ indicates an item repeated zero of more times. +* =item=/+/ indicates an item repeated one of more times. +* /{/[^item1 ] ['operation ] [^item2 ] ['operation ...}] indicates the item resulting after evaluating the contents within the curly parenthesis. +* =item1= [' || ] =item2= indicates that either items can be specified. +* /{/=item=/}::/ indicates that item is` specified only for member functions. + +For example: + +* /[/`(copyable)`/]/ indicates that `(copyable)` is optional (it will only be specified for variables with old values in postconditions). +* /{/`(inherit)(`/base-class-type/`)`/}*/ indicates that `(inherit)(`/base-class-type/`)` can be repeated zero or more times (it can be omitted, it will only be specified when subcontracting, and when specified it can be repeated multiple times to support subcontracting from multiple base classes in case of multiple inheritance). +* /{[/`(copyable)`/]/`(`/argument-type/`)(`argument-name`)`/}+/ indicates that the function arguments (when specified instead of `(void)`) must be repeated one or more type (together with their optional `(copyable)` tag). +* /[/`(public)` [' || ] `(protected)` [' || ] `(private)`/]/ indicates that the access level is optional but when specified it must be either `(public)`, `(protected)`, or `(private)`. + +The usual C++ syntax constraints apply. +For example, `(static)` cannot be specified together with `(virtual)` and they can only be specified for class members so when `(class)` is also specified. +The library will generate compile-time errors if /signature-sequence/ contains tokens combinations which are C++ syntactically invalid. + +Note that within /signature-sequence/, multiple function arguments (as well as function template parameters) are /not/ separated by commas (you can use a space or a new line instead): + + (``/function-name/``)( (``/argument-type1/``)(``/argument-name1/``) + /* no comma (a space or new line can be used instead) */ + (``/argument-type2/``)(``/arguments-name2/``) + /* no comma (a space or new line can be used instead) */ + (``/argument-type3/``)(``/argument-name3/``)`` /.../ ``) + +Furthermore, if the function has no arguments, the argument list must be specified `void`: + + (``/function-name/``)( (void) ) + +Note that `(`/function-name/`)( )` *cannot* be used instead and it will generate a cryptic compile-time error. + +[note +An empty function argument list cannot be represented simply by empty parenthesis `()` as in `(`/function-name/`)()` because the C++ standard does not allow to specify empty preprocessor sequence elements like `()` thus `(`/function-name/`)( (void) )` must be used instead. +Note that the C++ standard allows to use `void` to specify a function with no arguments /function-name/`(void)` (this is the syntax used in all the examples of this documentations to be consistent with the relative /signature-sequence/ syntax requirement). + +The C99 standard instead allows for empty preprocessor sequence elements `()` (because it allows for empty macro parameters, see __Nelson2004__ and __Boost_Preprocessor__ for details). C99 also defines deprecated the use of `void` for functions with no arguments -- /function-name/`(void)` is deprecated. +Therefore, on C99 compilers `(`/function-name/`)()` should be used in /signature-sequence/ for functions with no arguments instead of `(`/function-name/`)( (void) )`. + +This library supports both syntaxes `(`/function-name/`)( (void) )` and `(`/function-name/`)()` in /signature-sequence/ but the later syntax will only compile for C99 (so it is not recommended). + +The same limitation applies to the `__CONTRACT_INVARIANT__()` macro when the class has no invariant. +Also in this case the library supports both syntaxes `__CONTRACT_INVARIANT__( ({}) )` and `__CONTRACT_INVARIANT__()` bu the later syntax will only compile for C99 (so it is not recommended). +] + +Finally, the syntaxes of /signature-sequence/ used by `__CONTRACT_CONSTRUCTOR__()` and `__CONTRACT_DESTRUCTOR__()` are somewhat different because C++ uses different syntactic elements for constructor and destructor declarations than for member functions (constructors cannot be virtual, destructors cannot have function arguments, etc). +However, the syntax for these /signature-sequences/ are still obtained applying the basic rule of listing the constructor and destructor signature tokens in the exact same order as they appear in the constructor and destructor declarations. + +[*/signature-sequence/ syntax for `__CONTRACT_CONSTRUCTOR__()`:] + + (class) (``/class-type/``) + ``/{/``(public) ``/||/`` (protected) ``/||/`` (private)``/}/`` + ``/[/``(template)( ``/{/``(``/function-template-parameter-type/``)(``/function-template-parameter-name/``)``/}+/`` )``/]/`` + (``/class-name/``)( ``/{/``(void) ``/||/`` ``/{[/``(copyable)``/]/``(``/argument-type/``)(``/argument-name/``)``/}+}/`` ) + +Note that constructors are always class members so `(class)` is not optional and it must always be specified. + +[*/signature-sequence/ syntax for `__CONTRACT_DESTRUCTOR__()`:] + + (class) (``/class-type/``) + ``/{/``(public) ``/||/`` (protected) ``/||/`` (private)``/}/`` + ``(virtual)`` (``/class-name/``)( (void) ) + +Note that `"~"` is /not/ a valid preprocessor token so it is not used to name the destructor (just use the class name). + +Also note that constructors and destructors do not directly subcontract (their /signature-sequences/ do not accept any `(inherit)(`/base-class-type/`)` token). +This is because the C++ object construction and destruction mechanism will automatically execute the code that checks the base class constructor and destructor contracts if present. + +[warning *Cryptic Preprocessing Errors* + +There is only a limited amount of compile-time error checking which the library can do on /signature-sequence/. +In some cases, and depending on the compiler used, an error in programming the /signature-sequence/ syntax will result in cryptic compiler errors. + +These compiler errors might involve library internal templates and macros as well as __Boost_Preprocessor__ internal macros (`BOOST_PP_...`). Furthermore, the error line number will only refer to the first line of code at which the contract macro appears (because new lines within macro parameters are removed by the preprocessor). + +The best way to resolve these errors is usually to inspect the /signature-sequence/ by eye instead of trying to make sense of the compiler error messages. +Also, try to compile with contracts turned off to make sure that the errors are actually in the contract code. +Rarely, it might be useful to look at the code generated by the contract macro expansion after preprocessing using your compiler related options ("-E -P" on GCC, "/EP" on Microsoft Visual C++, etc). + +While the C++ preprocessor imposes limits on the amount of error checking that can be performed on /signature-sequence/, the current library implementation does /not/ implement the best possible preprocessor error detection and reporting strategy. +This is an area of improvement for the library that is currently being worked on. + +[_Please report on the library __help_website__ the criptic preprocessing errors you experience in order to facilitate this process.] +] + +[h5 Inheritance] + +The library supports subcontracting from multiple base classes in case of multiple inheritance. + +[*Multiple Inheritance] + +In case of multiple inheritance, it is possible to subcontract from multiple base classes by repeating `(inherit)(`/base-class-type/`)` multiple times in /signature-sequence/. For example, assuming `myvector` is inheriting and subcontracting from /both/ the `boundable` and the `basic_begin` base classes: + + template + class myvector: + public ``*boundable::const_iterator>*``, + private ``*basic_begin::const_iterator>*`` { + ... // Class invariants. + + public: + typedef std::vector::const_iterator const_iterator; + + const_iterator begin(void) const + CONTRACT_FUNCTION( (class) (myvector) + // Multiple inheritance. + ``[*(inherit)(boundable)]`` + ``[*(inherit)(basic_begin)]`` + (public) (const_iterator) (begin)( (void) ) (const) + // No preconditions (omitted). + (postcondition) (result) ({ // Return value `result` in postconditions. + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ({ + // Must use CONTRACT_BODY() when calling the base function. + if (basic_begin::``*CONTRACT_BODY*``(begin) == + const_iterator()) { + return const_iterator(); + } + return vector_.begin(); + }) ) + + ... // Rest of the class. + private: + std::vector vector_; + }; + +The subcontracted contracts are checked in the order in which their `(inherit)` tokens are listed in /signature-sequence/ and the derived class contracts are checked last. + +[note +The above implies that if a derived class relaxes the precondition of an overridden function, all the base contract preconditions will have be checked first to fails before the relaxed preconditions of the overridden function are checked to pass. + +In this case, it would appear more efficient to check the derived class contract first. +However, the derived class invariants could be written assuming that the base class invariants hold true (for example the base class invariants could assert a pointer to be not null and thus the derived class invariants could deference the pointer without checking for nullity). +In doing so, the derived class invariants assume that they are checked last in /AND/ with all base classes invariants. +The same argument can be made for postconditions. +Therefore, if derived class invariants (and postconditions) should be checked last in /AND/ with all base classes invariants (and postconditions). It is natural to follow the same policy and check derived class function preconditions last in the /OR/ with all base class function preconditions (even if this introduces the inefficiency to have to check and fail all the base class function preconditions when a derived class function if relaxing the base class function preconditions).] + +[*Base Function Call] + +When the derived class invokes the overridden function in the base class the `CONTRACT_BODY()` macro must be used: + + ``/base-class/``::CONTRACT_BODY(``/function-name/``)(...) + +as illustrated by the example above. +The overriding function should *not* call the overridden function directly without using the macro: + + ``/base-class/``::``/function-name/``)(...) + +because this call will cause the contracts to executed infinite recursive calls (due to the dynamic binding of the contracted virtual base function /base-class/`::`/function-name/). +[footnote Using the augmented object state the library could detect infinite recursion between overriding and overridden function. +However, to break the recursion the base contract will have to call the base body function forcing static binding (otherwise using dynamic binding the overriding function will be called causing the infinite recursion). +The contract itself cannot perform the static binding call (e.g., using static_cast<> to the object) because the object state is changed only if pointers or references to the objects are used to call the body, but if pointers or reference are used then C++ uses dynamic binding for the call. +So the contract function could call a special method of the contract class which performs the static binding call but such a static binding call will raise a compiler error if the body function is pure virtual. +The library does not know directly when a function is pure virtual (body is `= 0;`) or not so the library will have to define the contract class static binding method also for pure virtual functions and in this case the static binding call `B::f()` will raise a compile time error because the function called via static binding is pure virtual.] + +[warning *Base Calls via CONTRACT_BODY()* + +Overriding functions must use /base-class/`::CONTRACT_BODY(`/function-name/`)` and not just /base-class/`::`/function-name/ when calling the overridden functions (otherwise the contract calls will cause infinite recursion).] + +[h5 Operators] + +The library supports contracts for operators. + +For operators, the `(`/function-name/`)` token in /signature-sequence/ must contain both the operator symbol and the operator /name/ spelled out in words without using any special symbol (this is necessary because, in general, the operator special symbols (`[]`, `==`, `<<`, etc) are not valid preprocessor tokens). +For operators, `(`/function-name/`)` takes the following form: + + (operator(``/symbol/``, ``/name/``)) + +Note the necessary double closing parenthesis `"))"` at the end. +For example: + + template + class myvector { + ... // Class invariants. + + public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::const_reference const_reference; + + const_reference ``*operator[]*``(size_type index) const + CONTRACT_FUNCTION( (class) (myvector) + (public) (const_reference) ``*(operator([]*[*, at))]``( + (size_type)(index) ) (const) + (precondition) ({ + CONTRACT_ASSERT( index < size() ); + }) + // No postconditions (omitted). + (body) ({ + return vector_[index]; + }) ) + + ... // Rest of the class. + private: + std::vector vector_; + }; + +The operator name, in this example `"at"`, is arbitrary and any name without special symbols can been used. + +[h5 Overloaded Functions] + +The library supports contracts for overloaded functions. + +[note +However, the library uses the argument *names* to distinguish the overloaded function signatures whereas C++ uses the argument types (this is because, in general, the argument types, for example `const int&`, are not valid preprocessor tokens). + +If two functions share the same name, the same number of arguments, and the same `const` qualifier then their argument names (and not just their types) must be different to allow the library to distinguish these two functions from each other. +(This is usually not a significant limitation because different argument names can be given.) +] + +For example: + + class number { + public: + // Overloaded functions distinguished using argument names (not types) and const. + + number add(const int& n) // (1) + CONTRACT_FUNCTION(...) + + // OK -- different from (1) because this is `const`. + number& add(const int& n) const + CONTRACT_FUNCTION(...) + + // OK -- different from (1) because argument named "d" instead of "n". + number add(const double& d) + CONTRACT_FUNCTION(...) + + // Error -- same as (1) because both non-const and with argument named "n" (even if different argument type). + number add(const double& n) + CONTRACT_FUNCTION(...) // Same as (1), error! + + ... + }; + +[h5 Function Templates] + +The `(template)` token is used in /signature-sequence/ to specify a function template listing the relative template parameters. +The template parameters are specified using a syntax similar to the one of the function arguments. + +For example: + + template + class myvector { + ... // Class invariants. + + private: + ``[*template]`` + static bool all_equals(Iter first, Iter last, const T& element) + CONTRACT_FUNCTION( (class) (myvector) + (private) ``[*(template)( (class)(Iter) )]`` + (static) (bool) (all_equals)( + (Iter)(first) (Iter)(last) (const T&)(element) ) + (precondition) ({ + CONTRACT_ASSERT( first < last ); + }) + (body) ({ + for (Iter i = first; i < last; ++i) { + if (*i != element) return false; + } + return true; + }) ) + + ... // Rest of the class. + }; + +In this example, the function also happens to be a static member but any function (non-member, member, static member, constructor, etc) can be be declared a template function as usual in C++. + +[endsect] +[section Deferring the Body] + +Class invariants, preconditions, and postconditions are part of the function specifications (indeed they /assert/ the function specifications). +Therefore, this library requires contracts to be defined together with the function declarations. +However, the function body (i.e., the function implementation) can be defined either together with the function declaration or separately. + +In other words, the usual C++ feature that allows to separate a function definition from its declaration is retained by this library. + +[h5 Separating Declaration and Definition] + +When the function body is defined separately from the function declaration: + +* The `(body)(;)` tokens are used to define the body in the macro parameter passed to `__CONTRACT_FUNCTION__()`. The `";"` symbol is the usual C++ symbol used to separate the function definition from its declaration. +* The `__CONTRACT_BODY__(`/function-name/`)` macro is used to name the function where it is defined. Again, for operators /function-name/ must be specified as `operator(`/symbol/`, `/name/`)`. +* Similarly, it is possible to separate constructor and destructor body definitions. +In this case, the macros `__CONTRACT_CONSTRUCTOR_BODY__(`/class-type/`, `/class-name/`)` and `__CONTRACT_DESTRUCTOR_BODY__(`/class-type/`, `/class-name/`)` should be used when the constructor and destructor are defined respectively (note again that `"~"` is /not/ specified to name destructors, just use the class name instead). + +For example: + + // Declarations (usually in header files). + + template + class myvector: + public boundable::const_iterator>, + private basic_begin::const_iterator> { + ... // Class invariants. + + public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::const_reference const_reference; + typedef std::vector::const_iterator const_iterator; + + myvector(const myvector& right) + CONTRACT_CONSTRUCTOR( (class) (myvector) + (public) (myvector)( (const myvector&)(right) ) + (postcondition) ({ + CONTRACT_ASSERT( vector_ == right.vector_ ); + }) + (body) ``*(;)*`` ) // Deferres body definition. + + virtual ~myvector(void) + CONTRACT_DESTRUCTOR( + (class) (myvector) + (public) (virtual) (myvector)( (void) ) + (body) ``*(;)*`` ) + + const_iterator begin(void) const + CONTRACT_FUNCTION( (class) (myvector) + (inherit)(boundable) + (inherit)(basic_begin) + (public) (const_iterator) (begin)( (void) ) (const) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ``*(;)*`` ) + + const_reference operator[](size_type index) const + CONTRACT_FUNCTION( (class) (myvector) + (public) (const_reference) (operator([], at))( + (size_type)(index) ) (const) + (precondition) ({ + CONTRACT_ASSERT( index < size() ); + }) + (body) ``*(;)*`` ) + + ... // Rest of the class. + private: + std::vector vector_; + }; + + // Separated definitions (eventually in a different file). + + template + ``*CONTRACT_CONSTRUCTOR_BODY(myvector, myvector)*``(const myvector& right) { + vector_ = right.vector_; + } + + template + ``*CONTRACT_DESTRUCTOR_BODY(myvector, myvector)*``(void) { + // Do nothing in this case. + } + + template + typename myvector::iterator myvector::``*CONTRACT_BODY(begin)*``(void) { + return vector_.begin(); + } + + template + typename myvector::const_reference myvector:: + ``*CONTRACT_BODY(operator([]*[*, at))]``(size_type index) const { + return vector_[index]; + } + +In addition to the usual benefits of separating function definitions from their declarations (smaller and more readable header files, less recompilation needed, etc), this separation also improves the library compile-time error messages. +When a function is defined together with its declaration, the function implementation code is passed as one single macro parameter `(body)({ ... })` to the contract macros. +Macro preprocessing removes all newline characters from within the macro parameters so the implementation code is compiled as if it were written on a single line. +As a result, any compile-time error within the function body code will be reported having the same line number and it will be harder to track. +Instead, if the body definition is separated from the function declaration, the definition code is not wrapped within a macro parameter and the compiler errors will indicate useful line numbers. + +[note It is recommended to separate the body definition from the function declaration so that line numbers in compiler errors retain their usual values.] + +Finally, note how the /signature-sequence/ unusual syntax does /not/ propagate to the function definitions (only the function name is changed in the function definitions). +Therefore, when definitions are separated from declarations, the files containing the definitions (usually the ".cpp" files) will not contain the unusual /signature-sequence/ syntax and they will be easier to read. + +[warning *Constructor Member Initialization List* + +Because of a library limitation, it is not possible to separate a constructor definition from its declaration when the constructor uses a member initialization list (see `__CONTRACT_CONSTRUCTOR_BODY__()` macro for details and workarounds) +[footnote The library /could/ overcome this limitation if future versions of the C++ standard were to support delegating constructors (as proposed by __Sutter2005__).]. +] + +[h5 Pure Virtual Functions] + +The library also supports contracts for pure virtual functions. + +In this case, the `(body)(= 0;)` tokens are used to define the body in the macro parameter passed to `__CONTRACT_FUNCTION__()`. +The `"= 0;"` symbol is the usual C++ symbol used to specify pure virtual functions. + +For example: + + template + class pushable { + ... + + public: + virtual void push_back(const T& element) + CONTRACT_FUNCTION( + (class) (pushable) + (public) (virtual) (void) (push_back)( (const T&)(element) ) + (postcondition) ({ + CONTRACT_ASSERT( back() == element ); + }) + (body) (= 0;) ) // Pure virtual body. + }; + +[endsect] +[section Blocks and Loops] + +Block invariants `__CONTRACT_ASSERT_BLOCK_INVARIANT__()` can be used to assert conditions anywhere within a code block (not just loops). +When used within a loop, block invariants can be used to assert loop invariants. + +Loop variants can be used to check the correctness of a loop, including its termination, as explained in detail in __Meyer1997__ (and they can only appear within loops). +At each loop iteration, the specified loop variant integer expression is automatically asserted to be positive (> 0) and to decrease from the previous loop iteration. +Loop variants can be used to assert loop correctness. +Because the variant decreases and it cannot be zero or smaller than zero it is possible to guarantee loop termination. +A loop can only have one variant. + +When asserting loop variants using `__CONTRACT_ASSERT_LOOP_VARIANT__()` it is necessary to first call `__CONTRACT_INIT_LOOP_VARIANT__` once (and only once) within a code block that has same of higher scope level than the loop code block. + +For example: + + double abs_total(const myvector& vector) + CONTRACT_FUNCTION( + (double) (abs_total)( (const myvector&)(vector) ) + (postcondition) (total) ({ // Result value named `total`. + CONTRACT_ASSERT( total >= 0.0 ); + }) + (body) ({ + double total = 0.0; + // Block invariants can appear anywhere in code block. + ``*CONTRACT_ASSERT_BLOCK_INVARIANT( total == 0.0 );*`` + + { // Variant initialized locally to its loop. + ``*CONTRACT_INIT_LOOP_VARIANT;*`` + for (size_t i = 0; i < vector.size(); ++i) { + // Block invariants used to assert loop invariants. + ``*CONTRACT_ASSERT_BLOCK_INVARIANT( i < vector.size() );*`` + // Loop variant (can only appear in loops). + ``*CONTRACT_ASSERT_LOOP_VARIANT( vector.size() - i );*`` + + total += vector[i]; + } + } + return total < 0.0 ? -total : total; + }) ) + +[endsect] +[section Commas Within Macro Parameters] + +The C++ preprocessor only recognizes the `()` parenthesis. +It does not recognize any other parenthesis such as `<>`, `[]`, or `{}`. +As a consequence, any comma passed within a macro parameter that is not wrapped by the `()` parenthesis will be interpreted by the preprocessor as a parameter separation token and will generate a preprocessing error. +Also macro parameters passed as elements of __Boost_Preprocessor__ sequences cannot contain commas not wrapped by extra `()` parenthesis (the preprocessor sequence `()` parenthesis are not sufficient to wrap the commas). + +Consider the following example: + + template + std::map fill(const std::map& source, + const K& key, const T& element) + CONTRACT_FUNCTION( + (template)( (typename)(K) (typename)(T) ) + // Commas within another type expression. + ``*(std::map)*`` (set)( + // Commas within a type expression. + ``*(const std::map&)*``(source) + (const K&)(key) (const T&)(element) ) + (precondition) ({ + // Commas within a value expression. + CONTRACT_ASSERT( ``*std::map().empty()*`` ); + }) + (body) ({ + ... + }) ) + +[h5 Value Expressions] + +The example above will /not/ compile because the preprocessor will interpret the expression: + + CONTRACT_ASSERT( std::map().empty() ); + +as a call to the macro `__CONTRACT_ASSERT__()` passing /two/ parameters separated by the comma: + + std::map().empty() // 2nd macro parameter. + +Because `__CONTRACT_ASSERT__()` takes only one parameter, the above code will generate a preprocessing error. + +The expressions `std::map().empty()` is interpreted by the compiler as a value expression (it will be either be `true` or `false`). +Value expressions can be wrapped by an extra set of parenthesis `()` when passed as macro parameters. +The following will compile: + + CONTRACT_ASSERT( ``*(*``std::map().empty()``*)*`` ); + +[h5 Type Expressions] + +A similar issue arises for the preprocessor sequence element: + + (std::map) + +which will be interpreted as composed of 2 parameters separated by the comma (i.e., as a __Boost_Preprocessor__ 2-tuple instead than an element of a __Boost_Preprocessor__ sequence): + + std::map // 2nd macro parameter. + +However, in this case the expression `std::map` needs to be interpreted by the compiler as a type expression (indeed the type `std::map`) and it cannot be wrapped by the extra parenthesis `()`. +In fact, depending on the context where they are used, types wrapped within parenthesis can generate compiler-time syntactic errors. + +In order to wrap the type expression within parenthesis `()` that can be parsed correctly by the preprocessor and interpreted correctly the compiler, first we created a void-function type that contains the type expression as the function only argument type: + + void``*(*``std::map``*)*`` // Function type (wraps comma within parenthesis). + +Then, we apply the library metafunction `contract::__wrap__` that returns the type of the first argument of the specified void-function type: + + contract::wrap``*)*``>::type // Evaluates to the type `std::map`. + +For convenience, the library provides the macro `__CONTRACT_WRAP_TYPE__()` which expands to the code above: + + CONTRACT_WRAP_TYPE( ``*(*``std::macp``*)*`` ) + +Note the extra parenthesis `()` similar to what it was used for value expression. + +[h5 Body Code Block] + +Finally, both techniques are applied to eventual commas within code blocks depending if the code is a value or type expression. + +[note However, if the body definition is separated from the contract declaration then the body code does not appear within a macro parameter so there is no need to implement these workarounds in the body code.] + +Applying these techniques to the example above, we obtain the following code which compiles: + +[commas_cpp] + +[endsect] +[section A Fully Working Example] + +We conclude this section with a fully working example that can be compiled. +This example illustrates how to use the library contract macros to program contracts in all the different library usages scenarios (constructor, destructors, member functions, non-member functions, template functions, etc). + +For simplicity, this example only exposes a limited subset of the `std::vector` operations and it only programs simple contracts for them (see the STL Vector __Example__ for complete contracts of all `std::vector` operations). +Furthermore, the somewhat artificial base classes have been deliberately introduced to illustrate subcontracting and they will probably not be part of real code. + +[myvector_cpp] +[pushable_cpp] +[boundable_cpp] +[basic_begin_cpp] + +[endsect] +[endsect] + diff --git a/doc/qbk/without_the_macros.qbk b/doc/qbk/without_the_macros.qbk new file mode 100755 index 00000000..f367eefd --- /dev/null +++ b/doc/qbk/without_the_macros.qbk @@ -0,0 +1,583 @@ + +[section Without the Macros] + +This section explains how to program contracts without using the library macros. +This is useful to better understand how the library actually implements Contract Programming and to occasionally implement workarounds for compiler standard compliance issues. +However: + +[important *Recommended to Use Contract Macros* + +In general, it is recommended to write contracts using the library macros because they save programmers from writing a significant amount of setup code.] + +All the macros described in the __Tutorial__ section expand to code equivalent to the one explained in this section (with the exception of block invariants and loop variants which are not covered here). +See also the __Reference__ section for more details. + +[section An Example (Without the Macros)] + +The following example shows how to write a contract for the vector `push_back()` function without using the contract macros: + + #include "pushable.hpp" // Base class for subcontracting. + #include // This library. + #include // STL vector. + + template + class myvector: public pushable { + + #if defined CONTRACT_CHECK_CLASS_INVARIANT || /* Support for */ \ + defined CONTRACT_CHECK_PRECONDITION || /* optional contract */ \ + defined CONTRACT_CHECK_POSTCONDITION /* compilation. */ + // Augmented state. + friend class contract::state; + mutable contract::state contract_state_; + #endif // contracts + + #if defined CONTRACT_CHECK_CLASS_INVARIANT + // Static class invariants + static void contract_static_invariant_(void) { + // Assert nothing in this case. + } + // Class invariants. + void contract_invariant_(void) const { + if (!((size() == 0) == empty())) + throw contract::failure(__FILE__, __LINE__); + // More invariants here... + } + #endif // invariants + + public: + void push_back(const T& element) + #if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + // Contracted function. + { contract_push_back_element_<0>().call(this , element); } + private: // Private so not to alter user call public API. + #if defined CONTRACT_CHECK_PRECONDITION + void contract_precondition_push_back_element_(const T& element) const { + if (!(size() < max_size())) + throw contract::failure(__FILE__, __LINE__); + // More preconditions here... + } + #endif // preconditions + #if defined CONTRACT_CHECK_POSTCONDITION + void contract_postcondition_push_back_element_( + const myvector* old_this, // Old value for object. + const T& element, contract::noold // No old for `element` argument. + ) const { + if (!(size() == (old_this->size() + 1))) + throw contract::failure(__FILE__, __LINE__); + // More postconditions here... + } + #endif // postconditions + protected: // Must be protected (not private) to allow subcontracting. + void contract_body_push_back_(const T& element) + #endif // contracts + // Original function definition (the body). + { vector_.push_back(element); } + #if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + // Contract class. + template + struct contract_push_back_element_: contract::nonstatic_member_function< + // Function type for contracted function. + // Copyable class type for old object value in postconditions. + // For constant members use `myvector const` instead of `myvector`. + void (contract::copyable*, const T&), + // Base contract class for subcontracting. + typename pushable::template contract_push_back_element_<0> + > { + // Constructor specifies body, preconditions, and postconditions. + contract_push_back_element_(): contract::static_member_function< + void (contract::copyable*, const T&), + typename pushable::template contract_push_back_element_<0> + >( &myvector::contract_body_push_back_ + #if defined CONTRACT_CHECK_PRECONDITION + , &myvector::contract_precondition_push_back_element_ + #endif // preconditions + #if defined CONTRACT_CHECK_POSTCONDITION + , &myvector::contract_postcondition_push_back_element_ + #endif // postconditions + ) {} + }; + public: // Restore original access level. + #endif // contracts + + ... // Rest of the class. + + private: + std::vector vector_; + }; + +Let's take a close look at this code. + +[endsect] +[section Optional Contract Compilation] + +First of all, note that when programmers completely disable contract compilation by not #defining any of the `__CONTRACT_CHECK_CLASS_INVARIANT__`, `__CONTRACT_CHECK_PRECONDITION__`, and `__CONTRACT_CHECK_POSTCONDITION__` macro symbols, the code above reduces to just the function declaration and its definition without *any* contract code overhead: + + template + class myvector { + + ``*// Augmented state and class invariants disappear!*`` + + public: + void push_back(const T& value) + ``*// Preconditions, postconditions, and body functions disappear!*`` + { + vector_.push_back(value); // Original function implementation. + } + ``*// Contract class disappears!*`` + public: + + ... + private: + std::vector vector_; + }; + +Note how the `__CONTRACT_CHECK_CLASS_INVARIANT__`, `__CONTRACT_CHECK_PRECONDITION__`, and `__CONTRACT_CHECK_POSTCONDITION__` macros can be #defined independently to selectively turn on or off the compilation of class invariants only, preconditions only, postconditions only, or any combination of the above. + +The rest of this section illustrates what happens when contract compilation is turned on. +Therefore, from here on, we will assume that `__CONTRACT_CHECK_CLASS_INVARIANT__` , `__CONTRACT_CHECK_PRECONDITION__`, and `__CONTRACT_CHECK_POSTCONDITION__` are all #defined. + +[endsect] +[section Assertions] + +Note how class invariants, preconditions, and postconditions are asserted using an `if`-statement that throws a `contract::__failure__` exception in case the checked boolean condition is false (note the leading `"!"` within the `if`-condition): + + // Code from the non-static class invariants (but similar for + // static class invariants, preconditions, and postconditions). + if (``*!*``((size() == 0) == empty())) + throw contract::failure(__FILE__, __LINE__); + +When an exception (/any/ exception) is thrown from within class invariants, preconditions, or postconditions code blocks, the library will handle the exception invoking the relative `contract::__class_invariant_failed__()`, `contract::__precondition_failed__()`, or `contract::__postcondition_failed__()` function (but only if that is necessary according to subcontracting rules, see below). +Therefore, the fact that the contract condition check throws `contract::__failure__` does /not/ necessarily imply that the program itself will throw but only that the correct contract failure handler function will be invoked by the library. +All contract failure handler functions terminate by default but they can be customized (see __Throw_on_Failure__ for an example). + +It is not possible to directly call `contract::__class_invariant_failed__()`, `contract::__precondition_failed__()`, or `contract::__postcondition_failed__()` instead of throwing the exception because of subcontracting. +For example, if a precondition of a derived contract fails but the preconditions of an overridden contract hold true then the library will /not/ call `contract::__precondition_failed__()` even if the derived contract throws an exception (as specified by subcontracting requirements in __Member_Function_Call_Semantics__). + +The first two arguments of the `contract::__failure__` constructor are mandatory and they specify file name and line number of the assertion (used the C++ macros `__FILE__` and `__LINE__`). +The third argument of the constructor is an optional human readable description of the asserted condition. +For example: + + // More verbose error message with . + if (!((size() == 0) == empty())) + throw contract::failure(__FILE__, __LINE__, "size zero iff empty"); + +All this information is simply used to provide the user with a descriptive error message in case of a contract failure, for example: + +[pre +class invariant: terminate called after throwing an instance of 'contract::failure' + what(): contract "size zero iff empty" failed at myvector_nomacros.cpp:37 +Aborted +] + +[endsect] +[section Augmented State] + +This library needs to declare an additional member variable for the class. +This member variable is mainly used by the library to keep track of when contracts are being checked so to disable assertion checking in nested member function calls that could otherwise result in infinite recursion (this a common requirement in Contract Programming). + + template + class myvector: public pushable { + + // Augmented state. + friend class contract::state; + mutable contract::state contract_state_; + + ... + }; + +The state member variable must be declared of `mutable` type `contract::__state__` (so the library can modify it while still ensuring constant-correctness for the contracts), it should be in a private section of the class (so not to alter the class public API), and it must have the predefined name `__contract_state___` (so the library knows how to access it). +Furthermore, the `contract::__state__` class type must be declared a friend so the library can internally access the entire user class including its private and protected members. + +The details of the `contract::__state__` type are library implementation specific. +The state variable name begins with the `contract` prefix and ends with an underscore "`_`" so programmers should never directly use it in user code (see __Getting_Started__). + +[endsect] +[section Class Invariants] + +This library checks static and non-static class invariants invoking a static and a constant member function with the predefined names `__contract_static_invariant___` and `__contract_invariant__` respectively: + + template + class myvector: public pushable { + ... + + // Static class invariants + static void contract_static_invariant_(void) { + // Assert nothing in this case. + } + // Class invariants. + void contract_invariant_(void) const { + if (!((size() == 0) == empty())) + throw contract::failure(__FILE__, __LINE__); + // More invariants here... + } + + ... + }; + +The non-static class invariant function must a constant member so to enforce contract checking constant-correctness. +The static class invariants function is static so it cannot change the object state because it cannot access the object (static member functions cannot be constant). + +The class invariant function names begin with the `contract` prefix and end with an underscore "`_`" so programmers should never directly use it in user code (see __Getting_Started__). + +[endsect] +[section Contracted Function] + +The `push_back()` function is programmed to construct the `contract` object and to invoke its `__call__()` member function: + + template + class myvector: public pushable { + ... + + public: + void push_back(const T& element) + // Contracted function. + { + contract_push_back_element_<0>().call(this , element); + } + + ... + }; + +The `__call__()` function takes in input a pointer to the object (`this`) and the function arguments (just `element` in this example) in the order they appear in the function declaration. + +The `__call__()` function is the one implementing the correct Contract Programming call semantics (see __Member_Function_Call_Semantics__). +In this case, `__call__()` checks class invariants and preconditions (calling `__contract_static_invariant___()`, `__contract_invariant___()`, and the __precondition__ function, see below), then it executes the body, and lastly it checks class invariants and postconditions (calling `__contract_static_invariant___()`, `__contract_invariant___()`, and the __postcondition__ function, see below). + +[endsect] +[section Preconditions] + +A member function is defined to check the preconditions: + + template + class myvector: public pushable { + ... + + private: + void contract_precondition_push_back_element_(const T& element) const { + if (!(size() < max_size())) + throw contract::failure(__FILE__, __LINE__); + // More preconditions here... + } + + ... + }; + +Note the followings: + +* The precondition function is private so not to alter the user class public API. +* In order to support contracts for overloaded functions, the precondition function name must contain the contracted function name, the name of all arguments, and a trailing =const= if the contracted function is a constant member. +* The precondition function must be a constant member plus all its arguments must be constant so to enforce contract constant-correctness. +* The precondition function arguments are constant references to the contracted function arguments. + +The precondition function name begins with the `contract` prefix and ends with an underscore "`_`" so programmers should never directly use it in user code (see __Getting_Started__). + +[endsect] +[section Postconditions] + +A member function is defined to check the postconditions: + + template + class myvector: public pushable { + + private: + ... // Preconditions. + void contract_postcondition_push_back_element_( + const myvector* old_this, // Old value for object. + const T& element, contract::noold // No old for `element` argument. + ) const { + if (!(size() == (old_this->size() + 1))) + throw contract::failure(__FILE__, __LINE__); + // More postconditions here... + } + + ... + }; + +Note the followings: + +* The postcondition function is private so not to alter the user class public API. +* In order to support contracts for overloaded functions, the postcondition function name must contain the contracted function name, the name of all arguments, and a trailing =const= if the contracted function is a constant member. +* The postcondition function must be a constant member plus all its arguments must be constant so to enforce contract constant-correctness. +* The first postcondition function argument is a constant pointer to the object old value when the class type is tagged `contract::__copyable__` within the contract class (see below), otherwise it is of type `contract::noold`. +* The remaining postcondition function arguments are constant references to the contracted function argument current and old values. +A function argument old value is different from `contract::nold` only if the argument type is tagged `contract::__copyable__` within the contract class (see below). +* Finally, for non-void contracted functions, there is an extra argument at the very end of the postcondition function argument list which is a constant reference to the function result value being returned. + +The `contract::noold` type is used as a "placeholder" for an argument when its old value is /not/ provided in the postconditions. +An `contract::noold` argument cannot be mistakenly accessed or manipulated by programmers because `contract::noold` is an empty class with no member at all. +Furthermore, copying `contract::noold` performs no operation so `contract::noold` arguments can be passed to the postcondition function by value but without adding any run-time overhead. +This ensures that programmers can only access old values in postconditions for types that are tagged `contract::__copyable__`. + +This is an example where the old value is provided for both the object and one of the function arguments: + + template + class myvector: public pushable { + ... + + public: + iterator insert(iterator where, const T& element) + ... + void contract_postcondition_insert_insert_where_element_( + const myvector* old_this, // Old value for object. + const iterator& where, const iterator& old_where, // Old value for `where`. + + const T& element, contract::noold, // No old for `element` argument. + const iterator& result // Result value. + ) const { + ... // Assert postconditions using `old_this` and `old_where`. + } + ... // Both class type and `where` type are tagged `contract::copyable`. + // in the contract class (see below). + + ... + }; + +The postcondition function name begins with the `contract` prefix and ends with an underscore "`_`" so programmers should never directly use it in user code (see __Getting_Started__). + +[endsect] +[section Body] + +A member function is declared as the body function and it is defined to be the original function implementation as specified by the user: + + template + class myvector: public pushable { + ... + + protected: + void contract_body_push_back_(const T& element) + // Original function definition (the body). + { + vector_.push_back(element); + } + + ... + }; + +Note the followings: + +* The body function is protected to avoid changing the user's class public API but it cannot be private to allow for subcontracting of pure virtual functions. +* The body function declaration and definition must be /exactly/ the ones specified by the user for the original `push_back()` function (only the function name is different). +For example, if the original function is declared `virtual`, the body function should be declared `virtual` as well. +Also the body function signature (return type, argument type, argument names, eventual constant qualifier, etc) must match exactly the signature of the original `push_back()` function. + +The body function name begins with the `contract` prefix and ends with an underscore "`_`" so programmers should never directly use it in user code (see __Getting_Started__). + +[h5 Separating the Definition] + +In this example, the body function definition `{ vector_.push_back(element); }` is specified together with the body function declaration. +However, following C++ usual syntax, programmers can define the body function to be "`;`" in order to separate the function definition from its declaration: + + // Declarations (usually in header files). + + template + class myvector: public pushable { + ... + + protected: + void contract_body_push_back_(const T& element) + ``*;*`` // Separating body definition using `;`. + + ... + }; + + // Separated definitions (eventually in a different file). + + template + void myvector:: + #if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + ``*contract_body_push_back_*`` // Body function name. + #else + ``*push_back*`` // Actual function name if contract compilation is off. + #endif + (const T& element) { + vector_.push_back(element); // Original function definition. + } + +In this case, it is recommended to used the `__CONTRACT_BODY__()` macro instead of the hard to read `#if` around the function name. +If contract compilation is on, `__CONTRACT_BODY__(push_back)` expands to `contract_body_push_back_`, otherwise it expands to `push_back` (see __Reference__ and __Tutorial__ sections). +Using this macro, the above function definition is equivalently written as: + + // Separated definitions (eventually in a different file). + + template + void myvector::``*CONTRACT_FUNCTION_BODY(push_back)*``(const T& element) { + vector_.push_back(element); // Original function definition. + } + +[h5 Pure Virtual Functions] + +Programmers can also define the body function to be pure virtual so to defer its definition to derived classes. +In this case the usual C++ syntax "` = 0;`" is used: + + template + class pushable { + ... + + protected: + void contract_body_push_back_(const T& element) + ``*= 0;*`` // Contract for pure virtual functions. + + ... + }; + +[endsect] +[section Contract Class] + +A member class is defined as the contract class: + + template + class myvector: public pushable { + ... + + protected: + ... + // Contract class. + template + struct contract_push_back_element_: contract::nonstatic_member_function< + // Function type for contracted function. + // Copyable class type for old object value in postconditions. + // For const members, use `myvector const` instead of `myvector`. + void (contract::copyable*, const T&), + // Base contract class for subcontracting. + typename pushable::template contract_push_back_element_<0> + > { + // Constructor specifies body, preconditions, and postconditions. + contract_push_back_element_(): contract::nonstatic_member_function< + void (contract::copyable*, const T&), + typename pushable::template contract_push_back_element_<0> + >( &myvector::contract_body_push_back_ + , &myvector::contract_precondition_push_back_element_ + , &myvector::contract_postcondition_push_back_element_ + ) {} + }; + public: // Restore original access level. + + ... + }; + +Note the followings: + +* The contract class is protected to avoid changing the user's class public API but it cannot be private because derived classes might need to access it for subcontracting. +* The contract class publicly inherits (it is a `struct`) from `contract::__nonstatic_member_function__`. +The `__call__()` function, which implements the contract call semantics, is inherited from this base class. +* The `contract::__nonstatic_member_function__` template takes as first parameter the a function type matching the signature of the contracted `push_back()` function. + * For member functions (including static members, constructors, and destructors, see `contract::__static_member_function__`, `contract::__constructor__`, and `contract::__destructor__` respectively), the first argument of the function type if a pointer to the class type, followed by the contracted function argument types. +Instead, for non-member functions (see `contract::__nonmember_function__`), there is no class pointer type and the first argument of the function type matches the first argument type of the contract function. +(This is the same syntax used by __Boost_Function__ +[footnote A more natural syntax would have been to use C++ function pointer types because they already provide a syntax for non-member functions /result-type/` (*)(`/argument-type1/`, ...)` and a different syntax for member function /result-type/` (`/class-type/`::*)(`/argument-type1/,` ...)`. +However, the use of function pointer types to resolve partial template specializations (as needed by this library) it not fully supported by all compilers (notably MVSC 8.0 has issues in resolving template specializations between void constant and non-void constant member functions using function pointer types). +Therefore, the __Boost_Function__ preferred syntax was adopted for this library (also this harmonizes this library more with the __Boost__ libraries). +The __Boost_Function__ portable syntax was not used because it is maintained by __Boost_Function__ for backward compatibility only and it is not recommended (even if that would have been the most portable syntax across the different compilers, see __Boost_Function__ for more information). +].) + * For constant member functions, the first argument is specified as a constant pointer to the class type. +If the function in this example were to be a constant member function `void push_back(...) const` then the function type would have been `void (contract::__copyable__*, const T&)`. +Note that when both `const` and `contract::__copyable__` are used, `const` must be used within `contract::__copyable__` +[footnote However, if the member function is constant it cannot modify the object so there is in principle no need to copy the object value before body execution because the body cannot modify the object in the first place]. + * In the function type, the class type (which is specified only for member functions) and the argument types can be tagged `contract::__copyable__` if the relative old values are needed in postconditions. +Any type tagged `contract::__copyable__` (`myvector` in this example) must have an accessible constant-correct copy constructor otherwise the library will generate a compile-time error (see `contract::__copy__`). +Note that the object `contract::__copyable__` only wraps the class type and not the pointer (i.e., `contract::__copyable__` is invalid) but for all the contracted function argument types `contract::__copyable__` wraps the entire type including eventual pointers -- this is because for member functions, the first argument of the function type must always be a pointer to the class type (even when the class type is tagged `contract::__copyable__` and/or it is qualified `const`). +* When subcontracting, the base contract classes are specified as the optional template parameters following the function type for `contract::__nonstatic_member_function__` (one base contract is specified in this case `pushable::contract_push_back_element<0>`). +All these template parameters are optional and multiple base contract classes can be specified to support subcontracting for multiple inheritance. +* The contract class must define a public default constructor (i.e., with no arguments) which constructs the base class `contract::__nonstatic_member_function__` passing function pointers to the body, precondition, and postcondition (so the contract knows which function to invoke to execute the body, check preconditions, and check postconditions). + +[note +The contract class is declared as a template using the /artificial/ template parameter `int ZERO` to support an internal library workaround. +This allows the library to internally use the `typename` and `template` keywords freely to explicitly characterize types even without knowing if the contracted class is a template or not. +The artificial template parameter `int ZERO` is not needed if the contracted function is already a template (in which case `int ZERO` is replaced by the actual function template parameters). + +The value of artificial template parameter `int ZERO` is not used so any value can be specified. However, it is recommended to always specify the value `0` for consistency (this is practice followed by this documentation). +] + +[h5 Contract Class Name] + +Note how, similarly to the precondition and postcondition function names, the contract class name repeats the function name and the argument names. +Furthermore, for constant member functions, the contract class name should end with =const=. +This is necessary to support contracts for overloaded functions (with the limitation that overloaded functions, with the same number of arguments and same constant qualifier, must have different argument names and not just different argument types otherwise contract names will clash). +In summary, the contract class name should be as follow: + + contract_``/function-name/``_``/argument-name1/``_``/argument-name2/``_``/...argument-nameN/``_``/[/``const_``/]/`` + +In order to allow the contract macros to subcontract from hand-written contracts, you must follow the above convention in naming the contract class at all times (because this is the convention that the contract macros assume). + +The contract class name begins with the `contract` prefix and ends with an underscore "`_`" thus programmers should never directly use this class in user code (see __Getting_Started__). + +[endsect] +[section Static Member Functions] + +Contracts can also be programmed for static member functions (see the example at the end of this section). +However, compared with non-static member function contracts the following differences apply: + +* The `contract::__static_member_function__` class template is used instead of `contract::__nonstatic_member_function__`. +* The class type cannot be tagged `contract::__copyable__` or qualified `const` (because there is no object to copy or to not modify). +* The precondition, postcondition, and body functions must be `static` members (and therefore they cannot be `const`). +* No base contract class can be specified because `static` members cannot be `virtual` so they cannot subcontract. + +All these constraints are enforced by the library at compile-time. + +[endsect] +[section Constructors] + +Contracts can also be programmed for constructors (see the example at the end of this section). +However, compared with non-static member function contracts the following differences apply: + +* The `contract::__constructor__` class template is used instead of `contract::__nonstatic_member_function__`. +* The class type cannot be tagged `contract::__copyable__` or qualified `const` (because there is no object before body execution to copy and the object is always modified by the body as it is constructed). +* The `contract::__constructor__` function type template parameter must always specify a `void` return type (because constructors return no value). +* The precondition function must be `static` because constructor preconditions cannot access the object (as there is no object before constructor body execution). +* The postcondition function always specifies `contract::__noold__` for the object old value because constructor postconditions can never access the object old value (as there was no object before constructor body execution). +Furthermore, the function type passed to `contract::__constructor__` cannot tag the class type `contract::__copyable__`. +* No base contract class can be specified because constructors do not directly subcontract (the C++ object construction mechanism will automatically invoke the base class constructor contracts if present). + +All these constraints are enforced by the library at compile-time. + +[endsect] +[section Destructors] + +Contracts can also be programmed for destructors (see the example at the end of this section). +However, compared with non-static member function contracts the following differences apply: + +* The `contract::__destructor__` class template is used instead of `contract::__nonstatic_member_function__`. +* The class type cannot be tagged `contract::__copyable__` or qualified `const` (because there are no postconditions to accessed to copied object and the object is always modified by the body as it is destructed). +* The `contract::__destructor__` function type template parameter must always specify a `void` return type and have no argument (because destructors return no value and have no argument). +Furthermore, the function pointer cannot tag the class type `contract::__copyable__`. +* The `contract::__destructor__` constructor only takes the body function pointer and it does not take the precondition and postcondition function pointers (because destructors have no preconditions and no postconditions as they have no arguments and there is no object after destructor body execution). +* No base contract class can be specified because destructors do not directly subcontract (the C++ object destruction mechanism will automatically invoke the base class destructor contracts if present). + +All these constraints are enforced by the library at compile-time. + +[endsect] +[section Non-Member Functions] + +Contracts can also be programmed for non-member functions (see the example at the end of this section). +However, compared with non-static member function contracts the following differences apply: + +* The `contract::__nonmember_function__` class template is used instead of `contract::__nonstatic_member_function__`. +* The function type passed as the first template parameter to `contract::__nonmember_function__` does /not/ specify the class type (i.e., /result-type/` (`/argument-type1/`, ...)` is used instead of /result-type/` (`/class-type/`*,` /argument-type1/`, ...)`). +* The precondition, postcondition, body functions, and the contract class are not members. +* The contracted function definition must be `inline` and it must appear at the very end of the contract after the precondition, postcondition, body functions, and the contract class (to avoid duplicate definitions and missing definitions compile-time errors). + +All these constraints are enforced by the library at compile-time. + +[endsect] +[section A Fully Working Example (Without the Macros)] + +We conclude this section with a fully working example that can be compiled. +This example illustrates how to use the library to program contracts without the macros. + +For simplicity, this example only exposes a limited subset of the `std::vector` operations and it only programs simple contracts for them (see the STL Vector __Example__ for `std::vector` complete contracts). +Furthermore, the somewhat artificial base classes have been deliberately introduced to illustrate subcontracting and they will probably not be part of real code. + +Comparing this example with the one presented in the __Tutorial__ section, it is easy to note how much more setup code around the contract assertions is required when the contract macros are not used. +Therefore, the use of the contract macros is always recommended. + +[myvector_nomacros_cpp] + +[endsect] +[endsect] + diff --git a/example/Crowl2006/README.txt b/example/Crowl2006/README.txt new file mode 100755 index 00000000..2aafb1bc --- /dev/null +++ b/example/Crowl2006/README.txt @@ -0,0 +1,2 @@ +Examples taken from Crowl, Ottosen, "Proposal to add Contract +Programming to C++", 2006. diff --git a/example/Crowl2006/block/main.cpp b/example/Crowl2006/block/main.cpp new file mode 100755 index 00000000..a55d9bd4 --- /dev/null +++ b/example/Crowl2006/block/main.cpp @@ -0,0 +1,21 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Block invariant example. + +#include +#include + +int main() { + for (int i = 0; i < 100; ++i) { + // Invariant will intentionally fail. + CONTRACT_ASSERT_BLOCK_INVARIANT( i < 10 ); + + std::cout << i << std::endl; + } + + return 0; +} + diff --git a/example/Crowl2006/circle/main.cpp b/example/Crowl2006/circle/main.cpp new file mode 100755 index 00000000..094312d5 --- /dev/null +++ b/example/Crowl2006/circle/main.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Subcontracting (from pure virtual) example. + +#include +#include + +class shape { + + CONTRACT_INVARIANT( ({}) ) // Specify invariants even if `{}`. + +public: + virtual ~shape(void) {} + + virtual int compute_area(void) const + CONTRACT_FUNCTION( (class) (shape) + (public) (virtual) (int) (compute_area)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result > 0 ); + }) + (body) ( + = 0; // Contract for pure virtual function. + ) ) +}; + +class circle: public shape { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Hard-coded radius for simplicity of this example. + int radius(void) const { return 2; } + + virtual int compute_area(void) const + CONTRACT_FUNCTION( (class) (circle) + (inherit)(shape) // Subcontracting. + (public) (virtual) (int) (compute_area)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == PI * radius() * radius() ); + }) + (body) ({ + return PI * radius() * radius(); + }) ) + +private: + static const int PI = 3; // Truncated int of 3.14... +}; + +int main() { + circle c; + + std::cout << std::endl << "compute_area()" << std::endl; + std::cout << c.compute_area() << std::endl; + + return 0; +} + diff --git a/example/Crowl2006/factorial/main.cpp b/example/Crowl2006/factorial/main.cpp new file mode 100755 index 00000000..7e76e021 --- /dev/null +++ b/example/Crowl2006/factorial/main.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include +#include + +// Recursion example. +int factorial(int n) +CONTRACT_FUNCTION( + (int) (factorial)( (int)(n) ) +(precondition) ({ + CONTRACT_ASSERT( n >= 0 ); + CONTRACT_ASSERT( n <= 12 ); +}) +(postcondition) (result) ({ + CONTRACT_ASSERT( result >= 1 ); + + // Assertions disabled within assertions so factorial() can be + // recursively called also from the contract (not just the body). + // (Of course, this adds a lot of overhead...) + if (n < 2) { CONTRACT_ASSERT( result == 1 ); } + else { CONTRACT_ASSERT( result == n * factorial(n - 1) ); } +}) +(body) ({ + if (n < 2) return 1; + else return n * factorial(n - 1); +}) ) + +int main() { + std::cout << factorial(4) << std::endl; + return 0; +} + diff --git a/example/Crowl2006/operator_equal/equal.hpp b/example/Crowl2006/operator_equal/equal.hpp new file mode 100755 index 00000000..d0090aec --- /dev/null +++ b/example/Crowl2006/operator_equal/equal.hpp @@ -0,0 +1,27 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef EQUAL_HPP_ +#define EQUAL_HPP_ + +#include "not_equal.hpp" +#include +#include + +template +bool operator==(T l, T r) +CONTRACT_FUNCTION( + (template)( (typename)(T) ) + (bool) (operator(==, equal)) ( (T)(l) (T)(r) ) +(postcondition) (result) ({ + CONTRACT_ASSERT( result == !(l != r) ); +}) +(body) ({ + std::clog << "checking for equality" << std::endl; + return l.value == r.value; +}) ) + +#endif // #include guard + diff --git a/example/Crowl2006/operator_equal/main.cpp b/example/Crowl2006/operator_equal/main.cpp new file mode 100755 index 00000000..5df0a3ca --- /dev/null +++ b/example/Crowl2006/operator_equal/main.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Recursion example (works thanks to "assertions disabled within +// assertions" policy). + +#include "equal.hpp" +#include "not_equal.hpp" +#include + +struct number { double value; }; + +int main() { + number n; + n.value = 1.23; + + std::cout << (n == n) << std::endl; + std::cout << (n != n) << std::endl; + + return 0; +} + diff --git a/example/Crowl2006/operator_equal/not_equal.hpp b/example/Crowl2006/operator_equal/not_equal.hpp new file mode 100755 index 00000000..71bc79ea --- /dev/null +++ b/example/Crowl2006/operator_equal/not_equal.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef NOT_EQUAL_HPP_ +#define NOT_EQUAL_HPP_ + +#include "equal.hpp" +#include + +template +bool operator!=(T l, T r) +CONTRACT_FUNCTION( + (template)( (typename)(T) ) + (bool) (operator(!=, not_equal))( (T)(l) (T)(r) ) +(postcondition) (result) ({ + CONTRACT_ASSERT( result == !(l == r) ); +}) +(body) ({ + std::clog << "checking for inequality" << std::endl; + return l.value != r.value; +}) ) + +#endif // #include guard + diff --git a/example/Crowl2006/sqrt/main.cpp b/example/Crowl2006/sqrt/main.cpp new file mode 100755 index 00000000..591c1278 --- /dev/null +++ b/example/Crowl2006/sqrt/main.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include +#include +#include + +bool equal_within_precision(const double& x, const double& y, + const double& precision = 1e-6) { + return fabs(x - y) <= precision; +} + +// Non-member function example. +double mysqrt(double x) +CONTRACT_FUNCTION( + (double) (mysqrt)( (double)(x) ) +(precondition) ({ + CONTRACT_ASSERT( x >= 0.0 ); +}) +(postcondition) (root) ({ + CONTRACT_ASSERT( equal_within_precision(root * root, x) ); +}) +(body) ({ + return sqrt(x); +}) ) + +int main() { + std::cout << mysqrt(4.0) << std::endl; + std::cout << std::endl; + std::cout << mysqrt(-1.0) << std::endl; + return 0; +} + diff --git a/example/Crowl2006/sum/main.cpp b/example/Crowl2006/sum/main.cpp new file mode 100755 index 00000000..f7e2b0d1 --- /dev/null +++ b/example/Crowl2006/sum/main.cpp @@ -0,0 +1,16 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "sum.hpp" +#include + +int main() { + double a[8] = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1}; + + std::cout << sum(8, a) << std::endl; + + return 0; +} + diff --git a/example/Crowl2006/sum/sum.cpp b/example/Crowl2006/sum/sum.cpp new file mode 100755 index 00000000..99f7f800 --- /dev/null +++ b/example/Crowl2006/sum/sum.cpp @@ -0,0 +1,13 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "sum.hpp" + +double CONTRACT_BODY(sum)(int count, double* array) { + double accum = 0.0; + for (int i = 0; i < count; ++i) accum += array[i]; + return accum; +} + diff --git a/example/Crowl2006/sum/sum.hpp b/example/Crowl2006/sum/sum.hpp new file mode 100755 index 00000000..4417afa7 --- /dev/null +++ b/example/Crowl2006/sum/sum.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Non-member function with separate definition. + +#ifndef SUM_HPP_ +#define SUM_HPP_ + +#include + +double sum(int count, double* array) +CONTRACT_FUNCTION( (double) (sum)( (int)(count) (double*)(array) ) +(precondition) ({ + CONTRACT_ASSERT( count % 4 == 0 ); +}) +(body) ( + ; +) ) + +#endif // #include guard + diff --git a/example/Crowl2006/vector/main.cpp b/example/Crowl2006/vector/main.cpp new file mode 100755 index 00000000..e13c7f55 --- /dev/null +++ b/example/Crowl2006/vector/main.cpp @@ -0,0 +1,617 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Add complete contracts to STL C++ vector. + +#include +#include // For boost::prior(). +#include + +// Tools to write the contracts (for convenience). + +template +bool all_equals(Iter first, Iter last, const T& val) +CONTRACT_FUNCTION( + (template)( (class)(Iter) (class)(T) ) + (bool) (all_equals)( + (Iter)(first) (Iter)(last) (const T&)(val) ) +(body) ({ + // For simplicity, let's assume T can be compared. + for (Iter i = first; i < last; ++i) { + if (*i != val) return false; + } + return true; +}) ) + +template +bool equal_distance(Iter first, Iter last, Size size) +CONTRACT_FUNCTION( + (template)( (class)(Iter) (class)(Size) ) + (bool) (equal_distance)( + (Iter)(first) (Iter)(last) (Size)(size) ) +(body) ({ + // Could implement internal tagging to support input iterators. + return int(size) == std::distance(first, last); +}) ) + +// New vector interface. + +template > +class vector { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( (size() == 0) == empty() ); + CONTRACT_ASSERT( int(size()) == std::distance(begin(), end()) ); + CONTRACT_ASSERT( int(size()) == std::distance(rbegin(), rend()) ); + CONTRACT_ASSERT( size() <= capacity() ); + CONTRACT_ASSERT( capacity() <= max_size() ); + }) ) + +public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator + const_iterator; + typedef typename std::vector::reverse_iterator + reverse_iterator; + typedef typename std::vector::const_reverse_iterator + const_reverse_iterator; + typedef typename std::vector::reference reference; + typedef typename std::vector::const_reference + const_reference; + + vector(void): vector_() + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( empty() ); + }) + (body) ({ + }) ) + + explicit vector(const Alloc& al): vector_(al) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (const Alloc&)(al) ) + (postcondition) ({ + CONTRACT_ASSERT( empty() ); + CONTRACT_ASSERT( al == get_allocator() ); + }) + (body) ({ + }) ) + + explicit vector(size_type count): vector_(count) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (size_type)(count) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == count ); + CONTRACT_ASSERT( all_equals(begin(), end(), T()) ); + }) + (body) ({ + }) ) + + vector(size_type count, const T& val): vector_(count, val) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (size_type)(count) (const T&)(val) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == count ); + CONTRACT_ASSERT( all_equals(begin(), end(), val) ); + }) + (body) ({ + }) ) + + vector(size_type count, const T& val, const Alloc& al): + vector_(count, val, al) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (size_type)(count) (const T&)(val) + (const Alloc&)(al) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == count ); + CONTRACT_ASSERT( all_equals(begin(), end(), val) ); + CONTRACT_ASSERT( al == get_allocator() ); + }) + (body) ({ + }) ) + + vector(const vector& right): vector_(right.vector_) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (vector)( (const vector&)(right) ) + (postcondition) ({ + CONTRACT_ASSERT( right == *this ); + }) + (body) ({ + }) ) + + template + vector(InIt first, InIt last): vector_(first, last) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (template)( (class)(InIt) ) + (vector)( (InIt)(first) (InIt)(last) ) + (postcondition) ({ + CONTRACT_ASSERT( equal_distance(first, last, size()) ); + }) + (body) ({ + }) ) + + template + vector(InIt first, InIt last, const Alloc& al): + vector_(first, last, al) + CONTRACT_CONSTRUCTOR( (class) (vector) + (public) (template)( (class)(InIt) ) + (vector)( (InIt)(first) (InIt)(last) (const Alloc&)(al) ) + (postcondition) ({ + CONTRACT_ASSERT( equal_distance(first, last, size()) ); + CONTRACT_ASSERT( al == get_allocator() ); + }) + (body) ({ + }) ) + + ~vector(void) // Contracted so destructor checks invariants. + CONTRACT_DESTRUCTOR( (class) (vector) + (public) (vector)( (void) ) + (body) ({ + }) ) + + void reserve(size_type count) + CONTRACT_FUNCTION( (class) (vector) + (public) (void) (reserve)( (size_type)(count) ) + (precondition) ({ + CONTRACT_ASSERT( count < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( capacity() >= count ); + }) + (body) ({ + vector_.reserve(count); + }) ) + + size_type capacity(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (size_type) (capacity)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result >= size() ); + }) + (body) ({ + return vector_.capacity(); + }) ) + + iterator begin(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (iterator) (begin)( (void) ) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ({ + return vector_.begin(); + }) ) + + const_iterator begin(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_iterator) (begin)( (void) ) (const) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ({ + return vector_.begin(); + }) ) + + iterator end(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (iterator) (end)( (void) ) + // Contracted even if no pre/post condition so check invariants. + (body) ({ + return vector_.end(); + }) ) + + const_iterator end(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_iterator) (end)( (void) ) (const) + (body) ({ + return vector_.end(); + }) ) + + reverse_iterator rbegin(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (reverse_iterator) (rbegin)( (void) ) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == rend() ); + }) + (body) ({ + return vector_.rbegin(); + }) ) + + const_reverse_iterator rbegin(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reverse_iterator) (rbegin)( (void) ) (const) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == rend() ); + }) + (body) ({ + return vector_.rbegin(); + }) ) + + reverse_iterator rend(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (reverse_iterator) (rend)( (void) ) + (body) ({ + return vector_.rend(); + }) ) + + const_reverse_iterator rend(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reverse_iterator) (rend)( (void) ) (const) + (body) ({ + return vector_.rend(); + }) ) + + void resize(size_type newsize) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (resize)( (size_type)(newsize) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == newsize ); + // Version 1: with an if. + if (newsize > CONTRACT_OLDOF(this)->size()) CONTRACT_ASSERT( + all_equals(begin() + CONTRACT_OLDOF(this)->size(), + end(), T()) ); + }) + (body) ({ + vector_.resize(newsize); + }) ) + + void resize(size_type newsize, T val) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (resize)( (size_type)(newsize) (T)(val) ) + (postcondition) ({ + CONTRACT_ASSERT( size() == newsize ); + // Version 2: with a ternary operator. + CONTRACT_ASSERT( newsize > CONTRACT_OLDOF(this)->size() ? + all_equals(begin() + CONTRACT_OLDOF(this)->size(), + end(), val) : true ); + }) + (body) ({ + vector_.resize(newsize, val); + }) ) + + size_type size(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (size_type) (size)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result <= capacity() ); + }) + (body) ({ + return vector_.size(); + }) ) + + size_type max_size(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (size_type) (max_size)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result >= capacity() ); + }) + (body) ({ + return vector_.max_size(); + }) ) + + bool empty(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (bool) (empty)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (size() == 0) ); + }) + (body) ({ + return vector_.empty(); + }) ) + + Alloc get_allocator(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (Alloc) (get_allocator)( (void) ) (const) + (body) ({ + return vector_.get_allocator(); + }) ) + + reference at(size_type off) + CONTRACT_FUNCTION( (class) (vector) + (public) (reference) (at)( (size_type)(off) ) + (precondition) ({ + CONTRACT_ASSERT( off < size() ); + }) + (body) ({ + return at(off); + }) ) + + const_reference at(size_type off) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reference) (at)( (size_type)(off) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( off < size() ); + }) + (body) ({ + return at(off); + }) ) + + reference operator[](size_type off) + CONTRACT_FUNCTION( (class) (vector) + (public) (reference) (operator_at)( (size_type)(off) ) + (precondition) ({ + CONTRACT_ASSERT( off < size() ); + }) + (body) ({ + return operator[](off); + }) ) + + const_reference operator[](size_type off) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reference) (operator_at)( + (size_type)(off) ) (const) + (precondition) ({ + CONTRACT_ASSERT( off < size() ); + }) + (body) ({ + return operator[](off); + }) ) + + reference front(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (reference) (front)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (body) ({ + return vector_.front(); + }) ) + + const_reference front(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reference) (front)( (void) ) (const) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (body) ({ + return vector_.front(); + }) ) + + reference back(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (reference) (back)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (body) ({ + return vector_.back(); + }) ) + + const_reference back(void) const + CONTRACT_FUNCTION( (class) (vector) + (public) (const_reference) (back)( (void) ) (const) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (body) ({ + return vector_.back(); + }) ) + + void push_back(const T& val) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (push_back)( (const T&)(val) ) + (precondition) ({ + CONTRACT_ASSERT( size() < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( back() == val ); + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + CONTRACT_ASSERT( capacity() >= CONTRACT_OLDOF(this)->capacity() ); + }) + (body) ({ + vector_.push_back(val); + }) ) + + void pop_back(void) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (pop_back)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() - 1) ); + }) + (body) ({ + vector_.pop_back(); + }) ) + + template + void assign(InIt first, InIt last) + CONTRACT_FUNCTION( (class) (vector) + (public) (template)( (class)(InIt) ) + (void) (assign)( (InIt)(first) (InIt)(last) ) + (precondition) ({ + /** @pre [first, last) not sub-range of [begin(), end()). */ + }) + (postcondition) ({ + CONTRACT_ASSERT( equal_distance(first, last, size()) ); + }) + (body) ({ + vector_.assign(first, last); + }) ) + + void assign(size_type count, const T& val) + CONTRACT_FUNCTION( (class) (vector) + (public) (void) (assign)( + (size_type)(count) (const T&)(val) ) + (precondition) ({ + CONTRACT_ASSERT( count <= max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( all_equals(begin(), end(), val) ); + }) + (body) ({ + vector_.assign(count, val); + }) ) + + iterator insert(iterator where, const T& val) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (iterator) (insert)( + (iterator)(where) (const T&)(val) ) + (precondition) ({ + CONTRACT_ASSERT( size() < max_size() ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( *result == val ); + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + CONTRACT_ASSERT( capacity() >= CONTRACT_OLDOF(this)->capacity() ); + /** @post + * if capacity() > oldof capacity(): + * all iterators invalidated + * else: + * all iterators in [where, end()) invalidated + */ + }) + (body) ({ + return vector_.insert(where, val); + }) ) + + void insert(iterator where, size_type count, const T& val) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (insert)( (copyable)(iterator)(where) + (size_type)(count) (const T&)(val) ) + (precondition) ({ + CONTRACT_ASSERT( (size() + count) < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( size() == + (CONTRACT_OLDOF(this)->size() + count) ); + CONTRACT_ASSERT( capacity() >= CONTRACT_OLDOF(this)->capacity() ); + if (capacity() == CONTRACT_OLDOF(this)->capacity()) { + CONTRACT_ASSERT( all_equals( + boost::prior(CONTRACT_OLDOF(where)), + boost::prior(CONTRACT_OLDOF(where)) + count, + val) ); + /** @post All iterators in [where, end()) invalidated. */ + } + else { + /** @post All iterators invalidated. */ + } + }) + (body) ({ + vector_.insert(where, val); + }) ) + + template + void insert(iterator where, InIt first, InIt last) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (template)( (class)(InIt) ) + (void) (insert)( (copyable)(iterator)(where) + (InIt)(first) (InIt)(last) ) + (precondition) ({ + /** @pre [first, last) not a sub-range or [begin(), end()). */ + int count = std::distance(first, last); + CONTRACT_ASSERT( (size() + count) < max_size() ); + }) + (postcondition) ({ + int count = std::distance(first, last); + CONTRACT_ASSERT( size() == + (CONTRACT_OLDOF(this)->size() + count) ); + CONTRACT_ASSERT( capacity() >= CONTRACT_OLDOF(this)->capacity() ); + }) + (body) ({ + return vector_.insert(where, first, last); + }) ) + + iterator erase(iterator where) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (iterator) (erase)( (iterator)(where) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + CONTRACT_ASSERT( where != end() ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() - 1) ); + if (empty()) CONTRACT_ASSERT( result == end() ); + /** @post Iterators in [where, end()) invalidated. */ + }) + (body) ({ + return vector_.erase(where); + }) ) + + iterator erase(iterator first, iterator last) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (iterator) (erase)( (iterator)(first) + (iterator)(last) ) + (precondition) ({ + CONTRACT_ASSERT( size() >= std::distance(first, last) ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() - + std::distance(first, last)) ); + if (empty()) CONTRACT_ASSERT( result == end() ); + /** @post Iterators in [first, end()) invalidated. */ + }) + (body) ({ + return vector_.erase(first, last); + }) ) + + void clear(void) + CONTRACT_FUNCTION( (class) (vector) + (public) (void) (clear)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( empty() ); + }) + (body) ({ + vector_.clear(); + }) ) + + void swap(vector& right) + CONTRACT_FUNCTION( (class) (copyable)(vector) + (public) (void) (swap)( (copyable)(vector&)(right) ) + (postcondition) ({ + CONTRACT_ASSERT( *CONTRACT_OLDOF(this) == right ); + CONTRACT_ASSERT( CONTRACT_OLDOF(right) == *this ); + }) + (body) ({ + vector_.swap(right); + }) ) + + bool operator==(const vector& right) const + CONTRACT_FUNCTION( (class) (vector) + (public) (bool) (operator_equal)( + (const vector&)(right) ) (const) + (body) ({ + return vector_ == right.vector_; + }) ) + +private: + std::vector vector_; +}; + +int main() { + // Run a few of the operations (could test more of them...). + std::cout << std::endl << "constructor()" << std::endl; + vector v(3); + const vector& cv = v; // A reference, no copy. + + std::cout << std::endl << "copy constructor()" << std::endl; + vector w(v); + + std::cout << std::endl << "begin()" << std::endl; + vector::iterator b = v.begin(); + std::cout << *b << std::endl; + + std::cout << std::endl << "begin() const" << std::endl; + vector::const_iterator cb = cv.begin(); + std::cout << *cb << std::endl; + + std::cout << std::endl << "insert()" << std::endl; + v.insert(b, 2, -3.21); + + std::cout << std::endl << "operator[]" << std::endl; + double v0 = v[0]; + std::cout << v0 << std::endl; + + std::cout << std::endl << "push_back()" << std::endl; + v.push_back(1.23); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/Makefile b/example/Makefile new file mode 100755 index 00000000..501361b4 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,135 @@ +# Copyright (C) 2009-2010 Lorenzo Caminiti. +# Use, modification, and distribution is subject to the +# Contract++ Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt.) + +# Supported C++ compliers `make CXX=compiler ...', where compiler is: +# GCC GNU g++ (e.g., on Linux) (default) +# MSVC Microsoft Visual C++ (e.g., on Cygwin) +CXX=GCC + +bin:=./bin +ifeq ($(CXX), GCC) + cpp_nodef:=g++ -Wall -Werror -I./src + def:=-D + out:=-o +endif +ifeq ($(CXX), MSVC) + # Don't use /Wall for MSVC has very verbose warnings (even in Boost?!). + cpp_nodef:=source $(bin)/env-MSVC8.sh && cl.exe /EHsc /I./src + def:=/D + out:=/Fe +endif +cpp:=$(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION +ifeq ($(debug), 1) + cpp:=$(cpp) $(def)CONTRACT_CONFIG_DEBUG_=1 +endif + +src:=./example +build:=./build/example +codedoc:=./codedoc/example + +all: myvector myvector_checks commas throw Crowl2006 Mitchell2002 Meyer1997 Stroustrup1997 + +clean: + rm -rf $(build) + +mkdir_: + mkdir -p $(build) + +myvector: mkdir_ + $(cpp) $(src)/myvector/main.cpp $(out)$(build)/myvector +myvector_checks: mkdir_ + # Compile with all different contract checking combinations. + $(cpp_nodef) $(src)/myvector/main.cpp $(out)$(build)/myvector-check_none + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(src)/myvector/main.cpp $(out)$(build)/myvector-check_inv + $(cpp_nodef) $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_inv + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_post + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_inv_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_inv_post + $(cpp_nodef) $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_inv_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_inv_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_inv_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main.cpp $(out)$(build)/myvector-check_block_inv_pre_post + +myvector_nomacros: mkdir_ + $(cpp) $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros +myvector_nomacros_checks: mkdir_ + # Compile with all different contract checking combinations. + $(cpp_nodef) $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_none + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_inv + $(cpp_nodef) $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_inv + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_post + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_inv_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_inv_post + $(cpp_nodef) $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_inv_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_pre_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_inv_post + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_inv_pre + $(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION $(src)/myvector/main_nomacros.cpp $(out)$(build)/myvector_nomacros-check_block_inv_pre_post + +commas: mkdir_ + $(cpp) $(src)/commas/main.cpp $(out)$(build)/commas + +throw: mkdir_ + $(cpp) $(src)/throw/main.cpp $(out)$(build)/throw + +Crowl2006: sqrt block sum factorial circle operator_equal vector +sqrt: mkdir_ + $(cpp) $(src)/Crowl2006/sqrt/main.cpp $(out)$(build)/sqrt +block: mkdir_ + $(cpp) $(src)/Crowl2006/block/main.cpp $(out)$(build)/block +sum: mkdir_ + $(cpp) $(src)/Crowl2006/sum/sum.cpp $(src)/Crowl2006/sum/main.cpp $(out)$(build)/sum +factorial: mkdir_ + $(cpp) $(src)/Crowl2006/factorial/main.cpp $(out)$(build)/factorial +circle: mkdir_ + $(cpp) $(src)/Crowl2006/circle/main.cpp $(out)$(build)/circle +operator_equal: mkdir_ + $(cpp) $(src)/Crowl2006/operator_equal/main.cpp $(out)$(build)/operator_equal +vector: mkdir_ + $(cpp) $(src)/Crowl2006/vector/main.cpp $(out)$(build)/vector + +Mitchell2002: name_list stack simple_queue dictionary courier customer_manager observe counter +name_list: mkdir_ + $(cpp) $(src)/Mitchell2002/name_list/names.cpp $(src)/Mitchell2002/name_list/main.cpp $(out)$(build)/name_list +stack: mkdir_ + $(cpp) $(src)/Mitchell2002/stack/main.cpp $(out)$(build)/stack +simple_queue: mkdir_ + $(cpp) $(src)/Mitchell2002/simple_queue/main.cpp $(out)$(build)/simple_queue +dictionary: mkdir_ + $(cpp) $(src)/Mitchell2002/dictionary/main.cpp $(out)$(build)/dictionary +courier: mkdir_ + $(cpp) $(src)/Mitchell2002/courier/couriers.cpp $(src)/Mitchell2002/courier/main.cpp $(out)$(build)/courier +customer_manager: mkdir_ + $(cpp) $(src)/Mitchell2002/customer_manager/customer_manager.cpp $(src)/Mitchell2002/customer_manager/main.cpp $(out)$(build)/customer_manager +observe: mkdir_ + $(cpp) $(src)/Mitchell2002/observe/main.cpp $(out)$(build)/observe +counter: mkdir_ + $(cpp) $(src)/Mitchell2002/counter/main.cpp $(out)$(build)/counter + +Meyer1997: stack4 stack3 gcd maxarray +stack4: mkdir_ + $(cpp) $(src)/Meyer1997/stack4/main.cpp $(out)$(build)/stack4 +stack3: mkdir_ + $(cpp) $(src)/Meyer1997/stack3/main.cpp $(out)$(build)/stack3 +gcd: mkdir_ + $(cpp) $(src)/Meyer1997/gcd/main.cpp $(out)$(build)/gcd +maxarray: mkdir_ + $(cpp) $(src)/Meyer1997/maxarray/main.cpp $(out)$(build)/maxarray + +Stroustrup1997: string +string: mkdir_ + $(cpp) $(src)/Stroustrup1997/string/string.cpp $(src)/Stroustrup1997/string/main.cpp $(out)$(build)/string + diff --git a/example/Meyer1997/README.txt b/example/Meyer1997/README.txt new file mode 100755 index 00000000..cc8e3ad6 --- /dev/null +++ b/example/Meyer1997/README.txt @@ -0,0 +1,2 @@ +Examples taken from Meyer, "Object Oriented Software Construction", +1997. diff --git a/example/Meyer1997/gcd/main.cpp b/example/Meyer1997/gcd/main.cpp new file mode 100755 index 00000000..5f831c78 --- /dev/null +++ b/example/Meyer1997/gcd/main.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Loop variants and invariants (ported from Eiffel code). + +#include +#include +#include + +/** Calculate greater common divisor of given positive integers. */ +int gcd(const int& a, const int& b) +CONTRACT_FUNCTION( (int)(gcd)( (const int&)(a) (const int&)(b) ) +(precondition) ({ + CONTRACT_ASSERT( a > 0 ); + CONTRACT_ASSERT( b > 0 ); +}) +(postcondition) (result) ({ + /** @post result is greatest common divisor of a and b */ +}) +(body) ({ + int x = a; + int y = b; + // Block invariants can apper in any code block (not just loop). + CONTRACT_ASSERT_BLOCK_INVARIANT( x == a ); + CONTRACT_ASSERT_BLOCK_INVARIANT( y == b ); + + // Loop variant and invariants. + for (CONTRACT_INIT_LOOP_VARIANT; x != y; ) { + CONTRACT_ASSERT_BLOCK_INVARIANT( x > 0 ); + CONTRACT_ASSERT_BLOCK_INVARIANT( y > 0 ); + /** @inv gcd(x, y) == gcd(a, b) */ + CONTRACT_ASSERT_LOOP_VARIANT( std::max(x, y) ); + + if (x > y) x = x - y; + else y = y - x; + } + + return x; +}) ) + +int main() { + int a = 12, b = 18; + std::cout << "gcd(" << a << ", " << b << ") = " + << gcd(a, b) << std::endl; + + a = 4; b = 14; + std::cout << "gcd(" << a << ", " << b << ") = " + << gcd(a, b) << std::endl; + + return 0; +} + diff --git a/example/Meyer1997/maxarray/main.cpp b/example/Meyer1997/maxarray/main.cpp new file mode 100755 index 00000000..1ddd686e --- /dev/null +++ b/example/Meyer1997/maxarray/main.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Loop variants and invariants (ported from Eiffel code). + +#include +#include +#include + +int maxarray(const int* array, const size_t& size) +CONTRACT_FUNCTION( (int) (maxarray)( (const int*)(array) + (const size_t&)(size) ) +(precondition) ({ + CONTRACT_ASSERT( size >= 1 ); +}) +(body) ({ + size_t i = 0; + int result = array[i]; + + CONTRACT_INIT_LOOP_VARIANT; + while (i < (size - 1)) { + for (size_t j = 0; j < i; ++j) + CONTRACT_ASSERT_BLOCK_INVARIANT( result >= array[j] ); + // -2 because start from 0 and already done element at 0. + CONTRACT_ASSERT_LOOP_VARIANT( size - i - 2 ); + + ++i; + result = std::max(result, array[i]); + } + + return result; +}) ) + +int main() { + int a[] = {1, 5, 3}; + std::cout << maxarray(a, 3) << std::endl; + return 0; +} + diff --git a/example/Meyer1997/stack3/main.cpp b/example/Meyer1997/stack3/main.cpp new file mode 100755 index 00000000..96482970 --- /dev/null +++ b/example/Meyer1997/stack3/main.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "stack3.hpp" +#include +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + stack3 s(3); + + std::cout << std::endl << "count()" << std::endl; + std::cout << s.count() << std::endl; + + std::cout << std::endl << "empty()" << std::endl; + std::cout << s.empty() << std::endl; + + std::cout << std::endl << "full()" << std::endl; + std::cout << s.full() << std::endl; + + std::cout << std::endl << "put()" << std::endl; + s.put("Galileo"); + + std::cout << std::endl << "capacity()" << std::endl; + std::cout << s.capacity() << std::endl; + + std::cout << std::endl << "item()" << std::endl; + std::cout << s.item() << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + s.remove(); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/Meyer1997/stack3/stack3.hpp b/example/Meyer1997/stack3/stack3.hpp new file mode 100755 index 00000000..3d1fc971 --- /dev/null +++ b/example/Meyer1997/stack3/stack3.hpp @@ -0,0 +1,186 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for a stack reporting errors using error codes instead +// of asserting preconditions or invariants (ported from Eiffel code). + +#ifndef STACK3_HPP_ +#define STACK3_HPP_ + +#include "../stack4/stack4.hpp" +#include + +/** Dispenser structures with a Last-In, First-Out access policy, and + * a fixed maximum capacity. Tolerant version setting an error code + * in case of impossible operations. */ +template +class stack3 { + + CONTRACT_INVARIANT( ({}) ) + +public: + static const T DEFAULT_ITEM; + + /** Error codes. */ + enum Error { + NO_ERROR = 0, + OVERFLOW_ERROR, + UNDERFLOW_ERROR, + SIZE_ERROR, + }; + + // Initialization // + + /** Create stack for a maximum of n elements. If n < 0, set error + * to SIZE_ERROR (but no precondition). */ + stack3(const int& n): representation_(0), error_(NO_ERROR) + CONTRACT_CONSTRUCTOR( (class) (stack3) + (public) (stack3)( (const int&)(n) ) + (postcondition) ({ + CONTRACT_ASSERT( (n < 0) == (error() == SIZE_ERROR) ); + CONTRACT_ASSERT( (n >= 0) == !error() ); + if (!error()) CONTRACT_ASSERT( capacity() == n ); + }) + (body) ({ + if (n >= 0) { + representation_ = stack4(n); + } else { + error_ = SIZE_ERROR; + } + }) ) + + /** Destroy stack. */ + virtual ~stack3(void) + CONTRACT_DESTRUCTOR( (class) (stack3) + (public) (virtual) (stack3)( (void) ) + (body) ({ + }) ) + + // Access // + + /** Maximum number of stack elements. */ + int capacity(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (int) (capacity)( (void) ) (const) + (body) ({ + return representation_.capacity(); + }) ) + + /** Number of stack elements. */ + int count(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (int) (count)( (void) ) (const) + (body) ({ + return representation_.count(); + }) ) + + /** Top element if present. Otherwise, return type's default + * value and set error to UNDERFLOW_ERROR (but no precondition). */ + const T& item(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (const T&) (item)( (void) ) (const) + (postcondition) (result) ({ + // Const function so no need to user ODLOF(this)->empty(). + CONTRACT_ASSERT( empty() == (error() == UNDERFLOW_ERROR) ); + CONTRACT_ASSERT( !empty() == !error() ); + }) + (body) ({ + if (!empty()) { + error_ = NO_ERROR; + return representation_.item(); + } else { + error_ = UNDERFLOW_ERROR; + return DEFAULT_ITEM; + } + }) ) + + // Status Report // + + /** Error indicator, set by various operators to a non-zero (not + * NO_ERROR) value if they cannot perform their job. */ + Error error(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (Error) (error)( (void) ) (const) + (body) ({ + return error_; + }) ) + + /** Is stack has not item. */ + bool empty(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (bool) (empty)( (void) ) (const) + (body) ({ + return representation_.empty(); + }) ) + + /** If stack cannot accept any more item. */ + bool full(void) const + CONTRACT_FUNCTION( (class) (stack3) + (public) (bool) (full)( (void) ) (const) + (body) ({ + return representation_.full(); + }) ) + + // Element Change // + + /** Add x to top if there is capacity left. Otherwise, set error + * to OVERFLOW_ERROR (but no precondition). */ + void put(const T& x) + CONTRACT_FUNCTION( (class) (copyable)(stack3) + (public) (void) (put)( (const T&)(x) ) + (postcondition) ({ + CONTRACT_ASSERT( CONTRACT_OLDOF(this)->full() == + (error() == OVERFLOW_ERROR) ); + CONTRACT_ASSERT( !CONTRACT_OLDOF(this)->full() == + !error() ); + if (!error()) CONTRACT_ASSERT( !empty() ); + if (!error()) CONTRACT_ASSERT( item() == x ); + if (!error()) CONTRACT_ASSERT( + count() == (CONTRACT_OLDOF(this)->count() + 1) ); + }) + (body) ({ + if (full()) { + error_ = OVERFLOW_ERROR; + } else { + representation_.put(x); + error_ = NO_ERROR; + } + }) ) + + /** Remove element if present. Otherwise, set error to + * UNDERFLOW_ERROR (but no precondition) */ + void remove(void) + CONTRACT_FUNCTION( (class) (copyable)(stack3) + (public) (void) (remove)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( CONTRACT_OLDOF(this)->empty() == + (error() == UNDERFLOW_ERROR) ); + CONTRACT_ASSERT( !CONTRACT_OLDOF(this)->empty() == + !error() ); + if (!error()) CONTRACT_ASSERT( !full() ); + if (!error()) CONTRACT_ASSERT( + count() == (CONTRACT_OLDOF(this)->count() - 1) ); + }) + (body) ({ + if (empty()) { + error_ = UNDERFLOW_ERROR; + } else { + representation_.remove(); + error_ = NO_ERROR; + } + }) ) + +private: + stack4 representation_; + // Mutable, changed by logically const members to report error. + mutable Error error_; +}; + +// For simplicity, T must have default constructor. +template +const T stack3::DEFAULT_ITEM = T(); + +#endif // #include guard + diff --git a/example/Meyer1997/stack4/main.cpp b/example/Meyer1997/stack4/main.cpp new file mode 100755 index 00000000..65c8fe0a --- /dev/null +++ b/example/Meyer1997/stack4/main.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "stack4.hpp" +#include +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + stack4 s(3); + + std::cout << std::endl << "capacity()" << std::endl; + std::cout << s.capacity() << std::endl; + + std::cout << std::endl << "count()" << std::endl; + std::cout << s.count() << std::endl; + + std::cout << std::endl << "put()" << std::endl; + s.put("Galileo"); + + std::cout << std::endl << "empty()" << std::endl; + std::cout << s.empty() << std::endl; + + std::cout << std::endl << "full()" << std::endl; + std::cout << s.full() << std::endl; + + std::cout << std::endl << "item()" << std::endl; + std::cout << s.item() << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + s.remove(); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/Meyer1997/stack4/stack4.hpp b/example/Meyer1997/stack4/stack4.hpp new file mode 100755 index 00000000..13e8e518 --- /dev/null +++ b/example/Meyer1997/stack4/stack4.hpp @@ -0,0 +1,227 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for a stack (ported from Eiffel code). + +#ifndef STACK4_HPP_ +#define STACK4_HPP_ + +#include + +// Specification // + +/** Dispenser structures with a Last-In, First-Out access policy, + * and a fixed maximum capacity. */ +template +class stack4 { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT_MSG( representation_, "array allocated" ); + CONTRACT_ASSERT( count() >= 0 ); + CONTRACT_ASSERT( count() <= capacity() ); + CONTRACT_ASSERT( empty() == (count() == 0) ); + if (count() > 0) CONTRACT_ASSERT_MSG( + representation_[count() - 1] == item(), + "if positive, item at top" ); + }) ) + +public: + // Initialization // + + /** Create stack for a maximum of n elements. */ + stack4(const int& n): capacity_(0), count_(0), representation_() + CONTRACT_CONSTRUCTOR( (class) (stack4) + (public) (stack4)( (const int&)(n) ) + (precondition) ({ + CONTRACT_ASSERT( n >= 0 ); + }) + (postcondition) ({ + CONTRACT_ASSERT( capacity() == n ); + CONTRACT_ASSERT( empty() ); + }) + (body) ( + ; + ) ) + + /** Deep copy. */ + stack4(const stack4& other): capacity_(other.capacity_), + count_(other.count_), + representation_(new T[other.capacity_]) + CONTRACT_CONSTRUCTOR( (class) (stack4) + (public) (stack4)( (const stack4&)(other) ) + (body) ( + ; + ) ) + + /** Deep assignment. */ + stack4& operator=(const stack4& other) + CONTRACT_FUNCTION( (class) (stack4) + (public) (stack4&) (operator(=, assign))( + (const stack4&)(other) ) + (body) ( + ; + ) ) + + /** Destroy this stack. */ + virtual ~stack4(void) + CONTRACT_DESTRUCTOR( (class) (stack4) + (public) (virtual) (stack4)( (void) ) + (body) ( + ; + ) ) + + // Access // + + /** Maximum number of stack elements. */ + int capacity(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (int) (capacity)( (void) ) (const) + (body) ( + ; + ) ) + + /** Number of stack elements. */ + int count(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (int) (count)( (void) ) (const) + (body) ( + ; + ) ) + + /** Top element. */ + const T& item(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (const T&) (item)( (void) ) (const) + (body) ( + ; + ) ) + + // Status Report // + + /** If stack is empty. */ + bool empty(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (bool) (empty)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (count() == 0) ); + }) + (body) ( + ; + ) ) + + /** If stack is full. */ + bool full(void) const + CONTRACT_FUNCTION( (class) (stack4) + (public) (bool) (full)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (count() == capacity()) ); + }) + (body) ( + ; + ) ) + + // Element Change // + + /** Add x on top. */ + void put(const T& x) + CONTRACT_FUNCTION( (class) (copyable)(stack4) + (public) (void) (put)( (const T&)(x) ) + (precondition) ({ + CONTRACT_ASSERT( !full() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( !empty() ); + CONTRACT_ASSERT_MSG( item() == x, "added to top" ); + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT_MSG( representation_[count() - 1] == x, + "at top array entry" ); + }) + (body) ( + ; + ) ) + + /** Remove top item. */ + void remove(void) + CONTRACT_FUNCTION( (class) (copyable)(stack4) + (public) (void) (remove)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !empty() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( !full() ); + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() - 1) ); + }) + (body) ( + ; + ) ) + +private: + int capacity_; + int count_; + T* representation_; // C-style array. +}; + +// Implementation // + +template +CONTRACT_CONSTRUCTOR_BODY(stack4, stack4)(const int& n) { + capacity_ = n; + representation_ = new T[n]; +} + +template +CONTRACT_CONSTRUCTOR_BODY(stack4, stack4)(const stack4& other) { + for (int i = 0; i < other.count_; ++i) { + representation_[i] = other.representation_[i]; + } +} + +template +stack4& stack4::CONTRACT_BODY(operator(=, assign))( + const stack4& other) { + delete[] representation_; + capacity_ = other.capacity_; + count_ = other.count_; + representation_ = new T[other.capacity_]; + for (int i = 0; i < other.count_; ++i) { + representation_[i] = other.representation_[i]; + } + return *this; +} + +template +CONTRACT_DESTRUCTOR_BODY(stack4, ~stack4)(void) + { delete[] representation_; } + +template +int stack4::CONTRACT_BODY(capacity)(void) const + { return capacity_; } + +template +int stack4::CONTRACT_BODY(count)(void) const { return count_; } + +template +const T& stack4::CONTRACT_BODY(item)(void) const + { return representation_[count() - 1]; } + +template +bool stack4::CONTRACT_BODY(empty)(void) const + { return count() == 0; } + +template +bool stack4::CONTRACT_BODY(full)(void) const + { return count() == capacity(); } + +template +void stack4::CONTRACT_BODY(put)(const T& x) + { representation_[count_++] = x; } + +template +void stack4::CONTRACT_BODY(remove)(void) { --count_; } + +#endif // #include guard + diff --git a/example/Mitchell2002/README.txt b/example/Mitchell2002/README.txt new file mode 100755 index 00000000..7a5fa9aa --- /dev/null +++ b/example/Mitchell2002/README.txt @@ -0,0 +1,2 @@ +Examples taken from Mitchell, McKim, "Design by Contract, +by Example", 2002. diff --git a/example/Mitchell2002/counter/counter.hpp b/example/Mitchell2002/counter/counter.hpp new file mode 100755 index 00000000..dcbcb505 --- /dev/null +++ b/example/Mitchell2002/counter/counter.hpp @@ -0,0 +1,69 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// A somewhat more complex example using the observer design pattern +// (ported from Eiffel code). Also shows how to make the library +// access a private copy constructor to support old value for +// `decrement_button` objects. + +#ifndef COUNTER_HPP_ +#define COUNTER_HPP_ + +#include "../observe/observe.hpp" +#include + +/** Positive integer counter. */ +class counter: public subject { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Construct counter. */ + counter(const int& value = 10): value_(value) + CONTRACT_CONSTRUCTOR( (class) (counter) + (public) (counter)( (const int&)(value) ) + (body) ({ + }) ) + + /** Destroy counter. */ + virtual ~counter(void) + CONTRACT_DESTRUCTOR( (class) (counter) + (public) (counter)( (void) ) + (body) ({ + }) ) + + // Queries // + + /** Counter current value. */ + int value(void) const + CONTRACT_FUNCTION( (class) (counter) + (public) (int) (value)( (void) ) (const) + (body) ({ + return value_; + }) ) + + // Commands // + + /** Decrement counter value. */ + void decrement(void) + CONTRACT_FUNCTION( (class) (copyable)(counter) + (public) (void) (decrement)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( value() == + (CONTRACT_OLDOF(this)->value() - 1) ); + }) + (body) ({ + --value_; + notify(); // Notifies all attached observers. + }) ) + +private: + int value_; +}; + +#endif // #include guard + diff --git a/example/Mitchell2002/counter/decrement_button.hpp b/example/Mitchell2002/counter/decrement_button.hpp new file mode 100755 index 00000000..6c454528 --- /dev/null +++ b/example/Mitchell2002/counter/decrement_button.hpp @@ -0,0 +1,123 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Use `contract:copy` to relax the library copyable requirements. + +#ifndef DECREMENT_BUTTON_HPP_ +#define DECREMENT_BUTTON_HPP_ + +#include "push_button.hpp" +#include "counter.hpp" +#include "../observe/observe.hpp" +#include +#include + +class decrement_button: public push_button, protected observer, + // This class is non-copyable but postconditions can still + // access its old values (see below). + boost::noncopyable { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create button associated with given counter. */ + decrement_button(counter& the_counter): counter_ref_(the_counter) + CONTRACT_CONSTRUCTOR( (class) (decrement_button) + (public) (decrement_button)( (counter&)(the_counter) ) + (postcondition) ({ + CONTRACT_ASSERT( enabled() == (the_counter.value() > 0) ); + }) + (body) ({ + counter_ref_.attach(this); + }) ) + + /** Destroy button. */ + virtual ~decrement_button(void) + CONTRACT_DESTRUCTOR( (class) (decrement_button) + (public) (virtual) (decrement_button)( (void) ) + (body) ({ + }) ) + + // Commands // + + void on_bn_clicked(void) + CONTRACT_FUNCTION( (class) (copyable)(decrement_button) + (inherit)(push_button) + (public) (void) (on_bn_clicked)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( enabled() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( counter_ref_.value() == + (CONTRACT_OLDOF(this)->counter_ref_.value() - 1) ); + }) + (body) ({ + counter_ref_.decrement(); + }) ) + +private: + decrement_button& operator=(const decrement_button&); + + bool up_to_date_with_subject(void) const + CONTRACT_FUNCTION( (class) (decrement_button) (inherit)(observer) + (private) (bool) (up_to_date_with_subject)( (void) ) + (const) + (body) ({ + return true; // For simplicity, always return true. + }) ) + + void update(void) + CONTRACT_FUNCTION( (class) (decrement_button) (inherit)(observer) + (private) (void) (update)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( enabled() == (counter_ref_.value() > 0) ); + }) + (body) ({ + if (0 == counter_ref_.value()) disable(); + else enable(); + }) ) + + counter& counter_ref_; + + // Allow access to contracts to implement special "copy". + friend class contract::copy; +}; + +// WARNING: Specialize `contract::copy` with care and only if really +// necessary (as a wrongly implemented specialization could brake +// contract constant-correctness guarantees). +// +// The decrement_button class has a reference member. The referenced +// counter (and not the counter reference!) are copied here to support +// object old value semantics in contract preconditions. This special +// "copy" is for contracts only -- in fact, decrement_button is +// `boost::noncopyable` and cannot be copied for general purposes. +// +// Similar techniques can be used to handle copy of objects with +// member pointers, in which case the `contract::copy` constructor +// allocates and copies the pointed objects (and not the pointers!) +// and the destructor deallocates them. +namespace contract { + template<> + class copy { + private: + // Not a reference type so it is copied. + counter counter_; // Non-const but local to this class. + public: + const decrement_button value; + + copy(const decrement_button& source): + // Copy the referenced counter (not the reference). + counter_(source.counter_ref_), + // "Copy" decrement_button constructing one from + // the copied counter. + value(counter_) {} + }; +} + +#endif // #include guard + diff --git a/example/Mitchell2002/counter/main.cpp b/example/Mitchell2002/counter/main.cpp new file mode 100755 index 00000000..675193ee --- /dev/null +++ b/example/Mitchell2002/counter/main.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "counter.hpp" +#include "decrement_button.hpp" +#include "view_of_counter.hpp" +#include + +int main() { + counter cnt(3); + view_of_counter view(cnt); + decrement_button dec(cnt); + + // Simple text-based menu selection. + char ch = '\0'; + while (ch != 'q') { + if (dec.enabled()) { + std::cout << "(-) Decrement counter" << std::endl; + } + std::cout << "(q) Quit" << std::endl; + std::cout << "Select: "; + + std::cin >> ch; + if ('q' == ch) { + return 0; + } else if ('-' == ch && dec.enabled()) { + dec.on_bn_clicked(); + } else { + std::cout << "Invalid selection '" << ch << "'" + << std::endl; + } + } + + return 0; +} + diff --git a/example/Mitchell2002/counter/push_button.hpp b/example/Mitchell2002/counter/push_button.hpp new file mode 100755 index 00000000..d3a6bb7a --- /dev/null +++ b/example/Mitchell2002/counter/push_button.hpp @@ -0,0 +1,79 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef PUSH_BUTTON_HPP_ +#define PUSH_BUTTON_HPP_ + +#include + +/** Basic button. */ +class push_button { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create button. */ + push_button(void): enabled_(true) + CONTRACT_CONSTRUCTOR( (class) (push_button) + (public) (push_button)( (void) ) + (body) ({ + }) ) + + virtual ~push_button(void) + CONTRACT_DESTRUCTOR( (class) (push_button) + (public) (virtual) (push_button)( (void) ) + (body) ({ + }) ) + + // Queries // + + /** If button enabled. */ + bool enabled(void) const + CONTRACT_FUNCTION( (class) (push_button) + (public) (bool) (enabled)( (void) ) (const) + (body) ({ + return enabled_; + }) ) + + // Commands // + + /** Enable this button. */ + void enable(void) + CONTRACT_FUNCTION( (class) (push_button) + (public) (void) (enable)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( enabled() ); + }) + (body) ({ + enabled_ = true; + }) ) + + /** Disable this button. */ + void disable(void) + CONTRACT_FUNCTION( (class) (push_button) + (public) (void) (disable)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( !enabled() ); + }) + (body) ({ + enabled_ = false; + }) ) + + /** Invoked externally when this button is clicked. */ + virtual void on_bn_clicked(void) + CONTRACT_FUNCTION( (class) (push_button) + (public) (virtual) (void) (on_bn_clicked)( (void) ) + (body) ( + = 0; + ) ) + +private: + bool enabled_; +}; + +#endif // #include guard + diff --git a/example/Mitchell2002/counter/view_of_counter.hpp b/example/Mitchell2002/counter/view_of_counter.hpp new file mode 100755 index 00000000..cfb79116 --- /dev/null +++ b/example/Mitchell2002/counter/view_of_counter.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef VIEW_OF_COUNT_HPP_ +#define VIEW_OF_COUNT_HPP_ + +#include "../observe/observe.hpp" +#include "counter.hpp" +#include +#include // To view counter value on console. + +/** Show current value of associated counter. */ +class view_of_counter: private observer { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create viewer associated with given counter. */ + view_of_counter(counter& the_counter): counter_ref_(the_counter) + CONTRACT_CONSTRUCTOR( (class) (view_of_counter) + (public) (view_of_counter)( (counter&)(the_counter) ) + (body) ({ + counter_ref_.attach(this); + std::cout << std::endl << ">> Counter started at " + << counter_ref_.value() << std::endl << std::endl; + }) ) + +private: + bool up_to_date_with_subject(void) const + CONTRACT_FUNCTION( (class) (view_of_counter) (inherit)(observer) + (private) (bool) (up_to_date_with_subject)( (void) ) (const) + (body) ({ + return true; // For simplicity, always return true. + }) ) + + void update(void) + CONTRACT_FUNCTION( (class) (view_of_counter) (inherit)(observer) + (private) (void) (update)( (void) ) + (body) ({ + std::cout << std::endl << ">> Counter changed to " + << counter_ref_.value() << std::endl << std::endl; + }) ) + + counter& counter_ref_; +}; + +#endif // #include guard + diff --git a/example/Mitchell2002/courier/couriers.cpp b/example/Mitchell2002/courier/couriers.cpp new file mode 100755 index 00000000..4ca28df3 --- /dev/null +++ b/example/Mitchell2002/courier/couriers.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "couriers.hpp" + +// Courier // + +double courier::min_insurance_dollar = 10.0e+6; + +CONTRACT_CONSTRUCTOR_BODY(courier, courier)( + const double& insurance_cover_dollar) {} + +CONTRACT_DESTRUCTOR_BODY(courier, ~courier)(void) {} + +double courier::CONTRACT_BODY(insurance_cover_dollar)(void) const { + return insurance_cover_dollar_; +} + +void courier::CONTRACT_BODY(deliver)(package& the_package, + const std::string& 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_CONSTRUCTOR_BODY(different_courier, different_courier)( + const double& insurance_cover_dollar) {} + +CONTRACT_DESTRUCTOR_BODY(different_courier, ~different_courier)( + void) {} + +void different_courier::CONTRACT_BODY(deliver)(package& the_package, + const std::string& 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/Mitchell2002/courier/couriers.hpp b/example/Mitchell2002/courier/couriers.hpp new file mode 100755 index 00000000..b369c59f --- /dev/null +++ b/example/Mitchell2002/courier/couriers.hpp @@ -0,0 +1,175 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Subcontracting and static invariant example (ported from Eiffel code). + +#ifndef COURIERS_HPP_ +#define COURIERS_HPP_ + +#include +#include + +/** Basic package information. */ +struct package { + /** Weight in kilograms. */ + double weight_kg; + /** Current location. */ + std::string location; + /** Hour when it was accepted for delivery (from some 0-hour). */ + double accepted_hour; + /** Hour when was delivered (from some 0-hour). */ + double delivered_hour; + + package(const double& the_weight_kg, + const std::string the_location = "", + const double& the_accepted_hour = 0.0, + const double& the_delivered_hour = 0.0): + weight_kg(the_weight_kg), + location(the_location), + accepted_hour(the_accepted_hour), + delivered_hour(the_delivered_hour) + {} +}; + +/** Basic courier for package delivery. */ +class courier { + + CONTRACT_INVARIANT( (static) ({ + CONTRACT_ASSERT( min_insurance_dollar > 0.0 ); + }) ({ + CONTRACT_ASSERT( insurance_cover_dollar() >= + min_insurance_dollar ); + }) ) + +public: + static double min_insurance_dollar; + + // Creation // + + /** Create courier with specified insurance value. */ + courier(const double& insurance_cover_dollar = + min_insurance_dollar): + insurance_cover_dollar_(insurance_cover_dollar) + CONTRACT_CONSTRUCTOR( (class) (courier) + (public) (courier)( + (const double&)(insurance_cover_dollar) ) + (precondition) ({ + CONTRACT_ASSERT( insurance_cover_dollar > 0.0 ); + }) + (body) ( + ; + ) ) + + /** Destroy courier. */ + virtual ~courier(void) + CONTRACT_DESTRUCTOR( (class) (courier) + (public) (courier)( (void) ) + (body) ( + ; + ) ) + + // Queries // + + /** Return insurance cover. */ + double insurance_cover_dollar(void) const + CONTRACT_FUNCTION( (class) (courier) + (public) (double) (insurance_cover_dollar)( (void) ) + (const) + (body) ( + ; + ) ) + + // Commands // + + /** Deliver package to destination. */ + virtual void deliver(package& the_package, + const std::string& destination) + CONTRACT_FUNCTION( (class) (courier) + (public) (virtual) (void) (deliver)( + (package&)(the_package) + (const std::string&)(destination) ) + (precondition) ({ + CONTRACT_ASSERT_MSG( the_package.weight_kg <= 5.0, + "max weight" ); + }) + (postcondition) ({ + CONTRACT_ASSERT_MSG( (the_package.delivered_hour - + the_package.accepted_hour) <= 3.0, + "max delivery time" ); + CONTRACT_ASSERT_MSG( the_package.location == destination, + "delivered at destination" ); + }) + (body) ( + ; + ) ) + +private: + double insurance_cover_dollar_; +}; + +/** Different courier for package delivery. */ +class different_courier: public courier { + + CONTRACT_INVARIANT( (static) ({ + // Stronger invariant on insurance value (higher amount). + CONTRACT_ASSERT( different_insurance_dollar >= + courier::min_insurance_dollar ); + }) ({ + CONTRACT_ASSERT( insurance_cover_dollar() >= + different_insurance_dollar ); + }) ) + +public: + static double different_insurance_dollar; + + // Creation // + + /** Create courier with specified insurance value. */ + different_courier(const double& insurance_cover_dollar = + different_insurance_dollar): + courier(insurance_cover_dollar) + CONTRACT_CONSTRUCTOR( (class) (different_courier) + (public) (different_courier)( + (const double&)(insurance_cover_dollar) ) + (precondition) ({ + CONTRACT_ASSERT( insurance_cover_dollar >= 0.0 ); + }) + (body) ( + ; + ) ) + + /** Destroy courier. */ + virtual ~different_courier(void) + CONTRACT_DESTRUCTOR( (class) (different_courier) + (public) (virtual) (different_courier)( (void) ) + (body) ( + ; + ) ) + + // Commands // + + virtual void deliver(package& the_package, + const std::string& destination) + CONTRACT_FUNCTION( (class) (different_courier) (inherit)(courier) + (public) (virtual) (void) (deliver)( + (package&)(the_package) + (const std::string&)(destination) ) + (precondition) ({ + // Weaker precondition on weight (can weight more). + CONTRACT_ASSERT( the_package.weight_kg <= 8.0 ); + }) + (postcondition) ({ + // Stronger postcondition on deliver time (faster deliver). + CONTRACT_ASSERT( (the_package.delivered_hour - + the_package.accepted_hour) <= 2.0 ); + // Inherits "delivered at destination" postcondition. + }) + (body) ( + ; + ) ) +}; + +#endif // #include guard + diff --git a/example/Mitchell2002/courier/main.cpp b/example/Mitchell2002/courier/main.cpp new file mode 100755 index 00000000..49462899 --- /dev/null +++ b/example/Mitchell2002/courier/main.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "couriers.hpp" +#include + +int main() { + std::cout << std::endl << "courier constructor" << std::endl; + courier c; + { + std::cout << std::endl << "different courier constructor" + << std::endl; + different_courier dc; + + package cups(3.6, "store"); + package desk(7.2, "store"); + + std::cout << std::endl << "courier delivers cups home" + << std::endl; + c.deliver(cups, "home"); + + std::cout << std::endl << "different courier delivers desk " + << "to office" << std::endl; + dc.deliver(desk, "office"); + + std::cout << std::endl << "different courier destructor" + << std::endl; + } + std::cout << std::endl << "courier destructor" << std::endl; + return 0; +} + diff --git a/example/Mitchell2002/customer_manager/customer_manager.cpp b/example/Mitchell2002/customer_manager/customer_manager.cpp new file mode 100755 index 00000000..15e34212 --- /dev/null +++ b/example/Mitchell2002/customer_manager/customer_manager.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "customer_manager.hpp" + +CONTRACT_CONSTRUCTOR_BODY(customer_manager, customer_manager)(void) {} + +CONTRACT_DESTRUCTOR_BODY(customer_manager, ~customer_manager)(void) {} + +int customer_manager::CONTRACT_BODY(count)(void) const { + return customers_.size(); +} + +bool customer_manager::CONTRACT_BODY(id_active)( + const basic_customer_details::identifier& id) const { + return customers_.find(id) != customers_.end(); +} + +const std::string& customer_manager::CONTRACT_BODY(name_for)( + const basic_customer_details::identifier& id) const { + // Find != end() because of id_active() precondition. + return customers_.find(id)->second.name; +} + +void customer_manager::CONTRACT_BODY(add)( + const basic_customer_details& details) { + customers_.insert(std::pair(details.id, customer(details))); +} + +void customer_manager::CONTRACT_BODY(set_name)( + const basic_customer_details::identifier& id, + const std::string& name) { + // Find != end() because of id_active() precondition. + customers_.find(id)->second.name = name; +} + diff --git a/example/Mitchell2002/customer_manager/customer_manager.hpp b/example/Mitchell2002/customer_manager/customer_manager.hpp new file mode 100755 index 00000000..13f70b7c --- /dev/null +++ b/example/Mitchell2002/customer_manager/customer_manager.hpp @@ -0,0 +1,159 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contract example (ported from Eiffel code). + +#ifndef CUSTOMER_MANAGE_HPP_ +#define CUSTOMER_MANAGE_HPP_ + +#include +#include +#include + +/** Basic customer information. */ +class basic_customer_details { + friend class customer_manager; + +public: + /** Identifier type. */ + typedef std::string identifier; + + /** Construct basic customer information. */ + explicit basic_customer_details(const identifier& the_id): + id(the_id), name(), address(), birthday() {} + +protected: + /** Customer identifier. */ + identifier id; + /** Customer name. */ + std::string name; + /** Customer address. */ + std::string address; + /** Customer date of birth. */ + std::string birthday; +}; + +/** Manage customers. */ +class customer_manager { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( count() >= 0 ); + }) ) + +public: + // Construction // + + customer_manager(void): customers_() + CONTRACT_CONSTRUCTOR( (class) (customer_manager) + (public) (customer_manager)( (void) ) + (body) ( + ; + ) ) + + virtual ~customer_manager(void) + CONTRACT_DESTRUCTOR( (class) (customer_manager) + (public) (customer_manager)( (void) ) + (body) ( + ; + ) ) + + // Basic Queries // + + /** Number of customers. */ + int count(void) const + CONTRACT_FUNCTION( (class) (customer_manager) + (public) (int) (count)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result >= 0 ); + }) + (body) ( + ; + ) ) + + /** There is a customer with given identifier. */ + bool id_active(const basic_customer_details::identifier& id) + const + CONTRACT_FUNCTION( (class) (customer_manager) + (public) (bool) (id_active)( + (const basic_customer_details::identifier&)(id) ) + (const) + (body) ( + ; + ) ) + + // Derived Queries // + + /** Name of customer with given identifier. */ + const std::string& name_for( + const basic_customer_details::identifier& id) const + CONTRACT_FUNCTION( (class) (customer_manager) + (public) (const std::string&) (name_for)( + (const basic_customer_details::identifier&)(id) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( id_active(id) ); + }) + (body) ( + ; + ) ) + + // Commands // + + /** Add given customer. */ + void add(const basic_customer_details& details) + CONTRACT_FUNCTION( (class) (copyable)(customer_manager) + (public) (void) (add)( + (const basic_customer_details&)(details) ) + (precondition) ({ + CONTRACT_ASSERT( !id_active(details.id) ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT( id_active(details.id) ); + }) + (body) ( + ; + ) ) + + /** Set name of customer with given identifier. */ + void set_name(const basic_customer_details::identifier& id, + const std::string& name) + CONTRACT_FUNCTION( (class) (customer_manager) + (public) (void) (set_name)( + (const basic_customer_details::identifier&)(id) + (const std::string&)(name) ) + (precondition) ({ + CONTRACT_ASSERT( id_active(id) ); + }) + (postcondition) ({ + CONTRACT_ASSERT( name_for(id) == name ); + }) + (body) ( + ; + ) ) + +private: + /** Customer agent. */ + class agent {}; + + /** Basic customer. */ + class customer: public basic_customer_details { + public: + /** Customer agent/ */ + agent managing_agent; + /** Customer last contacted. */ + std::string last_contact; + + explicit customer(const basic_customer_details& details): + basic_customer_details(details), managing_agent(), + last_contact() {} + }; + + std::map customers_; +}; + +#endif // #include guard + diff --git a/example/Mitchell2002/customer_manager/main.cpp b/example/Mitchell2002/customer_manager/main.cpp new file mode 100755 index 00000000..c440c10c --- /dev/null +++ b/example/Mitchell2002/customer_manager/main.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "customer_manager.hpp" +#include + +int main() { + std::cout << "constructor()" << std::endl; + customer_manager mgr; + + basic_customer_details d("sci"); + std::cout << std::endl << "add()" << std::endl; + mgr.add(d); + + std::cout << std::endl << "set_name()" << std::endl; + mgr.set_name("sci", "Galileo"); + + std::cout << std::endl << "name_for()" << std::endl; + std::cout << mgr.name_for("sci"); + + std::cout << std::endl << "count()" << std::endl; + std::cout << mgr.count() << std::endl; + + std::cout << std::endl << "id_active()" << std::endl; + std::cout << mgr.id_active("sci") << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/Mitchell2002/dictionary/dictionary.hpp b/example/Mitchell2002/dictionary/dictionary.hpp new file mode 100755 index 00000000..9651dfc9 --- /dev/null +++ b/example/Mitchell2002/dictionary/dictionary.hpp @@ -0,0 +1,117 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for an Eiffel-like dictionary (ported from Eiffel code). + +#ifndef DICTINARY_HPP_ +#define DICTINARY_HPP_ + +#include +#include + +/** Simple dictionary. */ +template +class dictionary { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( count() >= 0 ); + }) ) + +public: + // Creation // + + /** Create empty dictionary. */ + dictionary(void) + CONTRACT_CONSTRUCTOR( (class) (dictionary) + (public) (dictionary)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( 0 == count() ); + }) + (body) ({ + }) ) + + /** Destroy dictionary. */ + virtual ~dictionary(void) + CONTRACT_DESTRUCTOR( (class) (dictionary) + (public) (dictionary)( (void) ) + (body) ({ + }) ) + + // Basic Queries // + + /** Number of key entries. */ + int count(void) const + CONTRACT_FUNCTION( (class) (dictionary) + (public) (int) (count)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result >= 0 ); + }) + (body) ({ + return items_.size(); + }) ) + + /** If there is an entry for specified key. */ + bool has(const Key& key) const + CONTRACT_FUNCTION( (class) (dictionary) + (public) (bool) (has)( (const Key&)(key) ) (const) + (postcondition) (result) ({ + if (count() == 0) CONTRACT_ASSERT( result == false ); + }) + (body) ({ + return items_.find(key) != items_.end(); + + }) ) + + /** Value for given key. */ + const Value& value_for(const Key& key) const + CONTRACT_FUNCTION( (class) (dictionary) + (public) (const Value&) (value_for)( (const Key&)(key) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( has(key) ); + }) + (body) ({ + return items_.find(key)->second; + }) ) + + // Commands // + + /** Put value for given key. */ + void put(const Key& key, const Value& value) + CONTRACT_FUNCTION( (class) (copyable)(dictionary) + (public) (void) (put)( (const Key&)(key) + (const Value&)(value) ) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT( has(key) ); + CONTRACT_ASSERT( value_for(key) == value ); + }) + (body) ({ + items_.insert(std::pair(key, value)); + }) ) + + /** Remove value for given key. */ + void remove(const Key& key) + CONTRACT_FUNCTION( (class) (copyable)(dictionary) + (public) (void) (remove)( (const Key&)(key) ) + (precondition) ({ + CONTRACT_ASSERT( has(key) ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() - 1) ); + CONTRACT_ASSERT( !has(key) ); + }) + (body) ({ + items_.erase(key); + }) ) + +private: + std::map items_; +}; + +#endif // #inlcude guard + diff --git a/example/Mitchell2002/dictionary/main.cpp b/example/Mitchell2002/dictionary/main.cpp new file mode 100755 index 00000000..48754aad --- /dev/null +++ b/example/Mitchell2002/dictionary/main.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "dictionary.hpp" +#include +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + dictionary ages; + + std::cout << std::endl << "has()" << std::endl; + std::cout << ages.has("Galileo") << std::endl; + + std::cout << std::endl << "put()" << std::endl; + ages.put("Galileo", 78); + + std::cout << std::endl << "value_for()" << std::endl; + std::cout << ages.value_for("Galileo") << std::endl; + + std::cout << std::endl << "count()" << std::endl; + std::cout << ages.count() << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + ages.remove("Galileo"); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/Mitchell2002/name_list/main.cpp b/example/Mitchell2002/name_list/main.cpp new file mode 100755 index 00000000..ad7e8e14 --- /dev/null +++ b/example/Mitchell2002/name_list/main.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "names.hpp" + +int main() { + std::string n = "Galileo"; + + std::cout << std::endl << "constructor()" << std::endl; + name_list nl; + relaxed_name_list rl; + + std::cout << std::endl << "put()" << std::endl; + rl.put(n); + std::cout << std::endl << "put() again (allowed)" << std::endl; + rl.put(n); + + std::cout << std::endl << "put()" << std::endl; + nl.put(n); + std::cout << std::endl << "put() again (not allowed)" << std::endl; + nl.put(n); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/Mitchell2002/name_list/names.cpp b/example/Mitchell2002/name_list/names.cpp new file mode 100755 index 00000000..3a7ecd42 --- /dev/null +++ b/example/Mitchell2002/name_list/names.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "names.hpp" +#include + +// name_list // + +CONTRACT_CONSTRUCTOR_BODY(name_list, name_list)(void) {} + +CONTRACT_DESTRUCTOR_BODY(name_list, ~name_list)(void) {} + +bool name_list::CONTRACT_BODY(has)(const std::string& name) const { + std::clog << "base has\n"; + return names_.end() != std::find(names_.begin(), names_.end(), + name); +} + +unsigned int name_list::CONTRACT_BODY(count)(void) const { + std::clog << "base count\n"; + return names_.size(); +} + +void name_list::CONTRACT_BODY(put)(const std::string& name) { + std::clog << "base put\n"; + 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_BODY(put)(const std::string& name) { + std::clog << "dervied put\n"; + if (!has(name)) { + // Base class operations must be called via BODY macro. + name_list::CONTRACT_BODY(put)(name); + // name_list::put(name); // ERROR: causes infinite recursion. + } +} + diff --git a/example/Mitchell2002/name_list/names.hpp b/example/Mitchell2002/name_list/names.hpp new file mode 100755 index 00000000..86a25245 --- /dev/null +++ b/example/Mitchell2002/name_list/names.hpp @@ -0,0 +1,127 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Subcontracting example (ported from Eiffel code). + +#ifndef NAMES_HPP_ +#define NAMES_HPP_ + +#include +#include +#include + +/** List of names. */ +class name_list { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create object. */ + name_list(void): names_() + CONTRACT_CONSTRUCTOR( (class) (name_list) + (public) (name_list)( (void) ) + (body) ( + ; + ) ) + + /** Destroy object. */ + virtual ~name_list(void) + CONTRACT_DESTRUCTOR( (class) (name_list) + (public) (virtual) (name_list)( (void) ) + (body) ( + ; + ) ) + + // Queries // + + /** If specified names is in list. */ + bool has(const std::string& name) const + CONTRACT_FUNCTION( (class) (name_list) + (public) (bool) (has)( (const std::string&)(name) ) + (const) + (body) ( + ; + ) ) + + /** Number of names in list. */ + unsigned int count(void) const + CONTRACT_FUNCTION( (class) (name_list) + (public) (unsigned int) (count)( (void) ) (const) + (body) ( + ; + ) ) + + // Commands // + + /** Add name to list. */ + virtual void put(const std::string& name) + CONTRACT_FUNCTION( (class) (copyable)(name_list) + (public) (virtual) (void) (put)( + (const std::string&)(name) ) + (precondition) ({ + CONTRACT_ASSERT( !has(name) ); + }) + (postcondition) ({ + // If-guard to allow subcontracts to relax postconditions. + if (!CONTRACT_OLDOF(this)->has(name)) { + CONTRACT_ASSERT( has(name) ); + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + } + }) + (body) ( + ; + ) ) + +private: + std::list names_; +}; + +/** List of names that allows for duplicates. */ +class relaxed_name_list: public name_list { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + relaxed_name_list(void): name_list() + CONTRACT_CONSTRUCTOR( (class) (relaxed_name_list) + (public) (relaxed_name_list)( (void) ) + (body) ( + ; + ) ) + + virtual ~relaxed_name_list(void) + CONTRACT_DESTRUCTOR( (class) (relaxed_name_list) + (public) (virtual) (relaxed_name_list)( (void) ) + (body) ( + ; + ) ) + + // Commands // + + void put(const std::string& name) + CONTRACT_FUNCTION( (class) (copyable)(relaxed_name_list) + (inherit)(name_list) + (public) (void) (put)( (const std::string&)(name) ) + (precondition) ({ + // Relax inherited precondition `!has(name)`. + CONTRACT_ASSERT( has(name) ); + }) + (postcondition) ({ + // Inherited postcondition not checked because of its if-guard. + if (CONTRACT_OLDOF(this)->has(name)) CONTRACT_ASSERT( + count() == CONTRACT_OLDOF(this)->count() ); + }) + (body) ( + ; + ) ) +}; + +#endif // #include guard + diff --git a/example/Mitchell2002/observe/main.cpp b/example/Mitchell2002/observe/main.cpp new file mode 100755 index 00000000..d98564a7 --- /dev/null +++ b/example/Mitchell2002/observe/main.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "observe.hpp" +#include +#include + +/** Implement an actual subject. */ +class concrete_subject: public subject { +public: + /** State being observed. */ + typedef int state; + + concrete_subject(): state_() {} + + /** Set state being observed. */ + void set_state(const state& the_state) { + std::cout << "Changing state to " << the_state << std::endl; + state_ = the_state; + notify(); // Notify observers. + } + + /** Get state being observed. */ + state get_state() const { return state_; } + +private: + state state_; +}; + +/** Implement of actual observer. */ +class concrete_observer: public observer { +public: + /** Create concrete observer. */ + concrete_observer(const concrete_subject& the_subject): + subject_(the_subject), observed_state_() {} + +private: + bool up_to_date_with_subject(void) const + CONTRACT_FUNCTION( (class) (concrete_observer) (inherit)(observer) + (private) (bool) (up_to_date_with_subject)( (void) ) + (const) + (body) ({ + return true; // For simplicity, always true. + }) ) + + void update(void) + CONTRACT_FUNCTION( (class) (concrete_observer) (inherit)(observer) + (private) (void) (update)( (void) ) + (body) ({ + observed_state_ = subject_.get_state(); + std::cout << "Observed state " << observed_state_ + << std::endl; + }) ) + + const concrete_subject& subject_; + concrete_subject::state observed_state_; +}; + +int main() { + std::cout << std::endl << "Constructing objects" << std::endl; + concrete_subject sbj; + concrete_observer ob(sbj); + + std::cout << std::endl << "Attaching observer " << &ob + << std::endl; + sbj.attach(&ob); + + concrete_subject::state st = -10; + std::cout << std::endl << "Setting state to " << st << std::endl; + sbj.set_state(st); + + st = +10; + std::cout << std::endl << "Re-setting state to " << st << std::endl; + sbj.set_state(st); + + std::cout << std::endl << "Destructing objects" << std::endl; + return 0; +} + diff --git a/example/Mitchell2002/observe/observe.hpp b/example/Mitchell2002/observe/observe.hpp new file mode 100755 index 00000000..c1fbfba1 --- /dev/null +++ b/example/Mitchell2002/observe/observe.hpp @@ -0,0 +1,184 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// A frame rule for observer design pattern (ported from Eiffel code). + +#ifndef OBSERVE_HPP_ +#define OBSERVE_HPP_ + +#include +#include +#include + +/** Observer. */ +class observer { + friend class subject; + + CONTRACT_INVARIANT( ({}) ) + +public: + // Creation // + + /** Create observer. */ + observer(void) + CONTRACT_CONSTRUCTOR( (class) (observer) + (public) (observer)( (void) ) + (body) ({ + }) ) + + /** Destroy observer. */ + virtual ~observer(void) + CONTRACT_DESTRUCTOR( (class) (observer) + (public) (virtual) (observer)( (void) ) + (body) ({ + }) ) + +protected: + // Commands // + + /** If up to date with its subject. */ + virtual bool up_to_date_with_subject(void) const + CONTRACT_FUNCTION( (class) (observer) + (protected) (virtual) (bool) (up_to_date_with_subject)( + (void) ) (const) + (body) ( + = 0; + ) ) + + virtual void update(void) + CONTRACT_FUNCTION( (class) (observer) + (protected) (virtual) (void) (update)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( up_to_date_with_subject() ); + }) + (body) ( + = 0; + ) ) +}; + +/** Subject for observer design pattern. */ +class subject { + + CONTRACT_INVARIANT( ({ + for (std::list::const_iterator + i = observers_.begin(); i != observers_.end(); ++i) + CONTRACT_ASSERT( *i ); + }) ) + +public: + // Creation // + + /** Construct subject. */ + subject(void): observers_() + CONTRACT_CONSTRUCTOR( (class) (subject) + (public) (subject)( (void) ) + (body) ({ + }) ) + + /** Destroy subject. */ + virtual ~subject(void) + CONTRACT_DESTRUCTOR( (class) (subject) + (public) (virtual) (subject)( (void) ) + (body) ({ + }) ) + + // Queries // + + /** If given observer is attached. */ + bool attached(const observer* const ob) const + CONTRACT_FUNCTION( (class) (subject) + (public) (bool) (attached)( (const observer* const)(ob) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( ob ); + }) + (postcondition) (result) ({ + const std::list obs = observers(); + CONTRACT_ASSERT( result == (std::find(obs.begin(), obs.end(), + ob) != obs.end()) ); + }) + (body) ({ + return std::find(observers_.begin(), observers_.end(), + ob) != observers_.end(); + }) ) + + // Commands // + + /** Remember given objects as on of the subject observers. */ + void attach(observer* const ob) + CONTRACT_FUNCTION( (class) (copyable)(subject) + (public) (void) (attach)( (observer* const)(ob) ) + (precondition) ({ + CONTRACT_ASSERT( ob ); + CONTRACT_ASSERT( !attached(ob) ); + }) + (postcondition) ({ + CONTRACT_ASSERT( attached(ob) ); + + // Frame rule. + const std::list& old = + CONTRACT_OLDOF(this)->observers(); + std::list now = observers(); + std::remove(now.begin(), now.end(), ob); + std::list::const_iterator nowi = now.begin(); + std::list::const_iterator oldi = old.begin(); + while (now.end() != nowi && old.end() != oldi) { + CONTRACT_ASSERT_MSG( *nowi == *oldi, + "all other observers unchanged" ); + ++nowi; + ++oldi; + } + }) + (body) ({ + observers_.push_back(ob); + }) ) + +protected: + // Queries // + + /** All observers attached to this subject. + * This is protected because it is intended to support contract + * specification only (including contracts of derived classes). + * See related discussion in [Mitchell2002] Section 9.9. */ + std::list observers(void) const + CONTRACT_FUNCTION( (class) (subject) + (protected) (std::list) + (observers)( (void) ) (const) + (body) ({ + // 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 // + + /** Update all attached observers. */ + void notify(void) + CONTRACT_FUNCTION( (class) (subject) + (protected) (void) (notify)( (void) ) + (postcondition) ({ + const std::list obs = observers(); + for (std::list::const_iterator + i = obs.begin(); i != obs.end(); ++i) { + CONTRACT_ASSERT( *i ); + CONTRACT_ASSERT( (*i)->up_to_date_with_subject() ); + } + }) + (body) ({ + for (std::list::iterator + i = observers_.begin(); i != observers_.end(); ++i) + // Invariant ensures no null pointers in observers. + (*i)->update(); + }) ) + +private: + std::list observers_; +}; + +#endif // #include guard + diff --git a/example/Mitchell2002/simple_queue/main.cpp b/example/Mitchell2002/simple_queue/main.cpp new file mode 100755 index 00000000..bd2f0854 --- /dev/null +++ b/example/Mitchell2002/simple_queue/main.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "simple_queue.hpp" +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + simple_queue q(10); + + std::cout << std::endl << "count()" << std::endl; + std::cout << q.count() << std::endl; + + std::cout << std::endl << "put()" << std::endl; + q.put('a'); + std::cout << std::endl << "put() (again)" << std::endl; + q.put('b'); + + std::cout << std::endl << "items()" << std::endl; + const std::vector& items = q.items(); + for (std::vector::const_iterator i = items.begin(); + items.end() != i; ++i) { + std::cout << *i << std::endl; + } + + std::cout << std::endl << "capacity()" << std::endl; + std::cout << q.capacity() << std::endl; + + std::cout << std::endl << "head()" << std::endl; + std::cout << q.head() << std::endl; + + std::cout << std::endl << "is_empty()" << std::endl; + std::cout << q.is_empty() << std::endl; + + std::cout << std::endl << "is_full()" << std::endl; + std::cout << q.is_full() << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + q.remove(); + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/Mitchell2002/simple_queue/simple_queue.hpp b/example/Mitchell2002/simple_queue/simple_queue.hpp new file mode 100755 index 00000000..971c6148 --- /dev/null +++ b/example/Mitchell2002/simple_queue/simple_queue.hpp @@ -0,0 +1,164 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for an Eiffel-like simple queue (ported from Eiffel code). + +#ifndef SIMPLE_QUEUE_HPP_ +#define SIMPLE_QUEUE_HPP_ + +#include +#include + +/** Simple queue. */ +template +class simple_queue { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( count() >= 0 ); + }) ) + +public: + // Creation // + + /** Create empty queue. */ + simple_queue(const int& the_capacity): items_() + CONTRACT_CONSTRUCTOR( (class) (simple_queue) + (public) (simple_queue)( (const int&)(the_capacity) ) + (precondition) ({ + CONTRACT_ASSERT( the_capacity >= 1 ); + }) + (postcondition) ({ + CONTRACT_ASSERT( capacity() == the_capacity ); + CONTRACT_ASSERT( is_empty() ); + }) + (body) ({ + items_.reserve(the_capacity); + }) ) + + /** Destroy queue. */ + virtual ~simple_queue(void) + CONTRACT_DESTRUCTOR( (class) (simple_queue) + (public) (virtual) (simple_queue)( (void) ) + (body) ({ + }) ) + + // Basic Queries // + + /** Items in the queue (in their order). */ + const std::vector& items(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (const std::vector&) (items)( (void) ) (const) + (body) ({ + return items_; + }) ) + + /** Maximum number of items queue can hold. */ + int capacity(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (int) (capacity)( (void) ) (const) + (body) ({ + return items_.capacity(); + }) ) + + // Derived Queries // + + /** Number of items. */ + int count(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (int) (count)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == int(items().size()) ); + }) + (body) ({ + return items_.size(); + }) ) + + /** Item at head. */ + const T& head(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (const T&) (head)( (void) ) (const) + (precondition) ({ + CONTRACT_ASSERT( !is_empty() ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == items().at(0) ); + }) + (body) ({ + return items_.at(0); + }) ) + + /** If queue contains no items. */ + bool is_empty(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (bool) (is_empty)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (0 == count()) ); + }) + (body) ({ + return 0 == items_.size(); + }) ) + + /** If queue has no room for another item. */ + bool is_full(void) const + CONTRACT_FUNCTION( (class) (simple_queue) + (public) (bool) (is_full)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == + (int(items().size()) == capacity()) ); + }) + (body) ({ + return items_.size() == items_.capacity(); + }) ) + + // Commands // + + /** Remove head item shifting all other items accordingly. */ + void remove(void) + CONTRACT_FUNCTION( (class) (copyable)(simple_queue) + (public) (void) (remove)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( !is_empty() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() - 1) ); + + for (size_t i = 1; i < CONTRACT_OLDOF(this)->items().size(); + ++i) + CONTRACT_ASSERT( items().at(i - 1) == + CONTRACT_OLDOF(this)->items().at(i) ); + }) + (body) ({ + items_.erase(items_.begin()); + }) ) + + /** Add item to tail. */ + void put(const T& item) + CONTRACT_FUNCTION( (class) (copyable)(simple_queue) + (public) (void) (put)( (const T&)(item) ) + (precondition) ({ + CONTRACT_ASSERT( count() < capacity() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT( items().at(count() - 1) == item ); + if (count() >= 2) { + for (int i = 0; i < CONTRACT_OLDOF(this)->count(); ++i) { + CONTRACT_ASSERT( items().at(i) == + CONTRACT_OLDOF(this)->items().at(i) ); + } + } + }) + (body) ({ + items_.push_back(item); + }) ) + +private: + std::vector items_; +}; + +#endif // #include guard + diff --git a/example/Mitchell2002/stack/main.cpp b/example/Mitchell2002/stack/main.cpp new file mode 100755 index 00000000..613592ad --- /dev/null +++ b/example/Mitchell2002/stack/main.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "stack.hpp" +#include +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + stack s; + + std::cout << std::endl << "count()" << std::endl; + std::cout << s.count() << std::endl; + + std::cout << std::endl << "put()" << std::endl; + s.put("Galileo"); + + std::cout << std::endl << "item_at()" << std::endl; + std::cout << s.item_at(1) << std::endl; + + std::cout << std::endl << "remove()" << std::endl; + s.remove(); + + std::cout << std::endl << "is_empty()" << std::endl; + std::cout << s.is_empty() << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/Mitchell2002/stack/stack.hpp b/example/Mitchell2002/stack/stack.hpp new file mode 100755 index 00000000..68f86fe4 --- /dev/null +++ b/example/Mitchell2002/stack/stack.hpp @@ -0,0 +1,127 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Contracts for an Eiffel-like stack (ported from Eiffel code). + +#ifndef STACK_HPP_ +#define STACK_HPP_ + +#include +#include + +/** Simple stack. */ +template +class stack { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( count() >= 0 ); + }) ) + +public: + // Creation // + + /** Create empty stack. */ + stack(void): items_() + CONTRACT_CONSTRUCTOR( (class) (stack) + (public) (stack)( (void) ) + (postcondition) ({ + CONTRACT_ASSERT( count() == 0 ); + }) + (body) ({ + }) ) + + /** Destroy stack. */ + ~stack(void) + CONTRACT_DESTRUCTOR( (class) (stack) + (public) (stack)( (void) ) + (body) ({ + }) ) + + // Basic Queries // + + /** Number of items. */ + int count(void) const + CONTRACT_FUNCTION( (class) (stack) + (public) (int) (count)( (void) ) (const) + (body) ({ + return items_.size(); + }) ) + + /** Item at index in [1, count()] (Eiffel index starts at 1). */ + const T& item_at(const int& index) const + CONTRACT_FUNCTION( (class) (stack) + (public) (const T&) (item_at)( (const int&)(index) ) + (const) + (precondition) ({ + CONTRACT_ASSERT( index >= 1 ); + CONTRACT_ASSERT( index <= count() ); + }) + (body) ({ + return items_.at(index - 1); + }) ) + + // Derived Queries // + + /** If no items. */ + bool is_empty(void) const + CONTRACT_FUNCTION( (class) (stack) + (public) (bool) (is_empty)( (void) ) (const) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == (count() == 0) ); + }) + (body) ({ + return items_.size() == 0; + }) ) + + /** Top item. */ + const T& item(void) const + CONTRACT_FUNCTION( (class) (stack) + (public) (const T&) (item)( (void) ) (const) + (precondition) ({ + CONTRACT_ASSERT( count() > 0 ); + }) + (postcondition) (result) ({ + CONTRACT_ASSERT( result == item_at(count()) ); + }) + (body) ({ + return items_.at(items_.size() - 1); + }) ) + + // Commands // + + /** Push new item to the top. */ + void put(const T& new_item) + CONTRACT_FUNCTION( (class) (copyable)(stack) + (public) (void) (put)( (const T&)(new_item) ) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() + 1) ); + CONTRACT_ASSERT( item() == new_item ); + }) + (body) ({ + items_.push_back(new_item); + }) ) + + /** Pop top item. */ + void remove(void) + CONTRACT_FUNCTION( (class) (copyable)(stack) + (public) (void) (remove)( (void) ) + (precondition) ({ + CONTRACT_ASSERT( count() > 0 ); + }) + (postcondition) ({ + CONTRACT_ASSERT( count() == + (CONTRACT_OLDOF(this)->count() - 1) ); + }) + (body) ({ + items_.resize(items_.size() - 1); + }) ) + +private: + std::vector items_; +}; + +#endif // #include guard + diff --git a/example/README.txt b/example/README.txt new file mode 100755 index 00000000..2827ee21 --- /dev/null +++ b/example/README.txt @@ -0,0 +1,6 @@ +Examples that illustrate how to use the library to write contracts. + +Many of these examples are taken from books and articles. The +directory names reflect the example source -- see the library +documentation for a complete reference list. + diff --git a/example/Stroustrup1997/README.txt b/example/Stroustrup1997/README.txt new file mode 100755 index 00000000..5c6c6564 --- /dev/null +++ b/example/Stroustrup1997/README.txt @@ -0,0 +1 @@ +Examples taken from B. Stroustrup. "The C++ Programming Language", 1997. diff --git a/example/Stroustrup1997/string/main.cpp b/example/Stroustrup1997/string/main.cpp new file mode 100755 index 00000000..8b2cd33a --- /dev/null +++ b/example/Stroustrup1997/string/main.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "string.hpp" +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + String s("Galileo"); + + std::cout << std::endl << "operator[]" << std::endl; + std::cout << s[0] << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/Stroustrup1997/string/string.cpp b/example/Stroustrup1997/string/string.cpp new file mode 100755 index 00000000..f919ec16 --- /dev/null +++ b/example/Stroustrup1997/string/string.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "string.hpp" + +CONTRACT_CONSTRUCTOR_BODY(String, String)(const char* q) { + sz = strlen(q); + p = new char[sz + 1]; + for (int i = 0; i < sz; ++i) p[i] = q[i]; + p[sz] = '\0'; +} + +CONTRACT_DESTRUCTOR_BODY(String, ~String)(void) { delete[] p; } + +char& String::CONTRACT_BODY(operator([], at))(int i) { + // check invariant and preconditions on entry + return p[i]; // do work + // check invariant on exit +} + +int String::CONTRACT_BODY(size)(void) { return sz; } + diff --git a/example/Stroustrup1997/string/string.hpp b/example/Stroustrup1997/string/string.hpp new file mode 100755 index 00000000..fb6e24b6 --- /dev/null +++ b/example/Stroustrup1997/string/string.hpp @@ -0,0 +1,70 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Example of invariant and simple preconditions that throw user +// defined exception on contract failure. + +#include + +// Adapted from an example presented in [Stroustrup1997] to illustrate +// importance of invariants. Simple preconditions were added where it +// made sense. This should be compiled with CHECK_POSTCONDITION off +// because postconditions are deliberately not used. +// See [Stroustrup1997] for a discussion on the importance of +// invariants, and on pros and cons of using pre and post conditions. +class String { + + CONTRACT_INVARIANT( ({ + if (p == 0 || sz < 0 || TOO_LARGE <= sz || p[sz]) + throw Invariant(); + }) ) + + int sz; + char* p; + +public: + class Range {}; // exception classes + class Invariant {}; + class Null {}; + class Too_large {}; + + enum { TOO_LARGE = 16000 }; // length limit + + String(const char* q) + CONTRACT_CONSTRUCTOR( (class) (String) + (public) (String)( (const char*)(q) ) + (precondition) ({ + if (!q) throw Null(); + if (strlen(q) > TOO_LARGE) throw Too_large(); + }) + (body) ( + ; + ) ) + + ~String(void) + CONTRACT_DESTRUCTOR( (class) (String) + (public) (String)( (void) ) + (body) ( + ; + ) ) + + char& operator[](int i) + CONTRACT_FUNCTION( (class) (String) + (public) (char&) (operator([], at))( (int)(i) ) + (precondition) ({ + if (i < 0 || sz <= i) throw Range(); + }) + (body) ( + ; + ) ) + + int size(void) + CONTRACT_FUNCTION( (class) (String) + (public) (int) (size)( (void) ) + (body) ( + ; + ) ) +}; + diff --git a/example/commas/README.txt b/example/commas/README.txt new file mode 100755 index 00000000..848068a8 --- /dev/null +++ b/example/commas/README.txt @@ -0,0 +1 @@ +Show how to pass commas within macro parameters (used by documentation). diff --git a/example/commas/main.cpp b/example/commas/main.cpp new file mode 100755 index 00000000..2838ec77 --- /dev/null +++ b/example/commas/main.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Show workarounds to pass commas within macro parameters. + +#include +#include +#include + +template +void print(const K& key, const T& element) { + std::cout << key << " -> " << element << std::endl; +} + +//[ commas_cpp + +template +std::map fill(const std::map& source, + const K& key, const T& element) +CONTRACT_FUNCTION( + (template)( (typename)(K) (typename)(T) ) + // Commas within type expression using the macro. + (typename CONTRACT_WRAP_TYPE( (std::map) )) (set)( + // Or equivalently, not using the macro. + (typename contract::wrap&) >::type)(source) + (const K&)(key) (const T&)(element) ) +(precondition) ({ + // Commas within value expressions must be wrapped by `()`. + CONTRACT_ASSERT( (std::map().empty()) ); +}) +(body) ({ + // Commas within code blocks use same workarounds as above + // wrapping differently commas within type or value expressions. + // Or better, separate body definition so it is outside the macro. + + // OK, commas already wrapped by function call `()`. + print(key, element); + + // Commas within type expression wrapped using the macro. + typename CONTRACT_WRAP_TYPE((std::map)) m = source; + + // OK, commas already wrapped by if-statement `()`. + if (0 == std::map().empty()) m[key] = element; + + return m; +}) ) + +//] + +int main() { + std::map m1; + std::map m2 = set(m1, 1, 2.3); + return 0; +} + diff --git a/example/myvector/README.txt b/example/myvector/README.txt new file mode 100755 index 00000000..d01ffc60 --- /dev/null +++ b/example/myvector/README.txt @@ -0,0 +1 @@ +This is the main example used in the library documentation. diff --git a/example/myvector/basic_begin.hpp b/example/myvector/basic_begin.hpp new file mode 100755 index 00000000..4291ffe2 --- /dev/null +++ b/example/myvector/basic_begin.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Base class for a myvector subcontracting example. + +#ifndef BASIC_BEGIN_HPP_ +#define BASIC_BEGIN_HPP_ + +//[ basic_begin_cpp + +#include + +template +class basic_begin { + + CONTRACT_INVARIANT( ({}) ) + +public: + virtual ConstIter begin(void) const + CONTRACT_FUNCTION( (class) (basic_begin) + (public) (virtual) (ConstIter) (begin)( (void) ) (const) + (body) ({ + return ConstIter(); // Dummy implementation (for example only). + }) ) +}; + +//] + +#endif // #include guard + diff --git a/example/myvector/boundable.hpp b/example/myvector/boundable.hpp new file mode 100755 index 00000000..bc8ce4d0 --- /dev/null +++ b/example/myvector/boundable.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Base class for a myvector subcontracting example. + +#ifndef BOUNDABLE_HPP_ +#define BOUNDABLE_HPP_ + +//[ boundable_cpp + +#include + +template +class boundable { + + CONTRACT_INVARIANT( ({ + CONTRACT_ASSERT( begin() <= end() ); + }) ) + +public: + virtual ConstIter begin(void) const + CONTRACT_FUNCTION( (class) (boundable) + (public) (virtual) (ConstIter) (begin)( (void) ) (const) + (body) (= 0;) ) + + virtual ConstIter end(void) const = 0; +}; + +//] + +#endif // #include guard + diff --git a/example/myvector/main.cpp b/example/myvector/main.cpp new file mode 100755 index 00000000..85b5b343 --- /dev/null +++ b/example/myvector/main.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "myvector.hpp" +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + myvector v(3); + const myvector& cv = v; // A reference, no copy. + + std::cout << std::endl << "copy constructor()" << std::endl; + myvector w(v); + + std::cout << std::endl << "begin()" << std::endl; + myvector::iterator b = v.begin(); + std::cout << *b << std::endl; + + std::cout << std::endl << "begin() const" << std::endl; + myvector::const_iterator cb = cv.begin(); + std::cout << *cb << std::endl; + + std::cout << std::endl << "insert()" << std::endl; + v.insert(b, 2, -3.21); + + std::cout << std::endl << "operator[]" << std::endl; + double v0 = v[0]; + std::cout << v0 << std::endl; + + std::cout << std::endl << "push_back()" << std::endl; + v.push_back(1.23); + + std::cout << std::endl << "all_equals()" << std::endl; + bool eq = myvector::all_equals(v.begin(), v.end(), 1.23); + std::cout << eq << std::endl; // It will be false. + + std::cout << std::endl << "abs_total()" << std::endl; + double tot = abs_total(v); + std::cout << tot << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/myvector/main_nomacros.cpp b/example/myvector/main_nomacros.cpp new file mode 100755 index 00000000..d2667bff --- /dev/null +++ b/example/myvector/main_nomacros.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#include "myvector_nomacros.hpp" +#include + +int main() { + std::cout << std::endl << "constructor()" << std::endl; + myvector v(3); + + std::cout << std::endl << "push_back()" << std::endl; + v.push_back(1.23); + + std::cout << std::endl << "all_equals()" << std::endl; + bool eq = myvector::all_equals(v.begin(), v.end(), 1.23); + std::cout << eq << std::endl; // It will be false. + + std::cout << std::endl << "abs_total()" << std::endl; + double tot = abs_total(v); + std::cout << tot << std::endl; + + std::cout << std::endl << "destructor()" << std::endl; + return 0; +} + diff --git a/example/myvector/myvector.hpp b/example/myvector/myvector.hpp new file mode 100755 index 00000000..31b56fb4 --- /dev/null +++ b/example/myvector/myvector.hpp @@ -0,0 +1,245 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Main documentation example that illustrates most library uses. + +#ifndef MYVECTOR_HPP_ +#define MYVECTOR_HPP_ + +//[ myvector_cpp + +// Base classes for subcontracting. +#include "pushable.hpp" +#include "boundable.hpp" +#include "basic_begin.hpp" +#include // This library. +#include // For `boost::prior()`. +#include // STL vector. + +// Wrapper that adds simple (not complete) contracts to C++ STL illustrating +// most library usages. For simplicity, assume T is comparable and copyable. +template +class myvector: public pushable, + public boundable::const_iterator>, + private basic_begin::const_iterator> { + + // Class invariants (checked by any function with a contract). + CONTRACT_INVARIANT( + (static)({ // Static invariants (optional). + // Static class invariants `(static)({ ... })` are optional and they + // could have been omitted since they assert nothing in this example. + // When present, they can only access static members. + }) ({ // Non-static invariants (can access object). + CONTRACT_ASSERT( (size() == 0) == empty() ); + // More invariants here... + }) ) + +public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::const_reference const_reference; + + // Contract for constructor. + explicit myvector(size_type count): vector_(count) + CONTRACT_CONSTRUCTOR( // Constructor contract macro. + (class) (myvector) // Constructor signature. + (public) (myvector)( (size_type)(count) ) + // Never object `this` in constructor preconditions. + (postcondition) ({ + // Never `CONTRACT_OLDOF(this)` in constructor postconditions. + CONTRACT_ASSERT( size() == count ); + }) + (body) ({ + // Do nothing in this case. + }) ) + + // Contractor for overloaded member (resolved by argumnet name). + myvector(const myvector& right) + CONTRACT_CONSTRUCTOR( (class) (myvector) + (public) (myvector)( (const myvector&)(right) ) + (postcondition) ({ + CONTRACT_ASSERT( vector_ == right.vector_ ); + }) + (body) (;) ) // Deferres body definition. + + // Contract for destructor. + virtual ~myvector(void) + CONTRACT_DESTRUCTOR( // Destructor contract macro. + (class) (myvector) // Destructor signature. + // Must use `(void)` for no arguments. + (public) (virtual) (myvector)( (void) ) + // No preconditions allowed (no arguments). + // No postconditions allowed (no object after destructor). + (body) (;) ) + + // Contract for member function. + void insert(iterator where, size_type count, const T& element) + CONTRACT_FUNCTION( // Function contract macro. + (class) (copyable)(myvector) // Function signature. + // Old values for object `this` and argument `where`. + (public) (void) (insert)( (copyable)(iterator)(where) + (size_type)(count) (const T&)(element) ) + (precondition) ({ // Function preconditions (optional). + CONTRACT_ASSERT( (size() + count) <= max_size() ); + // More preconditions here... + }) + (postcondition) ({ // Function postconditions (optional). + // Any C++ code allowed in contracts (but keep it simple). + // Old values of types tagged copyable via `CONTRACT_OLDOF()`. + if (capacity() == CONTRACT_OLDOF(this)->capacity()) { + CONTRACT_ASSERT( all_equals( + boost::prior(CONTRACT_OLDOF(where)), + boost::prior(CONTRACT_OLDOF(where)) + count, + element) ); + } + // More postconditions here... + }) + (body) ({ // Function body (mandatory). + vector_.insert(where, count, element); + }) ) + + // Contract for constant member. + const_iterator begin(void) const + CONTRACT_FUNCTION( (class) (myvector) + // Subcontracting for multiple inheritance. + (inherit)(boundable) + (inherit)(basic_begin) + (public) (const_iterator) // Non-void result type. + (begin)( (void) ) (const) // Constant. + (postcondition) (result) ({ // Named result value. + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ({ + return vector_.begin(); + }) ) + + // Contract for overloaded member (resolved because not const). + iterator begin(void) + CONTRACT_FUNCTION( (class) (myvector) (public) + (iterator) (begin)( (void) ) + (postcondition) (result) ({ + if (empty()) CONTRACT_ASSERT( result == end() ); + }) + (body) ( + ; + ) ) + + // Contract for operator. + const_reference operator[](size_type index) const + CONTRACT_FUNCTION( (class) (myvector) + // Must spell operator name also in words). + (public) (const_reference) (operator([], at))( + (size_type)(index) ) (const) + (precondition) ({ + CONTRACT_ASSERT( index < size() ); + }) + (body) (;) ) + + // Main function example used in documentation. + void push_back(const T& element) + CONTRACT_FUNCTION( + (class) (copyable)(myvector) (inherit)(pushable) + (public) (void) (push_back)( (const T&)(element) ) + (precondition) ({ + CONTRACT_ASSERT( size() < max_size() ); + }) + (postcondition) ({ + CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); + }) + (body) ({ + vector_.push_back(element); + }) ) + + // Contract for template plus static member function. + template + static bool all_equals(Iter first, Iter last, const T& element) + CONTRACT_FUNCTION( (class) (myvector) + (public) (template)( (class)(Iter) ) // Function template. + (static) (bool) (all_equals)( // Static member. + (Iter)(first) (Iter)(last) (const T&)(element) ) + (precondition) ({ + CONTRACT_ASSERT( first < last ); + }) + (body) ({ + // For simplicity, let's assume T can be compared. + for (Iter i = first; i < last; ++i) { + if (*i != element) return false; + } + return true; + }) ) + + // Similarly, complete contracts sketched here and add contracts + // for all other functions (see [Crowl2006] vector example). + bool empty(void) const { return vector_.empty(); } + size_type size(void) const { return vector_.size(); } + size_type max_size(void) const { return vector_.max_size(); } + size_type capacity(void) const { return vector_.capacity(); } + iterator end(void) { return vector_.end(); } + const_iterator end(void) const { return vector_.end(); } + const_reference back(void) const { return vector_.back(); } + +private: + std::vector vector_; +}; + +// Deferred constructor body definition. +template +CONTRACT_CONSTRUCTOR_BODY(myvector, myvector)( + const myvector& right) { + vector_ = right.vector_; +} + +// Deferred destructor body definition. +template +CONTRACT_DESTRUCTOR_BODY(myvector, myvector)(void) { + // Do nothing in this case. +} + +// Deferred member function definition. +template +typename myvector::iterator myvector::CONTRACT_BODY(begin)( + void) { + return vector_.begin(); +} + +// Deferred member operator definition. +template +typename myvector::const_reference myvector:: + CONTRACT_BODY(operator([], at))( + size_type index) const { + return vector_[index]; +} + +// Contract for non-member function. +double abs_total(const myvector& vector) +CONTRACT_FUNCTION( + (double) (abs_total)( (const myvector&)(vector) ) +(postcondition) (total) ({ // Result value named `total`. + CONTRACT_ASSERT( total >= 0.0 ); +}) +(body) ({ + double total = 0.0; + // Block invariants can appear anywhere in code block. + CONTRACT_ASSERT_BLOCK_INVARIANT( total == 0.0 ); + + { // Variant initialized locally to its loop. + CONTRACT_INIT_LOOP_VARIANT; + for (size_t i = 0; i < vector.size(); ++i) { + // Block invariants used to assert loop invariants. + CONTRACT_ASSERT_BLOCK_INVARIANT( i < vector.size() ); + // Loop variant (can only appear in loops). + CONTRACT_ASSERT_LOOP_VARIANT( vector.size() - i ); + + total += vector[i]; + } + } + return total < 0.0 ? -total : total; +}) ) + +//] + +#endif // #include guard + diff --git a/example/myvector/myvector_nomacros.hpp b/example/myvector/myvector_nomacros.hpp new file mode 100755 index 00000000..e9b01728 --- /dev/null +++ b/example/myvector/myvector_nomacros.hpp @@ -0,0 +1,320 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Main documentation example that illustrates contracts without the macros. + +#ifndef MYVECTOR_NOMACROS_HPP_ +#define MYVECTOR_NOMACROS_HPP_ + +//[ myvector_nomacros_cpp + +#include "pushable.hpp" // Base class for subcontracting. +#include // This library. +#include // STL vector. + +// Wrapper that adds simple (not complete) contracts to C++ STL +// without using the library contract macros. +template +class myvector: public pushable { + +#if defined CONTRACT_CHECK_CLASS_INVARIANT || /* Allow for */ \ + defined CONTRACT_CHECK_PRECONDITION || /* optional contract */ \ + defined CONTRACT_CHECK_POSTCONDITION /* compilation. */ + // Augmented state. + friend class contract::state; + mutable contract::state contract_state_; +#endif // contracts + +#if defined CONTRACT_CHECK_CLASS_INVARIANT + // Static class invariants + static void contract_static_invariant_(void) { + // Assert nothing in this case. + } + // Class invariants. + void contract_invariant_(void) const { + if (!((size() == 0) == empty())) + throw contract::failure(__FILE__, __LINE__); + // More invariants here... + } +#endif // invariants + +public: + typedef typename std::vector::size_type size_type; + typedef typename std::vector::const_reference const_reference; + typedef typename std::vector::const_iterator const_iterator; + + // Contract for constructor. + explicit myvector(size_type count): vector_(count) +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + { + contract_contract_constructor_count_<0>().call(this, count); + } +private: +#if defined CONTRACT_CHECK_PRECONDITION + // Static preconditions (i.e., no object). + static void contract_precondition_contract_constructor_count_( + const size_type& count) /* no `const` (it is `static`) */ { + } +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + void contract_postcondition_contract_constructor_count_( + contract::noold, // Always `noold` for old object. + const size_type& count, contract::noold) const { + if (!(size() == count)) + throw contract::failure(__FILE__, __LINE__); + } +#endif // postconditions +protected: + void contract_body_contract_constructor_(size_type count) +#endif // contracts + { + // Do nothing in this case + } +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + template + struct contract_contract_constructor_count_: + contract::constructor< // Use `constructor` (not `function`). + // Class type can never be tagged `copyable`. + void (myvector*, size_type)> { + contract_contract_constructor_count_(): contract::constructor < + void (myvector*, size_type) + >( &myvector::contract_body_contract_constructor_ + , &myvector::contract_precondition_contract_constructor_count_ + , &myvector::contract_postcondition_contract_constructor_count_ + ) {} + }; +public: +#endif // contracts + + // Contract for destructor. + virtual ~myvector(void) + // Destructors only check invariants. +#if defined CONTRACT_CHECK_CLASS_INVARIANT + { + contract_contract_destructor_<0>().call(this); + } +protected: + // No precondition and no postcondition functions. + virtual void contract_body_contract_destructor_(void) +#endif // invariant + { + // Do nothing in this case. + } +#if defined CONTRACT_CHECK_CLASS_INVARIANT + template + struct contract_contract_destructor_: + contract::destructor< // Use `destructor` (not `function`). + // Class type can never be tagged `copyable`. + void (myvector*)> { + contract_contract_destructor_(): contract::destructor< + void (myvector*) + >(&myvector::contract_body_contract_destructor_ ) {} + }; +public: +#endif // invariant + + // Contract for non-static member functions. + void push_back(const T& element) +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + // Contracted function. + { + contract_push_back_element_<0>().call(this , element); + } +private: // Private so not to alter user call public API. +#if defined CONTRACT_CHECK_PRECONDITION + void contract_precondition_push_back_element_(const T& element) const { + if (!(size() < max_size())) + throw contract::failure(__FILE__, __LINE__); + // More preconditions here... + } +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + void contract_postcondition_push_back_element_( + const myvector* contract_old_this_, // Old value for object. + const T& element, contract::noold // No old for element argument. + ) const { + if (!(size() == (contract_old_this_->size() + 1))) + throw contract::failure(__FILE__, __LINE__); + // More postconditions here... + } +#endif // postconditions +protected: // Must be protected (not private) to allow subcontracting. + void contract_body_push_back_(const T& element) +#endif // contracts + // Original function definition (the body). + { + vector_.push_back(element); + } +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + // Contract class. + template + struct contract_push_back_element_: contract::nonstatic_member_function< + // Function type for contracted function. + // Copyable class type for old object value in postconditions. + // For constant members, change `myvector` to `myvector const`. + void (contract::copyable*, const T&), + // Base contract class for subcontracting. + typename pushable::template contract_push_back_element_<0> + > { + // Constructor specifies body, preconditions, and postconditions. + contract_push_back_element_(): contract::nonstatic_member_function< + void (contract::copyable*, const T&), + typename pushable::template contract_push_back_element_<0> + >( &myvector::contract_body_push_back_ +#if defined CONTRACT_CHECK_PRECONDITION + , &myvector::contract_precondition_push_back_element_ +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + , &myvector::contract_postcondition_push_back_element_ +#endif // postconditions + ) {} + }; +public: // Restore original access level. +#endif // contracts + + // Contract for template plus static member function. + template + static bool all_equals(Iter first, Iter last, const T& element) + // Static members also check (static) class invariants. +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + { + return contract_all_equals_first_last_element_().call( + first, last, element); + } +private: + // Static template precondition and postcondition functions. +#if defined CONTRACT_CHECK_PRECONDITION + template + static void contract_precondition_all_equals_first_last_element_( + const Iter& first, const Iter& last, const T& element) + /* no `const` */ { + if (!(first < last)) + throw contract::failure(__FILE__, __LINE__); + } +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + template + static void contract_postcondition_all_equals_first_last_element_( + const Iter& first, contract::noold, + const Iter& last, contract::noold, + const T& element, contract::noold, + const bool& result ) // Result value. + /* no `const` */ { + } +#endif // postconditions +protected: + template + static bool contract_body_all_equals_( + Iter first, Iter last, const T& element) +#endif // contracts + { + for (Iter i = first; i < last; ++i) { + if (*i != element) return false; + } + return true; + } +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION + // Function template parameter `class Iter` already present so + // no artificial `int ZERO` parameter. + template + struct contract_all_equals_first_last_element_: contract::static_member_function< + bool (myvector*, Iter, Iter, const T&) + > { + contract_all_equals_first_last_element_(): contract:: static_member_function< + bool (myvector*, Iter, Iter, const T&) + >( &myvector::template contract_body_all_equals_ +#if defined CONTRACT_CHECK_PRECONDITION + , &myvector::template contract_precondition_all_equals_first_last_element_ +#endif // preconditions +#if defined CONTRACT_CHECK_POSTCONDITION + , &myvector::template contract_postcondition_all_equals_first_last_element_ +#endif // postconditions + ) {} + }; +public: +#endif // contracts + + // Similarly, complete contracts sketched here and add contracts + // for all other functions (see [Crowl2006] vector example). + size_type size(void) const { return vector_.size(); } + size_type max_size(void) const { return vector_.max_size(); } + bool empty(void) const { return vector_.empty(); } + const_reference back(void) const { return vector_.back(); } + const_iterator begin(void) const { return vector_.begin(); } + const_iterator end(void) const { return vector_.end(); } + const_reference operator[](size_type index) const + { return vector_[index]; } + +private: + std::vector vector_; +}; + +// Contract for non-member function. +double abs_total(const myvector& vector) +// Non-member members do not check invariants. +#if defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION +; +void contract_precondition_abs_total_vector_( + const myvector& vector ) { +} +void contract_postcondition_abs_total_vector_( + const myvector& vector, contract::noold, + const double& total) { + if (!(total >= 0.0)) + throw contract::failure(__FILE__, __LINE__); +} +double contract_body_abs_total_(const myvector& vector) +#endif // preconditions or postconditions +{ + double total = 0.0; + CONTRACT_ASSERT_BLOCK_INVARIANT( total == 0.0 ); + { + CONTRACT_INIT_LOOP_VARIANT; + for (size_t i = 0; i < vector.size(); ++i) { + CONTRACT_ASSERT_BLOCK_INVARIANT( i < vector.size() ); + CONTRACT_ASSERT_LOOP_VARIANT( vector.size() - i ); + + total += vector[i]; + } + } + return total < 0.0 ? -total : total; +} +#if defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION +template +struct contract_abs_total_vector_: contract::nonmember_function< + // Still use `function` but no class type, just use `(*)`. + double (const myvector&) + > { + contract_abs_total_vector_(): contract::nonmember_function< + double (const myvector&)> + ( &contract_body_abs_total_ + , &contract_precondition_abs_total_vector_ + , &contract_postcondition_abs_total_vector_ + ) {} +}; +// Contracted function defined last and `inline`. +inline double abs_total(const myvector& vector) { + return contract_abs_total_vector_<0>().call(vector); +} +#endif // preconditions or postconditions + +//] + +#endif // #include guard + diff --git a/example/myvector/pushable.hpp b/example/myvector/pushable.hpp new file mode 100755 index 00000000..5fd2e0f5 --- /dev/null +++ b/example/myvector/pushable.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Base class for a myvector subcontracting example. + +#ifndef PUSHABLE_HPP_ +#define PUSHABLE_HPP_ + +//[ pushable_cpp + +#include + +template +class pushable { + + CONTRACT_INVARIANT( ({}) ) + +public: + // Contract for pure virtual function. + virtual void push_back(const T& element) + CONTRACT_FUNCTION( + (class) (pushable) + (public) (virtual) (void) (push_back)( (const T&)(element) ) + (postcondition) ({ + CONTRACT_ASSERT( back() == element ); + }) + (body) (= 0;) ) // Pure virtual body. + + virtual const T& back() const = 0; +}; + +//] + +#endif // #include guard + + diff --git a/example/throw/README.txt b/example/throw/README.txt new file mode 100755 index 00000000..71cd705a --- /dev/null +++ b/example/throw/README.txt @@ -0,0 +1,2 @@ +Show how to configure the library to throw on contract failure +instead of terminating (used by documentation). diff --git a/example/throw/main.cpp b/example/throw/main.cpp new file mode 100755 index 00000000..32247701 --- /dev/null +++ b/example/throw/main.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Configure the library to throw on contract failure. + +//[ throw_on_failure_cpp + +#include +#include + +// User defined exception (not even derived from `std::exception`). +class not_a_number {}; + +double sqrt(double x) +CONTRACT_FUNCTION( (double) (sqrt)( (double)(x) ) +(precondition) ({ + // Eventually throws user-defined exception. + if (!( x >= 0.0 )) throw not_a_number(); +}) +(postcondition) (root) ({ + // Eventually throw library defined exception `contract::failure`. + CONTRACT_ASSERT( (root * root) == x ); +}) +(body) ({ + return 0.0; // Intentionally incorrect to fail postcondition. +}) ) + +void throwing_handler(const contract::from& where) { + if (where == contract::FROM_DESTRUCTOR) { + // Cannot throw from within destructor for STL exception safety. + 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. + } +} + +void postcondition_throwing_handler(const contract::from& where) { + // try/catch/re-throw to get active exception (for logging, etc.). + try { + throw; // Re-throw active exception thrown by precondition. + } catch (std::exception& error) { // Get exception object. + std::clog << "Throwing '" << error.what() << "'" << std::endl; + + throw; // Re-throw. + } // Non standard exception also thrown. +} + +int main() { + // Setup contract failure handlers that throw (instead of terminate). + contract::set_precondition_failed(&throwing_handler); + contract::set_postcondition_failed(&postcondition_throwing_handler); + // Invariants not used by this examples but set anyway... + contract::set_class_invariant_failed(&throwing_handler); + contract::set_block_invariant_failed(&throwing_handler); + + try { + std::cout << sqrt(-1.0) << std::endl; + } catch (not_a_number&) { + std::clog << "Ignored not a number exception" << std::endl; + } + + try { + std::cout << sqrt(4.0) << std::endl; + } catch (...) { + std::clog << "Unable to calculate square root" << std::endl; + } + + return 0; +} + +//] + diff --git a/src/README.txt b/src/README.txt new file mode 100755 index 00000000..e57ef138 --- /dev/null +++ b/src/README.txt @@ -0,0 +1 @@ +All the library source code. diff --git a/src/contract.hpp b/src/contract.hpp new file mode 100755 index 00000000..911ec62a --- /dev/null +++ b/src/contract.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_HPP_ +#define CONTRACT_HPP_ + +// GETTING STARTED +// +// See the library documentation in the "doc/" for more information. +// +// It is recommended to include the library simply by including +// this file ``#include '' (instead of separately +// including files from the "contract/" directory). +// The library is composed of header files only so the #include above +// is all it is needed to use the library and compile (there is no +// pre-compiled library object file to link). +// +// Contract compilation must be explicitly turned on at compile time +// #defining the following macro symbols: +// CONTRACT_CHECK_BLOCK_INVARIANT Compile and check block invariants. +// CONTRACT_CHECK_CLASS_INVARIANT Compile and check class invariants. +// CONTRACT_CHECK_PRECONDITION Compile and check preconditions. +// CONTRACT_CHECK_POSTCONDITION Compile and check postconditions. +// By default, all these macro symbols are #undefined and contract +// compilation is turned off. For example, the following turns on +// invariant and preconditions (but not postconditions) using g++: +// $ g++ -DCONTRACT_CHECK_CLASS INVARIANT +// -DCONTRACT_CHECK_PRECONDITION +// -UCONTRACT_CHECK_POSTCONDITION ... +// +// All library files in the "contract/aux_/" directory, all names in +// the 'contract::aux' namespace, all symbols starting with +// 'CONTRACT_AUX', all names and symbols starting with 'contract' or +// 'CONTRACT' and ending with an underscore '_' are library +// implementation specific and must NOT be used directly in user code. + +// Tools. +#include "contract/config.hpp" +#include "contract/from.hpp" +#include "contract/assert.hpp" +#include "contract/old.hpp" +#include "contract/body.hpp" +#include "contract/state.hpp" +#include "contract/wrap.hpp" + +// Contracts without macros. +#include "contract/nonmember_function.hpp" +#include "contract/nonstatic_member_function.hpp" +#include "contract/static_member_function.hpp" +#include "contract/constructor.hpp" +#include "contract/destructor.hpp" + +// Contract macros. +#include "contract/macros.hpp" +#include "contract/block.hpp" + +#endif // #include guard + diff --git a/src/contract/README.txt b/src/contract/README.txt new file mode 100755 index 00000000..f546233f --- /dev/null +++ b/src/contract/README.txt @@ -0,0 +1 @@ +Library public API. diff --git a/src/contract/assert.hpp b/src/contract/assert.hpp new file mode 100755 index 00000000..ce3d57ba --- /dev/null +++ b/src/contract/assert.hpp @@ -0,0 +1,136 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_ASSERT_HPP_ +#define CONTRACT_ASSERT_HPP_ + +#include "aux_/assert.hpp" +#include +#include +#include + +// IMPORTANT: Most of these functions do no throw so they comply with +// C++ STL exception safety requirements. + +#define CONTRACT_ASSERT_MSG(boolean_condition, string_description) \ + /* must use `!` as MSVC does not support he `not` keyword */ \ + if (!(boolean_condition)) { \ + throw ::contract::failure(__FILE__, __LINE__, \ + string_description); \ + } + +#define CONTRACT_ASSERT(boolean_condition) \ + /* Do not use BOOST_PP_STRINGIZE() so condition NOT expanded */ \ + CONTRACT_ASSERT_MSG(boolean_condition, # boolean_condition) + +namespace contract { + +// A contract condition failure is a logic error or "bug". +class failure: public std::logic_error { +public: + // File and line mandatory (use __FILE__ and __LINE__). + explicit failure(char const* file, unsigned long const& line, + char const* description = "") throw(): + std::logic_error(""), file_(file), line_(line), + description_(description) {} + + failure(failure const& source) throw(): std::logic_error(""), + file_(source.file_), line_(source.line_), + description_(source.description_) {} + + virtual failure& operator=(failure const& source) throw() { + file_ = source.file_; + line_ = source.line_; + description_ = source.description_; + return *this; + } + + virtual ~failure() throw() {} + + virtual char const* what() const throw() { + // File and line always present when constructed (but this + // code also handles case when they are "" and 0). + std::ostringstream oss; + oss << "contract"; + std::string d = description(); + // Use "'" beacuse that is what rest of terminate() msg uses. + if ("" != d) { oss << " \"" << d << "\" "; } + oss << "failed"; + std::string f = file(); + if ("" != f) { + oss << " at " << f; + unsigned long l = line(); + // Line printed only if there is also a file name. + if (0 != l) { oss << ":" << l; } + } + return oss.str().c_str(); + } + + virtual char const* file() const throw() { return file_.c_str(); } + + virtual unsigned long line() const throw() { return line_; } + + virtual char const* description() const throw() + { return description_.c_str(); } + +private: + std::string file_; + unsigned long line_; + std::string description_; +}; + +// Expose type from aux. +typedef aux::contract_failed_handler contract_failed_handler; + +// Inlining functions also to avoid multiple definitions error. + +// Block Invariant // + +inline contract_failed_handler set_block_invariant_failed( + contract_failed_handler handler) throw() { + return aux::block_invariant_failed_handler = handler; +} + +// In general this could throw for user defined handlers. +inline void block_invariant_failed(from const& where) + { aux::block_invariant_failed_handler(where); } + +// Class Invariant // + +inline contract_failed_handler set_class_invariant_failed( + contract_failed_handler handler) throw() { + return aux::class_invariant_failed_handler = handler; +} + +// In general this could throw for user defined handlers. +inline void class_invariant_failed(from const& where) + { aux::class_invariant_failed_handler(where); } + +// Precondition // + +inline contract_failed_handler set_precondition_failed( + contract_failed_handler handler) throw() { + return aux::precondition_failed_handler = handler; +} + +// In general this could throw for user defined handlers. +inline void precondition_failed(from const& where) + { aux::precondition_failed_handler(where); } + +// Postcondition // + +inline contract_failed_handler set_postcondition_failed( + contract_failed_handler handler) throw() { + return aux::postcondition_failed_handler = handler; +} + +// In general this could throw for user defined handlers. +inline void postcondition_failed(from const& where) + { aux::postcondition_failed_handler(where); } + +} // namespace + +#endif // #include guard + diff --git a/src/contract/aux_/README.txt b/src/contract/aux_/README.txt new file mode 100755 index 00000000..649320b5 --- /dev/null +++ b/src/contract/aux_/README.txt @@ -0,0 +1,4 @@ +Library PRIVATE API. + +Do NOT directly use any of the code from files in this directory or +any of the subdirectories. diff --git a/src/contract/aux_/arg.hpp b/src/contract/aux_/arg.hpp new file mode 100755 index 00000000..09ec78f3 --- /dev/null +++ b/src/contract/aux_/arg.hpp @@ -0,0 +1,71 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_ARG_HPP_ +#define CONTRACT_AUX_ARG_HPP_ + +#include + +namespace contract { + +class noold; // Farward declaration. + +namespace aux { + +// To ensure CONSTANT-CORRECTNESS: +// 1) Arguments are usually passed by cont& -- this makes sure that +// the referenced object is const and cannot be modified but the +// reference could be modified. This is the way C++ usually uses +// reference for const because eventual modifications to the +// reference will have local scope plus they are usually not +// possible because copy operators and constructors operatorate on +// const&. (The reference could be made const& const to absolutely +// avoid any modification also to the reference itself...) +// 2) Pointers are passed as const* -- this makes sure that the +// pointed object is const and cannot be modified but the pointer +// itself can still be modified. This is the way C++ usually uses +// pointers for const because eventual modification to the pointer +// only have local scope so do not violate const correctness. (The +// pointer could be passed as const* const to also prevent +// modification to the pointer itself...) +// 3) noold is passed by value (this does not affect +// constant-correctness because noold has no member so it cannot +// be used to do anything. + +template +struct arg { + typedef typename boost::add_reference::type>::type type; // T const& +}; + +template +struct arg { + typedef typename boost::add_pointer::type>::type type; // T const* +}; + +// Keep outer const for ptr if specified by user (but do not add it). +template +struct arg { + typedef typename boost::add_pointer::type>::type const type; // T const* const +}; + +// Avoid adding a reference to a reference (which gives an error). +template +struct arg { + typedef typename boost::add_reference::type>::type type; // T const& +}; + +template<> +struct arg { + typedef noold type; // noold (passed by value) +}; + +}} // namespace + +#endif // #include guard + diff --git a/src/contract/aux_/assert.hpp b/src/contract/aux_/assert.hpp new file mode 100755 index 00000000..758b4f82 --- /dev/null +++ b/src/contract/aux_/assert.hpp @@ -0,0 +1,88 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_ASSERT_HPP_ +#define CONTRACT_AUX_ASSERT_HPP_ + +#include "../from.hpp" +#include +#include // For default handlers. + +// Default failure handlers do not throw (exception specification +// throw()) so they comply with STL exception safety requirements. + +// Inlining functions also to avoid multiple definition error. + +namespace contract { namespace aux { + +// In general this could throw for user defined handlers. +// Failure handlers are automatically called by the library when +// contracts throw (any exception). Therefore, at the entry of failure +// handlers the exception thrown by the contract is always active and +// not yet handled and the exception object can be obtained by +// throw/catch: +// void throwing_handler(from const& where) { +// try { throw; } +// catch (std::exception& ex) { +// ... // Do something with ex (e.g., print ex.what()). +// throw; // Re-throw to pass up thrown exception. +// } // Thrown exception passed up. +// } +// @param where Used to take different actions based on where the +// contract failed (e.g., never throw from within destructors). +typedef void (* contract_failed_handler)(from const& where); + +// Block Invariant // + +// Default calls terminate and never throws. +inline void default_block_invariant_failed_handler(from const& where) + throw() { + std::cerr << "block invariant: "; // No trailing '\n'. + std::terminate(); +} + +static contract_failed_handler block_invariant_failed_handler = + &default_block_invariant_failed_handler; + +// Class Invariant // + +// Default calls terminate and never throws. +inline void default_class_invariant_failed_handler(from const& where) + throw() { + std::cerr << "class invariant: "; // No trailing '\n'. + std::terminate(); +} + +static contract_failed_handler class_invariant_failed_handler = + &default_class_invariant_failed_handler; + +// Precondition // + +// Default calls terminate and never throws. +inline void default_precondition_failed_handler(from const& where) + throw() { + std::cerr << "precondition: "; // No trailing '\n'. + std::terminate(); +} + +static contract_failed_handler precondition_failed_handler = + &default_precondition_failed_handler; + +// Postcondition // + +// Default calls terminate and never throws. +inline void default_postcondition_failed_handler(from const& where) + throw() { + std::cerr << "postcondition: "; // No trailing '\n'. + std::terminate(); +} + +static contract_failed_handler postcondition_failed_handler = + &default_postcondition_failed_handler; + +}} // namespace + +#endif // #include guard + diff --git a/src/contract/aux_/check01.hpp b/src/contract/aux_/check01.hpp new file mode 100755 index 00000000..34cf48ad --- /dev/null +++ b/src/contract/aux_/check01.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CHECK01_HPP_ +#define CONTRACT_AUX_CHECK01_HPP_ + +// These are equivalent to CONTRACT_CHECK_XYZ macro symbols but they +// are always defined to 0 or 1 instead of being #defined or +// #undefined. They are used internally because Boost.Preprocessor +// macros do not work on #undefined symbols directly. + +#if defined CONTRACT_CHECK_BLOCK_INVARIANT +# define CONTRACT_AUX_CHECK_BLOCK_INVARIANT_01 1 +#else +# define CONTRACT_AUX_CHECK_BLOCK_INVARIANT_01 0 +#endif + +#if defined CONTRACT_CHECK_CLASS_INVARIANT +# define CONTRACT_AUX_CHECK_CLASS_INVARIANT_01 1 +#else +# define CONTRACT_AUX_CHECK_CLASS_INVARIANT_01 0 +#endif + +#if defined CONTRACT_CHECK_PRECONDITION +# define CONTRACT_AUX_CHECK_PRECONDITION_01 1 +#else +# define CONTRACT_AUX_CHECK_PRECONDITION_01 0 +#endif + +#if defined CONTRACT_CHECK_POSTCONDITION +# define CONTRACT_AUX_CHECK_POSTCONDITION_01 1 +#else +# define CONTRACT_AUX_CHECK_POSTCONDITION_01 0 +#endif + +#if defined CONTRACT_CHECK_CLASS_INVARIANT || \ + defined CONTRACT_CHECK_PRECONDITION || \ + defined CONTRACT_CHECK_POSTCONDITION +# define CONTRACT_AUX_CHECK_CLASS_01 1 +#else +# define CONTRACT_AUX_CHECK_CLASS_01 0 +#endif + +#endif // #include guard + diff --git a/src/contract/aux_/checking.hpp b/src/contract/aux_/checking.hpp new file mode 100755 index 00000000..b486e523 --- /dev/null +++ b/src/contract/aux_/checking.hpp @@ -0,0 +1,18 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CHECKING_HPP_ +#define CONTRACT_AUX_CHECKING_HPP_ + +#include "sync.hpp" + +namespace contract { namespace aux { + +static sync globally_checking_contract; + +}} // namespace + +#endif // #include guard + diff --git a/src/contract/aux_/debug.hpp b/src/contract/aux_/debug.hpp new file mode 100755 index 00000000..4715f179 --- /dev/null +++ b/src/contract/aux_/debug.hpp @@ -0,0 +1,39 @@ + +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_DEBUG_HPP_ +#define CONTRACT_AUX_DEBUG_HPP_ + +#include "../config.hpp" + +// IMPORTANT: In order to remove *any* logging overhead when debug +// is turned off, *all* code used to generate the debug message must +// be passed as the 'code' param of the macro below (because that +// code is executed by the macro expansion only when debug is on). + +#if CONTRACT_CONFIG_DEBUG_ +# include +# include +# include + +# define CONTRACT_AUX_DEBUG(code) \ + { \ + std::ostringstream dbg; \ + { code; } \ + std::clog << dbg.str() << " at " << __FILE__ << ":" \ + << __LINE__ << std::endl; \ + } + +# define CONTRACT_AUX_DEBUGT(type, code) \ + CONTRACT_AUX_DEBUG(dbg << typeid(type).name() << ": "; code) + +#else +# define CONTRACT_AUX_DEBUG(code) /* expand to nothing */ +# define CONTRACT_AUX_DEBUGT(type, code) /* expand to nothing */ +#endif // debug + +#endif // #include guard + diff --git a/src/contract/aux_/function/README.txt b/src/contract/aux_/function/README.txt new file mode 100755 index 00000000..e1e19e65 --- /dev/null +++ b/src/contract/aux_/function/README.txt @@ -0,0 +1 @@ +Support for implementing contract classes. diff --git a/src/contract/aux_/function/contract_class_implement.hpp b/src/contract/aux_/function/contract_class_implement.hpp new file mode 100755 index 00000000..7e5ee6df --- /dev/null +++ b/src/contract/aux_/function/contract_class_implement.hpp @@ -0,0 +1,729 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// IMPORTANT: This code is grouped here because common between +// non-static member and non-member functions and it +// is #included to implement those. +// * Do not use #include guards here. +// See context #including this file. + +// These local macros must be #defined before #including this file. +#ifndef CONTRACT_arity +# error "Must define CONTRACT_arity before #inclusion (internal error)" +#endif +#ifndef CONTRACT_is_not_void +# error "Must define CONTRACT_is_not_void before #inclusion (internal error)" +#endif +#ifndef CONTRACT_is_member +# error "Must define CONTRACT_is_member before #inclusion (internal error)" +#endif + +// Start of class declaration here. + +#if CONTRACT_is_member +private: + CONTRACT_typedef_maybeconst_class_type; +public: // Must be public for subcontracting (but only class_type). + // C -- for function types. + CONTRACT_typedef_class_type +private: + // C [+ const] + ptr -- used by object this type. + CONTRACT_typedef_maybeconst_class_ptr + // arg -- used by this arg passing. + CONTRACT_typedef_arg_class_ptr; + // old -- used by old this variables. + CONTRACT_typedef_old_class_type + // arg< old > -- used by old + // this arg passing. + CONTRACT_typedef_arg_old_class_ptr +#endif // is_member + +private: + // typedef void ResultType; (needed to compile). + BOOST_PP_EXPR_IF(BOOST_PP_NOT(CONTRACT_is_not_void), + typedef void ResultType;) + + // arg -- used by result argument passing. + CONTRACT_typedef_arg_result_type + + // A -- used by function types. + // typedef remove_copyable argument_type0; ... + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_argument_type, ~) + + // A + ref -- used by call() argument passing. + // typedef add_reference argument_ref0; ... + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_argument_ref, ~) + + // arg -- used by argrument passing. + // typedef arg arg_argument_type0; ... + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_typedef_arg_argument_type, ~) + + // old -- used by old argument variables. + // typedef old old_argument_type0; ... + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_typedef_old_argument_type, ~) + + // arg< old > -- used by old argrument passing. + // typedef arg< old > arg_old_argument_type0; ... + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_typedef_arg_old_argument_type, ~) + + // typedef void (class_type::* precondition_function_ptr)( + // arg_argument_type0, ...) const; + CONTRACT_typedef_precondition_function_ptr + + // typedef void (class_type::* precondition_function_ptr)( + // arg_old_class_ptr, arg_argument_type0, arg_old_argument0, ... + // , arg_result_type) const; + CONTRACT_typedef_postcondition_function_ptr + + // typedef ResultType (class_type::* body_function_ptr)( + // argument_type0, ...) const; + CONTRACT_typedef_body_function_ptr(CONTRACT_is_member) + +#if CONTRACT_CONFIG_DEBUG_ + private: + typedef BOOST_PP_IF(CONTRACT_is_member, + class_type, body_function_ptr) debug_type; +#endif // debug + +public: + // Constructor arguments take body first so pre and post can + // always add leading comma (needed to facilitate code-based API). + BOOST_PP_IF(CONTRACT_is_member // Constructor function name. + , nonstatic_member_function + , nonmember_function + )(body_function_ptr body_function +#if defined CONTRACT_CHECK_PRECONDITION + , precondition_function_ptr precondition_function +#endif // check precondition +#if defined CONTRACT_CHECK_POSTCONDITION + , postcondition_function_ptr postcondition_function +#endif // check postcondition + ): BODY_FUNCTION_(body_function) +#if defined CONTRACT_CHECK_PRECONDITION + , PRECONDITION_FUNCTION_(precondition_function) +#endif // check precondition +#if defined CONTRACT_CHECK_POSTCONDITION + , POSTCONDITION_FUNCTION_(postcondition_function) +#endif // check postcondition +#if CONTRACT_is_member + BOOST_PP_ENUM_TRAILING( + CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_init_base_contract, ~) +#endif // is_member + { +#if CONTRACT_is_member + BOOST_PP_EXPR_IF(CONTRACT_is_member, + // if (BaseContractClass0 != void_base_contract) + // base_contract0_ = new BaseContractClass0(); ... + BOOST_PP_REPEAT(CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_alloc_base_contract, ~) + ) +#endif // is_member + } + + virtual // Compliers warn if no virtual destr but virt func. + BOOST_PP_IF(CONTRACT_is_member // Constructor function name. + , ~nonstatic_member_function + , ~nonmember_function + )() { +#if CONTRACT_is_member + // if (base_contract0_) delete base_contract0_; ... + BOOST_PP_REPEAT(CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_dealloc_base_contract, ~) +#endif // is member (else, default destructor) + } + + // Body function is passed at run-time to avoid errors for + // overloaded functions (compiler gets confused with overloaded + // constructors if body are passed as static function pointer in + // template arguments -- I got error "using unqualified id as + // template parameters"). Pre/post conditions function pointers + // instead MUST be passed as template parameters because they + // must be part of the base contract type for subcontrating. + virtual ResultType call( +#if CONTRACT_is_member + maybeconst_class_ptr object +#endif // is member + BOOST_PP_COMMA_IF(BOOST_PP_AND(CONTRACT_arity, + CONTRACT_is_member)) + // argument_type0 argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_noncopyable_argument, ~) + ) { + CONTRACT_AUX_DEBUGT(debug_type, dbg << "Called " + << (CONTRACT_is_member ? + "member" : "non-member") << " function contract"); + return exec( +#if CONTRACT_is_member + object +#endif // is member + BOOST_PP_COMMA_IF(BOOST_PP_AND(CONTRACT_arity, + CONTRACT_is_member)) + // argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, CONTRACT_argument, ~) +#if CONTRACT_is_member + , true // Pre-invariant check. +#endif // is member + BOOST_PP_COMMA_IF(BOOST_PP_OR(CONTRACT_arity, + CONTRACT_is_member)) + true // Precondition check. +#if CONTRACT_is_member + , true // Post-invariant check. +#endif // is member + , true // Postcondition check. + ); + } + + // For non-static members, check_xyz() must be pub (no prot/priv) + // for subcontracting, otherwise they can be private. +#if !CONTRACT_is_member +private: +#endif // is member + + // check_xyz() must throw for proper subcontracting (of + // preconditions) -- xyz_failed() must be called by exec(). + +#if defined CONTRACT_CHECK_CLASS_INVARIANT +#if CONTRACT_is_member + void check_invariant(arg_class_ptr object, + const bool& dynamic_invariant_check) { + try { + aux::globally_checking_contract = true; + // POLICY: First, check in AND all base + // invariants (following inheritance oreder + // of BaseContractClass template params), AND + // then check this class invariants. + + // And, all base invariants (subcontracting). + // if (base_contract0_) { + // typename BaseContractClass0::class_type + // const* base_object = 0; + // state::to_base_(object, base_object); + // base_contract0_->check_invariant( + // base_object, dynamic_invariant_check); + // } ... + BOOST_PP_REPEAT( + CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_check_base_invariant, ~) + + // AND, this class invariants. + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Checking static invariants"); + state::call_static_invariant_(); + // POLICTY: Static invariant checking is never disabled. + // Dynamic invariant checking instead is disabled in + // nested calls, constructors entry, destructor exit, + // etc (decided by this function caller). + if (dynamic_invariant_check) { + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Checking invariants"); + state::call_invariant_(object); + } + + aux::globally_checking_contract = false; + } catch (...) { + aux::globally_checking_contract = false; + throw; + } + } +#else // is member + // Do nothing for non-members but static members will override to + // check static invariants. + virtual void check_invariant() {} +#endif // is member +#endif // check invariant + +#if defined CONTRACT_CHECK_PRECONDITION + void check_precondition( +#if CONTRACT_is_member + arg_class_ptr object + BOOST_PP_COMMA_IF(CONTRACT_arity) +#endif // is member + // arg_argument_type0 argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, CONTRACT_arg_argument, ~) + ) { + try { + aux::globally_checking_contract = true; + bool failed = true; + +#if CONTRACT_is_member + // POLICY: First, check in OR all base + // preconditions (following inheritance oreder + // of BaseContractClass template params), OR else + // check this class preconditions at the end. + + // Check in OR all base postconditions (subcontracting). + // if (failed && base_contract0_) { + // try { + // typename BaseContractClass0::class_type + // const* base_object = 0; + // state::to_base_(object, base_object); + // base_contract0_->check_precondition( + // base_object + // BOOST_PP_ENUM_TRAILING( + // CONTRACT_arity, + // CONTRACT_argument, ~) + // ); + // failed = false; // Passed, done. + // } catch (...) {} // Keep checking. + // } ... + BOOST_PP_REPEAT( + CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_check_base_precondition, ~) +#endif // is member + + // OR, this class preconditions. + if (failed) { + // All base preconditions failed. Then we check + // this class preconditions. If they pass, no + // exception is thrown. If they fail, they throw + // a failure expection that is handeled by our + // caller exec() by invoking + // precondition_failed() with the thrown error. + // Therefore, precondition_failed() CANNOT be + // called from within here! + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Checking preconditions"); +#if CONTRACT_is_member + call_precondition(object + // , argument0, ... + BOOST_PP_ENUM_TRAILING(CONTRACT_arity, + CONTRACT_argument, ~) + ); +#else // is member + PRECONDITION_FUNCTION_( + // argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_argument, ~) + ); +#endif // is member + } + + aux::globally_checking_contract = false; + } catch (...) { + aux::globally_checking_contract = false; + throw; + } + } +#endif // check precondition + +#if defined CONTRACT_CHECK_POSTCONDITION + void check_postcondition( +#if CONTRACT_is_member + arg_class_ptr object + , arg_old_class_ptr old_object + BOOST_PP_COMMA_IF(CONTRACT_arity) +#endif // is member + // arg_argument_type0 argument0 + // , arg_old_argument_type0 old_argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_arg_now_and_old_argument, ~) + // , arg_result_type result (if not void) +#if CONTRACT_is_member || CONTRACT_arity + BOOST_PP_COMMA_IF(CONTRACT_is_not_void) +#endif // is member or arity != 0 + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, + arg_result_type result) + ) { + try { + aux::globally_checking_contract = true; + +#if CONTRACT_is_member + // POLICY: First, check in AND all base + // postconditions (following inheritance oreder + // of BaseContractClass template params), AND + // then check this class postconditions. + + // Check all base postconditions (subcontracting). + // if (base_contract0_) { + // typename BaseContractClass0::class_type + // const* base_object = 0; + // state::to_base_(object, base_object); + // base_contract0_->check_postcondition( + // base_object + // , old_object + // // , argument0, old_argument0, ... + // BOOST_PP_ENUM_TRAILING( + // CONTRACT_arity, + // CONTRACT_now_and_old_argument, ~) + // // , result (if non-void) + // BOOST_PP_COMMA_IF( + // CONTRACT_is_not_void) + // BOOST_PP_EXPR_IF( + // CONTRACT_is_not_void, + // result) + // ); + // } ... + BOOST_PP_REPEAT( + CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_check_base_postcondition, ~) +#endif // is member + + // AND, this class postconditions. + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Checking postconditions"); + ( +#if CONTRACT_is_member + object->* +#endif // is member + POSTCONDITION_FUNCTION_ + )( +#if CONTRACT_is_member + old_object + BOOST_PP_COMMA_IF(CONTRACT_arity) +#endif // is member + // argument0, old_argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_now_and_old_argument, ~) + // , result (if not void) +#if CONTRACT_is_member || CONTRACT_arity + BOOST_PP_COMMA_IF(CONTRACT_is_not_void) +#endif // is member || arity != 0 + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, + result) + ); + + aux::globally_checking_contract = false; + } catch (...) { + aux::globally_checking_contract = false; + throw; + } + } +#endif // check postcondition + +protected: + // Redefined for constructor, destructor, etc. + virtual from here() const { +#if CONTRACT_is_member + return FROM_NONSTATIC_MEMBER_FUNCTION; +#else // is member + return FROM_NONMEMBER_FUNCTION; +#endif // is member + } + + // Virtual wrapper to call precondition so contructor can overide + // it to drop object and static member, etc. +#if defined CONTRACT_CHECK_PRECONDITION && CONTRACT_is_member + virtual void call_precondition( + arg_class_ptr object + // , arg_argument_type0 argument0, ... + BOOST_PP_ENUM_TRAILING(CONTRACT_arity, + CONTRACT_arg_argument, ~) + ) { + (object->*PRECONDITION_FUNCTION_)( + // argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_argument, ~) + ); + } +#endif // check precondition && is member + + // Protected because accessed by derived constructor, etc (but + // no virtual because cannot be overridden). + inline ResultType exec( +#if CONTRACT_is_member + maybeconst_class_ptr object +#endif // is member + BOOST_PP_COMMA_IF(BOOST_PP_AND(CONTRACT_arity, + CONTRACT_is_member)) + // argument_type0 argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_noncopyable_argument, ~) +#if CONTRACT_is_member + , const bool& preinvariant_check +#endif // is member + BOOST_PP_COMMA_IF(BOOST_PP_OR(CONTRACT_arity, + CONTRACT_is_member)) + const bool& precondition_check +#if CONTRACT_is_member + , const bool& postinvariant_check +#endif // is member + , const bool& postcondition_check + ) { + // This code should be optimized as much as possible to limit + // contract calling and checking overhead. + + // Note on const-correctness: Arguments are const here + // because they were passed using arg<>. Object instaed + // is const only for const-members but object is always + // used in const context but when body is called. + +#if !defined CONTRACT_CHECK_CLASS_INVARIANT && \ + !defined CONTRACT_CHECK_PRECONDITION && \ + !defined CONTRACT_CHECK_POSTCONDITION + // For optimization, just call body when contracts off. + // If user contract programmed correctly, when contracts + // off this function will not even be called and the body + // is called directly (but this functions handles the + // contracts off case also to be more robust). + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Entering, executing body, and returning " + << "because contracts turned off at " + << "compile-time"); + return ( +#if CONTRACT_is_member + object->* +#endif // is member + BODY_FUNCTION_ + )( + // argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, CONTRACT_argument, ~) + ); +#else // check no contract + + // POLICY: Assertions disabled within assertions. + if (aux::globally_checking_contract) { + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Entering, executing body, and returning " + << "because assertions disabled within " + << "assertion checking"); + return ( +#if CONTRACT_is_member + object->* +#endif // is member + BODY_FUNCTION_ + )( + // argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_argument, ~) + ); + } + CONTRACT_AUX_DEBUGT(debug_type, dbg << "Entering"); + +#if CONTRACT_is_member +#if defined CONTRACT_CHECK_CLASS_INVARIANT + bool invariant_disabled = true; + if (preinvariant_check || postinvariant_check) { + // POLICY: Invariant checking disabled in object + // nested calls to avoid infinite recursion. In + // nested calls, object state will be already + // checking contracts. + invariant_disabled = state::get_state_( + object).object_checking_contract_; + if (invariant_disabled) { + // Follwing code will not check dyn. invariant. + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Dynamic invariant checking disabled in " + << "nested call"); + } + } +#endif // check invariant + state::get_state_(object).object_checking_contract_ = true; +#endif // is member + +#if defined CONTRACT_CHECK_CLASS_INVARIANT + // Only used when invariant checking turned on (so must wrap + // declaration with #ifdef to avoid unsused variable error). + bool calling_body = false; +#endif // check invariant + try { + + // Invariants are checked *before* pre/post- + // conditions so pre/post assertions can assume + // invariants are true (e.g., if inv assert a + // pointer is not NULL, pre/post can dereference it + // safely). However, invariant checking might be + // disabled in nested calls... + +#if defined CONTRACT_CHECK_CLASS_INVARIANT + try { + check_invariant( +#if CONTRACT_is_member + object, !invariant_disabled && preinvariant_check +#endif // is member + ); + } catch (...) { class_invariant_failed(here()); } +#endif // check invariant + +#if defined CONTRACT_CHECK_PRECONDITION + if (precondition_check) { + try { + check_precondition( +#if CONTRACT_is_member + object + BOOST_PP_COMMA_IF(CONTRACT_arity) +#endif // is member + // argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_argument, ~) + ); + } catch (...) { precondition_failed(here()); } + } +#endif // check precondition + +#if defined CONTRACT_CHECK_POSTCONDITION + // Ideally, the oldof variables should be declared + // only if postcondition_check is true but then they + // will be local to the if-statement code + // complicating this code structure quite a bit. For + // now, the only time postcondition_check is false is + // for destructors which have no arguments and + // non-copyable self so the oldof declarations do not + // make any copy and this code does not negatively + // affect performances even if postcondition_check is + // false. + // The oldof variables are declaraed only after + // pre-invariant and preconditions checking so to + // save their eventual copy operation in case of + // precondition failure [Crowl2006]. + + // Old variables (eventual copies). +#if CONTRACT_is_member + copy oldcopy_object(*object); +#endif // is member + // copy old_argument0(argument0); + // ... + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_copy_old_argument, ~) +#endif // check postcondition + + // For non-void functions, the following code will + // copy result. This introduces overhead but it is + // necessary even when post-invariants and + // postconditions are not checked because + // object_checking_contract_ must be updated to flase + // *after* body execution. + + // Execute body. + CONTRACT_AUX_DEBUGT(debug_type, dbg << "Executing body"); +#if defined CONTRACT_CHECK_CLASS_INVARIANT + calling_body = true; +#endif // check invariant + // If void: (object->*BODY_FUNCTION_)(argument0, ...); + // else: ResultType result( + // (object->*body)(argument0, ...) ); + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, + ResultType result) + BOOST_PP_LPAREN_IF(CONTRACT_is_not_void) + ( +#if CONTRACT_is_member + object->* +#endif // is member + BODY_FUNCTION_ + )( + // argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_argument, ~) + ) + BOOST_PP_RPAREN_IF(CONTRACT_is_not_void) + ; +#if defined CONTRACT_CHECK_CLASS_INVARIANT + calling_body = false; +#endif // check invariant + +#if defined CONTRACT_CHECK_CLASS_INVARIANT + try { + check_invariant( +#if CONTRACT_is_member + object, !invariant_disabled && postinvariant_check +#endif // is member + ); + } catch (...) { class_invariant_failed(here()); } +#endif // check invariant + +#if defined CONTRACT_CHECK_POSTCONDITION + if (postcondition_check) { + try { + check_postcondition( +#if CONTRACT_is_member + object + , &(oldcopy_object.value) // Pass pointer. + BOOST_PP_COMMA_IF(CONTRACT_arity) +#endif // is member + // argument0, , old_argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_now_and_oldcopy_argument, + ~) + // , result (if non-void) +#if CONTRACT_is_member || CONTRACT_arity + BOOST_PP_COMMA_IF( + CONTRACT_is_not_void) +#endif // is member || arity != 0 + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, + result) + ); + } catch (...) { postcondition_failed(here()); } + } +#endif // check postcondition + +#if CONTRACT_is_member + state::get_state_( + object).object_checking_contract_ = false; +#endif // is member + + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Returning normally"); + // If void 'return;', else 'return result;'. + return BOOST_PP_EXPR_IF(CONTRACT_is_not_void, result); + + } catch (...) { + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Returning because of an exception"); + +#if defined CONTRACT_CHECK_CLASS_INVARIANT + // POLICY: Invariants (but not postconditions) + // checked also when body exited abnormally for + // exception safety guarantees [Crowl2006]. + + if (calling_body) { // Exception thrown by body. + calling_body = false; + try { +#if defined CONTRACT_CHECK_CLASS_INVARIANT + try { + check_invariant( +#if CONTRACT_is_member + object, !invariant_disabled && + postinvariant_check +#endif // is member + ); + } catch (...) { class_invariant_failed(here()); } +#endif // check invariant + + } catch (...) { +#if CONTRACT_is_member + // Make sure to clear contract state even if + // class_invariant_failed() throws. + state::get_state_( + object).object_checking_contract_ = false; +#endif // is member + throw; // Re-throw invariant exception. + } + + // If invariant passed (no throw, no exit, etc). + throw; // Re-throw body exception. + } +#endif // check invariant + +#if CONTRACT_is_member + state::get_state_( + object).object_checking_contract_ = false; +#endif // is member + throw; + } +#endif // check contract + } + +private: + // Pointers to body, pre, post, and bases (they could be 0). + + body_function_ptr const BODY_FUNCTION_; +#if defined CONTRACT_CHECK_PRECONDITION + precondition_function_ptr const PRECONDITION_FUNCTION_; +#endif // check precondition +#if defined CONTRACT_CHECK_POSTCONDITION + postcondition_function_ptr const POSTCONDITION_FUNCTION_; +#endif // check postcondition + +#if CONTRACT_is_member + // BaseContractClass0* base_contract_class0_; ... + BOOST_PP_REPEAT(CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_declare_base_contract, ~) +#endif // is_member + +// End of class declaration here. + diff --git a/src/contract/aux_/function/local_macros_define.hpp b/src/contract/aux_/function/local_macros_define.hpp new file mode 100755 index 00000000..97ec6bf1 --- /dev/null +++ b/src/contract/aux_/function/local_macros_define.hpp @@ -0,0 +1,322 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// IMPORTANT: +// * No #include guard here +// * Do not #include any other headers here (do it in the file +// #including this one instead). +// * These macros are local to the #including file, they all must be #undef +// by "local_macros_undef.hpp" which must also be #include by the +// #including file. +// See "local_macros_undef.hpp". + +// These #defines are in a separate header only to split the code and +// make it more manageable. The #defines only make sense as part of +// the file that #include this file. + +// Result typedefs. +// RestultType := R (R is untagged result type). + +#define CONTRACT_typedef_arg_result_type \ + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, \ + typedef typename aux::arg::type arg_result_type; \ + ) + +// Argument types. + +#define CONTRACT_ArgumentType(z, n, data) \ + BOOST_PP_CAT(ArgumentType, n) + +#define CONTRACT_argument_type(z, n, data) \ + BOOST_PP_CAT(argument_type, n) + +#define CONTRACT_argument_ref(z, n, data) \ + BOOST_PP_CAT(argument_ref, n) + +#define CONTRACT_arg_argument_type(z, n, data) \ + BOOST_PP_CAT(arg_argument_type, n) + +#define CONTRACT_old_argument_type(z, n, data) \ + BOOST_PP_CAT(old_argument_type, n) + +#define CONTRACT_arg_old_argument_type(z, n, data) \ + BOOST_PP_CAT(arg_old_argument_type, n) + +// Agument names. + +#define CONTRACT_argument(z, n, data) \ + BOOST_PP_CAT(argument, n) + +#define CONTRACT_old_argument(z, n, data) \ + BOOST_PP_CAT(old_argument, n) + +#define CONTRACT_oldcopy_argument(z, n, data) \ + BOOST_PP_CAT(oldcopy_argument, n) + +#define CONTRACT_now_and_old_argument(z, n, data) \ + CONTRACT_argument(z, n, data) \ + BOOST_PP_COMMA() \ + CONTRACT_old_argument(z, n, data) + +#define CONTRACT_now_and_oldcopy_argument(z, n, data) \ + CONTRACT_argument(z, n, data) \ + BOOST_PP_COMMA() \ + CONTRACT_oldcopy_argument(z, n, data).value + +// Argument typedes. +// ArgumentType := A [+ copyable] (A is untagged argument type). + +#define CONTRACT_typedef_argument_type(z, n, data) \ + typedef typename aux::remove_copyable< \ + CONTRACT_ArgumentType(z, n, data)>::type \ + CONTRACT_argument_type(z, n, data); + +#define CONTRACT_typedef_argument_ref(z, n, data) \ + typedef typename boost::add_reference< \ + CONTRACT_argument_type(z, n, data)>::type \ + CONTRACT_argument_ref(z, n, data); + +#define CONTRACT_typedef_arg_argument_type(z, n, data) \ + typedef typename aux::arg< \ + CONTRACT_argument_type(z, n, data)>::type \ + CONTRACT_arg_argument_type(z, n, data); + +#define CONTRACT_typedef_old_argument_type(z, n, data) \ + typedef typename aux::old< \ + /* must keep eventual copyable for old */ \ + CONTRACT_ArgumentType(z, n, data)>::type \ + CONTRACT_old_argument_type(z, n, data); + +#define CONTRACT_typedef_arg_old_argument_type(z, n, data) \ + typedef typename aux::arg< \ + CONTRACT_old_argument_type(z, n, data)>::type \ + CONTRACT_arg_old_argument_type(z, n, data); + +// Now and old arguments. + +#define CONTRACT_noncopyable_argument(z, n, data) \ + CONTRACT_argument_type(z, n, data) \ + CONTRACT_argument(z, n, data) + +#define CONTRACT_arg_argument(z, n, data) \ + CONTRACT_arg_argument_type(z, n, data) \ + CONTRACT_argument(z, n, data) + +#define CONTRACT_arg_now_and_old_argument(z, n, data) \ + CONTRACT_arg_argument(z, n, data) /* now type and name */ \ + BOOST_PP_COMMA() \ + CONTRACT_arg_old_argument_type(z, n, data) \ + CONTRACT_old_argument(z, n, data) + +#define CONTRACT_copy_old_argument(z, n, data) \ + copy \ + CONTRACT_oldcopy_argument(z, n, data)( \ + CONTRACT_argument(z, n, data)); + +// Class types. +// ClassType := C [+ const ] [+ copyable] (C is untagged class type). + +#define CONTRACT_typedef_maybeconst_class_type \ + typedef typename aux::remove_copyable::type \ + maybeconst_class_type; + +#define CONTRACT_typedef_class_type \ + typedef typename boost::remove_const::type \ + class_type; + +#define CONTRACT_typedef_maybeconst_class_ptr \ + typedef typename boost::add_pointer::type maybeconst_class_ptr; + +#define CONTRACT_typedef_arg_class_ptr \ + typedef typename aux::arg::type \ + arg_class_ptr; + +#define CONTRACT_typedef_old_class_type \ + typedef typename aux::old::type old_class_type; + +#define CONTRACT_typedef_arg_old_class_ptr \ + typedef typename aux::arg::type>::type>::type arg_old_class_ptr; + +// Base contracts. + +#define CONTRACT_BaseContractClass(z, n, data) \ + BOOST_PP_CAT(BaseContractClass, n) + +#define CONTRACT_base_contract(z, n, data) \ + /* postfixed with '_' because private member variable */ \ + BOOST_PP_CAT(BOOST_PP_CAT(base_contract, n), _) + +#define CONTRACT_declare_base_contract(z, n, data) \ + CONTRACT_BaseContractClass(z, n, data)* \ + CONTRACT_base_contract(z, n, data); + +#define CONTRACT_init_base_contract(z, n, data) \ + CONTRACT_base_contract(z, n, data)(/* default constructor */) + +#define CONTRACT_alloc_base_contract(z, n, data) \ + if (!boost::is_same \ + >::value) { \ + CONTRACT_base_contract(z, n, data) = \ + new CONTRACT_BaseContractClass(z, n, data)(); \ + } + +#define CONTRACT_dealloc_base_contract(z, n, data) \ + if (CONTRACT_base_contract(z, n, data)) { \ + delete CONTRACT_base_contract(z, n, data); \ + } + +#define CONTRACT_check_base_invariant(z, n, data) \ + if (CONTRACT_base_contract(z, n, data)) { \ + typename CONTRACT_BaseContractClass(z, n, data)::class_type \ + const* base_object = 0; \ + state::to_base_(object, base_object); \ + CONTRACT_base_contract(z, n, data)->check_invariant( \ + base_object, dynamic_invariant_check); \ + } + +#define CONTRACT_check_base_precondition(z, n, data) \ + if (failed && CONTRACT_base_contract(z, n, data)) { \ + try { \ + typename CONTRACT_BaseContractClass(z, n, data):: \ + class_type const* base_object = 0; \ + state::to_base_(object, base_object); \ + CONTRACT_base_contract(z, n, data)->check_precondition( \ + base_object \ + BOOST_PP_ENUM_TRAILING( \ + CONTRACT_arity, \ + CONTRACT_argument, ~) \ + ); \ + failed = false; /* Passed, done. */ \ + } catch (...) {} /* Keep checking... */ \ + } + +#define CONTRACT_check_base_postcondition(z, n, data) \ + if (CONTRACT_base_contract(z, n, data)) { \ + typename CONTRACT_BaseContractClass(z, n, data):: \ + class_type const* base_object = 0; \ + state::to_base_(object, base_object); \ + CONTRACT_base_contract(z, n, data)->check_postcondition(\ + base_object \ + , old_object \ + /* , argument0, old_argument0, ... */ \ + BOOST_PP_ENUM_TRAILING(CONTRACT_arity, \ + CONTRACT_now_and_old_argument, ~) \ + /* , result (if non-void) */ \ + BOOST_PP_COMMA_IF(CONTRACT_is_not_void) \ + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, result) \ + ); \ + } + +// Template parameters. + +#define CONTRACT_tparam_ArgumentType(z, n, data) \ + typename CONTRACT_ArgumentType(z, n, data) + +#define CONTRACT_tparam_BaseContractClass(z, n, data) \ + class CONTRACT_BaseContractClass(z, n, data) + +#define CONTRACT_tparam_BaseContractClass_default(z, n, data) \ + class CONTRACT_BaseContractClass(z, n, data) = \ + aux::void_base_contract + +// Functions pointers. + +// F := ResultType (ClassType const*, ArgumentType0, ...). +// Class and argument types are optional, result type can be void. +#define CONTRACT_f(is_member) \ + BOOST_PP_IF(BOOST_PP_NOT(CONTRACT_is_not_void), void, ResultType) \ + ( \ + BOOST_PP_EXPR_IF(is_member, ClassType*) \ + BOOST_PP_COMMA_IF(BOOST_PP_AND(is_member, CONTRACT_arity)) \ + BOOST_PP_ENUM(CONTRACT_arity, CONTRACT_ArgumentType, ~) \ + ) + +#define CONTRACT_typedef_body_member_function_ptr_(unused) \ + /* Use two support types for compiler compatibility (MSVC). */ \ + typedef ResultType (class_type::* nonconst_body_function_ptr_)( \ + /* argument_type0, ... */ \ + BOOST_PP_ENUM(CONTRACT_arity, \ + CONTRACT_argument_type, ~) ) \ + ; \ + typedef ResultType (class_type::* const_body_function_ptr_)( \ + /* argument_type0, ... */ \ + BOOST_PP_ENUM(CONTRACT_arity, \ + CONTRACT_argument_type, ~) ) \ + const; \ + typedef typename boost::mpl::if_< \ + boost::is_const \ + , const_body_function_ptr_ \ + , nonconst_body_function_ptr_ \ + >::type body_function_ptr; + +#define CONTRACT_typedef_body_nonmember_function_ptr_(unused) \ + typedef ResultType (* body_function_ptr)( \ + /* argument_type0, ... */ \ + BOOST_PP_ENUM(CONTRACT_arity, \ + CONTRACT_argument_type, ~) ) \ + ; + +#define CONTRACT_typedef_body_function_ptr(is_member) \ + BOOST_PP_IF(is_member, \ + CONTRACT_typedef_body_member_function_ptr_ \ + , /* else */ \ + CONTRACT_typedef_body_nonmember_function_ptr_ \ + )(~) /* delay macro expansion to handle commas in mpl::if_<> */ + +#define CONTRACT_typedef_precondition_function_ptr \ + typedef void ( \ + BOOST_PP_EXPR_IF(CONTRACT_is_member, class_type::) \ + * precondition_function_ptr)( \ + /* arg_argument_type0 argument0, ... */ \ + BOOST_PP_ENUM(CONTRACT_arity, CONTRACT_arg_argument, ~) ) \ + BOOST_PP_EXPR_IF(CONTRACT_is_member, const) ; + +#define CONTRACT_typedef_static_precondition_function_ptr \ + typedef void ( \ + /* never class type (static so no object) */ \ + * static_precondition_function_ptr)( \ + /* arg_argument_type0 argument0, ... */ \ + BOOST_PP_ENUM(CONTRACT_arity, CONTRACT_arg_argument, ~) ) \ + /* never const (static so no object) */ ; + +#define CONTRACT_typedef_postcondition_function_ptr \ + typedef void ( \ + BOOST_PP_EXPR_IF(CONTRACT_is_member, class_type::) \ + * postcondition_function_ptr)( \ + /* arg_old_class_ptr (if memeber) */ \ + BOOST_PP_EXPR_IF(CONTRACT_is_member, arg_old_class_ptr) \ + /* , arg_argument_type0 argument0 */ \ + /* , arg_old_argument_type0 old_argument0, ... */ \ + BOOST_PP_COMMA_IF(BOOST_PP_AND(CONTRACT_arity, \ + CONTRACT_is_member)) \ + BOOST_PP_ENUM(CONTRACT_arity, \ + CONTRACT_arg_now_and_old_argument, ~) \ + /* , arg_result_type result (if not void) */ \ + BOOST_PP_COMMA_IF(BOOST_PP_AND(CONTRACT_is_not_void, \ + BOOST_PP_OR(CONTRACT_arity, CONTRACT_is_member))) \ + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, \ + arg_result_type result) \ + ) BOOST_PP_EXPR_IF(CONTRACT_is_member, const) ; + +#define CONTRACT_typedef_static_postcondition_function_ptr \ + typedef void ( \ + /* never class_type (static so no object) */ \ + * static_postcondition_function_ptr)( \ + /* ever old object type (static so no ojbect) */ \ + /* , arg_argument_type0 argument0 */ \ + /* , arg_old_argument_type0 old_argument0, ... */ \ + BOOST_PP_ENUM(CONTRACT_arity, \ + CONTRACT_arg_now_and_old_argument, ~) \ + /* , arg_result_type result (if not void) */ \ + BOOST_PP_COMMA_IF(BOOST_PP_AND(CONTRACT_is_not_void, \ + CONTRACT_arity)) \ + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, \ + arg_result_type result) \ + ) /* never const (static so no ojbect) */ ; + diff --git a/src/contract/aux_/function/local_macros_undef.hpp b/src/contract/aux_/function/local_macros_undef.hpp new file mode 100755 index 00000000..e5a1bee6 --- /dev/null +++ b/src/contract/aux_/function/local_macros_undef.hpp @@ -0,0 +1,56 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// IMPORTANT: +// * No #include guard here +// * Do not #include any other headers here (do it in the file +// * These must #undef all the macros #defined by "local_macros_define.hpp". +// See "local_macros_define.hpp". + +#undef CONTRACT_typedef_arg_result_type +#undef CONTRACT_ArgumentType +#undef CONTRACT_argument_type +#undef CONTRACT_argument_ref +#undef CONTRACT_arg_argument_type +#undef CONTRACT_old_argument_type +#undef CONTRACT_arg_old_argument_type +#undef CONTRACT_argument +#undef CONTRACT_old_argument +#undef CONTRACT_oldcopy_argument +#undef CONTRACT_now_and_old_argument +#undef CONTRACT_now_and_oldcopy_argument +#undef CONTRACT_typedef_argument_type +#undef CONTRACT_typedef_argument_ref +#undef CONTRACT_typedef_arg_argument_type +#undef CONTRACT_typedef_old_argument_type +#undef CONTRACT_typedef_arg_old_argument_type +#undef CONTRACT_noncopyable_argument +#undef CONTRACT_arg_argument +#undef CONTRACT_arg_now_and_old_argument +#undef CONTRACT_copy_old_argument +#undef CONTRACT_typedef_class_type +#undef CONTRACT_typedef_maybeconst_class_ptr +#undef CONTRACT_typedef_arg_class_ptr +#undef CONTRACT_typedef_old_class_type +#undef CONTRACT_typedef_arg_old_class_ptr +#undef CONTRACT_BaseContractClass +#undef CONTRACT_base_contract +#undef CONTRACT_declare_base_contract +#undef CONTRACT_init_base_contract +#undef CONTRACT_alloc_base_contract +#undef CONTRACT_dealloc_base_contract +#undef CONTRACT_check_base_invariant +#undef CONTRACT_check_base_precondition +#undef CONTRACT_check_base_postcondition +#undef CONTRACT_tparam_ArgumentType +#undef CONTRACT_tparam_BaseContractClass +#undef CONTRACT_tparam_BaseContractClass_default +#undef CONTRACT_f +#undef CONTRACT_typedef_body_function_ptr +#undef CONTRACT_typedef_precondition_function_ptr +#undef CONTRACT_typedef_static_precondition_function_ptr +#undef CONTRACT_typedef_postcondition_function_ptr +#undef CONTRACT_typedef_static_postcondition_function_ptr + diff --git a/src/contract/aux_/function/void_base_contract.hpp b/src/contract/aux_/function/void_base_contract.hpp new file mode 100755 index 00000000..e5c91d52 --- /dev/null +++ b/src/contract/aux_/function/void_base_contract.hpp @@ -0,0 +1,126 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#if !BOOST_PP_IS_ITERATING +# // #include guard (but only if not iter). +# ifndef CONTRACT_AUX_VOID_BASE_CONTRACT_HPP_ +# define CONTRACT_AUX_VOID_BASE_CONTRACT_HPP_ +# include "../../config.hpp" +# include "../../old.hpp" +# include "../old.hpp" +# include "../arg.hpp" +# include "../check01.hpp" +# include +# include +# include +# include + +namespace contract { namespace aux { + +template +class void_base_contract { + BOOST_MPL_ASSERT_MSG(0, CONTRACT_ERROR_only_void_base_contract_template_specializations_should_be_used, ()); +}; + +}} // namespace + +// Self-iterate this file over arity, void, and const (no iteration +// over non-member because base contracts do not apply to non member). +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (0, CONTRACT_CONFIG_MAX_FUNCTION_ARITY, \ + CONTRACT_CONFIG_AUX_VOID_BASE_CONTRACT_HPP_FILE_PATH_)) +# include BOOST_PP_ITERATE() // Iter over function arity. +# endif // #include guard +# // 1st self-iteration over function-arity. +#elif BOOST_PP_ITERATION_DEPTH() == 1 +# define BOOST_PP_ITERATION_PARAMS_2 (3, (0, 1, \ + CONTRACT_CONFIG_AUX_VOID_BASE_CONTRACT_HPP_FILE_PATH_)) +# include BOOST_PP_ITERATE() // Iter over 0 void, 1 non-void func. +# // 2nd self-iteration over void/non-void function. +#elif BOOST_PP_ITERATION_DEPTH() == 2 +# // Define local macros directly depending on iteration. +# define CONTRACT_rest_arity BOOST_PP_FRAME_ITERATION(1) +# define CONTRACT_arity \ + BOOST_PP_SUB(BOOST_PP_FRAME_FINISH(1), CONTRACT_rest_arity) +# define CONTRACT_is_void BOOST_PP_FRAME_ITERATION(2) +# define CONTRACT_is_not_void BOOST_PP_NOT(CONTRACT_is_void) +# // Base contracts only for members (so member is always 1 here). +# define CONTRACT_is_member 1 +# define CONTRACT_is_not_member BOOST_PP_NOT(CONTRACT_is_member) +# include "local_macros_define.hpp" + +namespace contract { namespace aux { + +template +class void_base_contract { +private: + CONTRACT_typedef_maybeconst_class_type; +public: + CONTRACT_typedef_class_type // Must be public for subcontracting. +private: + CONTRACT_typedef_maybeconst_class_ptr + CONTRACT_typedef_arg_class_ptr; + CONTRACT_typedef_old_class_type + CONTRACT_typedef_arg_old_class_ptr + BOOST_PP_EXPR_IF(CONTRACT_is_void, typedef void ResultType;) + CONTRACT_typedef_arg_result_type + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_argument_type, ~) + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_argument_ref, ~) + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_arg_argument_type, ~) + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_old_argument_type, ~) + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_arg_old_argument_type, ~) + +public: // Empty check_xyz() implementation "{}" needed to compile. +#if CONTRACT_AUX_CHECK_CLASS_INVARIANT_01 + void check_invariant(arg_class_ptr object, + const bool& dynamic_invariant_check) {} +#endif // check invariant + +#if CONTRACT_AUX_CHECK_PRECONDITION_01 + void check_precondition(arg_class_ptr object + // , arg_argument_type0 argument0, ... + BOOST_PP_ENUM_TRAILING(CONTRACT_arity, + CONTRACT_arg_argument, ~) + ) {} +#endif // check precondition + +#if CONTRACT_AUX_CHECK_POSTCONDITION_01 + void check_postcondition(arg_class_ptr object + , arg_old_class_ptr old_object + // , arg_argument_type0 argument0 + // , arg_old_argument_type0 old_argument0, ... + BOOST_PP_ENUM_TRAILING(CONTRACT_arity, + CONTRACT_arg_now_and_old_argument, ~) + // , arg_result_type result (if not void) + BOOST_PP_COMMA_IF(CONTRACT_is_not_void) + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, + arg_result_type result) + ) {} +#endif // check postcondition +}; + +}} // namespace + +# // Undef ALL local macros directly depending on iteration. +# undef CONTRACT_rest_arity +# undef CONTRACT_arity +# undef CONTRACT_is_void +# undef CONTRACT_is_not_void +# undef CONTRACT_is_const +# undef CONTRACT_is_not_const +# undef CONTRACT_is_member +# undef CONTRACT_is_not_member +# include "local_macros_undef.hpp" +#else // Self-iteration out-of-range (should never happen...). +# error "Preprocessor iteration depth out-of-range (internal error)" +#endif // BOOST_PP_IS_ITERATING + diff --git a/src/contract/aux_/macros/README.txt b/src/contract/aux_/macros/README.txt new file mode 100755 index 00000000..8ef1d854 --- /dev/null +++ b/src/contract/aux_/macros/README.txt @@ -0,0 +1 @@ +Support for contract macros. diff --git a/src/contract/aux_/macros/code_/README.txt b/src/contract/aux_/macros/code_/README.txt new file mode 100755 index 00000000..77c4b6ba --- /dev/null +++ b/src/contract/aux_/macros/code_/README.txt @@ -0,0 +1 @@ +Code generation. diff --git a/src/contract/aux_/macros/code_/args.hpp b/src/contract/aux_/macros/code_/args.hpp new file mode 100755 index 00000000..27adda77 --- /dev/null +++ b/src/contract/aux_/macros/code_/args.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_ARGS_HPP_ +#define CONTRACT_AUX_CODE_ARGS_HPP_ + +#include "../../preprocessor/sign/args.hpp" +#include + +#define CONTRACT_AUX_CODE_ARG_NAME_OP_(z, n, arg) \ + CONTRACT_AUX_PP_SIGN_ARG_NAME(arg) + +#define CONTRACT_AUX_CODE_ARG_NAMES(sign) \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM(sign, \ + CONTRACT_AUX_PP_SIGN_HAS_ARGS, \ + CONTRACT_AUX_PP_SIGN_ARGS, \ + CONTRACT_AUX_CODE_ARG_NAME_OP_) + +#define CONTRACT_AUX_CODE_ARG_NAMES_TRAILING(sign) \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM_TRAILING(sign, \ + CONTRACT_AUX_PP_SIGN_HAS_ARGS, \ + CONTRACT_AUX_PP_SIGN_ARGS, \ + CONTRACT_AUX_CODE_ARG_NAME_OP_) + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/body.hpp b/src/contract/aux_/macros/code_/body.hpp new file mode 100755 index 00000000..c62c038f --- /dev/null +++ b/src/contract/aux_/macros/code_/body.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_BODY_HPP_ +#define CONTRACT_AUX_CODE_BODY_HPP_ + +#include "function_sign.hpp" +#include + +#define CONTRACT_AUX_CODE_BODY_SIGN(kind, sign) \ + CONTRACT_AUX_CODE_FUNCTION_SIGN(kind, 0, /* no online */ \ + CONTRACT_BODY( \ + CONTRACT_AUX_CODE_FUNCTION_NAME(kind, sign)), \ + sign) + +#define CONTRACT_AUX_CODE_BODY(kind, sign) \ + CONTRACT_AUX_CODE_BODY_SIGN(kind, sign) /* signature */ \ + CONTRACT_AUX_PP_SIGN_BODY(sign) /* code block */ + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/contract_class.hpp b/src/contract/aux_/macros/code_/contract_class.hpp new file mode 100755 index 00000000..1acfa6c0 --- /dev/null +++ b/src/contract/aux_/macros/code_/contract_class.hpp @@ -0,0 +1,151 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_CONTRACT_CLASS_HPP_ +#define CONTRACT_AUX_CODE_CONTRACT_CLASS_HPP_ + +#include "kind.hpp" +#include "contract_name.hpp" +#include "precondition.hpp" +#include "postcondition.hpp" +#include "function_sign.hpp" +#include "function_template.hpp" +#include "../../check01.hpp" +#include "../../preprocessor/sign/static.hpp" +#include "../../preprocessor/sign/result_type.hpp" +#include "../../preprocessor/sign/class_type.hpp" +#include "../../preprocessor/sign/base_types.hpp" +#include "../../preprocessor/sign/args.hpp" +#include + +#define CONTRACT_AUX_CODE_CONTRACT_CLASS_BASE_CONTRACT_( \ + z, n, kind_n_sign) \ + /* base_type::contract_name */ \ + typename BOOST_PP_SEQ_ELEM(n, \ + CONTRACT_AUX_PP_SIGN_BASE_TYPES(BOOST_PP_TUPLE_ELEM( \ + 2, 1, kind_n_sign)))::template \ + CONTRACT_AUX_CODE_CONTRACT_NAME( \ + BOOST_PP_TUPLE_ELEM(2, 0, kind_n_sign), \ + BOOST_PP_TUPLE_ELEM(2, 1, kind_n_sign)) < \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_OR_UNUSED_ARG_NAMES( \ + BOOST_PP_TUPLE_ELEM(2, 1, kind_n_sign)) \ + > + +#define CONTRACT_AUX_CODE_CONTRACT_CLASS_BASE_CONTRACTS_(kind, sign) \ + BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE( \ + CONTRACT_AUX_PP_SIGN_BASE_TYPES(sign)), \ + CONTRACT_AUX_CODE_CONTRACT_CLASS_BASE_CONTRACT_, \ + (kind, sign)) \ + +// In a separate macro to handle eventual template param commas. +#define CONTRACT_AUX_CODE_CONTRACT_CLASS_TPARAM_OR_UNUSED_( \ + sign) \ + < CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_OR_UNUSED_ARG_NAMES(sign) > + +// Can be function, constructor, or destructor member. +#define CONTRACT_AUX_CODE_CONTRACT_CLASS_BASE_( \ + kind, sign) \ + ::contract:: \ + BOOST_PP_IF(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_CONSTRUCTOR), \ + constructor \ + , BOOST_PP_IF(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR), \ + destructor \ + , BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_IS_STATIC(sign), \ + static_member_function \ + , BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + nonstatic_member_function \ + , /* else (non member function) */ \ + nonmember_function \ + )))) < \ + CONTRACT_AUX_CODE_F(sign) \ + /* , base0::contract-name, ... (only non-static memi) */ \ + /* which is enforced by preprocessing) */ \ + BOOST_PP_COMMA_IF(CONTRACT_AUX_PP_SIGN_HAS_BASES(sign)) \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_HAS_BASES(sign), \ + CONTRACT_AUX_CODE_CONTRACT_CLASS_BASE_CONTRACTS_ \ + , \ + BOOST_PP_TUPLE_EAT(2) \ + )(kind, sign) \ + > + +#define CONTRACT_AUX_CODE_CONTRACT_CLASS(kind, sign) \ + /* struct for pub inherit of call() and pub default constr. */ \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_OR_UNUSED0_SIGN(sign) \ + struct CONTRACT_AUX_CODE_CONTRACT_NAME(kind, sign): \ + CONTRACT_AUX_CODE_CONTRACT_CLASS_BASE_(kind, sign) { \ + /* default constructor */ \ + CONTRACT_AUX_CODE_CONTRACT_NAME(kind, sign)(): \ + /* constr base class passing pre, post, and body */ \ + CONTRACT_AUX_CODE_CONTRACT_CLASS_BASE_(kind, sign)( \ + /* &class_type::contract_body_func_name_ */ \ + & /* make it a function pointer */ \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE(sign) :: \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS(sign), \ + template \ + ) /* endif */ \ + ) /* endif */ \ + CONTRACT_BODY( \ + CONTRACT_AUX_CODE_FUNCTION_NAME(kind, sign)) \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS(sign), \ + < \ + ) /* endif */ \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_NAMES(sign) \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS(sign), \ + > \ + ) \ + /* , &[class_type::]contract_precondition_f-name_ */ \ + /* (but not for destructor) */ \ + BOOST_PP_COMMA_IF(BOOST_PP_AND( \ + CONTRACT_AUX_CHECK_PRECONDITION_01, \ + BOOST_PP_NOT(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR)))) \ + BOOST_PP_IF(BOOST_PP_AND( \ + CONTRACT_AUX_CHECK_PRECONDITION_01, \ + BOOST_PP_NOT(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR))), \ + & /* make it a function pointer */ \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE(sign) \ + ::template /* typename workaround */ \ + ) /* endif */ \ + CONTRACT_AUX_CODE_PRECONDITION_NAME(kind, sign) \ + CONTRACT_AUX_CODE_CONTRACT_CLASS_TPARAM_OR_UNUSED_ \ + , /* else */ \ + BOOST_PP_TUPLE_EAT(1) \ + )(sign) \ + /* , &[class_type::]contract_postcondition_f-name_ */ \ + /* (but not for destructor) */ \ + BOOST_PP_COMMA_IF(BOOST_PP_AND( \ + CONTRACT_AUX_CHECK_POSTCONDITION_01, \ + BOOST_PP_NOT(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR)))) \ + BOOST_PP_IF(BOOST_PP_AND( \ + CONTRACT_AUX_CHECK_POSTCONDITION_01, \ + BOOST_PP_NOT(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR))), \ + & /* make it a function pointer */ \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE(sign) \ + ::template /* typename workaround */ \ + ) /* endif */ \ + CONTRACT_AUX_CODE_POSTCONDITION_NAME(kind, sign) \ + CONTRACT_AUX_CODE_CONTRACT_CLASS_TPARAM_OR_UNUSED_ \ + , /* else */ \ + BOOST_PP_TUPLE_EAT(1) \ + )(sign) \ + ) {} /* empty constructor implementation */ \ + }; /* contract class */ + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/contract_name.hpp b/src/contract/aux_/macros/code_/contract_name.hpp new file mode 100755 index 00000000..2100b291 --- /dev/null +++ b/src/contract/aux_/macros/code_/contract_name.hpp @@ -0,0 +1,70 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_CONTRACT_NAME_HPP_ +#define CONTRACT_AUX_CODE_CONTRACT_NAME_HPP_ + +#include "function_sign.hpp" +#include "../../preprocessor/sign/args.hpp" +#include "../../preprocessor/sign/const.hpp" +#include "../../symbol.hpp" +#include + +#define CONTRACT_AUX_CODE_CONTRACT_NAME_FROM_SEQ_OP_( \ + s, state, arg_name) \ + BOOST_PP_IF(BOOST_PP_IS_EMPTY(arg_name), state, \ + BOOST_PP_CAT(state, BOOST_PP_CAT(arg_name, _))) + +#define CONTRACT_AUX_CODE_CONTRACT_NAME_FROM_SEQ_( \ + name_args_const_seq) \ + CONTRACT_AUX_SYMBOL( \ + BOOST_PP_IF(BOOST_PP_SEQ_SIZE(name_args_const_seq), \ + BOOST_PP_SEQ_FOLD_LEFT, BOOST_PP_TUPLE_EAT(3) \ + )(CONTRACT_AUX_CODE_CONTRACT_NAME_FROM_SEQ_OP_, , \ + name_args_const_seq) \ + ) + +#define CONTRACT_AUX_CODE_CONTRACT_NAME_ARGS_OP_(z, state, arg) \ + state ( CONTRACT_AUX_PP_SIGN_ARG_NAME(arg) ) + +#define CONTRACT_AUX_CODE_CONTRACT_NAME_ARGS_(sign) \ + BOOST_PP_SEQ_FOLD_LEFT(CONTRACT_AUX_CODE_CONTRACT_NAME_ARGS_OP_, \ + , CONTRACT_AUX_PP_SIGN_ARGS(sign)) + +#define CONTRACT_AUX_CODE_CONTRACT_NAME_PREFIXED(kind, sign, \ + prefix_seq) \ + CONTRACT_AUX_CODE_CONTRACT_NAME_FROM_SEQ_( \ + prefix_seq \ + /* build seq (name) (arg0) ... (const) */ \ + ( CONTRACT_AUX_CODE_FUNCTION_NAME(kind, sign) ) \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_HAS_ARGS(sign), \ + CONTRACT_AUX_CODE_CONTRACT_NAME_ARGS_ \ + , \ + BOOST_PP_TUPLE_EAT(1) \ + )(sign) \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_IS_CONST(sign), \ + ( const ) \ + ) /* cannot just concat empty seq elem () if not const */ \ + ) + +// Cannot just call macro above with prefix () because some compiler +// do not support empty seq elements -- must repeat the code... +#define CONTRACT_AUX_CODE_CONTRACT_NAME(kind, sign) \ + CONTRACT_AUX_CODE_CONTRACT_NAME_FROM_SEQ_( \ + /* build seq (name) (arg0) ... (const) */ \ + ( CONTRACT_AUX_CODE_FUNCTION_NAME(kind, sign) ) \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_HAS_ARGS(sign), \ + CONTRACT_AUX_CODE_CONTRACT_NAME_ARGS_ \ + , \ + BOOST_PP_TUPLE_EAT(1) \ + )(sign) \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_IS_CONST(sign), \ + ( const ) \ + ) /* cannot just concat empty seq elem () if not const */ \ + ) + + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/contracted_function.hpp b/src/contract/aux_/macros/code_/contracted_function.hpp new file mode 100755 index 00000000..bc3e54e4 --- /dev/null +++ b/src/contract/aux_/macros/code_/contracted_function.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_CONTRACTED_FUNCTION_HPP_ +#define CONTRACT_AUX_CODE_CONTRACTED_FUNCTION_HPP_ + +#include "contract_name.hpp" +#include "args.hpp" +#include "function_sign.hpp" +#include "function_template.hpp" +#include "../../preprocessor/sign/result_type.hpp" +#include "../../preprocessor/sign/static.hpp" +#include "../../preprocessor/sign/function_name.hpp" +#include "../../preprocessor/sign/class.hpp" +#include + +#define CONTRACT_AUX_CODE_CONTRACTED_FUNCTION_MEMBER(kind, sign) \ + { \ + BOOST_PP_EXPR_IF(BOOST_PP_NOT( \ + CONTRACT_AUX_PP_SIGN_IS_VOID_RESULT(sign)), \ + return \ + ) \ + ( /* extra paren `(` to handle commas in macro params */ \ + CONTRACT_AUX_CODE_CONTRACT_NAME(kind, sign) \ + < \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_OR_UNUSED_ARG_NAMES(sign) \ + > \ + (/* creates contract object */ \ + ).call( \ + BOOST_PP_EXPR_IF(BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + BOOST_PP_NOT( \ + CONTRACT_AUX_PP_SIGN_IS_STATIC(sign))), \ + this \ + ) \ + BOOST_PP_COMMA_IF(BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_HAS_ARGS(sign), \ + BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + BOOST_PP_NOT( \ + CONTRACT_AUX_PP_SIGN_IS_STATIC(sign))))) \ + /* argument0, ... */ \ + CONTRACT_AUX_CODE_ARG_NAMES(sign) \ + ) \ + ); /* extra parenthesis `)` to handle commas in macro params */ \ + } + +#define CONTRACT_AUX_CODE_CONTRACTED_FUNCTION_NON_MEMBER(kind, sign) \ + CONTRACT_AUX_CODE_FUNCTION_SIGN(kind, \ + 1, /* inline avoid duplicate definition error */ \ + /* use name symbol to handle operators */ \ + CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_SYMBOL(sign), sign) \ + CONTRACT_AUX_CODE_CONTRACTED_FUNCTION_MEMBER(kind, sign) + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/function_sign.hpp b/src/contract/aux_/macros/code_/function_sign.hpp new file mode 100755 index 00000000..5ff3a574 --- /dev/null +++ b/src/contract/aux_/macros/code_/function_sign.hpp @@ -0,0 +1,91 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_FUNCTION_SIGN_HPP_ +#define CONTRACT_AUX_CODE_FUNCTION_SIGN_HPP_ + +#include "kind.hpp" +#include "function_template.hpp" +#include "../../../config.hpp" +#include "../../preprocessor/sign/function_name.hpp" +#include "../../preprocessor/sign/static.hpp" +#include "../../preprocessor/sign/virtual.hpp" +#include "../../preprocessor/sign/const.hpp" +#include "../../preprocessor/sign/args.hpp" +#include "../../preprocessor/sign/result_type.hpp" +#include + +#define CONTRACT_AUX_CODE_FUNCTION_ARG_(z, n, argument) \ + CONTRACT_AUX_PP_SIGN_ARG_TYPE(argument) \ + CONTRACT_AUX_PP_SIGN_ARG_NAME(argument) + +#define CONTRACT_AUX_CODE_FUNCTION_COPYABLE_ARG_( \ + z, n, argument) \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_ARG_IS_COPYABLE(argument), \ + ::contract::copyable< ) \ + CONTRACT_AUX_PP_SIGN_ARG_TYPE(argument) \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_ARG_IS_COPYABLE(argument), \ + > ) \ + +#define CONTRACT_AUX_CODE_FUNCTION_NAME(kind, sign) \ + BOOST_PP_IF(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_CONSTRUCTOR), \ + CONTRACT_CONFIG_CONSTRUCTOR_FUNCTION_NAME_ \ + , BOOST_PP_IF(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR), \ + CONTRACT_CONFIG_DESTRUCTOR_FUNCTION_NAME_ \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_FUNCTION_NAME(sign) \ + )) /* endif */ + +#define CONTRACT_AUX_CODE_FUNCTION_SIGN(kind, is_inline, name, sign) \ + /* no invalid combination (e.g., static and const) already */ \ + /* enforced by preprocessing */ \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_SIGN(sign) \ + BOOST_PP_EXPR_IF(is_inline, inline) \ + CONTRACT_AUX_PP_SIGN_STATIC(sign) /* `static` or empty */ \ + CONTRACT_AUX_PP_SIGN_VIRTUAL(sign) /* `virtual` or empty */ \ + CONTRACT_AUX_PP_SIGN_RESULT_TYPE(sign) \ + name \ + BOOST_PP_LPAREN() \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM(sign, \ + CONTRACT_AUX_PP_SIGN_HAS_ARGS, \ + CONTRACT_AUX_PP_SIGN_ARGS, \ + CONTRACT_AUX_CODE_FUNCTION_ARG_) \ + BOOST_PP_RPAREN() \ + CONTRACT_AUX_PP_SIGN_CONST(sign) /* `const` or empty */ + +// The function type template parameter `F`. +#define CONTRACT_AUX_CODE_F(sign) \ + /* result_type */ \ + CONTRACT_AUX_PP_SIGN_RESULT_TYPE(sign) \ + ( \ + /* [copyable] * */ \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER( \ + sign), \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE_IS_COPYABLE( \ + sign), \ + ::contract::copyable< ) \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE(sign) \ + CONTRACT_AUX_PP_SIGN_CONST(sign) \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE_IS_COPYABLE( \ + sign), \ + > ) \ + * /* pointer (must be outside of copyable<>) */ \ + ) /* endif */ \ + /* , [copyable]< argument_type0 >, ... */ \ + BOOST_PP_COMMA_IF(BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + CONTRACT_AUX_PP_SIGN_HAS_ARGS(sign))) \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM(sign, \ + CONTRACT_AUX_PP_SIGN_HAS_ARGS, \ + CONTRACT_AUX_PP_SIGN_ARGS, \ + CONTRACT_AUX_CODE_FUNCTION_COPYABLE_ARG_) \ + ) + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/function_template.hpp b/src/contract/aux_/macros/code_/function_template.hpp new file mode 100755 index 00000000..67e179cf --- /dev/null +++ b/src/contract/aux_/macros/code_/function_template.hpp @@ -0,0 +1,110 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_HPP_ +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_HPP_ + +#include "../../symbol.hpp" +#include "../../preprocessor/sign/function_template_args.hpp" +#include + +// TYPENAME/TEMPLATE WORLAROUND +// The UNUSED template parameter serves to ALWAYS make the function +// a templates so `typename` and `template` can always be used to +// identify types (workaround to avoid requiring the user to +// distinguish templates with (template) ). + +// A value template argument of type int is used `int UNUSED` and +// always assigned to `0`. Similarly, a type template argument +// `typename UNUSED` always assigned to `void` could have been +// used. The int value parameter was used hoping it is easier to +// handle thatn the type parameter for the compiler... but not sure. +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_UNUSED_TYPE_ int +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_UNUSED_VALUE_ 0 + +// In addition, the UNUSED parameter is named to indicate an +// overloading error because the compiler will error on redefinition +// of this parameter in case no different argument names are used. +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_UNUSED_NAME_ \ + CONTRACT_ERROR_overloaded_function_must_use_different_argument_names + +// Arguments. + +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_NAME_OP_(z, n, arg) \ + CONTRACT_AUX_PP_SIGN_ARG_NAME(arg) + +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_NAMES(sign) \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM(sign, \ + CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS, \ + CONTRACT_AUX_PP_SIGN_FUNCTION_TEMPLATE_ARGS, \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_NAME_OP_) + +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_OR_UNUSED_ARG_NAMES( \ + sign) \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS( \ + sign), \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_NAMES \ + , /* else */ \ + /* typename/template workaround */ \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_UNUSED_VALUE_ \ + BOOST_PP_TUPLE_EAT(1) \ + )(sign) /* delay expansion for commas in tparams */ + +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_OP_(z, n, arg) \ + CONTRACT_AUX_PP_SIGN_ARG_TYPE(arg) \ + CONTRACT_AUX_PP_SIGN_ARG_NAME(arg) + +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARGS(sign) \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM(sign, \ + CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS, \ + CONTRACT_AUX_PP_SIGN_FUNCTION_TEMPLATE_ARGS, \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_OP_) + +// Signatures. + +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_SIGN(sign) \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS(sign), \ + template< \ + ) \ + BOOST_PP_IF( \ + CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS(sign), \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARGS \ + , /* else */ \ + BOOST_PP_TUPLE_EAT(1) \ + )(sign) \ + BOOST_PP_EXPR_IF( \ + CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS(sign), \ + > \ + ) + +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_OR_UNUSED_SIGN(sign) \ + template< \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS( \ + sign), \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARGS \ + , /* else */ \ + /* typename/template workaround */ \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_UNUSED_TYPE_ \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_UNUSED_NAME_ \ + BOOST_PP_TUPLE_EAT(1) \ + )(sign) \ + > + +#define CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_OR_UNUSED0_SIGN(sign) \ + template< \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS( \ + sign), \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARGS \ + , /* else */ \ + /* typename/template workaround */ \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_UNUSED_TYPE_ \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_ARG_UNUSED_NAME_ \ + BOOST_PP_TUPLE_EAT(1) \ + )(sign) \ + > + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/kind.hpp b/src/contract/aux_/macros/code_/kind.hpp new file mode 100755 index 00000000..b6ab7298 --- /dev/null +++ b/src/contract/aux_/macros/code_/kind.hpp @@ -0,0 +1,14 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_KIND_HPP_ +#define CONTRACT_AUX_CODE_KIND_HPP_ + +#define CONTRACT_AUX_CODE_KIND_FUNCTION 0 +#define CONTRACT_AUX_CODE_KIND_CONSTRUCTOR 1 +#define CONTRACT_AUX_CODE_KIND_DESTRUCTOR 2 + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/postcondition.hpp b/src/contract/aux_/macros/code_/postcondition.hpp new file mode 100755 index 00000000..c6552f5c --- /dev/null +++ b/src/contract/aux_/macros/code_/postcondition.hpp @@ -0,0 +1,102 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_POSTCONDITION_HPP_ +#define CONTRACT_AUX_CODE_POSTCONDITION_HPP_ + +#include "function_sign.hpp" +#include "contract_name.hpp" +#include "function_template.hpp" +#include "../../symbol.hpp" +#include "../../preprocessor/sign/static.hpp" +#include "../../preprocessor/sign/class_type.hpp" +#include "../../preprocessor/sign/args.hpp" +#include "../../preprocessor/sign/postcondition.hpp" +#include + +#define CONTRACT_AUX_CODE_POSTCONDITION_ARG_(z, n, argument) \ + /* arg argument_name */ \ + typename ::contract::aux::arg< \ + CONTRACT_AUX_PP_SIGN_ARG_TYPE(argument) >::type \ + CONTRACT_AUX_PP_SIGN_ARG_NAME(argument) \ + /* , */ \ + BOOST_PP_COMMA() \ + /* arg< old< copyable > > OLDOF(argument_name) */ \ + /* or noold (with no argument name) if not copyable */ \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_ARG_IS_COPYABLE(argument), \ + typename ::contract::aux::arg< typename \ + ::contract::aux::old< ::contract::copyable< \ + CONTRACT_AUX_PP_SIGN_ARG_TYPE(argument) \ + > /* no ::type */ >::type >::type \ + CONTRACT_OLDOF(CONTRACT_AUX_PP_SIGN_ARG_NAME(argument)) \ + , /* else (not copyable) */ \ + ::contract::noold /* no old for this argument */ \ + ) /* endif */ + +// Postcondition name must be prefixed with full contract name to +// allow for overloading (because precondition signature eventually +// adds const qualifiers to function and its arguments). +#define CONTRACT_AUX_CODE_POSTCONDITION_NAME(kind, sign) \ + CONTRACT_AUX_CODE_CONTRACT_NAME_PREFIXED(kind, sign, \ + (postcondition)) + +#define CONTRACT_AUX_CODE_POSTCONDITION_SIGN(kind, sign) \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_OR_UNUSED_SIGN(sign) \ + /* static-member postcond. is static (no object) */ \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_IS_STATIC(sign), \ + static \ + ) \ + void CONTRACT_AUX_CODE_POSTCONDITION_NAME(kind, sign)( \ + /* old object only if non-static member, plus always */ \ + /* noold for constr. because non copyable class type */ \ + BOOST_PP_EXPR_IF(BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + BOOST_PP_NOT( \ + CONTRACT_AUX_PP_SIGN_IS_STATIC(sign))), \ + BOOST_PP_IF( \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE_IS_COPYABLE( \ + sign), \ + typename ::contract::aux::arg< typename \ + ::contract::aux::old< \ + ::contract::copyable< \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE( \ + sign)* /* pointer to class type */ \ + > /* no ::type */ >::type >::type \ + CONTRACT_OLDOF(this) \ + , /* else */ \ + ::contract::noold /* no old object */ \ + ) /* endif */ \ + ) /* endif */ \ + BOOST_PP_COMMA_IF(BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + BOOST_PP_AND(BOOST_PP_NOT( \ + CONTRACT_AUX_PP_SIGN_IS_STATIC(sign)), \ + CONTRACT_AUX_PP_SIGN_HAS_ARGS(sign)))) \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM(sign, \ + CONTRACT_AUX_PP_SIGN_HAS_ARGS, \ + CONTRACT_AUX_PP_SIGN_ARGS, \ + CONTRACT_AUX_CODE_POSTCONDITION_ARG_) \ + BOOST_PP_COMMA_IF(BOOST_PP_NOT( \ + CONTRACT_AUX_PP_SIGN_IS_VOID_RESULT(sign))) \ + BOOST_PP_EXPR_IF(BOOST_PP_NOT( \ + CONTRACT_AUX_PP_SIGN_IS_VOID_RESULT(sign)), \ + typename ::contract::aux::arg< \ + CONTRACT_AUX_PP_SIGN_RESULT_TYPE(sign) \ + >::type \ + CONTRACT_AUX_PP_SIGN_POSTCONDITION_RESULT(sign)) \ + ) \ + /* static-member and non-member no const (no object) */ \ + BOOST_PP_EXPR_IF(BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + BOOST_PP_NOT(CONTRACT_AUX_PP_SIGN_IS_STATIC(sign))), \ + const \ + ) + +#define CONTRACT_AUX_CODE_POSTCONDITION(kind, sign) \ + CONTRACT_AUX_CODE_POSTCONDITION_SIGN(kind, sign) /* signature */ \ + CONTRACT_AUX_PP_SIGN_POSTCONDITION(sign) /* code block */ + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/precondition.hpp b/src/contract/aux_/macros/code_/precondition.hpp new file mode 100755 index 00000000..af9b9eb2 --- /dev/null +++ b/src/contract/aux_/macros/code_/precondition.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_PRECONDITION_HPP_ +#define CONTRACT_AUX_CODE_PRECONDITION_HPP_ + +#include "kind.hpp" +#include "contract_name.hpp" +#include "function_sign.hpp" +#include "function_template.hpp" +#include "../../symbol.hpp" +#include "../../preprocessor/sign/static.hpp" +#include "../../preprocessor/sign/args.hpp" +#include "../../preprocessor/sign/precondition.hpp" +#include + +#define CONTRACT_AUX_CODE_PRECONDITION_ARG_(z, n, argument) \ + typename ::contract::aux::arg< \ + CONTRACT_AUX_PP_SIGN_ARG_TYPE(argument) >::type \ + CONTRACT_AUX_PP_SIGN_ARG_NAME(argument) + +// Precondition name must be prefixed with full contract name to +// allow for overloading (because precondition signature eventually +// adds const qualifiers to function and its arguments). +#define CONTRACT_AUX_CODE_PRECONDITION_NAME(kind, sign) \ + CONTRACT_AUX_CODE_CONTRACT_NAME_PREFIXED(kind, sign, \ + (precondition)) + +#define CONTRACT_AUX_CODE_PRECONDITION_SIGN(kind, sign) \ + CONTRACT_AUX_CODE_FUNCTION_TEMPLATE_OR_UNUSED_SIGN(sign) \ + /* static-member and constr. precond. is static (no object) */ \ + BOOST_PP_EXPR_IF(BOOST_PP_OR( \ + CONTRACT_AUX_PP_SIGN_IS_STATIC(sign), \ + BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_CONSTRUCTOR)), \ + static \ + ) \ + void CONTRACT_AUX_CODE_PRECONDITION_NAME(kind, sign)( \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM(sign, \ + CONTRACT_AUX_PP_SIGN_HAS_ARGS, \ + CONTRACT_AUX_PP_SIGN_ARGS, \ + CONTRACT_AUX_CODE_PRECONDITION_ARG_) \ + ) \ + /* static-member, constr, and non-member no const (no object) */ \ + BOOST_PP_EXPR_IF(BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + BOOST_PP_NOT(BOOST_PP_OR( \ + CONTRACT_AUX_PP_SIGN_IS_STATIC(sign), \ + BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_CONSTRUCTOR)))), \ + const \ + ) + +#define CONTRACT_AUX_CODE_PRECONDITION(kind, sign) \ + CONTRACT_AUX_CODE_PRECONDITION_SIGN(kind, sign) /* signature */ \ + CONTRACT_AUX_PP_SIGN_PRECONDITION(sign) /* code block */ + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/static_error.hpp b/src/contract/aux_/macros/code_/static_error.hpp new file mode 100755 index 00000000..e84f6497 --- /dev/null +++ b/src/contract/aux_/macros/code_/static_error.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_STATIC_ERROR_HPP_ +#define CONTRACT_AUX_CODE_STATIC_ERROR_HPP_ + +#include + +// @param message A symbol of the form +// `CONTRACT_ERROR_error_descriotion_here_in_lower_case`. This does +// not have to be a #define macro or anything else, its just a name. +#define CONTRACT_AUX_CODE_STATIC_ERROR(message) \ + ; /* close eventaul previous staments, otherwise no effect */ \ + BOOST_MPL_ASSERT_MSG(0, message, ()) + ; /* must close ASSERT macro within class scope */ + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_/static_validate.hpp b/src/contract/aux_/macros/code_/static_validate.hpp new file mode 100755 index 00000000..b50d720e --- /dev/null +++ b/src/contract/aux_/macros/code_/static_validate.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_STATIC_VALIDATE_HPP_ +#define CONTRACT_AUX_CODE_STATIC_VALIDATE_HPP_ + +#include "kind.hpp" +#include "../../preprocessor/sign/class_type.hpp" +#include "../../preprocessor/sign/function_name.hpp" +#include +#include +#include + +// Compile-time signature validation. Any signature validation that +// can be done earlier at preprocessing-time should be done by +// PP_SIGN_VALIDATE() instead. +#define CONTRACT_AUX_CODE_STATIC_VALIDATE(kind, sign) \ + /* enforce class_type == class_name for constr and destr */ \ + BOOST_PP_EXPR_IF(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_CONSTRUCTOR), \ + BOOST_MPL_ASSERT_MSG( (boost::is_same< \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE(sign), \ + CONTRACT_AUX_PP_SIGN_FUNCTION_NAME(sign) >::value), \ + /* must postfix contract so unique MPL class */ \ + BOOST_PP_CAT(CONTRACT_ERROR_constructor_name_must_match_class_type_for_, CONTRACT_AUX_CODE_CONTRACT_NAME(kind, sign)), \ + ()) \ + ; /* must close ASSERT macro within class scope */ \ + ) \ + /* enforce class_type == class_name for constr and destr */ \ + BOOST_PP_EXPR_IF(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR), \ + BOOST_MPL_ASSERT_MSG( (boost::is_same< \ + CONTRACT_AUX_PP_SIGN_CLASS_TYPE(sign), \ + CONTRACT_AUX_PP_SIGN_FUNCTION_NAME(sign) >::value), \ + /* must postfix contract so unique MPL class */ \ + BOOST_PP_CAT(CONTRACT_ERROR_destructor_name_must_match_class_type_, CONTRACT_AUX_CODE_CONTRACT_NAME(kind, sign)), \ + ()) \ + ; /* must close ASSERT macro within class scope */ \ + ) + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_function.hpp b/src/contract/aux_/macros/code_function.hpp new file mode 100755 index 00000000..e5763e74 --- /dev/null +++ b/src/contract/aux_/macros/code_function.hpp @@ -0,0 +1,158 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_FUNCTION_HPP_ +#define CONTRACT_AUX_CODE_FUNCTION_HPP_ + +#include "code_/kind.hpp" +#include "code_/body.hpp" +#include "code_/contract_class.hpp" +#include "code_/postcondition.hpp" +#include "code_/precondition.hpp" +#include "code_/contracted_function.hpp" +#include "code_/static_validate.hpp" +#include "../preprocessor/sign/class.hpp" +#include "../preprocessor/sign/postcondition.hpp" +#include "../preprocessor/sign/body.hpp" +#include "../preprocessor/sign/access.hpp" +#include "../check01.hpp" +#include + +// WORKAROUND: Commas in Macro Parameters +// This code works around preprocessor limitation of not handling +// commas within macros using the `IF(... TUPLE_EAT(1))(sign)` below. +// Note that all code blocks, contract class definitions, etc can +// contain commas not wrapped within () so the work around is needed. + +// WORKAROUND: typename/template Outside Templates +// C++ requires using typname/template to explicitely specify types +// when compiler cannot deduce them in templates but this explicit +// type specification is not allowed outside templates. For example, +// this is the case for `arg<>::type` which must be +// `typename arg<>::type` in templates, and `function::member<>` which +// must be `function::template member<>` in templates (this could +// have been avoided by not making `member` a nested type but for +// `arg` typename must be specified). Earlier version of the library +// required the user to specify `(template)` before `(class)` so the +// library knew when to use typename/template specification. In order +// to avoid asking the user to specify the additional `(template)` +// (which is strange because it does not require the actual class +// template parameters...) a workaround has been implemented which +// makes the pre/post condition functions and contract class always +// templates using an artificial `UNUSED` template parameter so the +// typname/template specification can be used regardless of weather +// the contracted class type and/or function are a template or not. +// * All the workaround code is marked by a special comment. +// * Does making the contract class and pre/post condition function +// always templates affect negatively compile-time performances? + +// CANNOT USE STATIC NON-MEMBER +// For non-member functions is NOT possible to make the non-member +// contract functions static to to contraint their use within the +// translation unit because this use of static for non-members is +// obsolete in C++ (i.e., still supported by the language but +// encouraged to not use it -- see [Stroustrup1997]). +// The contract class could instead be defined within the contracted +// non-member function code block so to limit its scope however some +// compilers do not fully support class declarations within code +// blocks. +// The contract class, precondition, postcondition, and body function +// are therefore declared and defined at same scope as the contracted +// function but their names are `contract_..._` so users should not +// use them directly. + +#define CONTRACT_AUX_CODE_FUNCTION(kind, sign) \ + /* original function signature here */ \ +\ + /* contracted function definition */ \ + BOOST_PP_IF(CONTRACT_AUX_CHECK_CLASS_01, \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + CONTRACT_AUX_CODE_CONTRACTED_FUNCTION_MEMBER /* block */ \ + , /* else */ \ + /* non-member deferr definition because of restricted */ \ + /* visibility rules outside class scope */ \ + ; /* deferred definition (see later below) */ \ + BOOST_PP_TUPLE_EAT(2) \ + )(kind, sign) \ + BOOST_PP_TUPLE_EAT(1) \ + , /* else */ \ + /* original body definition if contract off */ \ + CONTRACT_AUX_PP_SIGN_BODY \ + )(sign) \ +\ + /* pre/post conditions are private but access level changed */ \ + /* only for members, plus non-members cannot be static func */ \ + /* because func ptr template parameters need external linkage */ \ +\ + /* preconditions (but no for destructor) */ \ + BOOST_PP_IF(BOOST_PP_AND(CONTRACT_AUX_CHECK_PRECONDITION_01, \ + BOOST_PP_NOT(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR))), \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + private: \ + ) /* endif */ \ + CONTRACT_AUX_CODE_PRECONDITION /* sign and block */ \ + , /* else */ \ + BOOST_PP_TUPLE_EAT(2) \ + )(kind, sign) \ +\ + /* postconditions (but no for destructor) */ \ + BOOST_PP_IF(BOOST_PP_AND(CONTRACT_AUX_CHECK_POSTCONDITION_01, \ + BOOST_PP_NOT(BOOST_PP_EQUAL(kind, \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR))), \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + private: \ + ) /* endif */ \ + CONTRACT_AUX_CODE_POSTCONDITION /* sign and block */ \ + , /* else */ \ + BOOST_PP_TUPLE_EAT(2) \ + )(kind, sign) \ +\ + /* body -- must be defined before contract class for */ \ + /* typename/template workaround */ \ + BOOST_PP_IF(CONTRACT_AUX_CHECK_CLASS_01, \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + protected: /* must be protected for subcontracting */ \ + ) \ + CONTRACT_AUX_CODE_BODY /* sign and block */ \ + , /* else */ \ + BOOST_PP_TUPLE_EAT(2) \ + )(kind, sign) \ +\ + /* contract class definition */ \ + BOOST_PP_IF(CONTRACT_AUX_CHECK_CLASS_01, \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign), \ + protected: /* must be protected for subcontracting */ \ + ) \ + CONTRACT_AUX_CODE_CONTRACT_CLASS \ + , /* else */ \ + BOOST_PP_TUPLE_EAT(2) \ + )(kind, sign) \ +\ + /* restore original access level (for members only */ \ + BOOST_PP_EXPR_IF(BOOST_PP_AND(CONTRACT_AUX_CHECK_CLASS_01, \ + CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign)), \ + CONTRACT_AUX_PP_SIGN_ACCESS(sign): /* `:` for access */ \ + ) \ +\ + /* non-member contracted function separated definition */ \ + BOOST_PP_IF(BOOST_PP_AND(CONTRACT_AUX_CHECK_CLASS_01, \ + BOOST_PP_NOT(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER( \ + sign))), \ + /* macro expasion delayed to handle tparams commas */ \ + CONTRACT_AUX_CODE_CONTRACTED_FUNCTION_NON_MEMBER \ + , /* else */ \ + BOOST_PP_TUPLE_EAT(2) \ + )(kind, sign) \ +\ + /* compile-time (after preprocessing) signature validation */ \ + BOOST_PP_IF(CONTRACT_AUX_CHECK_CLASS_01, \ + CONTRACT_AUX_CODE_STATIC_VALIDATE \ + , \ + BOOST_PP_TUPLE_EAT(2) \ + )(kind, sign) /* delay expansion because validate can return nothing */ \ + +#endif // #include guard + diff --git a/src/contract/aux_/macros/code_invariant.hpp b/src/contract/aux_/macros/code_invariant.hpp new file mode 100755 index 00000000..57ec9738 --- /dev/null +++ b/src/contract/aux_/macros/code_invariant.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_CODE_INVARIANT_HPP_ +#define CONTRACT_AUX_CODE_INVARIANT_HPP_ + +#include "../../config.hpp" +#include "../check01.hpp" +#include + +#define CONTRACT_AUX_CODE_INVARIANT( \ + static_invariants_code_block, invariants_code_block) \ + /* assumes within a private section of a class */ \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_CHECK_CLASS_01, \ + /* friendship needed for object access */ \ + friend class ::contract::state; \ + mutable ::contract::state CONTRACT_CONFIG_STATE_VARIABLE_; \ + ) /* endif check any */ \ + BOOST_PP_EXPR_IF(CONTRACT_AUX_CHECK_CLASS_INVARIANT_01, \ + static void CONTRACT_CONFIG_STATIC_INVARIANT_FUNCTION_() \ + static_invariants_code_block \ + void CONTRACT_CONFIG_INVARIANT_FUNCTION_() const \ + invariants_code_block \ + ) /* endif check invariants */ + +#endif // #include guard + diff --git a/src/contract/aux_/macros/function.hpp b/src/contract/aux_/macros/function.hpp new file mode 100755 index 00000000..568cadbc --- /dev/null +++ b/src/contract/aux_/macros/function.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_FUNCTION_HPP_ +#define CONTRACT_AUX_FUNCTION_HPP_ + +#include "code_function.hpp" +#include "code_/static_error.hpp" +#include "code_/kind.hpp" +#include "../preprocessor/sign/parse_function.hpp" +#include "../preprocessor/sign/parse_constructor.hpp" +#include "../preprocessor/sign/parse_destructor.hpp" +#include + +#define CONTRACT_AUX_FUNCTION(seq) \ + CONTRACT_AUX_FUNCTION_PARSED_( \ + CONTRACT_AUX_CODE_KIND_FUNCTION, \ + CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION(seq)) + +#define CONTRACT_AUX_CONSTRUCTOR(seq) \ + CONTRACT_AUX_FUNCTION_PARSED_( \ + CONTRACT_AUX_CODE_KIND_CONSTRUCTOR, \ + CONTRACT_AUX_PP_SIGN_PARSE_CONSTRUCTOR(seq)) + +#define CONTRACT_AUX_DESTRUCTOR(seq) \ + CONTRACT_AUX_FUNCTION_PARSED_( \ + CONTRACT_AUX_CODE_KIND_DESTRUCTOR, \ + CONTRACT_AUX_PP_SIGN_PARSE_DESTRUCTOR(seq)) + +// Above intentionaly #defined before FUNCTION_PARSED_() to force +// single expansiion of PARSE_FUNCTION() + +#define CONTRACT_AUX_FUNCTION_OK_(kind, seq_sign_err) \ + CONTRACT_AUX_CODE_FUNCTION(kind, \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)) + +#define CONTRACT_AUX_FUNCTION_ERR_(kind, seq_sign_err) \ + CONTRACT_AUX_CODE_STATIC_ERROR(BOOST_PP_TUPLE_ELEM(2, 1, \ + BOOST_PP_TUPLE_ELEM(3, 2, seq_sign_err))) + +#define CONTRACT_AUX_FUNCTION_PARSED_(kind, seq_sign_err) \ + BOOST_PP_IF(BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_TUPLE_ELEM( \ + 3, 2, seq_sign_err)), \ + CONTRACT_AUX_FUNCTION_ERR_ /* expand to error */ \ + , /* else */ \ + CONTRACT_AUX_FUNCTION_OK_ /* expand to code */ \ + )(kind, seq_sign_err) + +#endif // #include guard + diff --git a/src/contract/aux_/macros/invariant.hpp b/src/contract/aux_/macros/invariant.hpp new file mode 100755 index 00000000..fffd2b5a --- /dev/null +++ b/src/contract/aux_/macros/invariant.hpp @@ -0,0 +1,67 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_INVARIANT_HPP_ +#define CONTRACT_AUX_INVARIANT_HPP_ + +#include "code_invariant.hpp" +#include "code_/static_error.hpp" +#include "../preprocessor/keyword/is_static.hpp" +#include + +// Seq size 3 for: CONTRACT_INVARIANT( +// (static)(static_invariants_code_block) (invariants_code_block) ) +#define CONTRACT_AUX_INVARIANT_3(seq) \ + BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_STATIC( \ + BOOST_PP_SEQ_ELEM(0, seq)), \ + CONTRACT_AUX_CODE_INVARIANT \ + , /* else */ \ + CONTRACT_AUX_CODE_STATIC_ERROR(CONTRACT_ERROR_expected_static_keyword_as_1st_parameter_of_invariant_definition) \ + BOOST_PP_TUPLE_EAT(2) \ + ) /* endif */ ( \ + BOOST_PP_SEQ_ELEM(1, seq), /* static invariants */ \ + BOOST_PP_SEQ_ELEM(2, seq) /* invariants */ \ + ) + +// Seq size 2 for: CONTRACT_INVARIANT( +// (static)(static_invariants_code_block) ) +#define CONTRACT_AUX_INVARIANT_2(seq) \ + BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_STATIC( \ + BOOST_PP_SEQ_ELEM(0, seq)), \ + CONTRACT_AUX_CODE_INVARIANT \ + , /* else */ \ + CONTRACT_AUX_CODE_STATIC_ERROR(CONTRACT_ERROR_expected_static_keyword_as_1st_parameter_of_invariant_definition) \ + BOOST_PP_TUPLE_EAT(2) \ + ) /* endif */ ( \ + BOOST_PP_SEQ_ELEM(1, seq), /* static invariants */ \ + {} /* invariants */ \ + ) + +// Seq size 1 for: CONTRACT_INVARIANT( (invariants_code_block) ) +#define CONTRACT_AUX_INVARIANT_1(seq) \ + CONTRACT_AUX_CODE_INVARIANT( \ + {}, /* static invariants */ \ + BOOST_PP_SEQ_ELEM(0, seq) /* invariants */ \ + ) + +// Seq size 0 for: CONTRACT_INVARIANT( ) -- only C99 or later version. +#define CONTRACT_AUX_INVARIANT_0(seq) \ + CONTRACT_AUX_CODE_INVARIANT( \ + {}, /* static invariants */ \ + {} /* invariants */ \ + ) + +#define CONTRACT_AUX_INVARIANT(seq) \ + /* Handles seq size 0 but that only works on C99 or later. */ \ + BOOST_PP_IF(BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE(seq), 3), \ + CONTRACT_AUX_CODE_STATIC_ERROR(CONTRACT_ERROR_too_many_parameters_in_invariant_definition) \ + BOOST_PP_TUPLE_EAT(1) \ + , /* else */ \ + BOOST_PP_CAT(CONTRACT_AUX_INVARIANT_, \ + BOOST_PP_SEQ_SIZE(seq)) \ + ) /* endif */ (seq) + +#endif // #include guard + diff --git a/src/contract/aux_/old.hpp b/src/contract/aux_/old.hpp new file mode 100755 index 00000000..5ecd5012 --- /dev/null +++ b/src/contract/aux_/old.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_OLD_HPP_ +#define CONTRACT_AUX_OLD_HPP_ + +#include "../old.hpp" +#include +#include +#include + +namespace contract { namespace aux { + +// Old // + +template struct old { typedef noold type; }; +template struct old< copyable > { typedef T type; }; + +// Copyable // + +template struct remove_copyable { typedef T type; }; +template struct remove_copyable< copyable > + { typedef T type; }; + +template struct is_copyable: boost::mpl::false_ {}; +template struct is_copyable< copyable >: + boost::mpl::true_ {}; + +template struct copyable_add_pointer + { typedef typename boost::add_pointer::type type; }; +template struct copyable_add_pointer< copyable > + { typedef copyable::type> type; }; + +}} // namespace + +#endif // #include guard diff --git a/src/contract/aux_/preprocessor/README.txt b/src/contract/aux_/preprocessor/README.txt new file mode 100755 index 00000000..f908c014 --- /dev/null +++ b/src/contract/aux_/preprocessor/README.txt @@ -0,0 +1 @@ +Preprocessor tools internally used by the library. diff --git a/src/contract/aux_/preprocessor/keyword/README.txt b/src/contract/aux_/preprocessor/keyword/README.txt new file mode 100755 index 00000000..4efc70a7 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/README.txt @@ -0,0 +1 @@ +Preprocessor macros to check if token is a keyword. diff --git a/src/contract/aux_/preprocessor/keyword/check_.hpp b/src/contract/aux_/preprocessor/keyword/check_.hpp new file mode 100755 index 00000000..98826e57 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/check_.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_CHECK_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_CHECK_HPP_ + +// IMPORTANT: The contents of this file are implementation specific +// and they should NOT be used from files outside the ones in this +// directory. + +#include + +// From the Boost mailing list, P. Mensonides (author of +// Boost.Preprocessor) mentioned that BOOST_PP_IS_UNARY is in +// "detail/" because it does not work with older versions of the +// Borland C++ compiler. Technically, this is part of the private API +// of Boost.Preprocessor (and it should not be used) but also +// P. Mensonides suggests to use this macro if its functionality were +// needed (as the macro is defined to be work on different compilers +// as much as possible) keeping in mind that it might not work on +// some compilers, like older Borland, that do not fully implement +// the C++ preprocessor ISO standard. This library uses this macro. +#include + +// Expand to true iff keyword_prefix ## token is #defined. +#define CONTRACT_AUX_PP_KEYWORD_CHECK(keyword_prefix, token) \ + BOOST_PP_IS_UNARY(BOOST_PP_CAT(keyword_prefix, token)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_body.hpp b/src/contract/aux_/preprocessor/keyword/is_body.hpp new file mode 100755 index 00000000..6bcacd25 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_body.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_BODY_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_BODY_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_BODY_body (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_BODY(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_BODY_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_class.hpp b/src/contract/aux_/preprocessor/keyword/is_class.hpp new file mode 100755 index 00000000..f55a5139 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_class.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_CLASS_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_CLASS_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_CLASS_class (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_CLASS(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_CLASS_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_const.hpp b/src/contract/aux_/preprocessor/keyword/is_const.hpp new file mode 100755 index 00000000..cdd19b2a --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_const.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_CONST_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_CONST_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_CONST_const (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_CONST(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_CONST_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_copyable.hpp b/src/contract/aux_/preprocessor/keyword/is_copyable.hpp new file mode 100755 index 00000000..c5e6dfa2 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_copyable.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_COPYABLE_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_COPYABLE_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_COPYABLE_copyable (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_COPYABLE(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_COPYABLE_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_inherit.hpp b/src/contract/aux_/preprocessor/keyword/is_inherit.hpp new file mode 100755 index 00000000..53b75999 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_inherit.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_INHERIT_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_INHERIT_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_INHERIT_inherit (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_INHERIT(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_INHERIT_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_operator.hpp b/src/contract/aux_/preprocessor/keyword/is_operator.hpp new file mode 100755 index 00000000..665743ca --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_operator.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_OPERATOR_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_OPERATOR_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_OPERATOR_operator (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_OPERATOR(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_OPERATOR_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_postcondition.hpp b/src/contract/aux_/preprocessor/keyword/is_postcondition.hpp new file mode 100755 index 00000000..cbe40afc --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_postcondition.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_POSTCONDITION_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_POSTCONDITION_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_POSTCONDITION_postcondition (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_POSTCONDITION(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_POSTCONDITION_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_precondition.hpp b/src/contract/aux_/preprocessor/keyword/is_precondition.hpp new file mode 100755 index 00000000..98ec40e0 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_precondition.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_PRECONDITION_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_PRECONDITION_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_PRECONDITION_precondition (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_PRECONDITION(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_PRECONDITION_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_private.hpp b/src/contract/aux_/preprocessor/keyword/is_private.hpp new file mode 100755 index 00000000..6fb5d5e6 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_private.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_PRIVATE_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_PRIVATE_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_PRIVATE_private (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_PRIVATE(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_PRIVATE_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_protected.hpp b/src/contract/aux_/preprocessor/keyword/is_protected.hpp new file mode 100755 index 00000000..69a2b2e4 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_protected.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_PROTECTED_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_PROTECTED_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_PROTECTED_protected (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_PROTECTED(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_PROTECTED_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_public.hpp b/src/contract/aux_/preprocessor/keyword/is_public.hpp new file mode 100755 index 00000000..42efdfad --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_public.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_PUBLIC_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_PUBLIC_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_PUBLIC_public (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_PUBLIC(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_PUBLIC_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_static.hpp b/src/contract/aux_/preprocessor/keyword/is_static.hpp new file mode 100755 index 00000000..ecf42ff4 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_static.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_STATIC_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_STATIC_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_STATIC_static (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_STATIC(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_STATIC_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_template.hpp b/src/contract/aux_/preprocessor/keyword/is_template.hpp new file mode 100755 index 00000000..be454700 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_template.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_TEMPLATE_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_TEMPLATE_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_TEMPLATE_template (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_TEMPLATE(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_TEMPLATE_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_virtual.hpp b/src/contract/aux_/preprocessor/keyword/is_virtual.hpp new file mode 100755 index 00000000..cf617ec0 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_virtual.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_VIRTUAL_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_VIRTUAL_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_VIRTUAL_virtual (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_VIRTUAL(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_VIRTUAL_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/keyword/is_void.hpp b/src/contract/aux_/preprocessor/keyword/is_void.hpp new file mode 100755 index 00000000..f85364d7 --- /dev/null +++ b/src/contract/aux_/preprocessor/keyword/is_void.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_KEYWORD_IS_VOID_HPP_ +#define CONTRACT_AUX_PP_KEYWORD_IS_VOID_HPP_ + +#include "check_.hpp" + +// Do NOT #undef this macro (mixed capital because postfix must match +// keyword, but not a local macro). The 1 can be any non-empty token. +#define CONTRACT_AUX_PP_KEYWORD_VOID_void (1) + +#define CONTRACT_AUX_PP_KEYWORD_IS_VOID(token) \ + CONTRACT_AUX_PP_KEYWORD_CHECK( \ + CONTRACT_AUX_PP_KEYWORD_VOID_, token) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/seq.hpp b/src/contract/aux_/preprocessor/seq.hpp new file mode 100755 index 00000000..3f330929 --- /dev/null +++ b/src/contract/aux_/preprocessor/seq.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SEQ_HPP_ +#define CONTRACT_AUX_PP_SEQ_HPP_ + +#include + +// Sequence manipulation in addition to Boost.Preprocessor ones. + +// Return element in the back. +#define CONTRACT_AUX_PP_SEQ_BACK(seq) \ + BOOST_PP_SEQ_ELEM(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(seq), 1), seq) + +// Conver last n elements of specified sequence into a tuple and +// conactenates it with first n elements for +// (t0)...(tn-2)( (tn-1, tn) ) (to support (copyable, type) ). +#define CONTRACT_AUX_PP_SEQ_REST_N_TO_TUPLE_(n, seq) \ + /* sequence of first n elems (t0)...(tn-2) */ \ + BOOST_PP_SEQ_FIRST_N(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(seq), n), \ + seq) \ + /* concatenate with tuple from last n elems ( (tn-1, tn) ) */ \ + ( BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_REST_N(BOOST_PP_SUB( \ + BOOST_PP_SEQ_SIZE(seq), n), seq)) ) + + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/README.txt b/src/contract/aux_/preprocessor/sign/README.txt new file mode 100755 index 00000000..40037b2c --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/README.txt @@ -0,0 +1 @@ +Preprocessor signature. diff --git a/src/contract/aux_/preprocessor/sign/access.hpp b/src/contract/aux_/preprocessor/sign/access.hpp new file mode 100755 index 00000000..fece9f88 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/access.hpp @@ -0,0 +1,31 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_ACCESS_HPP_ +#define CONTRACT_AUX_PP_SIGN_ACCESS_HPP_ + +#include "seq_.hpp" +#include "../keyword/is_private.hpp" +#include "../keyword/is_protected.hpp" +#include "../keyword/is_public.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_ACCESS(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_ACCESS_INDEX, sign) + +#define CONTRACT_AUX_PP_SIGN_IS_PRIVATE(sign) \ + CONTRACT_AUX_PP_KEYWORD_IS_PRIVATE_( \ + CONTRACT_AUX_PP_SIGN_ACCESS(sign)) + +#define CONTRACT_AUX_PP_SIGN_IS_PROTECTED(sign) \ + CONTRACT_AUX_PP_KEYWORD_IS_PROTECTED_( \ + CONTRACT_AUX_PP_SIGN_ACCESS(sign)) + +#define CONTRACT_AUX_PP_SIGN_IS_PUBLIC(sign) \ + CONTRACT_AUX_PP_KEYWORD_IS_PUBLIC( \ + CONTRACT_AUX_PP_SIGN_ACCESS(sign)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/arg.hpp b/src/contract/aux_/preprocessor/sign/arg.hpp new file mode 100755 index 00000000..a28dde1a --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/arg.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_ARG_HPP_ +#define CONTRACT_AUX_PP_SIGN_ARG_HPP_ + +#include + +// Utilities to inspect single argument trits. Used for both function +// arguments and function template parameters (called arguments). + +// arg := ([copyable] EMPTY, type EMPTY, name EMPTY) + +// Template parameters are never copyable... +#define CONTRACT_AUX_PP_SIGN_ARG_IS_COPYABLE(arg) \ + BOOST_PP_NOT(BOOST_PP_IS_EMPTY( \ + BOOST_PP_TUPLE_ELEM(3, 0, arg)(/* empand empty*/))) + +#define CONTRACT_AUX_PP_SIGN_ARG_TYPE(arg) \ + BOOST_PP_TUPLE_ELEM(3, 1, arg) \ + (/* expand empty (never empty, used to handle no arg) */) + +#define CONTRACT_AUX_PP_SIGN_ARG_NAME(arg) \ + BOOST_PP_TUPLE_ELEM(3, 2, arg) \ + (/* expand empty (never empty, used to handle no arg) */) + +// Argument enumeration. + +#define CONTRACT_AUX_PP_SIGN_ARG_ENUM_ARG_OP_(z, n, args_n_op) \ + BOOST_PP_TUPLE_ELEM(2, 1, args_n_op) /* operation macro */ \ + (z, n, \ + BOOST_PP_SEQ_ELEM(n, /* arg */ \ + BOOST_PP_TUPLE_ELEM(2, 0, args_n_op)) /* args */ \ + ) + +#define CONTRACT_AUX_PP_SIGN_ARG_ENUM_OP_(sign, \ + get_args_macro, op_arg_macro) \ + BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE(get_args_macro(sign)), \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM_ARG_OP_, \ + (get_args_macro(sign), op_arg_macro) ) + +/* Enumerate all argument applying op_arg_macro(z, n, argument). */ +#define CONTRACT_AUX_PP_SIGN_ARG_ENUM(sign, \ + has_args_macro, get_args_macro, op_arg_macro) \ + BOOST_PP_IF(has_args_macro(sign), \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM_OP_ \ + , \ + BOOST_PP_TUPLE_EAT(3) \ + )(sign, get_args_macro, op_arg_macro) + +#define CONTRACT_AUX_PP_SIGN_ARG_ENUM_TRAILING(sign, \ + has_args_macro, get_args_macro, op_arg_macro) \ + BOOST_PP_COMMA_IF(has_args_macro(sign)) \ + CONTRACT_AUX_PP_SIGN_ARG_ENUM(sign, \ + has_args_macro, get_args_macro, op_arg_macro) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/args.hpp b/src/contract/aux_/preprocessor/sign/args.hpp new file mode 100755 index 00000000..6652ad54 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/args.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_ARGS_HPP_ +#define CONTRACT_AUX_PP_SIGN_ARGS_HPP_ + +#include "arg.hpp" // #included here for caller to inspect single arg. +#include "seq_.hpp" +#include + +// You should get the args iff HAS_ARGS is true (otherwise you'll get +// a seq with 1 tuple with all empty +// ( (BOOST_PP_EMPTY, BOOST_PP_EMPTY, BOOST_PP_EMPTY) ) for no args). + +#define CONTRACT_AUX_PP_SIGN_ARGS(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_ARGS_INDEX, sign) + +#define CONTRACT_AUX_PP_SIGN_HAS_ARGS(f) \ + BOOST_PP_NOT(BOOST_PP_IS_EMPTY(BOOST_PP_TUPLE_ELEM(3, 2, \ + BOOST_PP_SEQ_HEAD(CONTRACT_AUX_PP_SIGN_ARGS(f))) \ + (/* exapnd emtpy */) )) + +// Expand in arg that can be inspected using macros in "arg.hpp". +#define CONTRACT_AUX_PP_SIGN_ARG(n, sign) \ + BOOST_PP_SEQ_ELEM(n, CONTRACT_AUX_PP_SIGN_ARGS(sign)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/base_types.hpp b/src/contract/aux_/preprocessor/sign/base_types.hpp new file mode 100755 index 00000000..49fc4dc7 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/base_types.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_BASE_TYPE_HPP_ +#define CONTRACT_AUX_PP_SIGN_BASE_TYPE_HPP_ + +#include "seq_.hpp" +#include + +// bases := ( (BOOST_PP_EMPTY) (base0) (base1) ... ) + +#define CONTRACT_AUX_PP_SIGN_HAS_BASES(sign) \ + /* size > 1 because 1st elem (EMPTY) always there */ \ + BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_ELEM( \ + CONTRACT_AUX_PP_SIGN_SEQ_BASE_TYPES_INDEX, sign)), 1) + +#define CONTRACT_AUX_PP_SIGN_BASE_TYPES(sign) \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_HAS_BASES(sign), \ + BOOST_PP_SEQ_TAIL /* skip leading (EMPTY) */ \ + , \ + BOOST_PP_TUPLE_EAT(1) /* return nothing */ \ + )(BOOST_PP_SEQ_ELEM( \ + CONTRACT_AUX_PP_SIGN_SEQ_BASE_TYPES_INDEX, sign)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/body.hpp b/src/contract/aux_/preprocessor/sign/body.hpp new file mode 100755 index 00000000..c1b7faf5 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/body.hpp @@ -0,0 +1,16 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_BODY_HPP_ +#define CONTRACT_AUX_PP_SIGN_BODY_HPP_ + +#include "seq_.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_BODY(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_BODY_INDEX, sign) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/class.hpp b/src/contract/aux_/preprocessor/sign/class.hpp new file mode 100755 index 00000000..9425bb95 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/class.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_CLASS_HPP_ +#define CONTRACT_AUX_PP_SIGN_CLASS_HPP_ + +#include "seq_.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_CLASS(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_CLASS_INDEX, sign) \ + (/* expand empty */) + +#define CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER(sign) \ + BOOST_PP_NOT(BOOST_PP_IS_EMPTY(CONTRACT_AUX_PP_SIGN_CLASS(sign))) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/class_type.hpp b/src/contract/aux_/preprocessor/sign/class_type.hpp new file mode 100755 index 00000000..236bc596 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/class_type.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_CLASS_TYPE_HPP_ +#define CONTRACT_AUX_PP_SIGN_CLASS_TYPE_HPP_ + +#include "seq_.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_CLASS_TYPE(sign) \ + BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_SEQ_ELEM( \ + CONTRACT_AUX_PP_SIGN_SEQ_CLASS_TYPE_INDEX, sign)) + +#define CONTRACT_AUX_PP_SIGN_CLASS_TYPE_IS_COPYABLE(sign) \ + BOOST_PP_NOT(BOOST_PP_IS_EMPTY( \ + BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_SEQ_ELEM( \ + CONTRACT_AUX_PP_SIGN_SEQ_CLASS_TYPE_INDEX, sign) \ + (/* expand empty */) ))) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/const.hpp b/src/contract/aux_/preprocessor/sign/const.hpp new file mode 100755 index 00000000..773430e9 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/const.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_CONST_HPP_ +#define CONTRACT_AUX_PP_SIGN_CONST_HPP_ + +#include "seq_.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_CONST(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_CONST_INDEX, sign) \ + (/* expand empty */) + +#define CONTRACT_AUX_PP_SIGN_IS_CONST(sign) \ + BOOST_PP_NOT(BOOST_PP_IS_EMPTY(CONTRACT_AUX_PP_SIGN_CONST(sign))) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/function_name.hpp b/src/contract/aux_/preprocessor/sign/function_name.hpp new file mode 100755 index 00000000..87beef21 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/function_name.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_HPP_ +#define CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_HPP_ + +#include "seq_.hpp" +#include "../keyword/is_operator.hpp" +#include + +// Handle special name `( operator (symbol, word) )` for operators. +// These are NOT local macros -- do NOT #undef them! Mixed case +// names are necesseray because they must be prefixed by "operator". + +#define CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_OP_WORD_operator( \ + symbol, word) \ + /* use ## instead of PP_CAT here for proper macro expansion */ \ + operator_ ## word /* e.g., operator_equal */ + +#define CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_OP_SYMBOL_operator( \ + symbol, word) \ + operator symbol /* e.g., operator== */ + +#define CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_WORD(name) \ + BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_OPERATOR(name), \ + /* CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_OP_WORD_operator() */ \ + BOOST_PP_CAT(CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_OP_WORD_, \ + name) \ + , /* else */ \ + name \ + ) /* endif */ + +#define CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_SYMBOLIC(name) \ + BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_OPERATOR(name), \ + /* CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_OP_SYMBOL_operator() */ \ + BOOST_PP_CAT(CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_OP_SYMBOL_, \ + name) \ + , /* else */ \ + name \ + ) /* endif */ + +#define CONTRACT_AUX_PP_SIGN_FUNCTION_NAME(sign) \ + CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_WORD(BOOST_PP_SEQ_ELEM( \ + CONTRACT_AUX_PP_SIGN_SEQ_FUNCTION_NAME_INDEX, sign)) + +#define CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_SYMBOL(sign) \ + CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_SYMBOLIC(BOOST_PP_SEQ_ELEM( \ + CONTRACT_AUX_PP_SIGN_SEQ_FUNCTION_NAME_INDEX, sign)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/function_template_args.hpp b/src/contract/aux_/preprocessor/sign/function_template_args.hpp new file mode 100755 index 00000000..2825e7e6 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/function_template_args.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_FUNCTION_TEMPLATE_ARGS_HPP_ +#define CONTRACT_AUX_PP_SIGN_FUNCTION_TEMPLATE_ARGS_HPP_ + +#include "arg.hpp" // #included here for caller to inspect single arg. +#include "seq_.hpp" +#include + +// You should get the args iff HAS_ARGS is true (otherwise you'll get +// a seq with 1 tuple with all empty +// ( (BOOST_PP_EMPTY, BOOST_PP_EMPTY, BOOST_PP_EMPTY) ) for no args). + +#define CONTRACT_AUX_PP_SIGN_FUNCTION_TEMPLATE_ARGS(sign) \ + BOOST_PP_SEQ_ELEM( \ + CONTRACT_AUX_PP_SIGN_SEQ_FUNCTION_TEMPLATE_ARGS_INDEX, \ + sign) + +#define CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS(f) \ + BOOST_PP_NOT(BOOST_PP_IS_EMPTY(BOOST_PP_TUPLE_ELEM(3, 2, \ + BOOST_PP_SEQ_HEAD( \ + CONTRACT_AUX_PP_SIGN_FUNCTION_TEMPLATE_ARGS(f))) \ + (/* exapnd emtpy */) )) + +// Expand in arg that can be inspected using macros in "arg.hpp". +#define CONTRACT_AUX_PP_SIGN_FUNCTION_TEMPLATE_ARG(n, sign) \ + BOOST_PP_SEQ_ELEM(n, \ + CONTRACT_AUX_PP_SIGN_FUNCTION_TEMPLATE_ARGS(sign)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/README.txt b/src/contract/aux_/preprocessor/sign/parse_/README.txt new file mode 100755 index 00000000..53027824 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/README.txt @@ -0,0 +1 @@ +Preprocessor signature parsing. diff --git a/src/contract/aux_/preprocessor/sign/parse_/access.hpp b/src/contract/aux_/preprocessor/sign/parse_/access.hpp new file mode 100755 index 00000000..18c23109 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/access.hpp @@ -0,0 +1,76 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_ACCESS_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_ACCESS_HPP_ + +#include "utility/apply.hpp" +#include "utility/returns.hpp" +#include "../../keyword/is_private.hpp" +#include "../../keyword/is_protected.hpp" +#include "../../keyword/is_public.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_ACCESS_OP_( \ + seq_sign_err, data) /**/ \ + BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_PRIVATE( \ + BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err)), (private) ) \ + , BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_PROTECTED( \ + BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err)), (protected) ) \ + , BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_PUBLIC( \ + BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err)), (public) ) \ + , /* else (error) */ \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, \ + /* no valid access given */ \ + seq_sign_err)), (BOOST_PP_EMPTY), \ + CONTRACT_ERROR_given_invalid_access_specifier_where_private_protected_or_public_expected) /* Invalid token is BOOST_PP_STRINGIZE(BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err))) */ \ + ))) /* end if */ + +#define CONTRACT_AUX_PP_SIGN_PARSE_ACCESS_ERR_( \ + seq_sign_err, data) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + (BOOST_PP_EMPTY) /* no valid access given */, \ + CONTRACT_ERROR_missing_access_specifier_where_private_protected_or_public_expected) + +#define CONTRACT_AUX_PP_SIGN_PARSE_ACCESS(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY( \ + CONTRACT_AUX_PP_SIGN_PARSE_ACCESS_OP_, \ + CONTRACT_AUX_PP_SIGN_PARSE_ACCESS_ERR_, \ + seq_sign_err, ~) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_ACCESS(seq_sign_err) \ + /* macro */ \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)), \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS \ + ) /* endif */ \ + /* params */ \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)), \ + ( BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + (BOOST_PP_EMPTY), \ + CONTRACT_ERROR_class_member_must_specify_private_protected_or_public_access ) \ + , /* else */ \ + ( (BOOST_PP_EMPTY), seq_sign_err ) \ + ) /* endif */ + +#endif // #include guar + diff --git a/src/contract/aux_/preprocessor/sign/parse_/args.hpp b/src/contract/aux_/preprocessor/sign/parse_/args.hpp new file mode 100755 index 00000000..edecee13 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/args.hpp @@ -0,0 +1,287 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_ARGS_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_HPP_ + +#include "utility/required.hpp" +#include "../../keyword/is_void.hpp" +#include "../../keyword/is_copyable.hpp" +#include + +// The arg traits is represented as 1 sequence element containing a +// sequence of 3-tuples (this requires a lot of parenthesis...): +// /* 1 seq elem */ ( /*seq inside the 1 seq*/ ( +// /* tuple */ ( arg-copyalbe +// BOOST_PP_EMPTY, arg-type BOOST_PP_EMPTY, arg-name BOOST_PP_EMPTY) +// ( (c, t, n) ) ( (c, t, n) ) ... +// ( (BOOST_PP_EMPTY, BOOST_PP_EMPTY, BOOST_PP_EMPTY) ) +// /* trailing tuple */ ) /* seq inside 1 seq */ ) /* 1 seq elem */ +// The trailing 3-tuple with all BOOST_PP_EMPTY is used to handle +// no-arguments (or "void-arguments" as in "(f)( (void) )" ). Because +// the arg-name is used to identify void-arguments, the arg-name of +// all arguments must end with BOOST_PP_EMPTY also. +// (This is very difficult to follow... _maybe_ PP_ARRAY could be +// used to simply this?? array size 0 means no arguments, size 1 +// there is one array element that is the 3-tuple, etc??) + +// Non-Copyable Argument // + +#define CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_ARG_OP_( \ + seq_sign_err_for_args) \ + /* got here only is args seq size >= 2 */ \ + BOOST_PP_IF(BOOST_PP_IS_EMPTY(BOOST_PP_SEQ_ELEM(0, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args))), \ + ( (BOOST_PP_EMPTY), (BOOST_PP_EMPTY), \ + (1, CONTRACT_ERROR_given_empty_function_argument_type)) /* in BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args)) */ \ + , BOOST_PP_IF(BOOST_PP_IS_EMPTY(BOOST_PP_SEQ_ELEM(1, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args))), \ + ( (BOOST_PP_EMPTY), (BOOST_PP_EMPTY), \ + (1, CONTRACT_ERROR_given_empty_function_argument_name)) /* in BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args)) */\ + , /* else */ \ + ( /* remove first 2 (type)(name) and continue */ \ + BOOST_PP_SEQ_REST_N(2, BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err_for_args)) \ + , BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err_for_args) \ + /* seq concat */ \ + ( BOOST_PP_SEQ_TO_TUPLE( \ + ( BOOST_PP_EMPTY ) /* ',' */ \ + ( BOOST_PP_SEQ_ELEM(0, BOOST_PP_TUPLE_ELEM(3, 0, \ + /* type */ \ + seq_sign_err_for_args)) BOOST_PP_EMPTY ) \ + ( BOOST_PP_SEQ_ELEM(1, BOOST_PP_TUPLE_ELEM(3, 0, \ + /* name */ \ + seq_sign_err_for_args)) BOOST_PP_EMPTY ) \ + ) /* tuple (EMPTY, type, name) */ \ + ) /* seq ( (EMPTY, type, name) ) */ \ + , (0, "") /* no error */ ) \ + )) /* end if */ + +#define CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_ARG_( \ + seq_sign_err_for_args) \ + BOOST_PP_IF(BOOST_PP_LESS(BOOST_PP_SEQ_SIZE( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args)), \ + 2), \ + ( (BOOST_PP_EMPTY), (BOOST_PP_EMPTY), \ + (1, CONTRACT_ERROR_missing_function_argument_type_or_name)) /* but only these given BOOST_PP_STRINGIZE(BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args))) "given as" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args)) */ \ + BOOST_PP_TUPLE_EAT(1) \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_ARG_OP_ \ + )(seq_sign_err_for_args) /* end if */ + +// Copyable Argumnet // + +#define CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_ARG_OP_( \ + seq_sign_err_for_args) \ + /* got here only is args seq size >= 3 */ \ + /* and elem 0 is (copyable) tag */ \ + /* SEQ_TAIL used below to hide copyable tag from err msg */ \ + BOOST_PP_IF(BOOST_PP_IS_EMPTY(BOOST_PP_SEQ_ELEM(1, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args))), \ + ( (BOOST_PP_EMPTY), (BOOST_PP_EMPTY), \ + (1, CONTRACT_ERROR_given_empty_funtion_argument_type)) /* in BOOST_PP_STRINGIZE(BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args))) */ \ + , BOOST_PP_IF(BOOST_PP_IS_EMPTY(BOOST_PP_SEQ_ELEM(2, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args))), \ + ( (BOOST_PP_EMPTY), (BOOST_PP_EMPTY), \ + (1, CONTRACT_ERROR_given_empty_funtion_argument_name)) /* in BOOST_PP_STRINGIZE(BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args)))*/ \ + , /* else */ \ + ( /* remove first 3 (copyable)(type)(name) and cont */ \ + BOOST_PP_SEQ_REST_N(3, BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err_for_args)) \ + , BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err_for_args) \ + /* seq concat */ \ + ( BOOST_PP_SEQ_TO_TUPLE( \ + (copyable BOOST_PP_EMPTY) /* copyable */ \ + ( BOOST_PP_SEQ_ELEM(1, BOOST_PP_TUPLE_ELEM(3, 0, \ + /* type */ \ + seq_sign_err_for_args)) BOOST_PP_EMPTY ) \ + ( BOOST_PP_SEQ_ELEM(2, BOOST_PP_TUPLE_ELEM(3, 0, \ + /* name */ \ + seq_sign_err_for_args)) BOOST_PP_EMPTY ) \ + ) /* tuple (copyable, type, name) */ \ + ) /* seq ( (copyable, type, name) ) */ \ + , (0, "") /* no error */ ) \ + )) /* end if */ + +#define CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_ARG_( \ + seq_sign_err_for_args) \ + BOOST_PP_IF(BOOST_PP_LESS(BOOST_PP_SEQ_SIZE( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args)), \ + 3), \ + ( (BOOST_PP_EMPTY), (BOOST_PP_EMPTY), \ + (1, CONTRACT_ERROR_missing_function_argument_type_or_name_for_copyable_type)) /* but only these given BOOST_PP_STRINGIZE(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args)), 1)) "given as" BOOST_PP_STRINGIZE(BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err_for_args))) */ \ + BOOST_PP_TUPLE_EAT(1) \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_ARG_OP_ \ + )(seq_sign_err_for_args) /* end if */ + +// Arguments Loop // + +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_LOOP_PRED_( \ + d, seq_sign_err_for_args) \ + /* size > 1, skip trailing (PP_EMPTY) (to avoid empty seq) */ \ + BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err_for_args)), 1) + +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_COPYABLE_LOOP_OP_( \ + d, seq_sign_err_for_args) \ + BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_COPYABLE( \ + BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err_for_args))), \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_ARG_ \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_ARG_ \ + )(seq_sign_err_for_args) /* end if */ + +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_NONCOPYABLE_LOOP_OP_( \ + d, seq_sign_err_for_args) \ + BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_COPYABLE( \ + BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err_for_args))), \ + ( (BOOST_PP_EMPTY), (BOOST_PP_EMPTY), \ + (1, CONTRACT_ERROR_argument_cannot_be_tagged_copyable_in_this_context)) \ + BOOST_PP_TUPLE_EAT(1) \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_ARG_ \ + )(seq_sign_err_for_args) /* end if */ + +// Helpers // + +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_RETURN_(seq_sign_err, \ + seq_sign_err_for_args, max_args) \ + BOOST_PP_IF(BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_TUPLE_ELEM(3, 2, \ + seq_sign_err_for_args)), /* error */ \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_SEQ_TAIL( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), \ + (BOOST_PP_EMPTY) /* empty seq elem on error */, \ + BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_TUPLE_ELEM(3, 2, \ + seq_sign_err_for_args))) \ + , BOOST_PP_IF(BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err_for_args)), \ + max_args), \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_SEQ_TAIL( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), \ + /* args seq that contains too many elems (error) */ \ + ( BOOST_PP_TUPLE_ELEM(3, 1, \ + seq_sign_err_for_args) ), \ + (1, CONTRACT_ERRPR_too_many_function_arguments)) \ + , /* else (no error) */ \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_SEQ_TAIL( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), \ + ( BOOST_PP_TUPLE_ELEM(3, 1, \ + seq_sign_err_for_args) ) \ + ) \ + )) /* end if */ + +// Parse some (one or more) arguments. +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_SOME_( \ + seq_sign_err, max_args, allow_copyable) \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_RETURN_(seq_sign_err, \ + BOOST_PP_WHILE(CONTRACT_AUX_PP_SIGN_PARSE_ARGS_LOOP_PRED_, \ + BOOST_PP_IF(allow_copyable, \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_COPYABLE_LOOP_OP_ \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_NONCOPYABLE_LOOP_OP_ \ + ), /* endif */ \ + /* init remaining arg sign */ \ + ( BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err)) (BOOST_PP_EMPTY) \ + , BOOST_PP_EMPTY() /* init parsed arg attrs seq */ \ + , (0, "") /* init no error */ ) \ + ) /* end while */ \ + , max_args) + +// Parse no (none) arguments. +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_NONE_( \ + seq_sign_err, max_args, allow_copyable) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_SEQ_TAIL( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), \ + /* all () needed, this is a 1-seq of seq of 3-typle */ \ + ( ( (BOOST_PP_EMPTY, BOOST_PP_EMPTY, BOOST_PP_EMPTY) ) ) \ + ) + +// Handle "(f)( (void) )" as no arguments. This syntax to specify no +// arguments is compliant with C++ standard and works on all +// compilers. +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_HANDLE_VOID_( \ + seq_sign_err, max_args, allow_copyable) \ + BOOST_PP_IF(CONTRACT_AUX_PP_KEYWORD_IS_VOID( \ + BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_HEAD( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)))), \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_NONE_ \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_SOME_ \ + )(seq_sign_err, max_args, allow_copyable) + +// Handle "(f)( )" as no arguments. This syntax to specify no +// arguments is NOT compliant with C++ standard and only with C99 +// standard (because it requires preprocessor to allow for empty +// sequences "()" and therefore for empty macro parameters). +// This library supports this syntax on compilers that accept empty +// sequences but "(f)( (void) )" is best used to ensure portability. +// You can disable support for this syntax "(f)( )" simply making +// PP_SIGN_PARSE_ARGS_ call PP_SIGN_PARSE_ARGS_HANDLE_VOID_ +// directly skipping the call to this macro. +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_HANDLE_EMPTY_( \ + seq_sign_err, max_n_copyable) \ + BOOST_PP_IF(BOOST_PP_NOT(BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_HEAD( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)))), \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_NONE_ \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_HANDLE_VOID_ \ + )( \ + seq_sign_err \ + , BOOST_PP_TUPLE_ELEM(2, 0, max_n_copyable) /* max_args */ \ + , BOOST_PP_TUPLE_ELEM(2, 1, max_n_copyable) /* allow cop. */ \ + ) + +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_NO_( \ + seq_sign_err, max_n_copyable) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + (/* empty seq elem in case of error */), \ + CONTRACT_ERROR_missing_function_arguments) + +// API // + +// Void and non-void args (void args are f(void)). +// To be standard compliant (f)() cannot be used because "()" is not +// legal. (f)( (void) ) should be used instead. However, this library +// also handels (f)() for these compilers (C99, etc) that support +// passing "()" macro params. +#define CONTRACT_AUX_PP_SIGN_PARSE_ARGS_(allow_copyable, max_args, \ + seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY( \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_HANDLE_EMPTY_, \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_NO_, \ + seq_sign_err, (max_args, allow_copyable) ) + +// Parse all arguments (could be empty, 1, 2, etc) allowing copyable. +#define CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_ARGS(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_( \ + 1, /* allow copyable (it's empty anyway...) */ \ + BOOST_PP_LIMIT_MAG, /* infinity (all args) */ \ + seq_sign_err) + +// Parse all arguments (could be empty, 1, 2, etc) none copyable. +#define CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_ARGS(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_( \ + 0, /* copyable not allowed (it's empty anyway...) */ \ + BOOST_PP_LIMIT_MAG, /* infinity (all args) */ \ + seq_sign_err) + +// Parse empty argumnets (must be f(void)). +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_ARGS(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_ARGS_( \ + 1, /* allow copyable (it's empty anyway...) */ \ + 0, /* no arg, must be (f)( (void) ) or (f)( ) */ \ + seq_sign_err) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/base_types.hpp b/src/contract/aux_/preprocessor/sign/parse_/base_types.hpp new file mode 100755 index 00000000..5ddb1b47 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/base_types.hpp @@ -0,0 +1,83 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_HPP_ + +#include "utility/apply.hpp" +#include "utility/returns.hpp" +#include "utility/required.hpp" +#include "utility/append_traits.hpp" +#include "../../keyword/is_inherit.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_REQUIRED_( \ + d, seq_sign_err) \ + BOOST_PP_IF(BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_TAIL( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err))), \ + /* now base must be there -- base option is now required */ \ + CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_OP \ + , /* else (no token left to parse in signature) */ \ + CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_NO \ + )( ( \ + BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err)) \ + , BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err) \ + , BOOST_PP_TUPLE_ELEM(3, 2, seq_sign_err) \ + ), \ + CONTRACT_ERROR_missing_base_class_type_for_inherit \ + ) /* endif */ + +#define CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_PRED_( \ + n, seq_sign_err) \ + CONTRACT_AUX_PP_KEYWORD_IS_INHERIT( \ + BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err))) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_WHILE_(seq_sign_err) \ + BOOST_PP_WHILE(CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_PRED_, \ + CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_REQUIRED_, \ + ( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err) \ + , (BOOST_PP_EMPTY) \ + , BOOST_PP_TUPLE_ELEM(3, 2, seq_sign_err) \ + ) ) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_APPEND_( \ + orig_seq_sign_err, bases_seq_sign_err) \ + ( \ + /* ramining seq from parsed bases */ \ + BOOST_PP_TUPLE_ELEM(3, 0, bases_seq_sign_err) \ + /* sign is original one plus (seq concat) bases one */ \ + , BOOST_PP_TUPLE_ELEM(3, 1, orig_seq_sign_err) \ + /* seq concat with base seq */ \ + ( BOOST_PP_TUPLE_ELEM(3, 1, bases_seq_sign_err) ) \ + /* err is from parsed bases */ \ + , BOOST_PP_TUPLE_ELEM(3, 2, bases_seq_sign_err) \ + ) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_OP_( \ + seq_sign_err, data) \ + CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_APPEND_(seq_sign_err, \ + CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_WHILE_(seq_sign_err)) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_NO_( \ + seq_sign_err, data) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + (BOOST_PP_EMPTY) /* empty seq elem if no token */) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY( \ + CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_OP_, \ + CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES_NO_, \ + seq_sign_err, ~) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_BASE_TYPES(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS( \ + ( (BOOST_PP_EMPTY) ), seq_sign_err) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/body.hpp b/src/contract/aux_/preprocessor/sign/parse_/body.hpp new file mode 100755 index 00000000..82622a07 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/body.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_BODY_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_BODY_HPP_ + +#include "../../keyword/is_body.hpp" +#include "utility/block.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_BODY(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_REQUIRED(seq_sign_err, \ + CONTRACT_AUX_PP_KEYWORD_IS_BODY, \ + 1, /* just one block (body_code_block) */ \ + CONTRACT_ERROR_missing_body_code_block, \ + BOOST_PP_EMPTY /* no other block error */ ) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/class.hpp b/src/contract/aux_/preprocessor/sign/parse_/class.hpp new file mode 100755 index 00000000..56a3ee52 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/class.hpp @@ -0,0 +1,17 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_CLASS_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_CLASS_HPP_ + +#include "utility/optional.hpp" +#include "../../keyword/is_class.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_CLASS(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL( \ + seq_sign_err, CONTRACT_AUX_PP_KEYWORD_IS_CLASS) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/class_type.hpp b/src/contract/aux_/preprocessor/sign/parse_/class_type.hpp new file mode 100755 index 00000000..d385fa57 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/class_type.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_CLASS_TYPE_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_CLASS_TYPE_HPP_ + +#include "utility/optional.hpp" +#include "utility/copyable.hpp" +#include "utility/match_not.hpp" +#include "utility/append_traits.hpp" +#include "utility/returns.hpp" +#include "../../keyword/is_template.hpp" +#include "../../keyword/is_copyable.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_CLASS_TYPE( \ + seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE( \ + seq_sign_err, \ + CONTRACT_ERROR_missing_class_type) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_CLASS_TYPE( \ + seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE( \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT( \ + CONTRACT_AUX_PP_KEYWORD_IS_COPYABLE, \ + CONTRACT_ERROR_class_type_cannot_be_tagged_copyable_in_this_context, \ + seq_sign_err), \ + CONTRACT_ERROR_missing_class_type) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_CLASS_TYPE(seq_sign_err) \ + /* macro */ \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)), \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS \ + ) /* endif */ \ + /* params */ \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)), \ + ( BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + ( (BOOST_PP_EMPTY, BOOST_PP_EMPTY) ), \ + CONTRACT_ERROR_class_member_must_specify_class_type ) \ + , /* else */ \ + ( ( (BOOST_PP_EMPTY, BOOST_PP_EMPTY) ), seq_sign_err ) \ + ) /* endif */ + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/const.hpp b/src/contract/aux_/preprocessor/sign/parse_/const.hpp new file mode 100755 index 00000000..27db7de3 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/const.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_CONST_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_CONST_HPP_ + +#include "utility/optional.hpp" +#include "utility/append_traits.hpp" +#include "utility/match_not.hpp" +#include "../../keyword/is_const.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_CONST(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL( \ + seq_sign_err, CONTRACT_AUX_PP_KEYWORD_IS_CONST) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_CONST(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS( (BOOST_PP_EMPTY), \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT( \ + CONTRACT_AUX_PP_KEYWORD_IS_CONST, \ + CONTRACT_ERROR_cannot_specify_constant_member_qualifier_in_this_context, \ + seq_sign_err)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/function_name.hpp b/src/contract/aux_/preprocessor/sign/parse_/function_name.hpp new file mode 100755 index 00000000..2d7e730b --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/function_name.hpp @@ -0,0 +1,16 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_NAME_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_NAME_HPP_ + +#include "utility/required.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_NAME(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED( \ + seq_sign_err, CONTRACT_ERROR_missing_function_name) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/postcondition.hpp b/src/contract/aux_/preprocessor/sign/parse_/postcondition.hpp new file mode 100755 index 00000000..6ad362d3 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/postcondition.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION_HPP_ + +#include "../../keyword/is_postcondition.hpp" +#include "../result_type.hpp" +#include "utility/block.hpp" +#include "utility/match_not.hpp" + +// If not specified defaults `result` and` {}` are used. In this case +// `result` (as any other name) can be used no name the result becase +// there is no postcondition code that uses it anyway. + +#define CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION_RESULT_( \ + seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_OPTIONAL(seq_sign_err, \ + CONTRACT_AUX_PP_KEYWORD_IS_POSTCONDITION, \ + 2, /* 2 blocks (result)(preconditions_code_block) */ \ + (result) ({}), /* default if not specified */ \ + CONTRACT_ERROR_missing_postcondition_code_block, \ + CONTRACT_ERROR_missing_postcondition_result_name) + +#define CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION_NORESULT_( \ + seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_OPTIONAL( \ + ( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err) \ + , BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err) \ + /* append EMPTY for result name */ \ + (result) /* default if not specified */ \ + , BOOST_PP_TUPLE_ELEM(3, 2, seq_sign_err) \ + ), \ + CONTRACT_AUX_PP_KEYWORD_IS_POSTCONDITION, \ + 1, /* 1 block (preconditions_code_block) */ \ + ({}), /* default if not specified */ \ + CONTRACT_ERROR_missing_postcondition_code_block, \ + BOOST_PP_EMPTY) + +#define CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION(seq_sign_err) \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_IS_VOID_RESULT( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)), \ + CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION_NORESULT_ \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION_RESULT_ \ + )(seq_sign_err) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_POSTCONDITION(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS( (BOOST_PP_EMPTY) ({}), \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT( \ + CONTRACT_AUX_PP_KEYWORD_IS_POSTCONDITION, \ + CONTRACT_ERROR_cannot_specify_postcondition_code_block, \ + seq_sign_err)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/precondition.hpp b/src/contract/aux_/preprocessor/sign/parse_/precondition.hpp new file mode 100755 index 00000000..19012610 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/precondition.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_PRECONDITION_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_PRECONDITION_HPP_ + +#include "../../keyword/is_precondition.hpp" +#include "utility/match_not.hpp" +#include "utility/block.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_PRECONDITION(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_OPTIONAL(seq_sign_err, \ + CONTRACT_AUX_PP_KEYWORD_IS_PRECONDITION, \ + 1, /* just one block (preconditions_code_block) */ \ + ( {} ), /* default if not specified */ \ + CONTRACT_ERROR_missing_precondition_code_block, \ + BOOST_PP_EMPTY /* no other block error */ ) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_PRECONDITION(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS( ({}), \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT( \ + CONTRACT_AUX_PP_KEYWORD_IS_PRECONDITION, \ + CONTRACT_ERROR_cannot_specify_precondition_code_block, \ + seq_sign_err)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/result_type.hpp b/src/contract/aux_/preprocessor/sign/parse_/result_type.hpp new file mode 100755 index 00000000..8518028e --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/result_type.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_RESULT_TYPE_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_RESULT_TYPE_HPP_ + +#include "utility/required.hpp" +#include "utility/append_traits.hpp" +#include "utility/match_not.hpp" +#include "../../keyword/is_void.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_RESULT_TYPE(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED( \ + seq_sign_err, CONTRACT_ERROR_missing_result_type) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_RESULT_TYPE(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS( (void), \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT( \ + CONTRACT_AUX_PP_KEYWORD_IS_VOID, \ + CONTRACT_ERROR_cannot_specify_result_type_not_even_void_within_this_context, \ + seq_sign_err)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/static.hpp b/src/contract/aux_/preprocessor/sign/parse_/static.hpp new file mode 100755 index 00000000..887db9d1 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/static.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_STATIC_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_STATIC_HPP_ + +#include "utility/optional.hpp" +#include "utility/append_traits.hpp" +#include "utility/match_not.hpp" +#include "../../keyword/is_static.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_STATIC(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL( \ + seq_sign_err, CONTRACT_AUX_PP_KEYWORD_IS_STATIC) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_STATIC(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS( (BOOST_PP_EMPTY), \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT( \ + CONTRACT_AUX_PP_KEYWORD_IS_STATIC, \ + CONTRACT_ERROR_cannot_specify_static_within_this_context, \ + seq_sign_err)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/template.hpp b/src/contract/aux_/preprocessor/sign/parse_/template.hpp new file mode 100755 index 00000000..ece48868 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/template.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_HPP_ + +#include "args.hpp" +#include "../../keyword/is_template.hpp" +#include "../../seq.hpp" +#include "utility/next.hpp" +#include "utility/match_not.hpp" +#include "utility/returns.hpp" + +// This code allows also for empty template args () or ( (void) ). +// This might be usefull for some template specializations... + +#define CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_ARGS_(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_ARGS( \ + /* skip leading (template) keyword */ \ + CONTRACT_AUX_PP_SIGN_PARSE_NEXT_SKIP(seq_sign_err)) + +#define CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_NO_(seq_sign_err) \ + /* not a template, return unchanged (seq, sign, err) */ \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + ( ( (BOOST_PP_EMPTY, BOOST_PP_EMPTY, BOOST_PP_EMPTY) ) ) \ + ) + +#define CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_ARGS(seq_sign_err) \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_PARSE_NEXT_IS_NOT( \ + seq_sign_err, CONTRACT_AUX_PP_KEYWORD_IS_TEMPLATE), \ + CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_NO_ \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_ARGS_ \ + )(seq_sign_err) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_TEMPLATE_ARGS(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS( \ + ( ( (BOOST_PP_EMPTY, BOOST_PP_EMPTY, BOOST_PP_EMPTY) ) ), \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT( \ + CONTRACT_AUX_PP_KEYWORD_IS_TEMPLATE, \ + CONTRACT_ERROR_cannot_specify_template_arguments_in_this_context, \ + seq_sign_err)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/README.txt b/src/contract/aux_/preprocessor/sign/parse_/utility/README.txt new file mode 100755 index 00000000..82717352 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/README.txt @@ -0,0 +1 @@ +Utilities for preprocessor signature parsing. diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/append_traits.hpp b/src/contract/aux_/preprocessor/sign/parse_/utility/append_traits.hpp new file mode 100755 index 00000000..b2c3ce92 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/append_traits.hpp @@ -0,0 +1,27 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS_HPP_ + +#include "apply.hpp" +#include "returns.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS_OP_( \ + seq_sign_err, traits_to_append) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + traits_to_append) + +#define CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS( \ + traits_to_append, seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY( \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS_OP_, \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS_OP_, \ + seq_sign_err, traits_to_append) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/apply.hpp b/src/contract/aux_/preprocessor/sign/parse_/utility/apply.hpp new file mode 100755 index 00000000..a3be3ae9 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/apply.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_APPLY_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_APPLY_HPP_ + +#include + +// Can't use BOOST_PP_IDENTITY() because trails with BOOST_PP_EMPTY. +#define CONTRACT_AUX_PP_SIGN_PARSE_APPLY_IDENTITY_( \ + seq_sign_err, data) \ + seq_sign_err + +// Token seq ends with (BOOST_PP_EMPTY) because C++ Standard does not +// allow empty seq "()" (some compilers are able to handle "()" but +// not all). The ending (BOOST_PP_EMPTY) is ignored. +#define CONTRACT_AUX_PP_SIGN_PARSE_APPLY(parse_macro, \ + parse_empty_macro, seq_sign_err, data) \ + BOOST_PP_IF(BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_TUPLE_ELEM( \ + 3, 2, seq_sign_err)), \ + /* error, just pass error up*/ \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY_IDENTITY_ \ + , BOOST_PP_IF(BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), 1), \ + parse_macro /* more tokens left, continue parsing */ \ + , /* else */ \ + parse_empty_macro /* only (BOOST_PP_EMPTY) left, done */ \ + ))(seq_sign_err, data) + +// Quietly pass trough if cannot apply because seq is empty. +#define CONTRACT_AUX_PP_SIGN_PARSE_APPLY_QUIET( \ + parse_macro, seq_sign_err, data) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY(parse_macro, \ + /* do nothing if cannot apply because seq empty */ \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY_IDENTITY_, \ + seq_sign_err, data) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/block.hpp b/src/contract/aux_/preprocessor/sign/parse_/utility/block.hpp new file mode 100755 index 00000000..87001024 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/block.hpp @@ -0,0 +1,120 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_HPP_ + +#include "next.hpp" +#include "returns.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_ERR_(seq_sign_err, \ + missing_token_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + (BOOST_PP_EMPTY), \ + missing_token_err) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_OK_(seq_sign_err, \ + missing_token_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err)), \ + ( BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM( \ + 3, 0, seq_sign_err)) ) ) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_OP_(seq_sign_err, \ + missing_token_err) \ + /* size: == 0 error, == 1 only trailing (EMPTY), >= 2 for pre */ \ + BOOST_PP_IF(BOOST_PP_LESS(BOOST_PP_SEQ_SIZE( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), 2), \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_ERR_ \ + , \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_OK_ \ + )(seq_sign_err, missing_token_err) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_(seq_sign_err, \ + missing_token_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY( \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_OP_, \ + /* BLOCK_CODE_OP_ can handle EMPTY, so used also here */ \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_OP_, \ + seq_sign_err, missing_token_err) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_1(seq_sign_err, \ + empty_seq, missing_token_err2, missing_token_err1) \ + /* 1st code block -- e.g., (precondition_code_block) */ \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_( \ + /* skip (precondition) */ \ + CONTRACT_AUX_PP_SIGN_PARSE_NEXT_SKIP(seq_sign_err), \ + missing_token_err2) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_2(seq_sign_err, \ + empty_seq, missing_token_err2, missing_token_err1) \ + /* 2nd code block -- e.g., (postcondition_code_block) */ \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_( \ + /* 1st code block -- e.g., (result) */ \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_CODE_( \ + /* skip tag -- e.g., (precondition) */ \ + CONTRACT_AUX_PP_SIGN_PARSE_NEXT_SKIP(seq_sign_err), \ + missing_token_err1), \ + missing_token_err2) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_NONE_OK_(seq_sign_err, \ + empty_seq, missing_token_err2, missing_token_err1) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + empty_seq /* empty code block(s) */ ) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_NONE_ERR_(seq_sign_err, \ + empty_seq, missing_token_err2, missing_token_err1) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + (BOOST_PP_EMPTY), \ + missing_token_err2) + +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_( \ + seq_sign_err, check_macro, required, number_of_blocks, \ + empty_seq, missing_token_err2, missing_token_err1) \ + BOOST_PP_IF(BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_TUPLE_ELEM( \ + 3, 2, seq_sign_err)), \ + /* error, just pass error up*/ \ + seq_sign_err \ + BOOST_PP_TUPLE_EAT(4) \ + , BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_PARSE_NEXT_IS_NOT( \ + seq_sign_err, check_macro), \ + BOOST_PP_IF(required, \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_NONE_ERR_ \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_NONE_OK_ \ + ) /* endif */ \ + , /* else */ \ + BOOST_PP_CAT(CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_, \ + number_of_blocks) \ + )) /* endif */ \ + (seq_sign_err, empty_seq, missing_token_err2, missing_token_err1) + +// number_of_blocks can be 1 or 2 -- e.g., 2 for postcondition w/ +// results. error 2 specified before 1 always because last block is +// most significative. + +// Optional but required after (tag) is specified. +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_OPTIONAL( \ + seq_sign_err, check_macro, number_of_blocks, \ + empty_seq, missing_token_err2, missing_token_err1) \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_(seq_sign_err, check_macro, \ + 0 /* optional */, number_of_blocks, empty_seq, \ + missing_token_err2, missing_token_err1) + +// Tag and block must always be present. +#define CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_REQUIRED( \ + seq_sign_err, check_macro, number_of_blocks, \ + missing_token_err2, missing_token_err1) \ + CONTRACT_AUX_PP_SIGN_PARSE_BLOCK_(seq_sign_err, check_macro, \ + 1 /* required */, number_of_blocks, ( BOOST_PP_EMPTY ), \ + missing_token_err2, missing_token_err1) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/copyable.hpp b/src/contract/aux_/preprocessor/sign/parse_/utility/copyable.hpp new file mode 100755 index 00000000..7aebccfc --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/copyable.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_HPP_ + +#include "apply.hpp" +#include "required.hpp" +#include "optional.hpp" +#include "../../../keyword/is_copyable.hpp" +#include "../../../seq.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_OP_( \ + seq_sign_err, data) \ + ( BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err) \ + , CONTRACT_AUX_PP_SEQ_REST_N_TO_TUPLE_( \ + 2, BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)) \ + , BOOST_PP_TUPLE_ELEM(3, 2, seq_sign_err)) + +#define CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE( \ + seq_sign_err, missing_token_error) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY( \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_OP_, \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_OP_, \ + CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED( \ + CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL( \ + seq_sign_err, \ + CONTRACT_AUX_PP_KEYWORD_IS_COPYABLE), \ + missing_token_error), \ + ~) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/match_not.hpp b/src/contract/aux_/preprocessor/sign/parse_/utility/match_not.hpp new file mode 100755 index 00000000..920e0992 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/match_not.hpp @@ -0,0 +1,43 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT_HPP_ + +#include "apply.hpp" +#include "returns.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT_NO_( \ + seq_sign_err, match_n_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + /* append nothing -- this is just a check */) + +#define CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT_OP_( \ + seq_sign_err, match_n_err) \ + /* match macro */ \ + BOOST_PP_IF(BOOST_PP_TUPLE_ELEM(2, 0, match_n_err)( \ + BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + /* append nothing -- this is just a check */, \ + /* err msg */ \ + BOOST_PP_TUPLE_ELEM(2, 1, match_n_err)) \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT_NO_( \ + seq_sign_err, check_macro) \ + ) /* endif */ + +#define CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT( \ + match_macro, match_err, seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY( \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT_OP_, \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT_NO_, \ + seq_sign_err, (match_macro, match_err)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/next.hpp b/src/contract/aux_/preprocessor/sign/parse_/utility/next.hpp new file mode 100755 index 00000000..138dbc13 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/next.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_NEXT_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_NEXT_HPP_ + +#include "optional.hpp" +#include "../../../seq.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_NEXT_IS_NOT( \ + seq_sign_err, check_macro) \ + BOOST_PP_IS_EMPTY(CONTRACT_AUX_PP_SEQ_BACK( \ + BOOST_PP_TUPLE_ELEM(3, 1, \ + CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL( \ + seq_sign_err, check_macro))) \ + (/* expand empty */)) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NEXT_SKIP(seq_sign_err) \ + ( \ + BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_ELEM(3, 0, \ + seq_sign_err)) \ + , BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err) \ + , BOOST_PP_TUPLE_ELEM(3, 2, seq_sign_err) \ + ) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/optional.hpp b/src/contract/aux_/preprocessor/sign/parse_/utility/optional.hpp new file mode 100755 index 00000000..190d15ba --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/optional.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL_HPP_ + +#include "apply.hpp" +#include "returns.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL_NO_( \ + seq_sign_err, check_macro) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + (BOOST_PP_EMPTY) /* empty seq elem if no token */) + +#define CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL_OP_( \ + seq_sign_err, check_macro) \ + BOOST_PP_IF(check_macro(BOOST_PP_SEQ_HEAD( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_SEQ_TAIL( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), \ + ( BOOST_PP_SEQ_HEAD( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)) \ + BOOST_PP_EMPTY ) \ + ) \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + (BOOST_PP_EMPTY) /* empty se elem if no macth */) \ + ) /* endif */ + +#define CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL( \ + seq_sign_err, check_macro) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY( \ + CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL_OP_, \ + CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL_NO_, \ + seq_sign_err, check_macro) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/required.hpp b/src/contract/aux_/preprocessor/sign/parse_/utility/required.hpp new file mode 100755 index 00000000..0b5e6c7e --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/required.hpp @@ -0,0 +1,69 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_HPP_ + +#include "apply.hpp" +#include "returns.hpp" +#include +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_OPTION_( \ + seq_sign_err, missing_token_err, is_option) \ + BOOST_PP_IF(BOOST_PP_IS_EMPTY(BOOST_PP_SEQ_HEAD( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR( \ + seq_sign_err, BOOST_PP_SEQ_TAIL( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), \ + (BOOST_PP_EMPTY), /* error, return empty seq */ \ + missing_token_err) \ + , BOOST_PP_IF(is_option, \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK( \ + seq_sign_err, BOOST_PP_SEQ_TAIL( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), \ + ( BOOST_PP_SEQ_HEAD( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)) \ + /* if option, seq elem must have EMPTY postfix */ \ + BOOST_PP_EMPTY ) ) \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK( \ + seq_sign_err, BOOST_PP_SEQ_TAIL( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), \ + ( BOOST_PP_SEQ_HEAD( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)) \ + /* if not an option, no empty postfix */ \ + ) ) \ + )) /* endif */ + +// These OP and NO macros are used outside this file (so they are +// part of the API). + +#define CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_OPTION_OP( \ + seq_sign_err, missing_token_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_OPTION_( \ + seq_sign_err, missing_token_err, 1) + +#define CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_OP( \ + seq_sign_err, missing_token_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_OPTION_( \ + seq_sign_err, missing_token_err, 0) + +#define CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_NO( \ + seq_sign_err, missing_token_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err), \ + (BOOST_PP_EMPTY) /* error, return empty seq */, \ + missing_token_err) \ + +#define CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED( \ + seq_sign_err, missing_token_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY( \ + CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_OP, \ + CONTRACT_AUX_PP_SIGN_PARSE_REQUIRED_NO, \ + seq_sign_err, missing_token_err) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/utility/returns.hpp b/src/contract/aux_/preprocessor/sign/parse_/utility/returns.hpp new file mode 100755 index 00000000..591861e6 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/utility/returns.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_RETURNS_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_RETURNS_HPP_ + +#include + +#define CONTRACT_AUX_PP_SIGN_PARSE_RETURN_OK(seq_sign_err, \ + remaining_seq, append_traits) \ + ( /* return new seq_sign_err 3-tuple */ \ + /* signature still to be parsed */ \ + remaining_seq, \ + /* append new traits to existing ones (seq concatenation) */ \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err) append_traits, \ + /* no error (code, message) */ \ + (0, "") \ + ) + +#define CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + remaining_seq, append_traits, error_msg) \ + ( /* return new seq_sing_err 3-tuple */ \ + /* signature still to be parsed */ \ + remaining_seq, \ + /* append new traits to existing ones (seq concatenation) */ \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err) append_traits, \ + /* error (code, message) */ \ + (1, error_msg) \ + ) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/validate.hpp b/src/contract/aux_/preprocessor/sign/parse_/validate.hpp new file mode 100755 index 00000000..b60fd989 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/validate.hpp @@ -0,0 +1,146 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_HPP_ + +#include "utility/returns.hpp" +#include "utility/apply.hpp" +#include + +// Validate parsed signature give more readable errors when possible. +// Also enforce common C++ constraints on signature -- static +// function cannot be virtual, etc. + +// NOTE: Only very basic checks are currently implemented. +// Validation checks could be improved to provide the +// user with better error checking and reporting in case of +// miss-usage of the preprocessor signature syntax (instead +// of often showing Boost.Preprocessor internal errors +// or C++ unreadable template errors of the code generated +// by the macro expansions all of which are of little help +// for the user). + +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_ERR_(seq_sign_err, \ + error_msg) \ + CONTRACT_AUX_PP_SIGN_PARSE_RETURN_ERR(seq_sign_err, \ + BOOST_PP_EMPTY(), /* empty signature */ \ + BOOST_PP_EMPTY(), /* don't append any traits */ \ + error_msg) + +// Internal Validations // + +// Validate common signature parts (but no contract code blocks yet). +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NO_CONTRACT_COMMON_( \ + seq_sign_err, data) \ + /* check: seq size is complete (as before code blocks) */ \ + BOOST_PP_IF(BOOST_PP_NOT_EQUAL( \ + CONTRACT_AUX_PP_SIGN_SEQ_SIZE_NO_CONTRACT, \ + BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3, 1, \ + seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_ERR_(seq_sign_err, \ + CONTRACT_ERROR_missing_one_or_more_signature_token) \ + /* check: cannot be both virtual and static */ \ + , BOOST_PP_IF(BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_IS_VIRTUAL( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)), \ + CONTRACT_AUX_PP_SIGN_IS_STATIC( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_ERR_(seq_sign_err, \ + CONTRACT_ERROR_static_functions_cannot_be_virtual) \ + /* check: cannot be both virtual and template */ \ + , BOOST_PP_IF(BOOST_PP_AND( \ + CONTRACT_AUX_PP_SIGN_IS_VIRTUAL( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)), \ + CONTRACT_AUX_PP_SIGN_HAS_FUNCTION_TEMPLATE_ARGS( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_ERR_(seq_sign_err, \ + CONTRACT_ERROR_function_templates_cannot_be_virtual) \ + , /* else (it's valid, no error) */ \ + seq_sign_err /* done */ \ + ))) + +// Validate member function signature (but no pre, post, body block). +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_MEMBER_( \ + seq_sign_err, data) \ + seq_sign_err /* validate nothing */ + +// Validate non-member func signature (but no pre, post, body block). +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NON_MEMBER_( \ + seq_sign_err, data) \ + seq_sign_err /* validate nothing */ + +// Validate constructor func signature (but no pre, post, body block). +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONSTRUCTOR_( \ + seq_sign_err, data) \ + seq_sign_err /* validate nothing */ + +// Validate destructor func signature (but no pre, post, body block). +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_DESTRUCTOR_( \ + seq_sign_err, data) \ + seq_sign_err /* validate nothing */ + +// Validation entire contract signature (including code blocks). +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONTRACT_( \ + seq_sign_err, data) \ + /* check: inly 1 elem left in seq (BOOST_PP_EMPTY) */ \ + BOOST_PP_IF(BOOST_PP_NOT_EQUAL(BOOST_PP_SEQ_SIZE( \ + BOOST_PP_TUPLE_ELEM(3, 0, seq_sign_err)), 1), \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_ERR_(seq_sign_err, \ + CONTRACT_ERROR_extra_tokens_left_in_signature) \ + /* check: seq size is complete (including code blocks) */ \ + , BOOST_PP_IF(BOOST_PP_NOT_EQUAL( \ + CONTRACT_AUX_PP_SIGN_SEQ_SIZE_WITH_CONTRACT, \ + BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3, 1, \ + seq_sign_err))), \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_ERR_(seq_sign_err, \ + CONTRACT_ERROR_missing_precondition_postcondition_or_body) \ + , /* else (it's valid, no error) */ \ + seq_sign_err /* done */ \ + )) + +// API // + +// Validate function signature but before parsing contract blocks. + +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NO_CONTRACT_( \ + specific_validate_macro, seq_sign_err, data) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY_QUIET( \ + /* second validate specific parts */ \ + specific_validate_macro, \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY_QUIET( \ + /* first validate common parts */ \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NO_CONTRACT_COMMON_, \ + seq_sign_err, data), data) + +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_MEMBER(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NO_CONTRACT_( \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_MEMBER_, \ + seq_sign_err, ~) + +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NON_MEMBER(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NO_CONTRACT_( \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NON_MEMBER_, \ + seq_sign_err, ~) + +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONSTRUCTOR(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NO_CONTRACT_( \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONSTRUCTOR_, \ + seq_sign_err, ~) + +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_DESTRUCTOR(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NO_CONTRACT_( \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_DESTRUCTOR_, \ + seq_sign_err, ~) + +// Validate after parsing entire contract including pre, post, body. + +#define CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONTRACT(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPLY_QUIET( \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONTRACT_, \ + seq_sign_err, ~) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_/virtual.hpp b/src/contract/aux_/preprocessor/sign/parse_/virtual.hpp new file mode 100755 index 00000000..6a39b646 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_/virtual.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_VIRTUAL_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_VIRTUAL_HPP_ + +#include "utility/optional.hpp" +#include "utility/append_traits.hpp" +#include "utility/match_not.hpp" +#include "../../keyword/is_virtual.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_VIRTUAL(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_OPTIONAL( \ + seq_sign_err, CONTRACT_AUX_PP_KEYWORD_IS_VIRTUAL) + +#define CONTRACT_AUX_PP_SIGN_PARSE_NO_VIRTUAL(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_APPEND_TRAITS( (BOOST_PP_EMPTY), \ + CONTRACT_AUX_PP_SIGN_PARSE_MATCH_NOT( \ + CONTRACT_AUX_PP_KEYWORD_IS_VIRTUAL, \ + CONTRACT_ERROR_cannot_specify_virtual_within_this_context, \ + seq_sign_err)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_constructor.hpp b/src/contract/aux_/preprocessor/sign/parse_constructor.hpp new file mode 100755 index 00000000..a7003eb3 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_constructor.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_CONSTRUCTOR_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_CONSTRUCTOR_HPP_ + +#include "parse_/body.hpp" +#include "parse_/postcondition.hpp" +#include "parse_/precondition.hpp" +#include "parse_/const.hpp" +#include "parse_/args.hpp" +#include "parse_/function_name.hpp" +#include "parse_/result_type.hpp" +#include "parse_/virtual.hpp" +#include "parse_/static.hpp" +#include "parse_/template.hpp" +#include "parse_/access.hpp" +#include "parse_/base_types.hpp" +#include "parse_/class_type.hpp" +#include "parse_/class.hpp" +#include "parse_/validate.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_CONSTRUCTOR(seq) \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONTRACT( \ + CONTRACT_AUX_PP_SIGN_PARSE_BODY( \ + CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION( \ + CONTRACT_AUX_PP_SIGN_PARSE_PRECONDITION( \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONSTRUCTOR( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_CONST( \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_ARGS( \ + CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_NAME( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_RESULT_TYPE( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_VIRTUAL( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_STATIC( \ + CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_ARGS( \ + CONTRACT_AUX_PP_SIGN_PARSE_ACCESS( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_BASE_TYPES( \ + CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_CLASS_TYPE( \ + CONTRACT_AUX_PP_SIGN_PARSE_CLASS( \ + /* init seq_sign_err 3-elem tuple */ \ + /* fun signature to parse */ \ + ( seq (BOOST_PP_EMPTY), \ + /* parsed fun attributes (empty sequence to start) */, \ + (0, "") /* error (code, message) */ ) \ + )))))))))))))))) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_destructor.hpp b/src/contract/aux_/preprocessor/sign/parse_destructor.hpp new file mode 100755 index 00000000..bd362d35 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_destructor.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_DESTRUCTOR_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_DESTRUCTOR_HPP_ + +#include "parse_/body.hpp" +#include "parse_/postcondition.hpp" +#include "parse_/precondition.hpp" +#include "parse_/const.hpp" +#include "parse_/args.hpp" +#include "parse_/function_name.hpp" +#include "parse_/result_type.hpp" +#include "parse_/virtual.hpp" +#include "parse_/static.hpp" +#include "parse_/template.hpp" +#include "parse_/access.hpp" +#include "parse_/base_types.hpp" +#include "parse_/class_type.hpp" +#include "parse_/class.hpp" +#include "parse_/validate.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_DESTRUCTOR(seq) \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONTRACT( \ + CONTRACT_AUX_PP_SIGN_PARSE_BODY( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_POSTCONDITION( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_PRECONDITION( \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_DESTRUCTOR( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_CONST( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_ARGS( \ + CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_NAME( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_RESULT_TYPE( \ + CONTRACT_AUX_PP_SIGN_PARSE_VIRTUAL( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_STATIC( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_TEMPLATE_ARGS( \ + CONTRACT_AUX_PP_SIGN_PARSE_ACCESS( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_BASE_TYPES( \ + CONTRACT_AUX_PP_SIGN_PARSE_NONCOPYABLE_CLASS_TYPE( \ + CONTRACT_AUX_PP_SIGN_PARSE_CLASS( \ + /* init seq_sign_err 3-elem tuple */ \ + /* fun signature to parse */ \ + ( seq (BOOST_PP_EMPTY), \ + /* parsed fun attributes (empty sequence to start) */, \ + (0, "") /* error (code, message) */ ) \ + )))))))))))))))) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/parse_function.hpp b/src/contract/aux_/preprocessor/sign/parse_function.hpp new file mode 100755 index 00000000..f7ff29dc --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/parse_function.hpp @@ -0,0 +1,82 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_HPP_ +#define CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_HPP_ + +#include "parse_/body.hpp" +#include "parse_/postcondition.hpp" +#include "parse_/precondition.hpp" +#include "parse_/const.hpp" +#include "parse_/args.hpp" +#include "parse_/function_name.hpp" +#include "parse_/result_type.hpp" +#include "parse_/virtual.hpp" +#include "parse_/static.hpp" +#include "parse_/template.hpp" +#include "parse_/access.hpp" +#include "parse_/base_types.hpp" +#include "parse_/class_type.hpp" +#include "parse_/class.hpp" +#include "parse_/validate.hpp" + +#define CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_MEMBER_(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONTRACT( \ + CONTRACT_AUX_PP_SIGN_PARSE_BODY( \ + CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION( \ + CONTRACT_AUX_PP_SIGN_PARSE_PRECONDITION( \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_MEMBER( \ + CONTRACT_AUX_PP_SIGN_PARSE_CONST( \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_ARGS( \ + CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_NAME( \ + CONTRACT_AUX_PP_SIGN_PARSE_RESULT_TYPE( \ + CONTRACT_AUX_PP_SIGN_PARSE_VIRTUAL( \ + CONTRACT_AUX_PP_SIGN_PARSE_STATIC( \ + CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_ARGS( \ + CONTRACT_AUX_PP_SIGN_PARSE_ACCESS( \ + CONTRACT_AUX_PP_SIGN_PARSE_BASE_TYPES( \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_CLASS_TYPE( \ + seq_sign_err \ + ))))))))))))))) + +#define CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_NON_MEMBER_(seq_sign_err) \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_CONTRACT( \ + CONTRACT_AUX_PP_SIGN_PARSE_BODY( \ + CONTRACT_AUX_PP_SIGN_PARSE_POSTCONDITION( \ + CONTRACT_AUX_PP_SIGN_PARSE_PRECONDITION( \ + CONTRACT_AUX_PP_SIGN_PARSE_VALIDATE_NON_MEMBER( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_CONST( \ + CONTRACT_AUX_PP_SIGN_PARSE_COPYABLE_ARGS( \ + CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_NAME( \ + CONTRACT_AUX_PP_SIGN_PARSE_RESULT_TYPE( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_VIRTUAL( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_STATIC( \ + CONTRACT_AUX_PP_SIGN_PARSE_TEMPLATE_ARGS( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_ACCESS( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_BASE_TYPES( \ + CONTRACT_AUX_PP_SIGN_PARSE_NO_CLASS_TYPE( \ + seq_sign_err \ + ))))))))))))))) + +#define CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_(seq_sign_err) \ + BOOST_PP_IF(CONTRACT_AUX_PP_SIGN_IS_CLASS_MEMBER( \ + BOOST_PP_TUPLE_ELEM(3, 1, seq_sign_err)), \ + CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_MEMBER_ \ + , /* else */ \ + CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_NON_MEMBER_ \ + )(seq_sign_err) + +#define CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION(seq) \ + CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION_( \ + CONTRACT_AUX_PP_SIGN_PARSE_CLASS( \ + /* init seq_sign_err 3-elem tuple */ \ + /* fun signature to parse */ \ + ( seq (BOOST_PP_EMPTY), \ + /* parsed fun attributes (empty sequence to start) */, \ + (0, "") /* error (code, message) */ ) \ + )) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/postcondition.hpp b/src/contract/aux_/preprocessor/sign/postcondition.hpp new file mode 100755 index 00000000..48556467 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/postcondition.hpp @@ -0,0 +1,22 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_POSTCONDITION_HPP_ +#define CONTRACT_AUX_PP_SIGN_POSTCONDITION_HPP_ + +#include "seq_.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_POSTCONDITION(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_POSTCONDITION_INDEX, \ + sign) + +#define CONTRACT_AUX_PP_SIGN_POSTCONDITION_RESULT(sign) \ + BOOST_PP_SEQ_ELEM( \ + CONTRACT_AUX_PP_SIGN_SEQ_POSTCONDITION_RESULT_INDEX, \ + sign) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/precondition.hpp b/src/contract/aux_/preprocessor/sign/precondition.hpp new file mode 100755 index 00000000..25cf7237 --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/precondition.hpp @@ -0,0 +1,17 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_PRECONDITION_HPP_ +#define CONTRACT_AUX_PP_SIGN_PRECONDITION_HPP_ + +#include "seq_.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_PRECONDITION(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_PRECONDITION_INDEX, \ + sign) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/result_type.hpp b/src/contract/aux_/preprocessor/sign/result_type.hpp new file mode 100755 index 00000000..12224b1d --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/result_type.hpp @@ -0,0 +1,22 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_RESULT_TYPE_HPP_ +#define CONTRACT_AUX_PP_SIGN_RESULT_TYPE_HPP_ + +#include "seq_.hpp" +#include "../keyword/is_void.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_RESULT_TYPE(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_RESULT_TYPE_INDEX, \ + sign) + +#define CONTRACT_AUX_PP_SIGN_IS_VOID_RESULT(sign) \ + CONTRACT_AUX_PP_KEYWORD_IS_VOID( \ + CONTRACT_AUX_PP_SIGN_RESULT_TYPE(sign)) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/seq_.hpp b/src/contract/aux_/preprocessor/sign/seq_.hpp new file mode 100755 index 00000000..3f9e802b --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/seq_.hpp @@ -0,0 +1,74 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_SEQ_HPP_ +#define CONTRACT_AUX_PP_SIGN_SEQ_HPP_ + +// IMPORTNAT: These are for internal use only. This file contents +// should NOT be used from files outside this directory. + +#define CONTRACT_AUX_PP_SIGN_SEQ_CLASS_INDEX 0 +#define CONTRACT_AUX_PP_SIGN_SEQ_CLASS_TYPE_INDEX 1 +#define CONTRACT_AUX_PP_SIGN_SEQ_BASE_TYPES_INDEX 2 +#define CONTRACT_AUX_PP_SIGN_SEQ_ACCESS_INDEX 3 +#define CONTRACT_AUX_PP_SIGN_SEQ_FUNCTION_TEMPLATE_ARGS_INDEX 4 +#define CONTRACT_AUX_PP_SIGN_SEQ_STATIC_INDEX 5 +#define CONTRACT_AUX_PP_SIGN_SEQ_VIRTUAL_INDEX 6 +#define CONTRACT_AUX_PP_SIGN_SEQ_RESULT_TYPE_INDEX 7 +#define CONTRACT_AUX_PP_SIGN_SEQ_FUNCTION_NAME_INDEX 8 +#define CONTRACT_AUX_PP_SIGN_SEQ_ARGS_INDEX 9 +#define CONTRACT_AUX_PP_SIGN_SEQ_CONST_INDEX 10 + +#define CONTRACT_AUX_PP_SIGN_SEQ_SIZE_NO_CONTRACT 11 + +#define CONTRACT_AUX_PP_SIGN_SEQ_PRECONDITION_INDEX 11 +#define CONTRACT_AUX_PP_SIGN_SEQ_POSTCONDITION_RESULT_INDEX 12 +#define CONTRACT_AUX_PP_SIGN_SEQ_POSTCONDITION_INDEX 13 +#define CONTRACT_AUX_PP_SIGN_SEQ_BODY_INDEX 14 + +#define CONTRACT_AUX_PP_SIGN_SEQ_SIZE_WITH_CONTRACT 15 + +// Signature Sequences +// +// A signature_sequence is first parsed using one of the +// PP_SIGN_PARSE_XYZ() macros. The parse macros return a 3-tuple +// (seq, sign, err): +// 0) Element 0 (seq) is the remaining signature_sequence elements +// (nothing if successfully parsed). +// 1) Element 1 (sign) is the parsed signature sequence which can +// be inspected using one of the PP_SIGN_XYZ macros (if the was +// no parsing error). +// 2) Element 2 (err) is the parsing error. This is a 2-tuple +// (error_code, error_message) and there was a parsing error iff +// error_code != 0, in which case error_message is a token +// describing the error. +// +// In this context function can be either a member or non-member +// function. For non member function some traits will trivially +// return BOOST_PP_EMPTY() (like the PP_SIGN_ACCESS() macro). +// +// Some of these elements can be empty (e.g., virtual) then these +// macro return nothing, the related trait in sign ends with +// BOOST_PP_EMPTY so it is expanded here applying a trailing () to +// the trait. This does not apply for non optional elements (e.g., +// access) which are always present so their traits do not end with +// BOOST_PP_EMPTY. +// For example, virtual is optional, the related trait in f will be +// (virtual BOOST_PP_EMPTY) if virtual was specified or just +// (BOOST_PP_EMPTY) if virtual was not specified, in eihter case the +// trait is expanded by the GET_VIRTUAL_ macro below applying a +// terminating () so to get either 'virtual' or nothing ''. Instead, +// access is not optional so its trait is either (public), (private), +// or (protected) (but never (BOOST_PP_EMPTY) ), the trait does not +// end in BOOST_PP_EMPTY and it does not have to be expanded. +// Using simply () for an optional trait instead of (BOOST_PP_EMPTY) +// is not supported by the C++ standard (and it is allowed by GCC but +// not by MSVC) because empty macro parameters are not supported by +// C++ (they are instead by C99). Therefore, the complication of +// using BOOST_PP_EMPTY for traits that are optinal and can be empty +// is necessary to ensure standard compliance. + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/static.hpp b/src/contract/aux_/preprocessor/sign/static.hpp new file mode 100755 index 00000000..0f2b398c --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/static.hpp @@ -0,0 +1,21 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_STATIC_HPP_ +#define CONTRACT_AUX_PP_SIGN_STATIC_HPP_ + +#include "seq_.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_STATIC(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_STATIC_INDEX, \ + sign)(/* expand empty */) + +#define CONTRACT_AUX_PP_SIGN_IS_STATIC(sign) \ + BOOST_PP_NOT(BOOST_PP_IS_EMPTY( \ + CONTRACT_AUX_PP_SIGN_STATIC(sign))) + +#endif // #include guard + diff --git a/src/contract/aux_/preprocessor/sign/virtual.hpp b/src/contract/aux_/preprocessor/sign/virtual.hpp new file mode 100755 index 00000000..ac55785c --- /dev/null +++ b/src/contract/aux_/preprocessor/sign/virtual.hpp @@ -0,0 +1,21 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SIGN_VIRTUAL_HPP_ +#define CONTRACT_AUX_PP_SIGN_VIRTUAL_HPP_ + +#include "seq_.hpp" +#include + +#define CONTRACT_AUX_PP_SIGN_VIRTUAL(sign) \ + BOOST_PP_SEQ_ELEM(CONTRACT_AUX_PP_SIGN_SEQ_VIRTUAL_INDEX, \ + sign)(/* expand empty */) + +#define CONTRACT_AUX_PP_SIGN_IS_VIRTUAL(sign) \ + BOOST_PP_NOT(BOOST_PP_IS_EMPTY( \ + CONTRACT_AUX_PP_SIGN_VIRTUAL(sign))) + +#endif // #include guard + diff --git a/src/contract/aux_/symbol.hpp b/src/contract/aux_/symbol.hpp new file mode 100755 index 00000000..2b2bdb7d --- /dev/null +++ b/src/contract/aux_/symbol.hpp @@ -0,0 +1,19 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_PP_SYMBOL_HPP_ +#define CONTRACT_AUX_PP_SYMBOL_HPP_ + +#include + +// Prefixes contract_ for library specific name. +#define CONTRACT_AUX_SYMBOL(name) BOOST_PP_CAT(contract_, name) + +// Prefixes contract_ and postfixes _ for library internal name. +#define CONTRACT_AUX_INTERNAL_SYMBOL(name) \ + BOOST_PP_CAT(CONTRACT_AUX_SYMBOL(name), _) + +#endif // #include guard + diff --git a/src/contract/aux_/sync.hpp b/src/contract/aux_/sync.hpp new file mode 100755 index 00000000..1a2c8bb1 --- /dev/null +++ b/src/contract/aux_/sync.hpp @@ -0,0 +1,27 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_AUX_SYNC_HPP_ +#define CONTRACT_AUX_SYNC_HPP_ + +namespace contract { namespace aux { + +template +class sync { +public: + sync(T const& value = DEFAULT): value_(value) {} + + // If threading, this accessors must be syncronized... + T const& operator=(T const& value) { return value_ = value; } + operator T() const { return value_; } + +private: + T value_; +}; + +}} // namespace + +#endif // #include guard + diff --git a/src/contract/block.hpp b/src/contract/block.hpp new file mode 100755 index 00000000..71a949f1 --- /dev/null +++ b/src/contract/block.hpp @@ -0,0 +1,91 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_BLOCK_HPP_ +#define CONTRACT_BLOCK_HPP_ + +#include "old.hpp" +#include "assert.hpp" +#include + +// Block Invariant // + +// Block invarinats apply to any code block (same of Eiffel's check). + +#ifdef CONTRACT_CHECK_BLOCK_INVARIANT +#define CONTRACT_ASSERT_BLOCK_INVARIANT_MSG(boolean_condition, \ + string_description) \ + try { \ + CONTRACT_AUX_DEBUG(dbg << "Checking block invariant '" \ + << string_description << "'"); \ + CONTRACT_ASSERT_MSG(boolean_condition, string_description) \ + } catch (...) { \ + ::contract::block_invariant_failed(::contract::FROM_BLOCK); \ + } +#else // check block invariants +# define CONTRACT_ASSERT_BLOCK_INVARIANT_MSG(boolean_condition, \ + string_description) /* expand to nothing */ +#endif // check block invariants + +#define CONTRACT_ASSERT_BLOCK_INVARIANT(boolean_condition) \ + /* Do not use BOOST_PP_STRINGIZE() so condition NOT expanded */ \ + CONTRACT_ASSERT_BLOCK_INVARIANT_MSG(boolean_condition, \ + # boolean_condition) + +// Loop Variant // + +// Loops are blocks that are iterated so block invariants are used as +// loop invariants and also to check loop variants. + +#ifdef CONTRACT_CHECK_BLOCK_INVARIANT +#define CONTRACT_INIT_LOOP_VARIANT \ + ::contract::loop_variant_type \ + CONTRACT_OLDOF(CONTRACT_CONFIG_VARIANT_VARIABLE_) = \ + std::numeric_limits< ::contract::loop_variant_type \ + >::quiet_NaN() \ + /* must NOT terminate with `;` to use it in for() loop */ +#else // check block invariants +#define CONTRACT_INIT_LOOP_VARIANT /* expand to nothing */ +#endif // check block invariants + +#ifdef CONTRACT_CHECK_BLOCK_INVARIANT +#define CONTRACT_ASSERT_LOOP_VARIANT_MSG(integer_expression, \ + string_description) \ + ::contract::loop_variant_type \ + /* extra `()` to force variant expression evaluation */ \ + CONTRACT_CONFIG_VARIANT_VARIABLE_ = (integer_expression); \ + CONTRACT_ASSERT_BLOCK_INVARIANT_MSG( /* variant >= 0 */ \ + CONTRACT_CONFIG_VARIANT_VARIABLE_ >= 0, \ + string_description " >= 0" ); \ + CONTRACT_ASSERT_BLOCK_INVARIANT_MSG( /* variant < old variant */ \ + /* NaN used to skip variant check at entry */ \ + (CONTRACT_OLDOF(CONTRACT_CONFIG_VARIANT_VARIABLE_) == \ + std::numeric_limits< \ + ::contract::loop_variant_type >::quiet_NaN()) \ + || (CONTRACT_CONFIG_VARIANT_VARIABLE_ < CONTRACT_OLDOF( \ + CONTRACT_CONFIG_VARIANT_VARIABLE_)), \ + string_description " < oldof " string_description ); \ + CONTRACT_OLDOF(CONTRACT_CONFIG_VARIANT_VARIABLE_) = \ + CONTRACT_CONFIG_VARIANT_VARIABLE_; +#else // check block invariants +#define CONTRACT_ASSERT_LOOP_VARIANT_MSG(integer_expression, \ + string_description) /* expand to nothing */ +#endif // check block invariants + +#define CONTRACT_ASSERT_LOOP_VARIANT(integer_expression) \ + /* Do not use BOOST_PP_STRINGIZE() so condition NOT expanded */ \ + CONTRACT_ASSERT_LOOP_VARIANT_MSG(integer_expression, \ + # integer_expression) + +namespace contract { + +// Do not used `unsigned` here bacause C++ implicitly converts singed +// to unsgined integers (instead, assert variant >= 0). +typedef long loop_variant_type; + +} // namespace + +#endif // #include guard + diff --git a/src/contract/body.hpp b/src/contract/body.hpp new file mode 100755 index 00000000..fc115fef --- /dev/null +++ b/src/contract/body.hpp @@ -0,0 +1,54 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_BODY_HPP_ +#define CONTRACT_BODY_HPP_ + +#include "config.hpp" +#include "aux_/symbol.hpp" +#include "aux_/preprocessor/sign/function_name.hpp" +#include + +// Constructor and destructor must specify both class type and name +// bacause they can be different from tempate `myclass::myclass` +// (if `myclass::myclass` cannot be used for constructor name, +// and the same gives an "obsolete" warning for destructors...). + +#if defined(CONTRACT_CHECK_CLASS_INVARIANT) || \ + defined(CONTRACT_CHECK_PRECONDITION) || \ + defined(CONTRACT_CHECK_POSTCONDITION) +# define CONTRACT_CTOR_BODY_(class_type, ctor_name, body_name) \ + void class_type::CONTRACT_AUX_INTERNAL_SYMBOL( \ + BOOST_PP_CAT(body_, body_name)) +#else +# define CONTRACT_CTOR_BODY_(class_type, ctor_name, body_name) \ + class_type::ctor_name +#endif // check contract + +#define CONTRACT_CONSTRUCTOR_BODY(class_type, class_name) \ + CONTRACT_CTOR_BODY_(class_type, class_name, \ + CONTRACT_CONFIG_CONSTRUCTOR_FUNCTION_NAME_) + +// The ~ is NOT specified by caller (it is added here). This is to +// be consistent with signature-sequence for destructors. +#define CONTRACT_DESTRUCTOR_BODY(class_type, class_name) \ + CONTRACT_CTOR_BODY_(class_type, ~class_name, \ + CONTRACT_CONFIG_DESTRUCTOR_FUNCTION_NAME_) + +// Use `BODY(operator(==, equal)` for operators. +#if defined(CONTRACT_CHECK_CLASS_INVARIANT) || \ + defined(CONTRACT_CHECK_PRECONDITION) || \ + defined(CONTRACT_CHECK_POSTCONDITION) +# define CONTRACT_BODY(function_name) \ + CONTRACT_AUX_INTERNAL_SYMBOL(BOOST_PP_CAT(body_, \ + CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_WORD( \ + function_name))) +#else +# define CONTRACT_BODY(function_name) \ + CONTRACT_AUX_PP_SIGN_FUNCTION_NAME_SYMBOLIC(function_name) +#endif // check contract + +#endif // #include guard + diff --git a/src/contract/config.hpp b/src/contract/config.hpp new file mode 100755 index 00000000..db84f6b2 --- /dev/null +++ b/src/contract/config.hpp @@ -0,0 +1,80 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_CONFIG_HPP_ +#define CONTRACT_CONFIG_HPP_ + +// User configs: change them rarely, only if *really* needed. + +#ifndef CONTRACT_CONFIG_MAX_FUNCTION_ARITY +#define CONTRACT_CONFIG_MAX_FUNCTION_ARITY 5 +#endif // config + +#ifndef CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE +#define CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE 5 +#endif // config + +// Internal configs: *never* change them (postfixed with `_`). + +#ifndef CONTRACT_CONFIG_DEBUG_ +#define CONTRACT_CONFIG_DEBUG_ 0 +#endif // config + +#ifndef CONTRACT_CONFIG_INVARIANT_FUNCTION_ +#define CONTRACT_CONFIG_INVARIANT_FUNCTION_ contract_invariant_ +#endif // config + +#ifndef CONTRACT_CONFIG_STATIC_INVARIANT_FUNCTION_ +#define CONTRACT_CONFIG_STATIC_INVARIANT_FUNCTION_ \ + contract_static_invariant_ +#endif // config + +#ifndef CONTRACT_CONFIG_STATE_VARIABLE_ +#define CONTRACT_CONFIG_STATE_VARIABLE_ contract_state_ +#endif // config + +// This must be `constructor` to allow for member initialization list +// workaround by using a special init function named `constructor`. +#ifndef CONTRACT_CONFIG_CONSTRUCTOR_FUNCTION_NAME_ +#define CONTRACT_CONFIG_CONSTRUCTOR_FUNCTION_NAME_ \ + constructor /* trailing _ automatically added */ +#endif // config + +#ifndef CONTRACT_CONFIG_DESTRUCTOR_FUNCTION_NAME_ +#define CONTRACT_CONFIG_DESTRUCTOR_FUNCTION_NAME_ \ + destructor /* trailing _ automatically added */ +#endif // config + +#ifndef CONTRACT_CONFIG_VARIANT_VARIABLE_ +#define CONTRACT_CONFIG_VARIANT_VARIABLE_ contract_variant_ +#endif // config + +#ifndef CONTRACT_CONFIG_NONMEMBER_FUNCTION_HPP_FILE_PATH_ +#define CONTRACT_CONFIG_NONMEMBER_FUNCTION_HPP_FILE_PATH_ \ + "contract/nonmember_function.hpp" +#endif // config + +#ifndef CONTRACT_CONFIG_NONSTATIC_MEMBER_FUNCTION_HPP_FILE_PATH_ +#define CONTRACT_CONFIG_NONSTATIC_MEMBER_FUNCTION_HPP_FILE_PATH_ \ + "contract/nonstatic_member_function.hpp" +#endif // config + +#ifndef CONTRACT_CONFIG_STATIC_MEMBER_FUNCTION_HPP_FILE_PATH_ +#define CONTRACT_CONFIG_STATIC_MEMBER_FUNCTION_HPP_FILE_PATH_ \ + "contract/static_member_function.hpp" +#endif // config + +#ifndef CONTRACT_CONFIG_CONSTRUCTOR_HPP_FILE_PATH_ +#define CONTRACT_CONFIG_CONSTRUCTOR_HPP_FILE_PATH_ \ + "contract/constructor.hpp" +#endif // config + +#ifndef CONTRACT_CONFIG_AUX_VOID_BASE_CONTRACT_HPP_FILE_PATH_ +#define CONTRACT_CONFIG_AUX_VOID_BASE_CONTRACT_HPP_FILE_PATH_ \ + "contract/aux_/function/void_base_contract.hpp" +#endif // config + +#endif // #include guard + diff --git a/src/contract/constructor.hpp b/src/contract/constructor.hpp new file mode 100755 index 00000000..9a3717c4 --- /dev/null +++ b/src/contract/constructor.hpp @@ -0,0 +1,165 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#if !BOOST_PP_IS_ITERATING +# // Include guards (but only if not iter). +# ifndef CONTRACT_CONSTRUCTOR_HPP_ +# define CONTRACT_CONSTRUCTOR_HPP_ +# include "config.hpp" +# include "nonstatic_member_function.hpp" +# include +# include +# include "aux_/function/local_macros_define.hpp" // #undef below. + +namespace contract { + +// Should never be used directly (use only the specializations). +template +class constructor { + BOOST_MPL_ASSERT_MSG(0, CONTRACT_ERROR_specified_invalid_function_type_template_parameter_F, ()); +}; + +} // namespace + +// Self-iterate this file over arity. +# define BOOST_PP_ITERATION_PARAMS_1 (3, \ + (0, CONTRACT_CONFIG_MAX_FUNCTION_ARITY, \ + CONTRACT_CONFIG_CONSTRUCTOR_HPP_FILE_PATH_)) +# include BOOST_PP_ITERATE() // Iter over arity. +# include "aux_/function/local_macros_undef.hpp" // #define above. +# endif // #include guard +# // 1st self-iteration over function-arity. +#elif BOOST_PP_ITERATION_DEPTH() == 1 +# // Define local macros directly depending on iteration. +# define CONTRACT_arity \ + BOOST_PP_SUB(BOOST_PP_FRAME_FINISH(1), BOOST_PP_FRAME_ITERATION(1)) +# define CONTRACT_is_not_void 0 // Construcotr always void. +# define CONTRACT_is_member 1 // Always a member. + +namespace contract { + +template +class constructor: + public nonstatic_member_function { + // Constructor class cannot be copyable because there was no + // object before body (so there is no old object). + BOOST_MPL_ASSERT_MSG( + boost::mpl::not_< aux::is_copyable >::value, + CONTRACT_ERROR_class_type_cannot_be_copyable_for_constructors, (ClassType)); + BOOST_MPL_ASSERT_MSG( + boost::mpl::not_< boost::is_const >::value, + CONTRACT_ERROR_class_type_cannot_be_const_for_constructors, (ClassType)); + +private: + // Type manipulations (see nonstatic_member_function<>). + CONTRACT_typedef_maybeconst_class_type + CONTRACT_typedef_class_type // No direct constr subcontract so private. + CONTRACT_typedef_maybeconst_class_ptr + CONTRACT_typedef_arg_class_ptr; + CONTRACT_typedef_old_class_type + CONTRACT_typedef_arg_old_class_ptr + typedef void ResultType; + CONTRACT_typedef_arg_result_type + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_argument_type, ~) + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_argument_ref, ~) + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_typedef_arg_argument_type, ~) + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_typedef_old_argument_type, ~) + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_typedef_arg_old_argument_type, ~) + + CONTRACT_typedef_static_precondition_function_ptr + CONTRACT_typedef_postcondition_function_ptr + CONTRACT_typedef_body_function_ptr(CONTRACT_is_member) + +#if CONTRACT_CONFIG_DEBUG_ + private: typedef class_type debug_type; +#endif // debug + +public: + constructor(body_function_ptr body_function +#if defined CONTRACT_CHECK_PRECONDITION + , static_precondition_function_ptr precondition_function +#endif // check precondition +#if defined CONTRACT_CHECK_POSTCONDITION + , postcondition_function_ptr postcondition_function +#endif // check postcondition + ): nonstatic_member_function< + CONTRACT_f(1 /* always member */)>( + body_function +#if defined CONTRACT_CHECK_PRECONDITION + , 0 // Pre call made by call_pre() below. +#endif // check precondition +#if defined CONTRACT_CHECK_POSTCONDITION + , postcondition_function +#endif // check postcondition + ) +#if defined CONTRACT_CHECK_PRECONDITION + , STATIC_PRECONDITION_FUNCTION_(precondition_function) +#endif // check precondition + {} + + inline ResultType call( + maybeconst_class_ptr object + // , argument_type0 argument0, ... + BOOST_PP_ENUM_TRAILING(CONTRACT_arity, + CONTRACT_noncopyable_argument, ~) + ) { + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Called constructor contract"); + return exec( + object + // , argument0, ... + BOOST_PP_ENUM_TRAILING(CONTRACT_arity, + CONTRACT_argument, ~) + , false // Never check invariant in precondition. + , true // Precondition check. + , true // Post-invariant check. + , true // Postcondition check. + ); + } + +private: + inline from here() const { return FROM_CONSTRUCTOR; } + +#if defined CONTRACT_CHECK_PRECONDITION + inline void call_precondition( + arg_class_ptr object + // , arg_argument_type0 argument0, ... + BOOST_PP_ENUM_TRAILING(CONTRACT_arity, + CONTRACT_arg_argument, ~) + ) { + // Drop object and call static member precondition. + STATIC_PRECONDITION_FUNCTION_( + // argument0, ... + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_argument, ~) + ); + } + + static_precondition_function_ptr const STATIC_PRECONDITION_FUNCTION_; +#endif // check precondition + +}; // class +} // namespace + +# // Undef ALL local macros directly depending on iteration. +# undef CONTRACT_arity +# undef CONTRACT_is_not_void +# undef CONTRACT_is_member +#else // Self-iteration out-of-range (should never happen...). +# error "Preprocessor iteration depth out-of-range (internal error)" + +#endif // BOOST_PP_IS_ITERATING + diff --git a/src/contract/destructor.hpp b/src/contract/destructor.hpp new file mode 100755 index 00000000..984c31cc --- /dev/null +++ b/src/contract/destructor.hpp @@ -0,0 +1,85 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_DESTRUCTOR_HPP_ +#define CONTRACT_DESTRUCTOR_HPP_ + +#include "config.hpp" +#include "nonstatic_member_function.hpp" +#include "aux_/debug.hpp" +#include + +#define CONTRACT_f void (ClassType*) // Local macros #define. + +namespace contract { + +// Should never be used directly (use only the specializations). +template +class destructor { + BOOST_MPL_ASSERT_MSG(0, CONTRACT_ERROR_specified_invalid_function_type_template_parameter_F, ()); +}; + +template +class destructor: + public nonstatic_member_function { + // Destructor class cannot be copyable because there is no + // object after body (so there is no postcondition). + BOOST_MPL_ASSERT_MSG( + boost::mpl::not_< aux::is_copyable >::value, + CONTRACT_ERROR_class_type_cannot_be_copyable_for_destructors, (ClassType)); + BOOST_MPL_ASSERT_MSG( + boost::mpl::not_< boost::is_const >::value, + CONTRACT_ERROR_class_type_cannot_be_const_for_destructors, (ClassType)); + +private: + // Type names consistent with nonstatic_member_function<>. + typedef ClassType* maybeconst_class_ptr; // But never const... + typedef void (ClassType::* body_function_ptr)(); + +#if CONTRACT_CONFIG_DEBUG_ + private: typedef ClassType debug_type; +#endif // debug + +public: + destructor(body_function_ptr body_function + ): nonstatic_member_function( + body_function +#if defined CONTRACT_CHECK_PRECONDITION + , 0 // Never preconditions. +#endif // check precondition +#if defined CONTRACT_CHECK_POSTCONDITION + , 0 // Never postconditions. +#endif // check postcondition + ) {} + + inline void call( + maybeconst_class_ptr object + // No function arguments. + ) { + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Called destructor contract"); + return exec( + object + // No function arguments. + , true // Only check invariants at entry. + , false // No precondition check. + , false // No post-invariant check. + , false // No postcondition check. + ); + } + +private: + inline from here() const { return FROM_DESTRUCTOR; } +}; + +} // namespace + +#undef CONTRACT_f // Local macros #undef. + +#endif // #include guard + diff --git a/src/contract/from.hpp b/src/contract/from.hpp new file mode 100755 index 00000000..b68d1009 --- /dev/null +++ b/src/contract/from.hpp @@ -0,0 +1,27 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_FOM_HPP_ +#define CONTRACT_FOM_HPP_ + +namespace contract { + +// This type has to be defined in a separate header in order to avoid +// duplicate definition errors because it is used by both contract +// and contract::aux and C++ does not support forward declarations +// for enumerative types. +typedef enum { + FROM_CONSTRUCTOR, + FROM_DESTRUCTOR, + FROM_NONSTATIC_MEMBER_FUNCTION, + FROM_STATIC_MEMBER_FUNCTION, + FROM_NONMEMBER_FUNCTION, + FROM_BLOCK, +} from; + +} // namespace + +#endif // #include guard + diff --git a/src/contract/macros.hpp b/src/contract/macros.hpp new file mode 100755 index 00000000..6cf1b093 --- /dev/null +++ b/src/contract/macros.hpp @@ -0,0 +1,31 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_MACROS_HPP_ +#define CONTRACT_MACROS_HPP_ + +#include "aux_/macros/invariant.hpp" +#include "aux_/macros/function.hpp" +// For the code of the macro expansion. +#include "nonmember_function.hpp" +#include "nonstatic_member_function.hpp" +#include "static_member_function.hpp" +#include "constructor.hpp" +#include "destructor.hpp" + +#define CONTRACT_INVARIANT(sequence) \ + CONTRACT_AUX_INVARIANT(sequence) + +#define CONTRACT_CONSTRUCTOR(sequence) \ + CONTRACT_AUX_CONSTRUCTOR(sequence) + +#define CONTRACT_DESTRUCTOR(sequence) \ + CONTRACT_AUX_DESTRUCTOR(sequence) + +#define CONTRACT_FUNCTION(sequence) \ + CONTRACT_AUX_FUNCTION(sequence) + +#endif // #include guard + diff --git a/src/contract/nonmember_function.hpp b/src/contract/nonmember_function.hpp new file mode 100755 index 00000000..f89f0d02 --- /dev/null +++ b/src/contract/nonmember_function.hpp @@ -0,0 +1,104 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#if !BOOST_PP_IS_ITERATING +# // Include guards (but only if not iter). +# ifndef CONTRACT_NONMEMBER_FUNCTION_HPP_ +# define CONTRACT_NONMEMBER_FUNCTION_HPP_ +# include "config.hpp" +# include "assert.hpp" +# include "state.hpp" +# include "old.hpp" +# include "aux_/old.hpp" +# include "aux_/arg.hpp" +# include "aux_/checking.hpp" +# include "aux_/debug.hpp" +# include "aux_/function/void_base_contract.hpp" +# include +# include +# include +# include +# include +# include "aux_/function/local_macros_define.hpp" // #undef below. + +namespace contract { + +// PRE/POST/BODY FUNCTION PTR PASSING +// Teorethically, precondition, postcondition, and body function +// pointers could be passed as template parameters. However, that +// does not compile on some compliers for overloaded templated +// functions (like MSVC)... so these function pointers are passed to +// the constructor. +// Both options are fine for subcontracting, because even in the +// second case the derived class constructs a base contract object +// via its default constructor which set pre, post, and body function +// pointer. Furthermore, the body function pointer could be passed to +// call() instead than to the consturctor because the body is not +// needed when subcontracting (only pre and post are) but all +// functions are passed together to the constructor for consistency. + +// Should never be used directly (use only the specializations). +template +class nonmember_function { + BOOST_MPL_ASSERT_MSG(0, CONTRACT_specified_invalid_function_type_template_parameter_F, ()); +}; + +} // namespace + +// Self-iterate this file over arity, void, const, and member. +# define BOOST_PP_ITERATION_PARAMS_1 (3, \ + (0, CONTRACT_CONFIG_MAX_FUNCTION_ARITY, \ + CONTRACT_CONFIG_NONMEMBER_FUNCTION_HPP_FILE_PATH_)) +# include BOOST_PP_ITERATE() // Iter over arity. +# include "aux_/function/local_macros_undef.hpp" // #define above. +# endif // #include guard +# // 1st self-iteration over function-arity. +#elif BOOST_PP_ITERATION_DEPTH() == 1 +# define BOOST_PP_ITERATION_PARAMS_2 (3, (0, 1, \ + CONTRACT_CONFIG_NONMEMBER_FUNCTION_HPP_FILE_PATH_)) +# include BOOST_PP_ITERATE() // Iter over 0 void, 1 non-void func. +# // 2nd self-iteration over void/non-void function. +#elif BOOST_PP_ITERATION_DEPTH() == 2 +# // Define local macros directly depending on iteration. +# define CONTRACT_arity \ + BOOST_PP_SUB(BOOST_PP_FRAME_FINISH(1), BOOST_PP_FRAME_ITERATION(1)) +# define CONTRACT_is_not_void BOOST_PP_NOT(BOOST_PP_FRAME_ITERATION(2)) +# define CONTRACT_is_member 0 // Never a member function. + +namespace contract { + +template< + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, typename ResultType) + // , ArgumentType0 ... + BOOST_PP_COMMA_IF(BOOST_PP_AND(CONTRACT_arity, CONTRACT_is_not_void)) + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_tparam_ArgumentType, ~) + > +class nonmember_function< + // ResultType ([ClassType::]*)(ArgumentType0, ...) [const] + CONTRACT_f(0 /* non-member */) + >: + + // This base class is made noncopyable so all contract classes are not + // copyable. This is because there was no need to copy contract classes + // but if there will ever be a need it might be possible to define + // copy operation with correct semantics and remove this constraint. + boost::noncopyable { + +# include "aux_/function/contract_class_implement.hpp" + +}; // class + +} // namespace + +# // Undef ALL local macros directly depending on iteration. +# undef CONTRACT_arity +# undef CONTRACT_is_not_void +# undef CONTRACT_is_member +#else // Self-iteration out-of-range (should never happen...). +# error "Preprocessor iteration depth out-of-range (internal error)" + +#endif // BOOST_PP_IS_ITERATING + diff --git a/src/contract/nonstatic_member_function.hpp b/src/contract/nonstatic_member_function.hpp new file mode 100755 index 00000000..a70c7195 --- /dev/null +++ b/src/contract/nonstatic_member_function.hpp @@ -0,0 +1,141 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#if !BOOST_PP_IS_ITERATING +# // Include guards (but only if not iter). +# ifndef CONTRACT_NONSTATIC_MEMBER_FUNCTION_HPP_ +# define CONTRACT_NONSTATIC_MEMBER_FUNCTION_HPP_ +# include "config.hpp" +# include "assert.hpp" +# include "state.hpp" +# include "old.hpp" +# include "aux_/old.hpp" +# include "aux_/arg.hpp" +# include "aux_/checking.hpp" +# include "aux_/debug.hpp" +# include "aux_/function/void_base_contract.hpp" +# include +# include +# include +# include +# include +# include "aux_/function/local_macros_define.hpp" // #undef below. + +namespace contract { + +// F TEMPLATE PARAMETER SYNTAX +// Boost.Function preferred syntax is used for F so class type is +// passed as pointer in the 1st argumetn +// `ResultType (ClassType*, ArgumentType1, ...)`. +// A more natural syntax would have been to use C++ function pointer +// types as they already have different syntaxes to distinguish +// between members `ResulType (ClassType::*)(ArgumentType1, ...)` and +// non-members `ResultType (*)(ArgumentType1, ...)` (this would aslo +// unified nonstatic_member_function and nonmember_function into a +// signle template). However, some compilers do not fully support +// function pointers to resolve partial template specializations as +// needed by this library (notably, I have tried this and it compiled +// well on GCC but MSVC could not distinguish +// `ResultType (ClassType::*)(...) const` from +// `void (ClassType::*)() const`). Using Boost.Function works well +// plus harmonizes this library more with Boost. +// (The most portable syntax would have been the portable, not +// preferred, Boost.Function syntax but that is obsolete and supported +// by Boost.Function only for backward compatibility). + +// PRE/POST/BODY FUNCTION PTR PASSING +// Teorethically, precondition, postcondition, and body function +// pointers could be passed as template parameters. However, that +// does not compile on some compliers for overloaded templated +// functions (like MSVC)... so these function pointers are passed to +// the constructor. +// Both options are fine for subcontracting, because even in the +// second case the derived class constructs a base contract object +// via its default constructor which set pre, post, and body function +// pointer. Furthermore, the body function pointer could be passed to +// call() instead than to the consturctor because the body is not +// needed when subcontracting (only pre and post are) but all +// functions are passed together to the constructor for consistency. + +// Should never be used directly (use only the specializations). +template ... + BOOST_PP_ENUM_TRAILING( + CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_tparam_BaseContractClass_default, ~) + > +class nonstatic_member_function { + BOOST_MPL_ASSERT_MSG(0, CONTRACT_specified_invalid_function_type_template_parameter_F, ()); +}; + +} // namespace + +// Self-iterate this file over arity, void, const, and member. +# define BOOST_PP_ITERATION_PARAMS_1 (3, \ + (0, CONTRACT_CONFIG_MAX_FUNCTION_ARITY, \ + CONTRACT_CONFIG_NONSTATIC_MEMBER_FUNCTION_HPP_FILE_PATH_)) +# include BOOST_PP_ITERATE() // Iter over arity. +# include "aux_/function/local_macros_undef.hpp" // #define above. +# endif // #include guard +# // 1st self-iteration over function-arity. +#elif BOOST_PP_ITERATION_DEPTH() == 1 +# define BOOST_PP_ITERATION_PARAMS_2 (3, (0, 1, \ + CONTRACT_CONFIG_NONSTATIC_MEMBER_FUNCTION_HPP_FILE_PATH_)) +# include BOOST_PP_ITERATE() // Iter over 0 void, 1 non-void func. +# // 2nd self-iteration over void/non-void function. +#elif BOOST_PP_ITERATION_DEPTH() == 2 +# // Define local macros directly depending on iteration. +# define CONTRACT_arity \ + BOOST_PP_SUB(BOOST_PP_FRAME_FINISH(1), BOOST_PP_FRAME_ITERATION(1)) +# define CONTRACT_is_not_void BOOST_PP_NOT(BOOST_PP_FRAME_ITERATION(2)) +# define CONTRACT_is_member 1 // Always a member function. + +namespace contract { + +template< + class ClassType + // , ResultType (if not void) + BOOST_PP_COMMA_IF(CONTRACT_is_not_void) + BOOST_PP_EXPR_IF(CONTRACT_is_not_void, typename ResultType) + // , ArgumentType0 ... + BOOST_PP_COMMA_IF(CONTRACT_arity) + BOOST_PP_ENUM(CONTRACT_arity, + CONTRACT_tparam_ArgumentType, ~) + // , BaseContractClass0 ... + BOOST_PP_COMMA_IF(CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE) + BOOST_PP_ENUM( + CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_tparam_BaseContractClass, ~) + > +class nonstatic_member_function< + // ResultType ([ClassType::]*)(ArgumentType0, ...) [const] + CONTRACT_f(1 /* member function */) + // , BaseContractClass0 ... + BOOST_PP_ENUM_TRAILING( + CONTRACT_CONFIG_MAX_MULTIPLE_INHERITANCE, + CONTRACT_BaseContractClass, ~) + >: + + // This base class is made noncopyable so all contract classes are not + // copyable. This is because there was no need to copy contract classes + // but if there will ever be a need it might be possible to define + // copy operation with correct semantics and remove this constraint. + boost::noncopyable { + +# include "aux_/function/contract_class_implement.hpp" + +}; // class + +} // namespace + +# // Undef ALL local macros directly depending on iteration. +# undef CONTRACT_arity +# undef CONTRACT_is_not_void +# undef CONTRACT_is_member +#else // Self-iteration out-of-range (should never happen...). +# error "Preprocessor iteration depth out-of-range (internal error)" + +#endif // BOOST_PP_IS_ITERATING + diff --git a/src/contract/old.hpp b/src/contract/old.hpp new file mode 100755 index 00000000..b2fdd593 --- /dev/null +++ b/src/contract/old.hpp @@ -0,0 +1,84 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_OLD_HPP_ +#define CONTRACT_OLD_HPP_ + +#include "aux_/symbol.hpp" +#include "boost/type_traits.hpp" +#include "boost/utility.hpp" + +#define CONTRACT_OLDOF(variable_name) \ + CONTRACT_AUX_INTERNAL_SYMBOL(BOOST_PP_CAT(old_, variable_name)) + +namespace contract { + +// Old // + +// IMPORTANT: This class should be an "empty shell" so compiler +// should be able to optimize away this type (0 size), the calls to +// its constructor (since they have no effect), and passing this type +// by value in function calls. Therefore, this class should add no +// runtime overhead in handling old values for non-copyable types. +class noold { +public: + // Needed by the library internally to pass old by value. + template + /* no explicit */ noold(T const&) + // IMPORTANT: This copy operation must do nothing so to + // add not overhead when copying noold values. + {} + + // IMPORTANT: Must have NO implementation so compile-time error + // if attempt to use any variable of noold type in postconditions. + +private: + noold& operator=(noold const&); // No copy operator. +}; + +// Copy // + +template class copyable; + +// Copy wrapper that holds copied object. +// IMPORTANT: This class template is declared here instead that in +// contract::aux because users might want to declare it friend when +// they want this library to access copy constructors that would be +// otherwise private. A class might be copyable only to support +// contract but not in general (see "counter" example in +// [Mitchell2002]): +// class c { +// private: +// // Only contract library can access copy constructor. +// friend class contract::copy; +// c(c const& source); +// }; +// Also the user could specialized this template for a user's defined +// type so to relax the constant-correct copy constructor requirement. +// NOTE: If T is noold, this copy does not add any overhead because +// noold implements its copy constructor to do nothing. +template +class copy: boost::noncopyable { +private: + // Value type removes ref (so it will deep copy ref) but keeps + // ptr (so it will NOT deep copy ptr). + typedef typename boost::add_const::type>::type const_type; + // For argument passing. + typedef typename boost::add_reference::type const_ref; + +public: + const_type value; // Hold copied object. + + // Source passed as const ref ensuring contract const-correctness. + copy(const_ref source): + // Value type not a ref so this will copy. + value(source) {} +}; + +} // namespace + +#endif // #include guard + diff --git a/src/contract/state.hpp b/src/contract/state.hpp new file mode 100755 index 00000000..34ef49ba --- /dev/null +++ b/src/contract/state.hpp @@ -0,0 +1,69 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_STATE_HPP_ +#define CONTRACT_STATE_HPP_ + +#include "aux_/sync.hpp" + +namespace contract { + +// Contracted class (ClassType) must declare this class a friend and +// it must declare a mutable (private) member variable of type +// `state` with name `contract_state_`. +class state { +public: + state(): object_checking_contract_(false) {} + + // WARNING: All contents of this class are library implementation + // specific -- that is why they are all postfixed with "_". + // !!!THEY MUST NOT BE USED DIRECTLY IN USER CODE!!! + + // If threading, this should be sync'd (use sync<>). + aux::sync object_checking_contract_; + + // WORKAROUND: Duplicate Friend Warning + // The following functions are used to access object private or + // protected components because this state class is made friend + // of the class type. This way, only one friendship is required. + // (The alternative would have been to declare function::member + // class friend but that would have required to repeat the + // friendship multiple times because for all the different used + // template instantiations of function::member causing warnings + // on some compilers.) + + template + static state& get_state_(ClassType const* const object) { + // contract_state_ mutable so non-const state& can be + // returned here from const object. + return object->CONTRACT_CONFIG_STATE_VARIABLE_; + } + + template + static void call_static_invariant_() { + // Static invariant function is static so no object. + ClassType::CONTRACT_CONFIG_STATIC_INVARIANT_FUNCTION_(); + } + + template + static void call_invariant_(ClassType const* const object) { + // Invariant function must be const-member (object is const). + object->CONTRACT_CONFIG_INVARIANT_FUNCTION_(); + } + + template + static void to_base_(ClassType const* const object, + BaseClassType const*& base_object) { + // This is not a cast! It will correctly generate a + // compile-time error if the library miss uses it when + // BaseClassType is not a base type of ClassType. + base_object = object; + } +}; + +} // namespace + +#endif // #include guard + diff --git a/src/contract/static_member_function.hpp b/src/contract/static_member_function.hpp new file mode 100755 index 00000000..f5712117 --- /dev/null +++ b/src/contract/static_member_function.hpp @@ -0,0 +1,155 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#if !BOOST_PP_IS_ITERATING +# // Include guards (but only if not iter). +# ifndef CONTRACT_STATIC_MEMBER_FUNCTION_HPP_ +# define CONTRACT_STATIC_MEMBER_FUNCTION_HPP_ +# include "nonmember_function.hpp" +# include +# include +# include "aux_/function/local_macros_define.hpp" // #undef below. + +namespace contract { + +// Should never be used directly (use only the specializations). +template +class static_member_function { + BOOST_MPL_ASSERT_MSG(0, CONTRACT_ERROR_specified_invalid_function_type_template_parameter_F, ()); +}; + +} // namespace + +// Self-iterate this file over arity, void, and const. +# define BOOST_PP_ITERATION_PARAMS_1 (3, \ + (0, CONTRACT_CONFIG_MAX_FUNCTION_ARITY, \ + CONTRACT_CONFIG_STATIC_MEMBER_FUNCTION_HPP_FILE_PATH_)) +# include BOOST_PP_ITERATE() // Iter over arity. +# include "aux_/function/local_macros_undef.hpp" // #define above. +# endif // #include guard +# // 1st self-iteration over function-arity. +#elif BOOST_PP_ITERATION_DEPTH() == 1 +# define BOOST_PP_ITERATION_PARAMS_2 (3, (0, 1, \ + CONTRACT_CONFIG_STATIC_MEMBER_FUNCTION_HPP_FILE_PATH_)) +# include BOOST_PP_ITERATE() // Iter over 0 void, 1 non-void func. +# // 2nd self-iteration over void/non-void function. +#elif BOOST_PP_ITERATION_DEPTH() == 2 +# // Define local macros directly depending on iteration. +# define CONTRACT_arity \ + BOOST_PP_SUB(BOOST_PP_FRAME_FINISH(1), BOOST_PP_FRAME_ITERATION(1)) +# define CONTRACT_is_not_void BOOST_PP_NOT(BOOST_PP_FRAME_ITERATION(2)) +# define CONTRACT_is_member 1 // Always a member function. + +namespace contract { + +template +class static_member_function: + // Static pre/post are like if not a member so inherit + // from non-member but override to check static inv. + public nonmember_function< + CONTRACT_f(0 /* static so as if non-member */)> { + BOOST_MPL_ASSERT_MSG( + boost::mpl::not_< aux::is_copyable >::value, + CONTRACT_ERROR_class_type_cannot_be_copyable_for_static_member_functions, (ClassType)); + BOOST_MPL_ASSERT_MSG( + boost::mpl::not_< boost::is_const >::value, + CONTRACT_ERROR_class_type_cannot_be_const_for_static_member_functions, (ClassType)); + +private: + // Type manipulations (see nonmember_function<>). + CONTRACT_typedef_maybeconst_class_type + CONTRACT_typedef_class_type // No static subcontract so private. + CONTRACT_typedef_maybeconst_class_ptr + CONTRACT_typedef_arg_class_ptr; + CONTRACT_typedef_old_class_type + CONTRACT_typedef_arg_old_class_ptr + BOOST_PP_EXPR_IF(BOOST_PP_NOT(CONTRACT_is_not_void), + typedef void ResultType;) + CONTRACT_typedef_arg_result_type + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_argument_type, ~) + BOOST_PP_REPEAT(CONTRACT_arity, CONTRACT_typedef_argument_ref, ~) + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_typedef_arg_argument_type, ~) + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_typedef_old_argument_type, ~) + BOOST_PP_REPEAT(CONTRACT_arity, + CONTRACT_typedef_arg_old_argument_type, ~) + + CONTRACT_typedef_static_precondition_function_ptr + CONTRACT_typedef_static_postcondition_function_ptr + CONTRACT_typedef_body_function_ptr(0 /* static body */) + +#if CONTRACT_CONFIG_DEBUG_ + // Use body type (not class) for consistency with non-member. +private: typedef body_function_ptr debug_type; +#endif // debug + +public: + static_member_function(body_function_ptr body_function + // Static pre/post condition function types (no object). +#if defined CONTRACT_CHECK_PRECONDITION + , static_precondition_function_ptr precondition_function +#endif // check precondition +#if defined CONTRACT_CHECK_POSTCONDITION + , static_postcondition_function_ptr postcondition_function +#endif // check postcondition + ): nonmember_function< + CONTRACT_f(0 /* static as if non-member */)>( + body_function +#if defined CONTRACT_CHECK_PRECONDITION + , precondition_function +#endif // check precondition +#if defined CONTRACT_CHECK_POSTCONDITION + , postcondition_function +#endif // check postcondition + ) {} + +private: + inline from here() const { return FROM_STATIC_MEMBER_FUNCTION; } + +#if defined CONTRACT_CHECK_CLASS_INVARIANT + // Override to check static invariants. + inline void check_invariant() { + try { + aux::globally_checking_contract = true; + // POLICTY: For static member, only check static + // invariants (never disabled). + + // Log using static body sign (not class_type). + CONTRACT_AUX_DEBUGT(debug_type, dbg + << "Checking static invariants"); + state::call_static_invariant_(); + + aux::globally_checking_contract = false; + } catch (...) { + aux::globally_checking_contract = false; + throw; + } + } +#endif // check invariant + +}; // class + +} // namespace + +# // Undef ALL local macros directly depending on iteration. +# undef CONTRACT_arity +# undef CONTRACT_is_not_void +# undef CONTRACT_is_member +#else // Self-iteration out-of-range (should never happen...). +# error "Preprocessor iteration depth out-of-range (internal error)" + +#endif // BOOST_PP_IS_ITERATING + diff --git a/src/contract/wrap.hpp b/src/contract/wrap.hpp new file mode 100755 index 00000000..beb2e765 --- /dev/null +++ b/src/contract/wrap.hpp @@ -0,0 +1,57 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +#ifndef CONTRACT_WRAP_HPP_ +#define CONTRACT_WRAP_HPP_ + +#include + +// Tools to workaround preprocessor limitations when passing macro +// parameters containing commas. +// All these approaches require using a large number of `()` because +// these are the only parenthesis recognized by the preprocessor. +// Essentially these tools provide a method to wrap all expressions +// (code blocks, types, etc) that might be passed as a macro +// parameter within `()` (and in addition to the `()` wrapping +// already required to build preprocessor sequences). +// +// VALUES +// Value expressions with commas must be wrapped by an extra +// `( ... )` when passed as macro parameters: +// CONTRACT_ASSERT( ( std::map().empty() ) ); +// +// TYPES +// Type macro parameters with commas are wrapped by `( ... )` using +// the wrapper template that wraps the comma-separated type as the +// first argument of a function type. A macro is also provided to +// ease the use of the template class: +// (typename CONTRACT_WRAP_TYPE( (std::map) )) +// `typename` must be used _outside_ the macro when within templates. +// +// CODE bLOCKS +// Use a combination of value and type expression wrapping. + +#define CONTRACT_WRAP_TYPE(parenthesized_type) \ + /* must NOT prefix with `::` to work within contract macros */ \ + contract::wrap::type + +namespace contract { + +// Never used. +template struct wrap { + BOOST_MPL_ASSERT_MSG(false, + CONTRACT_ERROR_invalid_use_of_wrap_class_see_CONTRACT_WRAP_TYPE_macro, ()); +}; + + +// In the past I had to drop const here.. why? That was done with +// an additional specialization like below, is that still needed? +// template struct wrap { typedef T& type; }; +template struct wrap { typedef T type; }; + +} // namespace + +#endif // #include guard + diff --git a/svnignore b/svnignore new file mode 100755 index 00000000..0e06b3ed --- /dev/null +++ b/svnignore @@ -0,0 +1,5 @@ +#!/bin/bash + +svn propset svn:ignore ' +build +' . diff --git a/test/Makefile b/test/Makefile new file mode 100755 index 00000000..c584242c --- /dev/null +++ b/test/Makefile @@ -0,0 +1,48 @@ +# Copyright (C) 2009-2010 Lorenzo Caminiti. +# Use, modification, and distribution is subject to the +# Contract++ Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt.) + +# Supported C++ compliers `make CXX=compiler ...', where compiler is: +# GCC GNU g++ (e.g., on Linux) (default) +# MSVC Microsoft Visual C++ (e.g., on Cygwin) +CXX=GCC + +bin:=./bin +ifeq ($(CXX), GCC) + cpp_nodef:=g++ -Wall -Werror -I./src + def:=-D + out:=-o +endif +ifeq ($(CXX), MSVC) + # Don't use /Wall for MSVC has very verbose warnings (even in Boost?!). + cpp_nodef:=source $(bin)/env-MSVC8.sh && cl.exe /EHsc /I./src + def:=/D + out:=/Fe +endif +cpp:=$(cpp_nodef) $(def)CONTRACT_CHECK_BLOCK_INVARIANT $(def)CONTRACT_CHECK_CLASS_INVARIANT $(def)CONTRACT_CHECK_PRECONDITION $(def)CONTRACT_CHECK_POSTCONDITION +ifeq ($(debug), 1) + cpp:=$(cpp) $(def)CONTRACT_CONFIG_DEBUG_=1 +endif + +src:=./test +build:=./build/test +codedoc:=./codedoc/test + +all: usages subcontracting overloading templates + +clean: + rm -rf $(build) + +mkdir_: + mkdir -p $(build) + +usages: mkdir_ + $(cpp) $(src)/usages/main.cpp $(out)$(build)/usages +subcontracting: mkdir_ + $(cpp) $(src)/subcontracting/main.cpp $(out)$(build)/subcontracting +overloading: mkdir_ + $(cpp) $(src)/overloading/main.cpp $(out)$(build)/overloading +templates: mkdir_ + $(cpp) $(src)/templates/main.cpp $(out)$(build)/templates + diff --git a/test/README.txt b/test/README.txt new file mode 100755 index 00000000..73a14281 --- /dev/null +++ b/test/README.txt @@ -0,0 +1,2 @@ +Programs to test the library correct implementation. + diff --git a/test/overloading/main.cpp b/test/overloading/main.cpp new file mode 100755 index 00000000..5e785bbc --- /dev/null +++ b/test/overloading/main.cpp @@ -0,0 +1,167 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Test overloaded and overridden functions. +// This is important because the library implementation uses function +// pointer so this tests compilers can resolve the calls of +// ovierloaded (overridden and templated) function pointers correctly. + +#include +#include +#include +#include + +class name_list { + + CONTRACT_INVARIANT( ({}) ) + +public: + virtual void put(const std::string& name) + CONTRACT_FUNCTION( (class) (name_list) + (public) (virtual) (void) (put)( + (const std::string&)(name) ) + (precondition) ({ + std::cout << "base pre put(string)\n"; + }) + (postcondition) ({ + std::cout << "base post put(string)\n"; + }) + (body) ({ + std::cout << "base body put(string)\n"; + std::cout << name << std::endl; + }) ) + + virtual void put(const std::string& name) const + CONTRACT_FUNCTION( (class) (name_list) + (public) (virtual) (void) (put)( + (const std::string&)(name) ) (const) + (precondition) ({ + std::cout << "base pre put(string) const\n"; + }) + (postcondition) ({ + std::cout << "base post put(string) const\n"; + }) + (body) ({ + std::cout << "base body put(string) const\n"; + std::cout << name << std::endl; + }) ) +}; + +class relaxed_name_list: public name_list { + + CONTRACT_INVARIANT( ({}) ) + +public: + virtual void put(const std::string& name) + CONTRACT_FUNCTION( (class) (relaxed_name_list) (inherit)(name_list) + (public) (virtual) (void) (put)( + (const std::string&)(name) ) + (precondition) ({ + std::cout << "derived pre put(string)\n"; + }) + (postcondition) ({ + std::cout << "derived post put(string)\n"; + }) + (body) ({ + std::cout << "derived body put(string)\n"; + std::cout << name << std::endl; + }) ) + + // Overload based on const qualifier. + virtual void put(const std::string& name) const + CONTRACT_FUNCTION( (class) (relaxed_name_list) (inherit)(name_list) + (public) (virtual) (void) (put)( + (const std::string&)(name) ) (const) + (precondition) ({ + std::cout << "derived pre put(string) const\n"; + }) + (postcondition) ({ + std::cout << "derived post put(string) const\n"; + }) + (body) ({ + std::cout << "derived body put(string) const\n"; + std::cout << name << std::endl; + }) ) + + // Library requires that all but const qualified overloads must + // use different argument names (not just different types). + + // No subcontractin for the following because they have no + // matching functions in base class. + + // Overload based on argument type. + virtual void put(const int& number) + CONTRACT_FUNCTION( (class) (relaxed_name_list) + (public) (virtual) (void) (put)( (const int&)(number) ) + (precondition) ({ + std::cout << "derived pre put(int)\n"; + }) + (postcondition) ({ + std::cout << "derived post put(int)\n"; + }) + (body) ({ + std::cout << "derived body put(int)\n"; + std::cout << number << std::endl; + }) ) + + // Overload based on argument number. + virtual void put(const std::string& name, const int& number) + CONTRACT_FUNCTION( (class) (relaxed_name_list) + (public) (virtual) (void) (put)( + (const std::string&)(name) (const int&)(number) ) + (precondition) ({ + std::cout << "derived pre put(string, int)\n"; + }) + (postcondition) ({ + std::cout << "derived post put(string, int)\n"; + }) + (body) ({ + std::cout << "derived body put(string, int)\n"; + std::cout << name << " " << number << std::endl; + }) ) + + // Overload based on templated parameter. + template + void put(const T& element) // Template cannot be virtual. + CONTRACT_FUNCTION( (class) (relaxed_name_list) + (public) (template)( (typename)(T) ) + (void) (put)( (const T&)(element) ) + (precondition) ({ + std::cout << "derived pre put(T)\n"; + }) + (postcondition) ({ + std::cout << "derived post put(T)\n"; + }) + (body) ({ + std::cout << "derived body put(T)\n"; + std::cout << element << std::endl; + }) ) +}; + +int main() { + std::string s; // Make sure string type is used (not char*). + + name_list n; + const name_list& const_n = n; + std::cout << std::endl; + n.put(s = "abc"); // Call put(string). + std::cout << std::endl; + const_n.put(s = "ijk"); // Call put(string) const. + + relaxed_name_list r; + const relaxed_name_list& const_r = r; + std::cout << std::endl; + r.put(s = "xyz"); // Call put(string). + std::cout << std::endl; + const_r.put(s = "uvw"); // Call put(string) const. + std::cout << std::endl; + r.put(3); // Call put(int). + std::cout << std::endl; + r.put(s = "rst", 5); // Call put(string, int). + std::cout << std::endl; + r.put(1.23); // Call put(T) T=double. + + return 0; +} diff --git a/test/subcontracting/main.cpp b/test/subcontracting/main.cpp new file mode 100755 index 00000000..9881bb5e --- /dev/null +++ b/test/subcontracting/main.cpp @@ -0,0 +1,161 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Test subcontracting overridden functions with multiple inheritance. + +// Multiple inheritance of a0 and b0 creates inheritance loop because +// also b0 inherits from a0. Loop is resolved using C++ virtual +// inheritance and the library works correctly (but this causes +// duplicate contract checking of a0). + +// Deep inheritance from c0 which has 2 more base classes. + +#include +#include + +// Base classes a. + +class a0 { + + CONTRACT_INVARIANT( ({ + std::cout << "a0::inv()" << std::endl; + }) ) + +public: + virtual void f(int i) + CONTRACT_FUNCTION( (class) (a0) + (public) (virtual) (void) (f)( (int)(i) ) + (precondition) ({ + std::cout << "a0::pre()" << std::endl; + }) + (postcondition) ({ + std::cout << "a0::post()" << std::endl; + }) + (body) ({ + std::cout << "a0::body()" << std::endl; + }) ) +}; + +// Base classes b. + +class b0: virtual public a0 { + + CONTRACT_INVARIANT( ({ + std::cout << "b0::inv()" << std::endl; + }) ) + +public: + virtual void f(int i) + CONTRACT_FUNCTION( (class) (b0) + (inherit)(a0) + (public) (virtual) (void) (f)( (int)(i) ) + (precondition) ({ + std::cout << "b0::pre()" << std::endl; + }) + (postcondition) ({ + std::cout << "b0::post()" << std::endl; + }) + (body) ({ + std::cout << "b0::body()" << std::endl; + }) ) +}; + +// Base classes c. + +class c2 { + + CONTRACT_INVARIANT( ({ + std::cout << "c2::inv()" << std::endl; + }) ) + +public: + virtual void f(int i) + CONTRACT_FUNCTION( (class) (c2) + (public) (virtual) (void) (f)( (int)(i) ) + (precondition) ({ + std::cout << "c2::pre()" << std::endl; + }) + (postcondition) ({ + std::cout << "c2::post()" << std::endl; + }) + (body) ({ + std::cout << "c2::body()" << std::endl; + }) ) +}; + +class c1: public c2 { + + CONTRACT_INVARIANT( ({ + std::cout << "c1::inv()" << std::endl; + }) ) + +public: + virtual void f(int i) + CONTRACT_FUNCTION( (class) (c1) + (inherit)(c2) + (public) (virtual) (void) (f)( (int)(i) ) + (precondition) ({ + std::cout << "c1::pre()" << std::endl; + }) + (postcondition) ({ + std::cout << "c1::post()" << std::endl; + }) + (body) ({ + std::cout << "c1::body()" << std::endl; + }) ) +}; + +class c0: public c1 { + + CONTRACT_INVARIANT( ({ + std::cout << "c0::inv()" << std::endl; + }) ) + +public: + virtual void f(int i) + CONTRACT_FUNCTION( (class) (c0) + (inherit)(c1) + (public) (virtual) (void) (f)( (int)(i) ) + (precondition) ({ + std::cout << "c0::pre()" << std::endl; + }) + (postcondition) ({ + std::cout << "c0::post()" << std::endl; + }) + (body) ({ + std::cout << "c0::body()" << std::endl; + }) ) +}; + +// Derived class x. + +class x: virtual public a0, public b0, public c0 { + + CONTRACT_INVARIANT( ({ + std::cout << "x::inv()" << std::endl << std::endl; + }) ) + +public: + virtual void f(int i) + CONTRACT_FUNCTION( (class) (x) + // Subcontract from 3 base classes (multiple inheritance). + (inherit)(a0) (inherit)(b0) (inherit)(c0) + (public) (virtual) (void) (f)( (int)(i) ) + (precondition) ({ + std::cout << "x::pre()" << std::endl << std::endl; + }) + (postcondition) ({ + std::cout << "x::post()" << std::endl << std::endl; + }) + (body) ({ + std::cout << std::endl << "x::body()" << std::endl << std::endl; + }) ) +}; + +int main() { + x xx; + xx.f(1); + return 0; +} diff --git a/test/templates/main.cpp b/test/templates/main.cpp new file mode 100755 index 00000000..d9f318ec --- /dev/null +++ b/test/templates/main.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Test support for template class and functions. + +#include +#include + +// Class template params (types and variables with default values). +template +class x { + + CONTRACT_INVARIANT( (static) ({ + CONTRACT_ASSERT( N_NUMBER > 0 ); + }) ) + +public: + // Funciton template params (types and variables -- C++ forbids + // default function template params). + // Multiple template params to test commas within macro expansion. + template + void add(V value = V_DEFAULT) + CONTRACT_FUNCTION( (class) (x) + (public) (template)( (typename)(V) (V)(V_DEFAULT) ) + (void) (add)( (V)(value) ) + (body) ({ + std::cout << value + N_NUMBER << std::endl; + }) ) +}; + +int main() { + x<> xx; + xx.add(); + return 0; +} + diff --git a/test/usages/main.cpp b/test/usages/main.cpp new file mode 100755 index 00000000..751bfe9e --- /dev/null +++ b/test/usages/main.cpp @@ -0,0 +1,156 @@ +// Copyright (C) 2009-2010 Lorenzo Caminiti. +// Use, modification, and distribution is subject to the +// Contract++ Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt.) + +// Test most of library usages. + +#include +#include + +class c { + + CONTRACT_INVARIANT( (static)({ + std::cout << "inv (static)\n"; + CONTRACT_ASSERT( x >= 0 ); + }) + ({ + std::cout << "inv (dynamic)\n"; + CONTRACT_ASSERT( i_ >= 0 ); + }) ) + +public: + + // Constructor. + c(int i = 0): i_(i) + CONTRACT_CONSTRUCTOR( (class) (c) + (public) (c)( (int)(i) ) + (precondition) ({ + std::cout << "pre c::c()\n"; + }) + (postcondition) ({ + std::cout << "post c::c()\n"; + }) + (body) ({ + std::cout << "body c::c()\n"; + }) ) + + // Destructor (virtual). + virtual ~c(void) + CONTRACT_DESTRUCTOR( (class) (c) + (public) (virtual) (c)( (void) ) + (body) ({ + std::cout << "body c::~c()\n"; + }) ) + + // Non-const member function with cooyable object. + double f(int i) + CONTRACT_FUNCTION( (class) (copyable)(c) + (public) (double) (f)( (int)(i) ) + (precondition) ({ + std::cout << "pre c::f()\n"; + }) + (postcondition) (result) ({ + std::cout << "post c::f()\n"; + }) + (body) ({ + std::cout << "body c::f()\n"; + return i; + }) ) + + // Overloaded const member function template. + template + double f(T t) const + CONTRACT_FUNCTION( (class) (c) + (public) (template)( (typename)(T) ) + (double) (f)( (T)(t) ) (const) + (precondition) ({ + std::cout << "pre template c::f() const\n"; + }) + (postcondition) (result) ({ + std::cout << "post template c::f() const\n"; + }) + (body) ({ + std::cout << "body template c::f() const\n"; + return t; + }) ) + + // Static member function. + static double s(int i) + CONTRACT_FUNCTION( (class) (c) + (public) (static) (double) (s)( (int)(i) ) + (precondition) ({ + std::cout << "pre c::s()\n"; + CONTRACT_ASSERT( i > 0 ); + }) + (postcondition) (result) ({ + std::cout << "post c::s()\n"; + CONTRACT_ASSERT( x == i ); + CONTRACT_ASSERT( result == double(x) ); + }) + (body) ({ + std::cout << "body c::s()\n"; + return x = i; + }) ) + +private: + static int x; + int i_; +}; + +template +class t { + + CONTRACT_INVARIANT( ({}) ) + +public: + + double f(T i) const + CONTRACT_FUNCTION( (class) (t) + (public) (double) (f)( (T)(i) ) (const) + (precondition) ({ + std::cout << "pre template c::f() const\n"; + }) + (postcondition) (result) ({ + std::cout << "post template c::f() const\n"; + }) + (body) ({ + std::cout << "body template c::f() const\n"; + return i; + }) ) +}; + +int c::x = 0; + +// Non-member function witha copyable argument. +void a(const int&x, int& y) +CONTRACT_FUNCTION( (void) (a)( (const int&)(x) (copyable)(int&)(y) ) +(precondition) ({ + std::cout << "pre a()\n"; +}) +(postcondition) ({ + std::cout << "post a()\n"; + std::cout << " oldof(y) = " << CONTRACT_OLDOF(y) << std::endl; + std::cout << " y = " << y << std::endl; +}) +(body) ({ + std::cout << "body a()\n"; + y = x; +}) ) + +int main() { + c cc; + const c& const_cc = cc; + cc.f(1); + const_cc.f(1.2); // Call const member. + c::s(3); + + t tt; + tt.f(1.23); + + int z = -1; + a(2, z); + + return 0; +}; +