diff --git a/doc/qbk/contract.qbk b/doc/qbk/contract.qbk index 6dd6fc4..fc5fc47 100644 --- a/doc/qbk/contract.qbk +++ b/doc/qbk/contract.qbk @@ -127,7 +127,7 @@ Consult this documentation in [@index.html HTML] or [@contractpp.pdf PDF] format [/ include virtual_specifiers.qbk] [/ include concepts.qbk] [/ include named_parameters.qbk] -[/ include examples.qbk] +[include examples.qbk] [include grammar.qbk] [/ include no_variadic_macros.qbk] [/ xinclude reference.xml] diff --git a/doc/qbk/examples.qbk b/doc/qbk/examples.qbk index ac55374..18e03fb 100644 --- a/doc/qbk/examples.qbk +++ b/doc/qbk/examples.qbk @@ -8,7 +8,7 @@ [section Examples] This section lists non-trivial examples programmed using this library. -The listed examples are taken from the foloowing sources (which are referenced in the title of each example). +The listed examples are taken from the following sources (which are referenced in the title of each example). [table [ [Sources] [Notes] ] @@ -55,9 +55,9 @@ A comparison between this library and A++ syntax. ] [section \[N1962\] Vector: Comparison with C++ proposed syntax] -[import ../example/n1962/vector.hpp] -[import ../example/n1962/vector.cpp] -[import ../example/n1962/vector_npaper.hpp] +[/ import ../example/n1962/vector.hpp] +[/ import ../example/n1962/vector.cpp] +[/ import ../example/n1962/vector_npaper.hpp] [table [ [This Library (C++03)] [\[N1962\] and \[N2081\] Proposals (not part of C++)] ] [ [[n1962_vector]] [[n1962_vector_npaper]] ] @@ -66,36 +66,36 @@ A comparison between this library and A++ syntax. [endsect] [section \[N1962\] Circle: Subcontracting] -[import ../example/n1962/circle.cpp] +[/ import ../example/n1962/circle.cpp] [n1962_circle] [endsect] [section \[N1962\] Factorial: Recursion and assertion computational complexity] -[import ../example/n1962/factorial.cpp] +[/ import ../example/n1962/factorial.cpp] [n1962_factorial] [endsect] [section \[N1962\] Equal: Operators] -[import ../example/n1962/equal.hpp] +[/ import ../example/n1962/equal.hpp] [n1962_equal_header] -[import ../example/n1962/equal_not.hpp] +[/ import ../example/n1962/equal_not.hpp] [n1962_equal_not_header] -[import ../example/n1962/equal_main.cpp] +[/ import ../example/n1962/equal_main.cpp] [n1962_equal_main] [endsect] [section \[N1962\] Sum: Separated body definitions] -[import ../example/n1962/sum.hpp] +[/ import ../example/n1962/sum.hpp] [n1962_sum_header] -[import ../example/n1962/sum.cpp] +[/ import ../example/n1962/sum.cpp] [n1962_sum] -[import ../example/n1962/sum_main.cpp] +[/ import ../example/n1962/sum_main.cpp] [n1962_sum_main] [endsect] [section \[N1962\] Square Root: Default parameters and comparison with D syntax] -[import ../example/n1962/sqrt.cpp] -[import ../example/n1962/sqrt.d] +[/ import ../example/n1962/sqrt.cpp] +[/ import ../example/n1962/sqrt.d] [table [ [This Library (C++03)] [The D Programming Language] ] [ [[n1962_sqrt]] [[n1962_sqrt_d]] ] @@ -103,87 +103,87 @@ A comparison between this library and A++ syntax. [endsect] [section \[N1962\] Block: Block invariants] -[import ../example/n1962/block_invariant.cpp] +[/ import ../example/n1962/block_invariant.cpp] [n1962_block_invariant] [endsect] [section \[N2081\] Add: Generic addition algorithm] -[import ../example/n2081/add.hpp] +[/ import ../example/n2081/add.hpp] [n2081_add_header] -[import ../example/n2081/add.cpp] +[/ import ../example/n2081/add.cpp] [n2081_add] -[import ../example/n2081/add_error.cpp] +[/ import ../example/n2081/add_error.cpp] [n2081_add_error] [endsect] [section \[N2081\] Advance: Concept-based iterator overloading (emulated using tags)] -[import ../example/n2081/advance.cpp] +[/ import ../example/n2081/advance.cpp] [n2081_advance] [endsect] [section \[N2081\] Find: Generic find algorithm] -[import ../example/n2081/find.hpp] +[/ import ../example/n2081/find.hpp] [n2081_find_header] -[import ../example/n2081/find.cpp] +[/ import ../example/n2081/find.cpp] [n2081_find] -[import ../example/n2081/find_error.cpp] +[/ import ../example/n2081/find_error.cpp] [n2081_find_error] [endsect] [section \[N2081\] Apply: Overloaded invocation of functors] -[import ../example/n2081/apply.cpp] +[/ import ../example/n2081/apply.cpp] [n2081_apply] [endsect] [section \[N2081\] For Each: Generic for-each algorithm] -[import ../example/n2081/for_each.cpp] +[/ import ../example/n2081/for_each.cpp] [n2081_for_each] [endsect] [section \[N2081\] Transform: Generic binary transformation algorithm] -[import ../example/n2081/transform.cpp] +[/ import ../example/n2081/transform.cpp] [n2081_transform] [endsect] [section \[N2081\] Count: Generic counting algorithm] -[import ../example/n2081/count.cpp] +[/ import ../example/n2081/count.cpp] [n2081_count] [endsect] [section \[N2081\] Convert: Conversion between two types] -[import ../example/n2081/convert.hpp] +[/ import ../example/n2081/convert.hpp] [n2081_convert_header] -[import ../example/n2081/convert.cpp] +[/ import ../example/n2081/convert.cpp] [n2081_convert] -[import ../example/n2081/convert_error.cpp] +[/ import ../example/n2081/convert_error.cpp] [n2081_convert_error] [endsect] [section \[N2081\] Equal: Generic equality comparison] -[import ../example/n2081/equal.hpp] +[/ import ../example/n2081/equal.hpp] [n2081_equal_header] -[import ../example/n2081/equal.cpp] +[/ import ../example/n2081/equal.cpp] [n2081_equal] -[import ../example/n2081/equal_error.cpp] +[/ import ../example/n2081/equal_error.cpp] [n2081_equal_error] [endsect] [section \[N2081\] Less Equal: Generic less-than or equal-to comparison] -[import ../example/n2081/less_eq.cpp] +[/ import ../example/n2081/less_eq.cpp] [n2081_less_eq] [endsect] [section \[N2081\] De-Ref: Generic iterator dereferencing] -[import ../example/n2081/deref.cpp] +[/ import ../example/n2081/deref.cpp] [n2081_deref] [endsect] [section \[N2081\] Min: Generic minimum algorithm] -[import ../example/n2081/min.hpp] +[/ import ../example/n2081/min.hpp] [n2081_min_header] -[import ../example/n2081/min.cpp] +[/ import ../example/n2081/min.cpp] [n2081_min] -[import ../example/n2081/min_error.cpp] +[/ import ../example/n2081/min_error.cpp] [n2081_min_error] [endsect] @@ -204,8 +204,8 @@ A comparison between this library and A++ syntax. [endsect] [section \[Meyer97\] GCD: Loop variants and invariants plus comparison with Eiffel syntax] -[import ../example/meyer97/gcd.cpp] -[import ../example/meyer97/gcd.e] +[/ import ../example/meyer97/gcd.cpp] +[/ import ../example/meyer97/gcd.e] [table [ [This Library (C++03)] [The Eiffel Programming Language] ] [ [[meyer97_gcd]] [[teletype] [meyer97_gcd_e] [c++]] ] @@ -213,85 +213,85 @@ A comparison between this library and A++ syntax. [endsect] [section \[Meyer97\] Max-Array: Nested loop variants and invariants] -[import ../example/meyer97/maxarray.cpp] +[/ import ../example/meyer97/maxarray.cpp] [meyer97_maxarray] [endsect] [section \[Mitchell02\] Name List: Relaxed subcontracts] -[import ../example/mitchell02/name_list.hpp] +[/ import ../example/mitchell02/name_list.hpp] [mitchell02_name_list_header] -[import ../example/mitchell02/name_list.cpp] +[/ import ../example/mitchell02/name_list.cpp] [mitchell02_name_list] -[import ../example/mitchell02/name_list_main.cpp] +[/ import ../example/mitchell02/name_list_main.cpp] [mitchell02_name_list_main] [endsect] [section \[Mitchell02\] Dictionary: Simple key-value map] -[import ../example/mitchell02/dictionary.cpp] +[/ import ../example/mitchell02/dictionary.cpp] [mitchell02_dictionary] [endsect] [section \[Mitchell02\] Courier: Subcontracting and static class invariants] -[import ../example/mitchell02/courier.hpp] +[/ import ../example/mitchell02/courier.hpp] [mitchell02_courier_header] -[import ../example/mitchell02/courier.cpp] +[/ import ../example/mitchell02/courier.cpp] [mitchell02_courier] -[import ../example/mitchell02/courier_main.cpp] +[/ import ../example/mitchell02/courier_main.cpp] [mitchell02_courier_main] [endsect] [section \[Mitchell02\] Stack: Simple stack dispenser] -[import ../example/mitchell02/stack.cpp] +[/ import ../example/mitchell02/stack.cpp] [mitchell02_stack] [endsect] [section \[Mitchell02\] Simple Queue: Simple queue dispenser] -[import ../example/mitchell02/simple_queue.cpp] +[/ import ../example/mitchell02/simple_queue.cpp] [mitchell02_simple_queue] [endsect] [section \[Mitchell02\] Customer Manager: Contracts instead of Defensive Programming] -[import ../example/mitchell02/customer_manager.hpp] +[/ import ../example/mitchell02/customer_manager.hpp] [mitchell02_customer_manager_header] -[import ../example/mitchell02/customer_manager.cpp] +[/ import ../example/mitchell02/customer_manager.cpp] [mitchell02_customer_manager] -[import ../example/mitchell02/customer_manager_main.cpp] +[/ import ../example/mitchell02/customer_manager_main.cpp] [mitchell02_customer_manager_main] [endsect] [section \[Mitchell02\] Observer: Contracts for pure virtual functions] -[import ../example/mitchell02/observer/observer.hpp] +[/ import ../example/mitchell02/observer/observer.hpp] [mitchell02_observer_header] -[import ../example/mitchell02/observer/subject.hpp] +[/ import ../example/mitchell02/observer/subject.hpp] [mitchell02_subject_header] -[import ../example/mitchell02/observer_main.cpp] +[/ import ../example/mitchell02/observer_main.cpp] [mitchell02_observer_main] [endsect] [section \[Mitchell02\] Counter: Subcontracting and virtual specifiers (final, override, new, and pure virtual)] -[import ../example/mitchell02/counter/push_button.hpp] +[/ import ../example/mitchell02/counter/push_button.hpp] [mitchell02_push_button_header] -[import ../example/mitchell02/counter/decrement_button.hpp] +[/ import ../example/mitchell02/counter/decrement_button.hpp] [mitchell02_decrement_button_header] -[import ../example/mitchell02/counter/counter.hpp] +[/ import ../example/mitchell02/counter/counter.hpp] [mitchell02_counter_header] -[import ../example/mitchell02/counter_main.cpp] +[/ import ../example/mitchell02/counter_main.cpp] [mitchell02_counter_main] [endsect] [section \[Stroustrup97\] String: Throw when contract is broken] -[import ../example/stroustrup97/string.hpp] +[/ import ../example/stroustrup97/string.hpp] [stroustrup97_string_header] -[import ../example/stroustrup97/string.cpp] +[/ import ../example/stroustrup97/string.cpp] [stroustrup97_string] -[import ../example/stroustrup97/string_main.cpp] +[/ import ../example/stroustrup97/string_main.cpp] [stroustrup97_string_main] [endsect] [section \[Cline90\] Vector: Comparison with A++ proposed syntax] -[import ../example/cline90/vector.hpp] -[import ../example/cline90/vector_main.cpp] -[import ../example/cline90/vector_app.hpp] +[/ import ../example/cline90/vector.hpp] +[/ import ../example/cline90/vector_main.cpp] +[/ import ../example/cline90/vector_app.hpp] [table [ [This Library (C++03)] [A++ Proposal (not part of C++)] ] [ [[cline90_vector_header]] [[cline90_vector_app_header]] ] @@ -300,17 +300,17 @@ A comparison between this library and A++ syntax. [endsect] [section \[Cline90\] Stack: Function-Try blocks and exception specifications] -[import ../example/cline90/stack.cpp] +[/ import ../example/cline90/stack.cpp] [cline90_stack] [endsect] [section \[Cline90\] Vector-Stack: Subcontracting from Abstract Data Type (ADT)] -[import ../example/cline90/vstack.cpp] +[/ import ../example/cline90/vstack.cpp] [cline90_vstack] [endsect] [section \[Cline90\] Calendar: A very simple calendar] -[import ../example/cline90/calendar.cpp] +[/ import ../example/cline90/calendar.cpp] [cline90_calendar] [endsect] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 8045db9..ab43ca9 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -5,5 +5,12 @@ subdir-run meyer97 : stack3 ; subdir-run mitchell02 : stack ; subdir-run mitchell02 : simple_queue ; subdir-run mitchell02 : dictionary ; +subdir-run mitchell02 : customer_manager ; subdir-run mitchell02 : name_list ; +subdir-run mitchell02 : courier ; +subdir-run mitchell02 : observer_main ; +subdir-run mitchell02 : counter_main ; + +subdir-run cline90 : stack ; +subdir-run cline90 : vector_main ; diff --git a/example/cline90/stack.cpp b/example/cline90/stack.cpp new file mode 100644 index 0000000..7bef246 --- /dev/null +++ b/example/cline90/stack.cpp @@ -0,0 +1,88 @@ + +#include +#include +#include + +template +class stack + #define BASES private boost::contract::constructor_precondition > + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + // NOTE: Incomplete contract assertions, addressing only `empty` and `full`. + + static void stack_precondition(int const& capacity) { + BOOST_CONTRACT_ASSERT(capacity >= 0); + } + explicit stack(int capacity) : + boost::contract::constructor_precondition(boost::bind( + &stack::stack_precondition, boost::cref(capacity))), + data_(new T[capacity]), capacity_(capacity), size_(0) + { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(this->empty()); + BOOST_CONTRACT_ASSERT(full() == (capacity == 0)); + }) + ; + + for(int i = 0; i < capacity_; ++i) data_[i] = T(); + } + + virtual ~stack() { + auto c = boost::contract::destructor(this); + delete[] data_; + } + + bool empty() const { + auto c = boost::contract::public_function(this); + return size_ == 0; + } + + bool full() const { + auto c = boost::contract::public_function(this); + return size_ == capacity_; + } + + void push(T const& value) { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!full()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + ; + + data_[size_++] = value; + } + + T pop() { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!full()); + }) + ; + + return data_[--size_]; + } + +private: + T* data_; + int capacity_; + int size_; +}; + +int main() { + stack s(3); + s.push(123); + BOOST_TEST_EQ(s.pop(), 123); + return boost::report_errors(); +} + diff --git a/example/cline90/vector.hpp b/example/cline90/vector.hpp new file mode 100644 index 0000000..2a25549 --- /dev/null +++ b/example/cline90/vector.hpp @@ -0,0 +1,85 @@ + +#ifndef VECTOR_HPP_ +#define VECTOR_HPP_ + +#include +#include + +template +class vector + #define BASES private boost::contract::constructor_precondition > + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + // NOTE: Incomplete contract assertions, addressing only `size`. + + void invariant() const { + BOOST_CONTRACT_ASSERT(size() >= 0); + } + + static void vector_precondition(int const& count) { + BOOST_CONTRACT_ASSERT(count >= 0); + } + explicit vector(int count = 10) : + boost::contract::constructor_precondition(boost::bind( + &vector::vector_precondition, boost::cref(count))), + data_(new T[count]), + size_(count) + { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(this->size() == count); + }) + ; + + for(int i = 0; i < size_; ++i) data_[i] = T(); + } + + virtual ~vector() { + auto c = boost::contract::destructor(this); + delete[] data_; + } + + int size() const { + auto c = boost::contract::public_function(this); + return size_; // Non-negative result already checked by invariant. + } + + void resize(int count) { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(count >= 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(this->size() == count); + }) + ; + + T* slice = new T[count]; + for(int i = 0; i < count && i < size_; ++i) slice[i] = data_[i]; + delete[] data_; + data_ = slice; + size_ = count; + } + + T& operator[](int index) { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(index >= 0); + BOOST_CONTRACT_ASSERT(index < size()); + }) + ; + + return data_[index]; + } + +private: + T* data_; + int size_; +}; + +#endif // #include guard + diff --git a/example/cline90/vector_axx.hpp b/example/cline90/vector_axx.hpp new file mode 100644 index 0000000..2a0207d --- /dev/null +++ b/example/cline90/vector_axx.hpp @@ -0,0 +1,73 @@ + +// Copyright (C) 2008-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://sourceforge.net/projects/contractpp + +//[cline90_vector_app_header +// File: vector_app.hpp +// Extra spaces, newlines, etc used to align text with this library code. + + + + + +template< typename T> +class vector +{ + legal: size() >= 0; // Class invariants (legal). + + public: explicit vector ( int count = 10 ) + : data_(new T[count]), size_(count) + { + for(int i = 0; i < size_; ++i) data_[i] = T(); + } + + public: virtual ~vector ( void ) + { + delete[] data_; + } + + public: int size ( void ) const + { + return size_; + } + + public: void resize ( int count ) + { + T* slice = new T[count]; + for(int i = 0; i < count && i < size_; ++i) slice[i] = data_[i]; + delete[] data_; + data_ = slice; + size_ = count; + } + + public: T& operator[] ( int index ) + { + return data_[index]; + } + + // Preconditions (require) and postconditions (promise) for each function. + axioms: [ int count; require count >= 0; promise size() == count ] + vector(count); + axioms: [ int count; require count >= 0; promise size() == count ] + resize(count); + axioms: [ int index; require index >= 0 && index < size() ] + (*this)[x]; + + private: T* data_; + private: int size_; +}; + + + + + + + + + + +//] + diff --git a/example/cline90/vector_main.cpp b/example/cline90/vector_main.cpp new file mode 100644 index 0000000..f3d8c70 --- /dev/null +++ b/example/cline90/vector_main.cpp @@ -0,0 +1,16 @@ + +#include "vector.hpp" +#include + +int main() { + vector v (3); + BOOST_TEST_EQ(v.size(), 3); + + v[0] = 123; + v.resize(2); + BOOST_TEST_EQ(v[0], 123); + BOOST_TEST_EQ(v.size(), 2); + + return boost::report_errors(); +} + diff --git a/example/cline90/vstack.cpp b/example/cline90/vstack.cpp new file mode 100644 index 0000000..8b0b5cc --- /dev/null +++ b/example/cline90/vstack.cpp @@ -0,0 +1,204 @@ + +#include "vector.hpp" +#include +#incldue + +template +class abstract_stack { +public: + // NOTE: Incomplete contract assertions, addressing `empty` and `full` only. + + abstract_stack() { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(empty()); + }) + ; + } + + virtual ~abstract_stack() { auto c = boost::contract::destructor(this); } + + bool full() const { + bool result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result == (length() == capacity())); + }) + ; + + return result = (length() == capacity()); + } + + bool empty() const { + bool result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result = (length() == 0)); + }) + ; + + return result = (length() == 0); + } + + virtual int length(boost::contract::virtual_* v = 0) const = 0; + + virtual int capacity(boost::contract::virtual_* v = 0) const = 0; + + virtual void push(T const& value, boost::contract::virtual_* v = 0) = 0; + + virtual T pop(boost::contract::virtual_* v = 0) = 0; + + virtual void clear(boost::contract::virtual_* v = 0) = 0; +}; + +template +int abstract_stack::length(boost::contract::virtual_* v) const { + auto c = boost::contract::public_function(v, this) + .postcondition([&] (int const& result) { + BOOST_CONTRACT_ASSERT(result >= 0); + }) + ; + + throw std::logic_error(); + return -1; +} + +template +int abstract_stack::capacity(boost::contract::virtual_* v) const { + auto c = boost::contract::public_function(v, this) + .postcondition([&] (int const& result) { + BOOST_CONTRACT_ASSERT(result >= 0); + }) + ; + + throw std::logic_error(); + return -1; +} + +template +void abstract_stack::push(T const& value, boost::contract::virtual_* v) { + auto c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!full()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + ; + + throw std::logic_error(); +} + +template +void abstract_stack::pop(boost::contract::virtual_* v) { + auto c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!full()); + }) + ; + + throw std::logic_error(); +} + +template +void abstract_stack::clear(boost::contract::virtual_* v) { + auto c = boost::contract::public_function(v, this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(empty()); + }) + ; + + throw std::logic_error(); +} + +template +class vstack + #define BASES private boost::contract::constructor_precondition< \ + vstack >, public abstract_stack + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { + BOOST_CONTRACT_ASSERT(length() >= 0); + BOOST_CONTRACT_ASSERT(length() < capacity()); + } + + static vstack_precondition(int const& count) { + BOOST_CONTRACT_ASSERT(count >= 0); + } + explicit vstack(int count = 10) : + boost::contract::constructor_precondition(boost::bind( + &vstack::vstack_precondition, boost::cref(count))), + v_(count), // OK, executed after precondition so count >= 0. + len_(0) + { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(length() == 0); + BOOST_CONTRACT_ASSERT(capacity() == count); + }) + ; + } + + virtual ~vstack() { auto c = boost::contract::destrucotr(this); } + + // Inherited from abstract_stack. + + virtual int length(boost::contract::virtual_* v = 0) const /* override */ { + auto c = boost::contract::public_function( + v, &vstack::length, this); + return len_; + } + BOOST_CONTRACT_OVERRIDE(length) + + virtual int capacity() const /* override */ { + auto c = boost::contract::public_function( + v, &vstack::capacity, this); + return v_.size(); + } + BOOST_CONTRACT_OVERRIDE(capacity) + + virtual void push(T const& value, boost::contract::virtual_* v = 0) + /* override */ { + auto c = boost::contract::public_function( + v, &vstack::push, this, value); + v_[len_++] = value; + } + BOOST_CONTRACT_OVERRIDE(push) + + virtual T pop(boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function( + v, &vstack::pop, this); + return v_[--len_]; + } + BOOST_CONTRACT_OVERRIDE(pop) + + virtual void clear(boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function( + v, &vstack::clear, this); + len_ = 0; + } + BOOST_CONTRACT_OVERRIDE(clear); + +private: + vector v_; + int len_; +}; + +int main() { + vstack s(3); + BOOST_TEST_EQ(s.capacity(), 3); + + s.push(123); + BOOST_TEST_EQ(s.length(), 1); + BOOST_TEST_EQ(s.pop(), 123); + + return boost::report_errors(); +} + diff --git a/example/meyer97/stack3.cpp b/example/meyer97/stack3.cpp index 2409bd4..60646a4 100644 --- a/example/meyer97/stack3.cpp +++ b/example/meyer97/stack3.cpp @@ -1,4 +1,6 @@ +//[meyer97_stack3 +// File: stack3.cpp #include "stack4.hpp" #include #include @@ -48,21 +50,21 @@ public: // Max number of stack items. int capacity() const { - auto c = boost::contract::public_member(this); // Check invariants. + auto c = boost::contract::public_function(this); // Check invariants. return stack_.capacity(); } // Number of stack items. int count() const { - auto c = boost::contract::public_member(this); // Check invariants. + auto c = boost::contract::public_function(this); // Check invariants. return stack_.count(); } // Top item if present, otherwise none and set error (no preconditions). boost::optional item() const { - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT( // Error if impossible. this->empty() == (error() == underflow_error)); @@ -84,19 +86,19 @@ public: // Error indicator set by various operations. error_code error() const { - auto c = boost::contract::public_member(this); // Check invariants. + auto c = boost::contract::public_function(this); // Check invariants. return error_; } bool empty() const { - auto c = boost::contract::public_member(this); // Check invariants. + auto c = boost::contract::public_function(this); // Check invariants. return stack_.empty(); } bool full() const { - auto c = boost::contract::public_member(this); // Check invariants. + auto c = boost::contract::public_function(this); // Check invariants. return stack_.full(); } @@ -107,7 +109,7 @@ public: void put(T const& x) { auto old_full = BOOST_CONTRACT_OLDOF(full()); auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { // Error if impossible. BOOST_CONTRACT_ASSERT(*old_full == (error() == overflow_error)); @@ -133,7 +135,7 @@ public: void remove() { auto old_empty = BOOST_CONTRACT_OLDOF(empty()); auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { // Error if impossible. BOOST_CONTRACT_ASSERT(*old_empty == (error() == @@ -178,4 +180,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/meyer97/stack4.e b/example/meyer97/stack4.e new file mode 100644 index 0000000..d27b075 --- /dev/null +++ b/example/meyer97/stack4.e @@ -0,0 +1,76 @@ + +//[meyer97_stack4_e +-- File: stack4.e + +indexing + destription: "Dispenser with LIFO access policy and a fixed max capacity." +class interface STACK4[G] creation make + +invariant + count_non_negative: count >= 0 + count_bounded: count <= capacity + empty_if_no_elements: empty = (count = 0) + +feature -- Initialization. + + -- Allocate stack for a maximum of n elements. + make ( n : INTEGER ) is + require + non_negative_capacity: n >= 0 + ensure + capacity_set: capacity = n + end + +feature -- Access. + + -- Max number of stack elements. + capacity : INTEGER + + -- Number of stack elements. + count : INTEGER + + -- Top element + item : G is + require + not_empty: not empty -- i.e., count > 0 + end + +feature -- Status report. + + -- Is stack empty? + empty : BOOLEAN is + ensure + empty_definition: result = (count = 0) + end + + -- Is stack full? + full : BOOLEAN is + ensure + full_definition: result = (count = capacity) + end + +feature -- Element change. + + -- Add x on top. + put ( x : G ) is + require + not_full: not full + ensure + not_empty: not empty + added_to_top: item = x + one_more_item: count = old count + 1 + end + + -- Remove top element. + remove is + require + not_empty: not empty -- i.e., count > 0 + ensure + not_full: not full + one_fewer_item: count = old count - 1 + + end + +end -- class interface STACK4 +//] + diff --git a/example/meyer97/stack4.hpp b/example/meyer97/stack4.hpp index e485f69..4ca7ada 100644 --- a/example/meyer97/stack4.hpp +++ b/example/meyer97/stack4.hpp @@ -1,4 +1,6 @@ +//[meyer97_stack4_header +// File: stack4.hpp #ifndef STACK4_HPP_ #define STACK4_HPP_ @@ -59,7 +61,7 @@ public: // Deep copy via assignment. stack4& operator=(stack4 const& other) { - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(capacity() == other.capacity()); BOOST_CONTRACT_ASSERT(count() == other.count()); @@ -78,7 +80,6 @@ public: // Destroy this stack. virtual ~stack4() { auto c = boost::contract::destructor(this); // Check invariants. - delete[] array_; } @@ -86,21 +87,19 @@ public: // Max number of stack items. int capacity() const { - auto c = boost::contract::public_member(this); // Check invariants. - + auto c = boost::contract::public_function(this); // Check invariants. return capacity_; } // Number of stack items. int count() const { - auto c = boost::contract::public_member(this); // Check invariants. - + auto c = boost::contract::public_function(this); // Check invariants. return count_; } // Top item. T const& item() const { - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!empty()); // Not empty (count > 0). }) @@ -114,7 +113,7 @@ public: // Is stack empty? bool empty() const { bool result; - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { // Empty definition. BOOST_CONTRACT_ASSERT(result == (count() == 0)); @@ -127,7 +126,7 @@ public: // Is stack full? bool full() const { bool result; - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT( // Full definition. result == (count() == capacity())); @@ -142,7 +141,7 @@ public: // Add x on top. void put(T const& x) { auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!full()); // Not full. }) @@ -159,7 +158,7 @@ public: // Remove top item. void remove() { auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!empty()); // Not empty (count > 0). }) @@ -179,4 +178,5 @@ private: }; #endif // #include guard +//] diff --git a/example/meyer97/stack4_main.cpp b/example/meyer97/stack4_main.cpp index f72617c..3d3d893 100644 --- a/example/meyer97/stack4_main.cpp +++ b/example/meyer97/stack4_main.cpp @@ -1,4 +1,6 @@ +//[meyer97_stack4_main +// File: stack4_main.cpp #include "stack4.hpp" #include @@ -20,4 +22,5 @@ int main() { return boost::report_errors(); } +//] diff --git a/example/mitchell02/counter/counter.hpp b/example/mitchell02/counter/counter.hpp new file mode 100644 index 0000000..771896d --- /dev/null +++ b/example/mitchell02/counter/counter.hpp @@ -0,0 +1,58 @@ + +#ifndef COUNTER_HPP_ +#define COUNTER_HPP_ + +#include "../observer/subject.hpp" +#include + +class counter + #define BASES public subject + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + /* Creation */ + + // Construct counter with specified value. + explicit counter(int _value = 10) : value_(_value) { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(value() == _value); // Value set. + }) + ; + } + + // Destroy counter. + virtual ~counter() { auto c = boost::contract::destructor(this); } + + /* Queries */ + + // Current counter value. + int value() const { + auto c = boost::contract::public_function(this); + return value_; + } + + /* Commands */ + + // Decrement counter value. + void decrement() { + auto old_value = BOOST_CONTRACT_OLDOF(value()); + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(value() == *old_value - 1); // Decrement. + }) + ; + + --value_; + notify(); // Notify all attached observers. + } + +private: + int value_; +}; + +#endif // #include guard + diff --git a/example/mitchell02/counter/decrement_button.hpp b/example/mitchell02/counter/decrement_button.hpp new file mode 100644 index 0000000..f09f3c7 --- /dev/null +++ b/example/mitchell02/counter/decrement_button.hpp @@ -0,0 +1,81 @@ + +#ifndef DECREMENT_BUTTON_HPP_ +#define DECREMENT_BUTTON_HPP_ + +#include "push_button.hpp" +#include "counter.hpp" +#include "../observer/observer.hpp" +#include +#include + +class decrement_button + #define BASES public push_button, public observer, \ + private boost::noncopyable + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + /* Creation */ + + explicit decrement_button(counter& _counter) : counter_(_counter) { + auto c = boost::contract::constructor(this) + .postcondition([&] { + // Enable iff positive value. + BOOST_CONTRACT_ASSERT(enabled() == (_counter.value() > 0)); + }) + ; + counter_.attach(this); + } + + // Destroy button. + virtual ~decrement_button() { auto c = boost::contract::destructor(this); } + + /* Commands */ + + virtual void on_bn_clicked(boost::contract::virtual_* v = 0) + /* override */ { + auto old_value = BOOST_CONTRACT_OLDOF(v, counter_.value()); + auto c = boost::contract::public_function( + v, &decrement_button::on_bn_clicked, this) + .postcondition([&] { + // Counter decremented. + BOOST_CONTRACT_ASSERT(counter_.value() == *old_value - 1); + }) + ; + counter_.decrement(); + } + BOOST_CONTRACT_OVERRIDE(on_bn_clicked) + + virtual bool up_to_date_with_subject(boost::contract::virtual_* v = 0) + const /* override */ { + bool result; + auto c = boost::contract::public_function< + override_up_to_date_with_subject + >(v, result, &decrement_button::up_to_date_with_subject, this); + + return result = true; // For simplicity, assume always up-to-date. + } + BOOST_CONTRACT_OVERRIDE(up_to_date_with_subject) + + virtual void update(boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function( + v, &decrement_button::update, this) + .postcondition([&] { + // Enabled iff positive value. + BOOST_CONTRACT_ASSERT(enabled() == (counter_.value() > 0)); + }) + ; + + if(counter_.value() == 0) disable(); + else enable(); + } + BOOST_CONTRACT_OVERRIDE(update); + +private: + counter& counter_; +}; + +#endif // #include guard + diff --git a/example/mitchell02/counter/push_button.hpp b/example/mitchell02/counter/push_button.hpp new file mode 100644 index 0000000..0bec023 --- /dev/null +++ b/example/mitchell02/counter/push_button.hpp @@ -0,0 +1,71 @@ + +#ifndef PUSH_BUTTON_HPP_ +#define PUSH_BUTTON_HPP_ + +#include + +class push_button { +public: + /* Creation */ + + // Create an enabled button. + push_button() : enabled_(true) { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(enabled()); // Enabled. + }) + ; + } + + // Destroy button. + virtual ~push_button() { auto c = boost::contract::destructor(this); } + + /* Queries */ + + // If button is enabled. + bool enabled() const { + auto c = boost::contract::public_function(this); + return enabled_; + } + + /* Commands */ + + // Enable button. + void enable() { + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(enabled()); // Enabled. + }) + ; + + enabled_ = true; + } + + // Disable button. + void disable() { + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!enabled()); // Disabled. + }) + ; + + enabled_ = false; + } + + // Invoke externally when button clicked. + virtual void on_bn_clicked(boost::contract::virtual_* v = 0) = 0; + +private: + bool enabled_; +}; + +void push_button::on_bn_clicked(boost::contract::virtual_* v) { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(enabled()); // Enabled. + }) + ; +} + +#endif // #include guard + diff --git a/example/mitchell02/counter_main.cpp b/example/mitchell02/counter_main.cpp new file mode 100644 index 0000000..db53548 --- /dev/null +++ b/example/mitchell02/counter_main.cpp @@ -0,0 +1,68 @@ + +#include "counter/counter.hpp" +#include "counter/decrement_button.hpp" +#include "observer/observer.hpp" +#include + +int test_counter; + +class view_of_counter + #define BASES public observer + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + /* Creation */ + + // Create view associated with given counter. + explicit view_of_counter(counter& _counter) : counter_(_counter) { + auto c = boost::contract::constructor(this); + + counter_.attach(this); + BOOST_TEST_EQ(counter_.value(), test_counter); + } + + // Destroy view. + virtual ~view_of_counter() { auto c = boost::contract::destructor(this); } + + /* Commands */ + + virtual bool up_to_date_with_subject(boost::contract::virtual_* v = 0) + const /* override */ { + bool result; + auto c = boost::contract::public_function< + override_up_to_date_with_subject + >(v, result, &view_of_counter::up_to_date_with_subject, this); + + return result = true; // For simplicity, assume always up-to-date. + } + BOOST_CONTRACT_OVERRIDE(up_to_date_with_subject) + + virtual void update(boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function( + v, &view_of_counter::update, this); + + BOOST_TEST_EQ(counter_.value(), test_counter); + } + BOOST_CONTRACT_OVERRIDE(update) + +private: + counter& counter_; +}; + +int main() { + counter cnt(test_counter = 1); + view_of_counter view(cnt); + + decrement_button dec(cnt); + BOOST_TEST(dec.enabled()); + + test_counter--; + dec.on_bn_clicked(); + BOOST_TEST(!dec.enabled()); + + return boost::report_errors(); +} + diff --git a/example/mitchell02/courier.cpp b/example/mitchell02/courier.cpp new file mode 100644 index 0000000..fb43528 --- /dev/null +++ b/example/mitchell02/courier.cpp @@ -0,0 +1,190 @@ + +#include +#include +#include + +struct package { + double weight_kg; + std::string location; + double accepted_hour; + double delivered_hour; + + explicit package( + double _weight_kg, + std::string const& _location = "", + double _accepted_hour = 0.0, + double _delivered_hour = 0.0 + ) : + weight_kg(_weight_kg), + location(_location), + accepted_hour(_accepted_hour), + delivered_hour(_delivered_hour) + {} +}; + +// Courier for package delivery. +class courier + #define BASES private boost::contract::constructor_precondition + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { + // Above min. insurance. + BOOST_CONTRACT_ASSERT(insurance_cover_usd() >= min_insurance_usd); + } + + static void static_invariant() { + // Positive min. insurance. + BOOST_CONTRACT_ASSERT(min_insurance_usd >= 0.0); + } + + static double min_insurance_usd; + + /* Creation */ + + // Create courier with specified insurance value. + explicit courier(double _insurance_cover_usd = min_insurance_usd) : + boost::contract::constructor_precondition([&] { + // Positive insurance. + BOOST_CONTRACT_ASSERT(_insurance_cover_usd >= 0.0); + }), + insurance_cover_usd_(_insurance_cover_usd) + { + auto c = boost::contract::constructor(this); // Check invariants. + } + + // Destroy courier. + virtual ~courier() { + auto c = boost::contract::destructor(this); // Check invariants. + } + + /* Queries */ + + // Return insurance cover. + double insurance_cover_usd() const { + auto c = boost::contract::public_function(this); // Check invariants. + return insurance_cover_usd_; + } + + /* Commands */ + + // Deliver package to destination. + virtual void deliver( + package& package_delivery, + std::string const& destination, + boost::contract::virtual_* v = 0 + ) { + auto c = boost::contract::public_function(v, this) + .precondition([&] { + // Within max weight of this delivery. + BOOST_CONTRACT_ASSERT(package_delivery.weight_kg < 5.0); + }) + .postcondition([&] { + // Within max delivery type. + BOOST_CONTRACT_ASSERT(double(package_delivery.delivered_hour - + package_delivery.accepted_hour) <= 3.0); + // Delivered at destination. + BOOST_CONTRACT_ASSERT(package_delivery.location == destination); + }) + ; + + package_delivery.location = destination; + // Delivery takes 2.5 hours. + package_delivery.delivered_hour = package_delivery.accepted_hour + 2.5; + } + +private: + double insurance_cover_usd_; +}; + +double courier::min_insurance_usd = 10.0e+6; + +// Different courier for package delivery. +class different_courier + #define BASES private boost::contract::constructor_precondition< \ + different_courier>, public courier + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Subcontracting. + #undef BASES + + void invariant() const { + // Above different insurance value. + BOOST_CONTRACT_ASSERT(insurance_cover_usd() >= different_insurance_usd); + } + + static void static_invariant() { + BOOST_CONTRACT_ASSERT( // Better insurance amount. + different_insurance_usd >= courier::min_insurance_usd); + } + + static double different_insurance_usd; + + /* Creation */ + + // Create courier with specified insurance value. + explicit different_courier( + double insurance_cover_usd = different_insurance_usd) : + boost::contract::constructor_precondition([&] { + // Positive insurance value. + BOOST_CONTRACT_ASSERT(insurance_cover_usd > 0.0); + }), + courier(insurance_cover_usd) + { + auto c = boost::contract::constructor(this); // Check invariants. + } + + // Destroy courier. + virtual ~different_courier() { + auto c = boost::contract::destructor(this); // Check invariants. + } + + /* Commands */ + + virtual void deliver( + package& package_delivery, + std::string const& destination, + boost::contract::virtual_* v = 0 + ) /* override */ { + auto c = boost::contract::public_function( + v, &different_courier::deliver, this, package_delivery, destination + ) + .precondition([&] { + // Package can weight more (weaker precondition). + BOOST_CONTRACT_ASSERT(package_delivery.weight_kg <= 8.0); + }) + .postcondition([&] { + // Faster delivery (stronger postcondition). + BOOST_CONTRACT_ASSERT(double(package_delivery.delivered_hour - + package_delivery.accepted_hour) <= 2.0); + // Inherited "delivery at destination" postcondition. + }) + ; + + package_delivery.location = destination; + // Delivery takes 0.5 hours. + package_delivery.delivered_hour = package_delivery.accepted_hour + 0.5; + } + BOOST_CONTRACT_OVERRIDE(deliver) +}; + +double different_courier::different_insurance_usd = 20.0e+6; + +int main() { + package cups(3.6, "store"); + courier c; + c.deliver(cups, "home"); + BOOST_TEST_EQ(cups.location, "home"); + + package desk(7.2, "store"); + different_courier dc; + dc.deliver(desk, "office"); + BOOST_TEST_EQ(desk.location, "office"); + + return boost::report_errors(); +} + diff --git a/example/mitchell02/customer_manager.cpp b/example/mitchell02/customer_manager.cpp new file mode 100644 index 0000000..385ff55 --- /dev/null +++ b/example/mitchell02/customer_manager.cpp @@ -0,0 +1,126 @@ + +#include +#include +#include +#include +#include + +// Basic customer information. +struct customer_info { + typedef std::string identifier; + + identifier id; + + explicit customer_info(identifier const& _id) : + id(_id), name_(), address_(), birthday_() {} + +private: + std::string name_; + std::string address_; + std::string birthday_; + + friend class customer_manager; +}; + +// Manage customers. +class customer_manager { +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(count() >= 0); // Non-negative count. + } + + /* Creation */ + + customer_manager() { + auto c = boost::contract::constructor(this); // Check invariants. + } + + virtual ~customer_manager() { + auto c = boost::contract::destructor(this); // Check invariants. + } + + /* Basic Queries */ + + int count() const { + auto c = boost::contract::public_function(this); // Check invariants. + return customers_.size(); + } + + bool id_active(customer_info::identifier const& id) const { + auto c = boost::contract::public_function(this); // Check invariants. + return customers_.find(id) != customers_.cend(); + } + + /* Derived Queries */ + + std::string const& name_for(customer_info::identifier const& id) const { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(id_active(id)); // Active. + }) + ; + + // Find != end because of preconditions (no defensive programming). + return customers_.find(id)->second.name_; + } + + /* Commands */ + + void add(customer_info const& info) { + auto old_count = BOOST_CONTRACT_OLDOF(count()); + auto c = boost::contract::public_function(this) + .precondition([&] { + // Not already active. + BOOST_CONTRACT_ASSERT(!id_active(info.id)); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(count() == *old_count + 1); // Count inc. + BOOST_CONTRACT_ASSERT(id_active(info.id)); // Activated. + }) + ; + + customers_.insert(std::make_pair(info.id, customer(info))); + } + + void set_name( + customer_info::identifier const& id, std::string const& name) { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(id_active(id)); // Already active. + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(name_for(id) == name); // Name set. + }) + ; + + // Find != end because of precondition (no defensive programming). + customers_.find(id)->second.name_ = name; + } + +private: + class agent {}; // Customer agent. + + struct customer : customer_info { + agent managing_agent; + std::string last_contact; + + explicit customer(customer_info const& info) : customer_info(info), + managing_agent(), last_contact() {} + }; + + std::map customers_; +}; + +int main() { + customer_manager m; + + customer_info const js("john_smith_123"); + m.add(js); + m.set_name(js.id, "John Smith"); + BOOST_TEST_EQ(m.name_for(js.id), "John Smith"); + BOOST_TEST_EQ(m.count(), 1); + BOOST_TEST(m.id_active(js.id)); + + return boost::report_errors(); +} + diff --git a/example/mitchell02/dictionary.cpp b/example/mitchell02/dictionary.cpp index 0d15498..7b7228d 100644 --- a/example/mitchell02/dictionary.cpp +++ b/example/mitchell02/dictionary.cpp @@ -31,15 +31,14 @@ public: // Number of key entries. int count() const { - auto c = boost::contract::public_member(this); // Check invariants. - + auto c = boost::contract::public_function(this); // Check invariants. return items_.size(); } // Has entry for key? bool has(K const& key) const { bool result; - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { // Empty has no key. if(count() == 0) BOOST_CONTRACT_ASSERT(!result); @@ -51,12 +50,13 @@ public: // Value for a given key. T const& value_for(K const& key) const { - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(has(key)); // Has key. }) ; + // Find != end because of precondition (no defensive programming). return items_.find(key)->second; } @@ -65,7 +65,7 @@ public: // Add value of a given key. void put(K const& key, T const& value) { auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!has(key)); // Has not key already. }) @@ -83,7 +83,7 @@ public: // Remove value for given key. void remove(K const& key) { auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(has(key)); // Has key. }) diff --git a/example/mitchell02/name_list.cpp b/example/mitchell02/name_list.cpp index 5927f54..c12344b 100644 --- a/example/mitchell02/name_list.cpp +++ b/example/mitchell02/name_list.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include // List of names. @@ -32,15 +32,14 @@ public: // Number of names in list. int count() const { - auto c = boost::contract::public_member(this); // Check invariants. - + auto c = boost::contract::public_function(this); // Check invariants. return names_.size(); } // Is name in list? bool has(std::string const& name) const { bool result; - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { // If empty, has not. if(count() == 0) BOOST_CONTRACT_ASSERT(!result); @@ -58,7 +57,7 @@ public: boost::contract::virtual_* v = 0) { auto old_has_name = BOOST_CONTRACT_OLDOF(v, has(name)); auto old_count = BOOST_CONTRACT_OLDOF(v, count()); - auto c = boost::contract::public_member(v, this) + auto c = boost::contract::public_function(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(!has(name)); // Not already in list. }) @@ -74,7 +73,7 @@ public: } private: - std::list names_; + std::vector names_; }; class relaxed_name_list @@ -92,7 +91,7 @@ public: boost::contract::virtual_* v = 0) /* override */ { auto old_has_name = BOOST_CONTRACT_OLDOF(v, has(name)); auto old_count = BOOST_CONTRACT_OLDOF(v, count()); - auto c = boost::contract::public_member(v, + auto c = boost::contract::public_function(v, &relaxed_name_list::put, this, name) .precondition([&] { // Relax inherited preconditions. BOOST_CONTRACT_ASSERT(has(name)); // Already in list. @@ -105,7 +104,7 @@ public: }) ; - if(!has(name)) name_list::put(name); + if(!has(name)) name_list::put(name); // Else, do nothing. } BOOST_CONTRACT_OVERRIDE(put); }; diff --git a/example/mitchell02/observer/observer.hpp b/example/mitchell02/observer/observer.hpp new file mode 100644 index 0000000..9ed7f7c --- /dev/null +++ b/example/mitchell02/observer/observer.hpp @@ -0,0 +1,45 @@ + +#ifndef OBSERVER_HPP_ +#define OBSERVER_HPP_ + +#include + +// Observer. +class observer { +public: + // No inv so contracts could have been omitted when also no pre/post... + + /* Creation */ + + observer() { auto c = boost::contract::constructor(this); } + + virtual ~observer() { auto c = boost::contract::destructor(this); } + + /* Commands */ + + // If up-to-date with related subject. + virtual bool up_to_date_with_subject(boost::contract::virtual_* v = 0) + const = 0; + + // Update this observer. + virtual void update(boost::contract::virtual_* v = 0) = 0; + +private: + friend class subject; +}; + +bool observer::up_to_date_with_subject(boost::contract::virtual_* v) const { + auto c = boost::contract::public_function(this); + return false; // Never reached. +} + +void observer::update(boost::contract::virtual_* v) { + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(up_to_date_with_subject()); // Up-to-date. + }) + ; +} + +#endif // #include guard + diff --git a/example/mitchell02/observer/subject.hpp b/example/mitchell02/observer/subject.hpp new file mode 100644 index 0000000..cc5ec35 --- /dev/null +++ b/example/mitchell02/observer/subject.hpp @@ -0,0 +1,166 @@ + +#ifndef SUBJECT_HPP_ +#define SUBJECT_HPP_ + +#include "observer.hpp" +#include +#include +#include +#include + +// Following used to selectively disable checking of more complex assertions. +#define O_1 0 // O(1): constant complexity. +#define O_N 1 // O(n): linear complexity. +#define COMPLEXITY_MAX O_N + +// Subject for observer design pattern. +class subject { +public: + void invariant() const { + if(O_N <= COMPLEXITY_MAX) { + BOOST_CONTRACT_ASSERT(all_observers_valid(observers())); // Valid. + } + } + + /* Creation */ + + // Construct subject with no observer. + subject() { + auto c = boost::contract::constructor(this); // Check invariant. + } + + // Destroy subject. + virtual ~subject() { + auto c = boost::contract::destructor(this); // Check invariant. + } + + /* Queries */ + + // If given object is attached. + bool attached(observer const* ob) const { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(ob); // Not null. + }) + ; + + return std::find(observers_.cbegin(), observers_.cend(), ob) != + observers_.cend(); + } + + /* Commands */ + + // Attach given object as an observer. + void attach(observer* ob) { + auto old_observers = BOOST_CONTRACT_OLDOF(observers()); + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(ob); // Not null. + BOOST_CONTRACT_ASSERT(!attached(ob)); // Not already attached. + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(attached(ob)); // Attached. + if(O_N <= COMPLEXITY_MAX) { + // Others not changed (frame rule). + BOOST_CONTRACT_ASSERT(other_observers_unchanged( + *old_observers, observers(), ob)); + } + }) + ; + + observers_.push_back(ob); + } + +protected: + // Contracts could have been omitted for protected/private with no pre/post. + + /* Queries */ + + // All observers attached to this subject. + std::vector observers() const { + auto c = boost::contract::protected_function(); + + std::vector obs; + for(std::vector::const_iterator i = observers_.cbegin(); + i != observers_.cend(); ++i) { + obs.push_back(*i); + } + return obs; + } + + /* Commands */ + + // Update all attached observers. + void notify() { + auto c = boost::contract::protected_function() + .postcondition([&] { + if(O_N <= COMPLEXITY_MAX) { + // All updated. + BOOST_CONTRACT_ASSERT(all_observers_updated(observers())); + } + }) + ; + + for(std::vector::iterator i = observers_.begin(); + i != observers_.end(); ++i) { + // Class invariants ensure no null pointers in observers but class + // invariants not checked for non-public functions so assert here. + assert(*i); // Pointer not null (defensive programming). + (*i)->update(); + } + } + +private: + /* Contract Helpers */ + + static bool all_observers_valid(std::vector const& obs) { + auto c = boost::contract::private_function(); + + for(std::vector::const_iterator i = obs.cbegin(); + i != obs.cend(); ++i) { + if(!*i) return false; + } + return true; + } + + static bool other_observers_unchanged( + std::vector const& old_obs, + std::vector const& new_obs, + observer const* ob + ) { + auto c = boost::contract::private_function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(ob); // Not null. + }) + ; + + std::vector remaining = new_obs; + std::remove(remaining.begin(), remaining.end(), ob); + + std::vector::const_iterator remaining_it = + remaining.begin(); + std::vector::const_iterator old_it = old_obs.begin(); + while(remaining.cend() != remaining_it && old_obs.cend() != old_it) { + if(*remaining_it != *old_it) return false; + ++remaining_it; + ++old_it; + } + return true; + } + + static bool all_observers_updated(std::vector const& obs) { + auto c = boost::contract::private_function(); + + for(std::vector::const_iterator i = obs.cbegin(); + i != obs.cend(); ++i) { + if(!*i) return false; + if(!(*i)->up_to_date_with_subject()) return false; + } + return true; + } + + std::vector observers_; +}; + +#endif // #include guard + diff --git a/example/mitchell02/observer_main.cpp b/example/mitchell02/observer_main.cpp new file mode 100644 index 0000000..93e452b --- /dev/null +++ b/example/mitchell02/observer_main.cpp @@ -0,0 +1,97 @@ + +#include "observer/observer.hpp" +#include "observer/subject.hpp" +#include +#include + +int test_state; // For unit testing only. + +// Implement an actual subject. +class concrete_subject + #define BASES public subject + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Subcontracting. + #undef BASES + + typedef int state; // Some state being observed. + + concrete_subject() : state_() { + auto c = boost::contract::constructor(this); + } + + ~concrete_subject() { auto c = boost::contract::destructor(this); } + + void set_state(state const& new_state) { + auto c = boost::contract::public_function(this); + + state_ = new_state; + BOOST_TEST_EQ(state_, test_state); + notify(); // Notify all observers. + } + + state get_state() const { + auto c = boost::contract::public_function(this); + return state_; + } + +private: + state state_; +}; + +// Implement an actual observer. +class concrete_observer + #define BASES public observer + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Subcontracting. + #undef BASES + + // Create concrete observer. + explicit concrete_observer(concrete_subject const& subj) : + subject_(subj), observed_state_() { + auto c = boost::contract::constructor(this); // Check subcontracts. + } + + ~concrete_observer() { auto c = boost::contract::destructor(this); } + + // Implement base virtual functions. + + bool up_to_date_with_subject(boost::contract::virtual_* v = 0) + const /* override */ { + bool result; + auto c = boost::contract::public_function< + override_up_to_date_with_subject + >(v, result, &concrete_observer::up_to_date_with_subject, this); + + return result = true; // For simplicity, assume always up-to-date. + } + BOOST_CONTRACT_OVERRIDE(up_to_date_with_subject) + + void update(boost::contract::virtual_* v = 0) /* override */ { + auto c = boost::contract::public_function( + v, &concrete_observer::update, this); + + observed_state_ = subject_.get_state(); + BOOST_TEST_EQ(observed_state_, test_state); + } + BOOST_CONTRACT_OVERRIDE(update) + +private: + concrete_subject const& subject_; + concrete_subject::state observed_state_; +}; + +int main() { + concrete_subject subj; + concrete_observer ob(subj); + subj.attach(&ob); + + subj.set_state(test_state = 123); + subj.set_state(test_state = 456); + + return boost::report_errors(); +} + diff --git a/example/mitchell02/simple_queue.cpp b/example/mitchell02/simple_queue.cpp index f3f3b44..e196061 100644 --- a/example/mitchell02/simple_queue.cpp +++ b/example/mitchell02/simple_queue.cpp @@ -57,14 +57,14 @@ public: // Items in queue (in their order). // (Somewhat exposes implementation but allows to check more contracts.) std::vector const& items() const { - auto c = boost::contract::public_member(this); // Check invariants. + auto c = boost::contract::public_function(this); // Check invariants. return items_; } // Max number of items queue can hold. int capacity() const { - auto c = boost::contract::public_member(this); // Check invariants. + auto c = boost::contract::public_function(this); // Check invariants. return items_.capacity(); } @@ -74,7 +74,7 @@ public: // Number of items. int count() const { int result; - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { // Return items count. BOOST_CONTRACT_ASSERT(result == int(items().size())); @@ -87,7 +87,7 @@ public: // Item at head. T const& head() const { boost::optional result; - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!is_empty()); // Not empty. }) @@ -103,7 +103,7 @@ public: // If queue contains no item. bool is_empty() const { bool result; - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { // Consistent with count. BOOST_CONTRACT_ASSERT(result == (count() == 0)); @@ -116,7 +116,7 @@ public: // If queue as no room for another item. bool is_full() const { bool result; - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT( // Consistent with size and capacity. result == (capacity() == int(items().size()))); @@ -135,7 +135,7 @@ public: if(O_N <= COMPLEXITY_MAX) old_items = BOOST_CONTRACT_OLDOF(items()); auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(!is_empty()); // Not empty. }) @@ -157,7 +157,7 @@ public: if(O_N <= COMPLEXITY_MAX) old_items = BOOST_CONTRACT_OLDOF(items()); auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(count() < capacity()); // Room for add. }) @@ -176,7 +176,7 @@ private: // Contract helper. static bool all_equal(std::vector const& left, std::vector const& right, unsigned offset = 0) { - auto c = boost::contract::private_member() + auto c = boost::contract::private_function() .precondition([&] { // Correct offset. BOOST_CONTRACT_ASSERT(right.size() == left.size() + offset); diff --git a/example/mitchell02/stack.cpp b/example/mitchell02/stack.cpp index 6788a96..d513dd5 100644 --- a/example/mitchell02/stack.cpp +++ b/example/mitchell02/stack.cpp @@ -31,14 +31,14 @@ public: // Number of items. int count() const { - auto c = boost::contract::public_member(this); // Check invariants. + auto c = boost::contract::public_function(this); // Check invariants. return items_.size(); } // Item at index in [1, count()] (as in Eiffel). T const& item_at(int index) const { - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(index > 0); // Positive index. BOOST_CONTRACT_ASSERT(index <= count()); // Index within count. @@ -53,7 +53,7 @@ public: // If no items. bool is_empty() const { bool result; - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { // Consistent with count. BOOST_CONTRACT_ASSERT(result == (count() == 0)); @@ -66,7 +66,7 @@ public: // Top item. T const& item() const { boost::optional result; // Avoid extra construction of T. - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(count() > 0); // Not empty. }) @@ -84,7 +84,7 @@ public: // Push item to the top. void put(T const& new_item) { auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(count() == *old_count + 1); // Count inc. BOOST_CONTRACT_ASSERT(item() == new_item); // Item set. @@ -97,7 +97,7 @@ public: // Pop top item. void remove() { auto old_count = BOOST_CONTRACT_OLDOF(count()); - auto c = boost::contract::public_member(this) + auto c = boost::contract::public_function(this) .precondition([&] { BOOST_CONTRACT_ASSERT(count() > 0); // Not empty. }) diff --git a/features.txt b/features.txt index c9852d3..85b8507 100644 --- a/features.txt +++ b/features.txt @@ -43,4 +43,7 @@ x Old values with/without subcontracting * Overloading for all contracts * Volatile inv * No static inv / const inv / volatile inv when static_inv / inv const / inv const volatile func not defined (for ctor, dtor, and pub member) +* Derived public function override base protected virtual function (subst + princ does not apply here because base protected virtual cannot be called + by users so it cannot be "substituted")... what will this lib do? diff --git a/generate.py b/generate.py deleted file mode 100644 index f7288e1..0000000 --- a/generate.py +++ /dev/null @@ -1,12 +0,0 @@ - -import fnmatch -import os - -for root, dirs, files in os.walk('.'): - for file in fnmatch.filter(files, '*-generate.py'): - cwd = os.getcwd() - os.chdir(root) - print "In directory:", root - os.system("python " + file) - os.chdir(cwd) - diff --git a/include/boost/contract.hpp b/include/boost/contract.hpp index a74766d..f1387f0 100644 --- a/include/boost/contract.hpp +++ b/include/boost/contract.hpp @@ -12,9 +12,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #endif // #include guard diff --git a/include/boost/contract/aux_/condition/check_pre_only.hpp b/include/boost/contract/aux_/check/check_pre_only.hpp similarity index 100% rename from include/boost/contract/aux_/condition/check_pre_only.hpp rename to include/boost/contract/aux_/check/check_pre_only.hpp diff --git a/include/boost/contract/aux_/condition/check_pre_post.hpp b/include/boost/contract/aux_/check/check_pre_post.hpp similarity index 96% rename from include/boost/contract/aux_/condition/check_pre_post.hpp rename to include/boost/contract/aux_/check/check_pre_post.hpp index 7b6fddb..ed42efc 100644 --- a/include/boost/contract/aux_/condition/check_pre_post.hpp +++ b/include/boost/contract/aux_/check/check_pre_post.hpp @@ -3,7 +3,7 @@ #define BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ #include -#include +#include #include #include /** @cond */ diff --git a/include/boost/contract/aux_/condition/check_pre_post_inv.hpp b/include/boost/contract/aux_/check/check_pre_post_inv.hpp similarity index 97% rename from include/boost/contract/aux_/condition/check_pre_post_inv.hpp rename to include/boost/contract/aux_/check/check_pre_post_inv.hpp index 9fd2b5f..f93230f 100644 --- a/include/boost/contract/aux_/condition/check_pre_post_inv.hpp +++ b/include/boost/contract/aux_/check/check_pre_post_inv.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include /** @cond */ diff --git a/include/boost/contract/aux_/condition/check_subcontracted_pre_post_inv.hpp b/include/boost/contract/aux_/check/check_subcontracted_pre_post_inv.hpp similarity index 90% rename from include/boost/contract/aux_/condition/check_subcontracted_pre_post_inv.hpp rename to include/boost/contract/aux_/check/check_subcontracted_pre_post_inv.hpp index 8441b15..f4855fd 100644 --- a/include/boost/contract/aux_/condition/check_subcontracted_pre_post_inv.hpp +++ b/include/boost/contract/aux_/check/check_subcontracted_pre_post_inv.hpp @@ -4,7 +4,7 @@ // TODO: Review and cleanup all #includes. #include -#include +#include #include #include #include @@ -42,16 +42,19 @@ namespace check_subcontracted_pre_post_inv_ { // TODO: Can I make this, other check_... classes, and maybe even other // calsses noncopyable? What does truly need to be copyable and why? +// TODO: Here I must assert that if O != none then at least one of the bases +// contains a virtual contracted function that can be overridden. + // O, R, F, and A-i can be none types (but C cannot). -template +template class check_subcontracted_pre_post_inv : // Copyable (as * and &). public check_pre_post_inv { // Base types as pointers because mpl::for_each will construct them. typedef typename boost::mpl::transform< - typename boost::mpl::eval_if, - base_types_of - , + typename boost::mpl::eval_if, boost::mpl::identity > + , + base_types_of // Already asserted has_base_types if O != none. >::type, boost::add_pointer >::type base_ptrs; @@ -64,8 +67,8 @@ class check_subcontracted_pre_post_inv : // Copyable (as * and &). public: explicit check_subcontracted_pre_post_inv(boost::contract::from from, - boost::contract::virtual_* v, C* obj, R& r, A0& a0) : - check_pre_post_inv(from, obj), r_(r), a0_(a0) + boost::contract::virtual_* v, C* obj, R& r, A0& a0, A1& a1) : + check_pre_post_inv(from, obj), r_(r), a0_(a0), a1_(a1) { if(v) { base_call_ = true; @@ -172,7 +175,7 @@ private: boost::contract::virtual_::no_action); try { O::template BOOST_CONTRACT_AUX_NAME1(base_call)( - nest_->object(), nest_->a0_, nest_->v_); + nest_->object(), nest_->a0_, nest_->a1_, nest_->v_); } catch(check_subcontracted_pre_post_inv_::no_error const&) { if(nest_->v_->action_ == boost::contract::virtual_::check_pre) { throw; // Pre logic-or: 1st no_err stops (throw to caller). @@ -191,7 +194,8 @@ private: bool base_call_; check_base check_base_; // Copyable (as *). R& r_; - A0& a0_; // TODO: Support configurable func arity. + A0& a0_; + A1& a1_; // TODO: Support configurable func arity. }; } } } // namespace diff --git a/include/boost/contract/aux_/function/constructor.hpp b/include/boost/contract/aux_/function/constructor.hpp index 90a36a6..b7fed45 100644 --- a/include/boost/contract/aux_/function/constructor.hpp +++ b/include/boost/contract/aux_/function/constructor.hpp @@ -3,7 +3,7 @@ #define BOOST_CONTRACT_AUX_CONSTRUCTOR_HPP_ #include -#include +#include #include #include /** @cond */ diff --git a/include/boost/contract/aux_/function/destructor.hpp b/include/boost/contract/aux_/function/destructor.hpp index 282c9ea..c0ef05c 100644 --- a/include/boost/contract/aux_/function/destructor.hpp +++ b/include/boost/contract/aux_/function/destructor.hpp @@ -3,7 +3,7 @@ #define BOOST_CONTRACT_AUX_DESTRUCTOR_HPP_ #include -#include +#include #include #include /** @cond */ diff --git a/include/boost/contract/aux_/function/free_function.hpp b/include/boost/contract/aux_/function/free_function.hpp index 23c9d63..59bbaa9 100644 --- a/include/boost/contract/aux_/function/free_function.hpp +++ b/include/boost/contract/aux_/function/free_function.hpp @@ -3,7 +3,7 @@ #define BOOST_CONTRACT_AUX_FREE_FUNCTION_HPP_ #include -#include +#include #include #include /** @cond */ @@ -13,7 +13,7 @@ namespace boost { namespace contract { namespace aux { -// Also used for private and protected members. +// Also used for private and protected member functions. template class basic_free_function : public check_pre_post { public: diff --git a/include/boost/contract/aux_/function/private_function.hpp b/include/boost/contract/aux_/function/private_function.hpp new file mode 100644 index 0000000..6ab6006 --- /dev/null +++ b/include/boost/contract/aux_/function/private_function.hpp @@ -0,0 +1,20 @@ + +#ifndef BOOST_CONTRACT_AUX_PRIVATE_FUNCTION_HPP_ +#define BOOST_CONTRACT_AUX_PRIVATE_FUNCTION_HPP_ + +#include +#include + +namespace boost { namespace contract { namespace aux { + +// Non-public member functions (e.g., private member functions) are allowed to +// fail class invariants (so no inv), plus they do not participate in virtual +// function polymorphism according to substitution principle (so no +// subcontracting). Therefore, these contract like free functions. +typedef boost::contract::aux::basic_free_function< + boost::contract::from_private_function> private_function; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/function/private_member.hpp b/include/boost/contract/aux_/function/private_member.hpp deleted file mode 100644 index c3ab4f8..0000000 --- a/include/boost/contract/aux_/function/private_member.hpp +++ /dev/null @@ -1,20 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_PRIVATE_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_PRIVATE_MEMBER_HPP_ - -#include -#include - -namespace boost { namespace contract { namespace aux { - -// Not public members (i.e., private members) are allowed to fail class -// invariants (so no inv) and they do not participate in virtual function -// polymorphism according to substitution principle (so no subcontracting). -// Therefore, their contracts behave like contracts of free functions. -typedef boost::contract::aux::basic_free_function< - boost::contract::from_private_member> private_member; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/function/protected_function.hpp b/include/boost/contract/aux_/function/protected_function.hpp new file mode 100644 index 0000000..8d00326 --- /dev/null +++ b/include/boost/contract/aux_/function/protected_function.hpp @@ -0,0 +1,20 @@ + +#ifndef BOOST_CONTRACT_AUX_PROTECTED_FUNCTION_HPP_ +#define BOOST_CONTRACT_AUX_PROTECTED_FUNCTION_HPP_ + +#include +#include + +namespace boost { namespace contract { namespace aux { + +// Non-public member functions (e.g., protected member functions) are allowed +// to fail class invariants (so no inv) and they do not participate in virtual +// function polymorphism according to substitution principle (so no +// subcontracting). Therefore, these contract like free functions. +typedef boost::contract::aux::basic_free_function< + boost::contract::from_protected_function> protected_function; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/function/protected_member.hpp b/include/boost/contract/aux_/function/protected_member.hpp deleted file mode 100644 index 12326e4..0000000 --- a/include/boost/contract/aux_/function/protected_member.hpp +++ /dev/null @@ -1,20 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_PROTECTED_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_PROTECTED_MEMBER_HPP_ - -#include -#include - -namespace boost { namespace contract { namespace aux { - -// Not public members (i.e., protected members) are allowed to fail class -// invariants (so no inv) and they do not participate in virtual function -// polymorphism according to substitution principle (so no subcontracting). -// Therefore, their contracts behave like contracts of free functions. -typedef boost::contract::aux::basic_free_function< - boost::contract::from_protected_member> protected_member; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/function/public_member.hpp b/include/boost/contract/aux_/function/public_function.hpp similarity index 67% rename from include/boost/contract/aux_/function/public_member.hpp rename to include/boost/contract/aux_/function/public_function.hpp index 5eba09a..79b8d17 100644 --- a/include/boost/contract/aux_/function/public_member.hpp +++ b/include/boost/contract/aux_/function/public_function.hpp @@ -1,9 +1,9 @@ -#ifndef BOOST_CONTRACT_AUX_PUBLIC_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_PUBLIC_MEMBER_HPP_ +#ifndef BOOST_CONTRACT_AUX_PUBLIC_FUNCTION_HPP_ +#define BOOST_CONTRACT_AUX_PUBLIC_FUNCTION_HPP_ #include -#include +#include #include #include /** @cond */ @@ -12,12 +12,14 @@ namespace boost { namespace contract { namespace aux { -template -class public_member : public check_subcontracted_pre_post_inv { +template +class public_function : + public check_subcontracted_pre_post_inv { public: - explicit public_member(boost::contract::virtual_* v, C* obj, R& r, A0& a0) : - check_subcontracted_pre_post_inv( - boost::contract::from_public_member, v, obj, r, a0) + explicit public_function( + boost::contract::virtual_* v, C* obj, R& r, A0& a0, A1& a1) : + check_subcontracted_pre_post_inv( + boost::contract::from_public_function, v, obj, r, a0, a1) { BOOST_CONTRACT_AUX_SUBCONTRACTED_CHECK_GUARD_OR_RETURN this->copy_subcontracted_oldof(); @@ -41,7 +43,7 @@ private: } public: - ~public_member() { + ~public_function() { BOOST_CONTRACT_AUX_SUBCONTRACTED_CHECK_GUARD_OR_RETURN if(!this->base_call()) { this->check_subcontracted_exit_inv(); diff --git a/include/boost/contract/aux_/function/public_static_member.hpp b/include/boost/contract/aux_/function/public_static_function.hpp similarity index 61% rename from include/boost/contract/aux_/function/public_static_member.hpp rename to include/boost/contract/aux_/function/public_static_function.hpp index 5704ff2..5092c56 100644 --- a/include/boost/contract/aux_/function/public_static_member.hpp +++ b/include/boost/contract/aux_/function/public_static_function.hpp @@ -1,10 +1,10 @@ -#ifndef BOOST_CONTRACT_AUX_PUBLIC_STATIC_MEMBER_HPP_ -#define BOOST_CONTRACT_AUX_PUBLIC_STATIC_MEMBER_HPP_ +#ifndef BOOST_CONTRACT_AUX_PUBLIC_STATIC_FUNCTION_HPP_ +#define BOOST_CONTRACT_AUX_PUBLIC_STATIC_FUNCTION_HPP_ #include #include -#include +#include #include #include /** @cond */ @@ -14,12 +14,12 @@ namespace boost { namespace contract { namespace aux { -// No subcontracting because static so no obj and no subst. principle. +// No subcontracting because static so no obj and no substitution principle. template -class public_static_member : public check_pre_post_inv { +class public_static_function : public check_pre_post_inv { public: - explicit public_static_member() : check_pre_post_inv( - boost::contract::from_public_member, 0) { + explicit public_static_function() : check_pre_post_inv( + boost::contract::from_public_function, /* obj = */ 0) { BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN this->check_entry_static_inv(); } @@ -31,7 +31,7 @@ private: } public: - ~public_static_member() { + ~public_static_function() { BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN this->check_exit_static_inv(); if(!std::uncaught_exception()) this->check_post(); diff --git a/include/boost/contract/core/exception.hpp b/include/boost/contract/core/exception.hpp index 3eff9ef..ca1d637 100644 --- a/include/boost/contract/core/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -56,9 +56,9 @@ private: enum from { from_constructor, from_destructor, - from_public_member, - from_protected_member, - from_private_member, + from_public_function, + from_protected_function, + from_private_function, from_free_function }; diff --git a/include/boost/contract/core/set_nothing.hpp b/include/boost/contract/core/set_nothing.hpp index 63a36d1..2f8fcd4 100644 --- a/include/boost/contract/core/set_nothing.hpp +++ b/include/boost/contract/core/set_nothing.hpp @@ -4,7 +4,7 @@ /** @file */ -#include +#include /** @cond */ #include /** @endcond */ @@ -18,7 +18,7 @@ namespace boost { namespace contract { class set_nothing { // Copyable as shared * (OK also for RAII). public: - // No set function members here. + // No set member functions here. private: typedef boost::shared_ptr check_ptr; diff --git a/include/boost/contract/core/set_postcondition_only.hpp b/include/boost/contract/core/set_postcondition_only.hpp index 9623348..cd1951a 100644 --- a/include/boost/contract/core/set_postcondition_only.hpp +++ b/include/boost/contract/core/set_postcondition_only.hpp @@ -5,7 +5,7 @@ /** @file */ #include -#include +#include #include /** @cond */ #include diff --git a/include/boost/contract/core/set_precondition_only.hpp b/include/boost/contract/core/set_precondition_only.hpp index a36ec52..bbb6be0 100644 --- a/include/boost/contract/core/set_precondition_only.hpp +++ b/include/boost/contract/core/set_precondition_only.hpp @@ -5,7 +5,7 @@ /** @file */ #include -#include +#include /** @cond */ #include /** @endcond */ diff --git a/include/boost/contract/core/set_precondition_postcondition.hpp b/include/boost/contract/core/set_precondition_postcondition.hpp index 9be5ad2..e43d073 100644 --- a/include/boost/contract/core/set_precondition_postcondition.hpp +++ b/include/boost/contract/core/set_precondition_postcondition.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include /** @cond */ #include @@ -48,39 +48,51 @@ private: // Friendship used to limit library's public API. friend class guard; friend set_precondition_postcondition<> free_function(); - friend set_precondition_postcondition<> protected_member(); - friend set_precondition_postcondition<> private_member(); + friend set_precondition_postcondition<> protected_function(); + friend set_precondition_postcondition<> private_function(); template - friend set_precondition_postcondition<> public_member(); + friend set_precondition_postcondition<> public_function(); template - friend set_precondition_postcondition<> public_member(C*); + friend set_precondition_postcondition<> public_function(C*); template - friend set_precondition_postcondition<> public_member(virtual_*, C*); + friend set_precondition_postcondition<> public_function(virtual_*, C*); template - friend set_precondition_postcondition public_member(virtual_*, R_&, C*); + friend set_precondition_postcondition public_function( + virtual_*, R_&, C*); /* arity = 0 */ template - friend set_precondition_postcondition<> public_member(virtual_*, F, C*); + friend set_precondition_postcondition<> public_function(virtual_*, F, C*); template - friend set_precondition_postcondition public_member( + friend set_precondition_postcondition public_function( virtual_*, R_&, F, C*); /* arity = 1 */ template - friend set_precondition_postcondition<> public_member( + friend set_precondition_postcondition<> public_function( virtual_*, F, C*, A0&); template - friend set_precondition_postcondition public_member( + friend set_precondition_postcondition public_function( virtual_*, R_&, F, C*, A0&); + + /* arity = 2 */ + + template + friend set_precondition_postcondition<> public_function( + virtual_*, F, C*, A0&, A1&); + + template + friend set_precondition_postcondition public_function( + virtual_*, R_&, F, C*, A0&, A1&); // TODO: Support configurable arity. }; diff --git a/include/boost/contract/core/virtual.hpp b/include/boost/contract/core/virtual.hpp index eb4f9c7..bd72ca6 100644 --- a/include/boost/contract/core/virtual.hpp +++ b/include/boost/contract/core/virtual.hpp @@ -11,7 +11,7 @@ namespace boost { namespace contract { namespace aux { - template + template class check_subcontracted_pre_post_inv; } } @@ -42,7 +42,7 @@ private: friend bool copy_old(virtual_*); friend class old; - template + template friend class boost::contract::aux::check_subcontracted_pre_post_inv; }; diff --git a/include/boost/contract/guard.hpp b/include/boost/contract/guard.hpp index dc6d718..2a1b728 100644 --- a/include/boost/contract/guard.hpp +++ b/include/boost/contract/guard.hpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include /** @cond */ #include #include diff --git a/include/boost/contract/override.hpp b/include/boost/contract/override.hpp index 952b8db..c1397a9 100644 --- a/include/boost/contract/override.hpp +++ b/include/boost/contract/override.hpp @@ -26,7 +26,7 @@ struct trait { \ BOOST_CONTRACT_AUX_INTROSPECTION_HAS_MEMBER_FUNCTION( \ BOOST_CONTRACT_AUX_NAME1(has_member_function), f) \ - \ + /* arity = 0 */ \ template< \ class BOOST_CONTRACT_AUX_NAME1(B), \ class BOOST_CONTRACT_AUX_NAME1(C) \ @@ -34,13 +34,14 @@ static void BOOST_CONTRACT_AUX_NAME1(base_call)( \ BOOST_CONTRACT_AUX_NAME1(C)* BOOST_CONTRACT_AUX_NAME1(obj), \ boost::contract::aux::none&, \ + boost::contract::aux::none&, \ boost::contract::virtual_* BOOST_CONTRACT_AUX_NAME1(v) \ ) { \ BOOST_CONTRACT_AUX_NAME1(obj)->BOOST_CONTRACT_AUX_NAME1(B)::f( \ BOOST_CONTRACT_AUX_NAME1(v) \ ); \ } \ - \ + /* arity = 1 */ \ template< \ class BOOST_CONTRACT_AUX_NAME1(B), \ class BOOST_CONTRACT_AUX_NAME1(C), \ @@ -49,6 +50,7 @@ static void BOOST_CONTRACT_AUX_NAME1(base_call)( \ BOOST_CONTRACT_AUX_NAME1(C)* BOOST_CONTRACT_AUX_NAME1(obj), \ BOOST_CONTRACT_AUX_NAME1(A0)& BOOST_CONTRACT_AUX_NAME1(a0), \ + boost::contract::aux::none&, \ boost::contract::virtual_* BOOST_CONTRACT_AUX_NAME1(v) \ ) { \ BOOST_CONTRACT_AUX_NAME1(obj)->BOOST_CONTRACT_AUX_NAME1(B)::f( \ @@ -56,6 +58,25 @@ BOOST_CONTRACT_AUX_NAME1(v) \ ); \ } \ + /* arity = 2 */ \ + template< \ + class BOOST_CONTRACT_AUX_NAME1(B), \ + class BOOST_CONTRACT_AUX_NAME1(C), \ + typename BOOST_CONTRACT_AUX_NAME1(A0), \ + typename BOOST_CONTRACT_AUX_NAME1(A1) \ + > \ + static void BOOST_CONTRACT_AUX_NAME1(base_call)( \ + BOOST_CONTRACT_AUX_NAME1(C)* BOOST_CONTRACT_AUX_NAME1(obj), \ + BOOST_CONTRACT_AUX_NAME1(A0)& BOOST_CONTRACT_AUX_NAME1(a0), \ + BOOST_CONTRACT_AUX_NAME1(A1)& BOOST_CONTRACT_AUX_NAME1(a1), \ + boost::contract::virtual_* BOOST_CONTRACT_AUX_NAME1(v) \ + ) { \ + BOOST_CONTRACT_AUX_NAME1(obj)->BOOST_CONTRACT_AUX_NAME1(B)::f( \ + BOOST_CONTRACT_AUX_NAME1(a0), \ + BOOST_CONTRACT_AUX_NAME1(a1), \ + BOOST_CONTRACT_AUX_NAME1(v) \ + ); \ + } \ }; #endif // #include guard diff --git a/include/boost/contract/private_member.hpp b/include/boost/contract/private_function.hpp similarity index 51% rename from include/boost/contract/private_member.hpp rename to include/boost/contract/private_function.hpp index f732b97..cf9b373 100644 --- a/include/boost/contract/private_member.hpp +++ b/include/boost/contract/private_function.hpp @@ -1,20 +1,20 @@ -#ifndef BOOST_CONTRACT_PRIVATE_MEMBER_HPP_ -#define BOOST_CONTRACT_PRIVATE_MEMBER_HPP_ +#ifndef BOOST_CONTRACT_PRIVATE_FUNCTION_HPP_ +#define BOOST_CONTRACT_PRIVATE_FUNCTION_HPP_ /** @file */ #include -#include +#include /** @cond */ #include /** @endcond */ namespace boost { namespace contract { -set_precondition_postcondition<> private_member() { +set_precondition_postcondition<> private_function() { return set_precondition_postcondition<>(boost::make_shared< - boost::contract::aux::private_member>()); + boost::contract::aux::private_function>()); } } } // namespace diff --git a/include/boost/contract/protected_member.hpp b/include/boost/contract/protected_function.hpp similarity index 50% rename from include/boost/contract/protected_member.hpp rename to include/boost/contract/protected_function.hpp index 24067b2..58e9724 100644 --- a/include/boost/contract/protected_member.hpp +++ b/include/boost/contract/protected_function.hpp @@ -1,20 +1,20 @@ -#ifndef BOOST_CONTRACT_PROTECTED_MEMBER_HPP_ -#define BOOST_CONTRACT_PROTECTED_MEMBER_HPP_ +#ifndef BOOST_CONTRACT_PROTECTED_FUNCTION_HPP_ +#define BOOST_CONTRACT_PROTECTED_FUNCTION_HPP_ /** @file */ #include -#include +#include /** @cond */ #include /** @endcond */ namespace boost { namespace contract { -set_precondition_postcondition<> protected_member() { +set_precondition_postcondition<> protected_function() { return set_precondition_postcondition<>(boost::make_shared< - boost::contract::aux::protected_member>()); + boost::contract::aux::protected_function>()); } } } // namespace diff --git a/include/boost/contract/public_function.hpp b/include/boost/contract/public_function.hpp new file mode 100644 index 0000000..e90dc3b --- /dev/null +++ b/include/boost/contract/public_function.hpp @@ -0,0 +1,250 @@ + +#ifndef BOOST_CONTRACT_PUBLIC_FUNCTION_HPP_ +#define BOOST_CONTRACT_PUBLIC_FUNCTION_HPP_ + +/** @file */ + +#include +#include +#include +#include +#include +#include +/** @cond */ +#include +#include +#include +#include +#include +/** @endcond */ + +/* PRIVATE */ + +// Always enforce this so this lib can check and enforce override. +#define BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) \ + BOOST_STATIC_ASSERT_MSG( \ + boost::contract::aux::has_base_types::value, \ + "enclosing class missing 'base types' typdef" \ + ); + +#define BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_RESULT_(F, R) \ + BOOST_STATIC_ASSERT_MSG( \ + boost::is_same< \ + typename boost::remove_reference::type>::type, \ + R \ + >::value, \ + "miss-matching result type for specified function" \ + ); + +#define BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, arity) \ + BOOST_STATIC_ASSERT_MSG( \ + /* -1 for this and -1 for virtual_* so -2 total */ \ + boost::function_types::function_arity::value - 2 == arity, \ + "missing one or more parameters for specified function" \ + ); + +// Always enforce this so base contracts can always specify postconditions with +// result, without need to change derived contracts. +#define BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_VOID_RESULT_(F) \ + BOOST_STATIC_ASSERT_MSG( \ + boost::is_same< \ + typename boost::function_types::result_type::type, \ + void \ + >::value, \ + "missing result parameter for non-void function" \ + ); + +/* CODE */ + +namespace boost { namespace contract { + +// For static member functions. +template +set_precondition_postcondition<> public_function() { + return set_precondition_postcondition<>(boost::make_shared< + boost::contract::aux::public_static_function >()); +} + +// For non-virtual, non-overriding member functions. +template +set_precondition_postcondition<> public_function(C* obj) { + return set_precondition_postcondition<>(boost::make_shared< + boost::contract::aux::public_function< + boost::contract::aux::none, + boost::contract::aux::none, + boost::contract::aux::none, + C, + boost::contract::aux::none, boost::contract::aux::none + > + >( + static_cast(0), + obj, + boost::contract::aux::none::value, + boost::contract::aux::none::value, boost::contract::aux::none::value + )); +} + +// NOTE: O and R (optionally) allowed only when v is present because: +// * An overriding func must override a base func declared virtual so with +// v extra param, thus the overriding func must also always have v (i.e., O +// might be present only if v is also present). +// However, the first appearing virtual func (e.g., in root class) will not +// override any previously declared virtual func so does not need O (i.e., O +// always optional). +// Furthermore, F needs to be specified only together with O. +// * R is only used for virtual functions (i.e., R might be present only if v +// is also present). +// However, R is never specified, not even for virtual functions, when the +// return type is void (i.e., R always optional). + +// For virtual, non-overriding, void function. +template +set_precondition_postcondition<> public_function(virtual_* v, C* obj) { + // NOTE: No F so cannot enforce enclosing function is void (up to user). + return set_precondition_postcondition<>(boost::make_shared< + boost::contract::aux::public_function< + boost::contract::aux::none, + boost::contract::aux::none, + boost::contract::aux::none, + C, + boost::contract::aux::none, boost::contract::aux::none + > + >(v, obj, boost::contract::aux::none::value, boost::contract::aux::none:: + value, boost::contract::aux::none::value)); +} + +// For virtual, non-overriding, non-void member functions. +template +set_precondition_postcondition public_function(virtual_* v, R& r, C* obj) { + // NOTE: No F so cannot enforce enclosing function returns R (up to user). + return set_precondition_postcondition(boost::make_shared< + boost::contract::aux::public_function< + boost::contract::aux::none, + R, + boost::contract::aux::none, + C, + boost::contract::aux::none, boost::contract::aux::none + > + >(v, obj, r, boost::contract::aux::none::value, + boost::contract::aux::none::value)); +} + +/* Overriding (arity = 0) */ + +// For virtual, overriding, void member functions. +template +set_precondition_postcondition<> public_function(virtual_* v, F, C* obj) { + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 0) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_VOID_RESULT_(F) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) + return set_precondition_postcondition<>(boost::make_shared< + boost::contract::aux::public_function< + O, + boost::contract::aux::none, + F, + C, + boost::contract::aux::none, boost::contract::aux::none + > + >(v, obj, boost::contract::aux::none::value, boost::contract::aux::none:: + value, boost::contract::aux::none::value)); +} + +// For virtual, overriding, non-void member functions of class with bases. +template +set_precondition_postcondition public_function( + virtual_* v, R& r, F, C* obj) { + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 0) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_RESULT_(F, R) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) + return set_precondition_postcondition(boost::make_shared< + boost::contract::aux::public_function< + O, + R, + F, + C, + boost::contract::aux::none, boost::contract::aux::none + > + >(v, obj, r, boost::contract::aux::none::value, + boost::contract::aux::none::value)); +} + +/* Overriding (arity = 1) */ + +template +set_precondition_postcondition<> public_function( + virtual_* v, F, C* obj, A0& a0) { + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 1) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_VOID_RESULT_(F) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) + return set_precondition_postcondition<>(boost::make_shared< + boost::contract::aux::public_function< + O, + boost::contract::aux::none, + F, + C, + A0, boost::contract::aux::none + > + >(v, obj, boost::contract::aux::none::value, a0, + boost::contract::aux::none::value)); +} + +template +set_precondition_postcondition public_function( + virtual_* v, R& r, F, C* obj, A0& a0) { + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 1) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_RESULT_(F, R) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) + return set_precondition_postcondition(boost::make_shared< + boost::contract::aux::public_function< + O, + R, + F, + C, + A0, boost::contract::aux::none + > + >(v, obj, r, a0, boost::contract::aux::none::value)); +} + +/* Overriding (arity = 2) */ + +template +set_precondition_postcondition<> public_function( + virtual_* v, F, C* obj, A0& a0, A1& a1) { + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 2) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_VOID_RESULT_(F) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) + return set_precondition_postcondition<>(boost::make_shared< + boost::contract::aux::public_function< + O, + boost::contract::aux::none, + F, + C, + A0, A1 + > + >(v, obj, boost::contract::aux::none::value, a0, a1)); +} + +template +set_precondition_postcondition public_function( + virtual_* v, R& r, F, C* obj, A0& a0, A1& a1) { + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 2) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_RESULT_(F, R) + BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) + return set_precondition_postcondition(boost::make_shared< + boost::contract::aux::public_function< + O, + R, + F, + C, + A0, A1 + > + >(v, obj, r, a0, a1)); +} + +// TODO: Support configurable arity. + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/public_member.hpp b/include/boost/contract/public_member.hpp deleted file mode 100644 index f3e6579..0000000 --- a/include/boost/contract/public_member.hpp +++ /dev/null @@ -1,148 +0,0 @@ - -#ifndef BOOST_CONTRACT_PUBLIC_MEMBER_HPP_ -#define BOOST_CONTRACT_PUBLIC_MEMBER_HPP_ - -/** @file */ - -#include -#include -#include -#include -#include -/** @cond */ -#include -/** @endcond */ - -namespace boost { namespace contract { - -// For static members. -template -set_precondition_postcondition<> public_member() { - return set_precondition_postcondition<>(boost::make_shared< - boost::contract::aux::public_static_member >()); -} - -// For non-virtual, non-overriding members. -template -set_precondition_postcondition<> public_member(C* obj) { - return set_precondition_postcondition<>(boost::make_shared< - boost::contract::aux::public_member< - boost::contract::aux::none, - boost::contract::aux::none, - boost::contract::aux::none, - C, - boost::contract::aux::none - > - >(static_cast(0), obj, boost::contract::aux:: - none::value, boost::contract::aux::none::value)); -} - -// NOTE: O and R (optionally) allowed only when v is present because: -// * An overriding func must override a base func declared virtual so with -// v extra param, thus the overriding func must also always have v (i.e., O -// might be present only if v is also present). -// However, the first appearing virtual func (e.g., in root class) will not -// override any previously declared virtual func so does not need O (i.e., O -// always optional). -// Furthermore, F needs to be specified only together with O. -// * R is only used for virtual functions (i.e., R might be present only if v -// is also present). -// However, R is never specified, not even for virtual functions, when the -// return type is void (i.e., R always optional). - -// For virtual, non-overriding, void members. -template -set_precondition_postcondition<> public_member(virtual_* v, C* obj) { - return set_precondition_postcondition<>(boost::make_shared< - boost::contract::aux::public_member< - boost::contract::aux::none, - boost::contract::aux::none, - boost::contract::aux::none, - C, - boost::contract::aux::none - > - >(v, obj, boost::contract::aux::none::value, - boost::contract::aux::none::value)); -} - -// For virtual, non-overriding, non-void members. -template -set_precondition_postcondition public_member(virtual_* v, R& r, C* obj) { - return set_precondition_postcondition(boost::make_shared< - boost::contract::aux::public_member< - boost::contract::aux::none, - R, - boost::contract::aux::none, - C, - boost::contract::aux::none - > - >(v, obj, r, boost::contract::aux::none::value)); -} - -/* Overriding (arity = 0) */ - -// For virtual, overriding, void members. -template -set_precondition_postcondition<> public_member(virtual_* v, F, C* obj) { - return set_precondition_postcondition<>(boost::make_shared< - boost::contract::aux::public_member< - O, - boost::contract::aux::none, - F, - C, - boost::contract::aux::none - > - >(v, obj, boost::contract::aux::none::value, - boost::contract::aux::none::value)); -} - -// For virtual, overriding, non-void members of class with bases. -template -set_precondition_postcondition public_member(virtual_* v, R& r, F, C* obj) { - return set_precondition_postcondition(boost::make_shared< - boost::contract::aux::public_member< - O, - R, - F, - C, - boost::contract::aux::none - > - >(v, obj, r, boost::contract::aux::none::value)); -} - -/* Overriding (arity = 1) */ - -template -set_precondition_postcondition<> public_member( - virtual_* v, F, C* obj, A0& a0) { - return set_precondition_postcondition<>(boost::make_shared< - boost::contract::aux::public_member< - O, - boost::contract::aux::none, - F, - C, - A0 - > - >(v, obj, boost::contract::aux::none::value, a0)); -} - -template -set_precondition_postcondition public_member( - virtual_* v, R& r, F, C* obj, A0& a0) { - return set_precondition_postcondition(boost::make_shared< - boost::contract::aux::public_member< - O, - R, - F, - C, - A0 - > - >(v, obj, r, a0)); -} - -// TODO: Support configurable arity. - -} } // namespace - -#endif // #include guard - diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index aa42031..1c42f42 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -7,18 +7,18 @@ subdir-run destructor : bases ; subdir-run destructor : body_throw ; subdir-compile-fail destructor : no_pre-error ; -subdir-run public_member : bases ; -subdir-run public_member : bases_virtual ; -subdir-run public_member : bases_branch ; -subdir-run public_member : body_throw ; -subdir-run public_member : static ; -subdir-run public_member : static_body_throw ; +subdir-run public_function : bases ; +subdir-run public_function : bases_virtual ; +subdir-run public_function : bases_branch ; +subdir-run public_function : body_throw ; +subdir-run public_function : static ; +subdir-run public_function : static_body_throw ; -subdir-run protected_member : bases ; -subdir-run protected_member : body_throw ; +subdir-run protected_function : bases ; +subdir-run protected_function : body_throw ; -subdir-run private_member : bases ; -subdir-run private_member : body_throw ; +subdir-run private_function : bases ; +subdir-run private_function : body_throw ; subdir-run free_function : main ; subdir-run free_function : body_throw ; diff --git a/test/disable/checking.cpp b/test/disable/checking.cpp index 2bf1d24..088ee76 100644 --- a/test/disable/checking.cpp +++ b/test/disable/checking.cpp @@ -5,7 +5,7 @@ #include "../aux_/cpcnt.hpp" #include #include -#include +#include #include #include #include @@ -23,7 +23,7 @@ struct a { int result; boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF( x_type::eval(x)); - boost::contract::guard c = boost::contract::public_member(this) + boost::contract::guard c = boost::contract::public_function(this) .precondition([&] { out << "a::f::pre" << std::endl; }) .postcondition([&] { out << "a::f::post" << std::endl; @@ -49,7 +49,7 @@ struct b { static void static_invariant() { out << "b::static_inv" << std::endl; } void g() { - boost::contract::guard c = boost::contract::public_member(this) + boost::contract::guard c = boost::contract::public_function(this) .precondition([&] { out << "b::g::pre" << std::endl; BOOST_CONTRACT_ASSERT(call_f()); diff --git a/test/private_member/bases.cpp b/test/private_function/bases.cpp similarity index 90% rename from test/private_member/bases.cpp rename to test/private_function/bases.cpp index 1bfa04a..2f7c14a 100644 --- a/test/private_member/bases.cpp +++ b/test/private_function/bases.cpp @@ -3,7 +3,7 @@ #include "../aux_/oteststream.hpp" #include -#include +#include #include #include #include @@ -16,7 +16,7 @@ struct b { private: virtual void f() { - boost::contract::guard c = boost::contract::private_member() + boost::contract::guard c = boost::contract::private_function() .precondition([&] { out << "b::f::pre" << std::endl; }) @@ -42,7 +42,7 @@ struct a private: virtual void f() { - boost::contract::guard c = boost::contract::private_member() + boost::contract::guard c = boost::contract::private_function() .precondition([&] { out << "a::f::pre" << std::endl; }) diff --git a/test/private_member/body_throw.cpp b/test/private_function/body_throw.cpp similarity index 90% rename from test/private_member/body_throw.cpp rename to test/private_function/body_throw.cpp index b632061..2779250 100644 --- a/test/private_member/body_throw.cpp +++ b/test/private_function/body_throw.cpp @@ -2,7 +2,7 @@ // Test private member function throwing. #include "../aux_/oteststream.hpp" -#include +#include #include #include #include @@ -19,7 +19,7 @@ struct a { private: virtual void f() { - boost::contract::guard c = boost::contract::private_member() + boost::contract::guard c = boost::contract::private_function() .precondition([&] { out << "a::f::pre" << std::endl; }) .postcondition([&] { out << "a::f::post" << std::endl; }) ; diff --git a/test/protected_member/bases.cpp b/test/protected_function/bases.cpp similarity index 89% rename from test/protected_member/bases.cpp rename to test/protected_function/bases.cpp index c2339ba..c4c7b59 100644 --- a/test/protected_member/bases.cpp +++ b/test/protected_function/bases.cpp @@ -3,7 +3,7 @@ #include "../aux_/oteststream.hpp" #include -#include +#include #include #include #include @@ -16,7 +16,7 @@ struct b { protected: virtual void f() { - boost::contract::guard c = boost::contract::protected_member() + boost::contract::guard c = boost::contract::protected_function() .precondition([&] { out << "b::f::pre" << std::endl; }) @@ -42,7 +42,7 @@ struct a protected: virtual void f() { - boost::contract::guard c = boost::contract::protected_member() + boost::contract::guard c = boost::contract::protected_function() .precondition([&] { out << "a::f::pre" << std::endl; }) diff --git a/test/protected_member/body_throw.cpp b/test/protected_function/body_throw.cpp similarity index 90% rename from test/protected_member/body_throw.cpp rename to test/protected_function/body_throw.cpp index ae1ed16..c6325fe 100644 --- a/test/protected_member/body_throw.cpp +++ b/test/protected_function/body_throw.cpp @@ -2,7 +2,7 @@ // Test protected member function throwing. #include "../aux_/oteststream.hpp" -#include +#include #include #include #include @@ -19,7 +19,7 @@ struct a { protected: virtual void f() { - boost::contract::guard c = boost::contract::protected_member() + boost::contract::guard c = boost::contract::protected_function() .precondition([&] { out << "a::f::pre" << std::endl; }) .postcondition([&] { out << "a::f::post" << std::endl; }) ; diff --git a/test/public_member/bases.cpp b/test/public_function/bases.cpp similarity index 100% rename from test/public_member/bases.cpp rename to test/public_function/bases.cpp diff --git a/test/public_member/bases.hpp b/test/public_function/bases.hpp similarity index 94% rename from test/public_member/bases.hpp rename to test/public_function/bases.hpp index 1280f5d..41ba39a 100644 --- a/test/public_member/bases.hpp +++ b/test/public_function/bases.hpp @@ -2,11 +2,11 @@ #ifndef BASES_HPP_ #define BASES_HPP_ -// Test public member subcontracting (also with old and return values). +// Test public member function subcontracting (also with old and return values). #include "../aux_/oteststream.hpp" #include "../aux_/cpcnt.hpp" -#include +#include #include #include #include @@ -56,7 +56,7 @@ result_type& t::f(s_type& s, boost::contract::virtual_* v) { BOOST_CONTRACT_OLDOF(v, z_type::eval(z)); boost::shared_ptr old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s)); - boost::contract::guard c = boost::contract::public_member(v, result, this) + boost::contract::guard c = boost::contract::public_function(v, result, this) .precondition([&] { out << Id << "::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(s.value[0] == Id); @@ -101,7 +101,7 @@ struct c BOOST_CONTRACT_OLDOF(v, y_type::eval(y)); boost::shared_ptr old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s)); - boost::contract::guard c = boost::contract::public_member< + boost::contract::guard c = boost::contract::public_function< override_f>(v, result, &c::f, this, s) .precondition([&] { out << "c::f::pre" << std::endl; @@ -152,7 +152,7 @@ struct b { } }; -// Test public member with both non-contracted and contracted bases. +// Test public function with both non-contracted and contracted bases. struct a #define BASES public b, public c : BASES @@ -180,7 +180,7 @@ struct a BOOST_CONTRACT_OLDOF(v, x_type::eval(x)); boost::shared_ptr old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s)); - boost::contract::guard c = boost::contract::public_member< + boost::contract::guard c = boost::contract::public_function< override_f>(v, result, &a::f, this, s) .precondition([&] { out << "a::f::pre" << std::endl; diff --git a/test/public_member/bases_branch.cpp b/test/public_function/bases_branch.cpp similarity index 100% rename from test/public_member/bases_branch.cpp rename to test/public_function/bases_branch.cpp diff --git a/test/public_member/bases_virtual.cpp b/test/public_function/bases_virtual.cpp similarity index 100% rename from test/public_member/bases_virtual.cpp rename to test/public_function/bases_virtual.cpp diff --git a/test/public_member/body_throw.cpp b/test/public_function/body_throw.cpp similarity index 92% rename from test/public_member/body_throw.cpp rename to test/public_function/body_throw.cpp index 0b11752..1fdd65d 100644 --- a/test/public_member/body_throw.cpp +++ b/test/public_function/body_throw.cpp @@ -2,7 +2,7 @@ // Test constructor body throwing (in inheritance tree). #include "../aux_/oteststream.hpp" -#include +#include #include #include #include @@ -19,7 +19,7 @@ struct c { struct e {}; virtual void f(boost::contract::virtual_* v = 0) { - boost::contract::guard c = boost::contract::public_member(v, this) + boost::contract::guard c = boost::contract::public_function(v, this) .precondition([&] { out << "c::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(false); // To check derived pre. @@ -44,7 +44,7 @@ struct b struct e {}; virtual void f(boost::contract::virtual_* v = 0) /* override */ { - boost::contract::guard c = boost::contract::public_member( + boost::contract::guard c = boost::contract::public_function( v, &b::f, this) .precondition([&] { out << "b::f::pre" << std::endl; @@ -71,7 +71,7 @@ struct a struct e {}; void f(boost::contract::virtual_* v = 0) /* override */ { - boost::contract::guard c = boost::contract::public_member( + boost::contract::guard c = boost::contract::public_function( v, &a::f, this) .precondition([&] { out << "a::f::pre" << std::endl; }) .postcondition([&] { out << "a::f::post" << std::endl; }) diff --git a/test/public_member/static.cpp b/test/public_function/static.cpp similarity index 90% rename from test/public_member/static.cpp rename to test/public_function/static.cpp index ba531e7..e84207b 100644 --- a/test/public_member/static.cpp +++ b/test/public_function/static.cpp @@ -3,7 +3,7 @@ #include "../aux_/oteststream.hpp" #include -#include +#include #include #include #include @@ -15,7 +15,7 @@ struct b { static void static_invariant() { out << "b::static_inv" << std::endl; } static void f() { - boost::contract::guard c = boost::contract::public_member() + boost::contract::guard c = boost::contract::public_function() .precondition([&] { out << "b::f::pre" << std::endl; }) @@ -38,7 +38,7 @@ struct a static void static_invariant() { out << "a::static_inv" << std::endl; } static void f() { - boost::contract::guard c = boost::contract::public_member() + boost::contract::guard c = boost::contract::public_function() .precondition([&] { out << "a::f::pre" << std::endl; }) diff --git a/test/public_member/static_body_throw.cpp b/test/public_function/static_body_throw.cpp similarity index 87% rename from test/public_member/static_body_throw.cpp rename to test/public_function/static_body_throw.cpp index 72f5bb0..dc479f7 100644 --- a/test/public_member/static_body_throw.cpp +++ b/test/public_function/static_body_throw.cpp @@ -1,8 +1,8 @@ -// Test public static member throwing. +// Test public static member function throwing. #include "../aux_/oteststream.hpp" -#include +#include #include #include #include @@ -16,7 +16,7 @@ struct a { struct e {}; static void f() { - boost::contract::guard c = boost::contract::public_member() + boost::contract::guard c = boost::contract::public_function() .precondition([&] { out << "a::f::pre" << std::endl; }) diff --git a/wave.cfg b/wave.cfg deleted file mode 100644 index 7a0e4a5..0000000 --- a/wave.cfg +++ /dev/null @@ -1,30 +0,0 @@ - -# NOTE: Some of the paths in this file may need to be changed for your system. - --DDEBUG ---variadics - -# MSVC --S"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include" --D_WIN32 --D_WCHAR_T_DEFINED --D_MSC_EXTENSIONS --D_DLL --D_M_IX86 - -## GCC/CLang (still, this doesn't really work...) -#-S"C:\cygwin\lib\gcc\i686-pc-cygwin\4.8.3\include\c++" -#-S"C:\cygwin\lib\gcc\i686-pc-cygwin\4.8.3\include\c++\i686-pc-cygwin" -#-S"C:\cygwin\lib\gcc\i686-pc-cygwin\4.8.3\include\c++\backward" -##-S"C:\cygwin\lib\clang\i686-pc-cygwin\3.4.2\include" -#-S"C:\cygwin\lib\gcc\i686-pc-cygwin\4.8.3\include" -#-S"C:\cygwin\usr\include" -#-S"C:\cygwin\usr\include\w32api" -#-D__IEEE_LITTLE_ENDIAN -#-D__WCHAR_UNSIGNED__ -##-D__has_feature(x)=0 -##-D__has_include_next(x)=0 - --S"C:\git\modular-boost.win" --S"C:\git\boost-contract\include" -