diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/contract/example/features | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/contract/example/features')
42 files changed, 4180 insertions, 0 deletions
diff --git a/src/boost/libs/contract/example/features/access.cpp b/src/boost/libs/contract/example/features/access.cpp new file mode 100644 index 00000000..07586172 --- /dev/null +++ b/src/boost/libs/contract/example/features/access.cpp @@ -0,0 +1,95 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <cassert> + +template<typename T> +class pushable { + friend class boost::contract::access; + + void invariant() const { + BOOST_CONTRACT_ASSERT(capacity() <= max_size()); + } + +public: + virtual void push_back(T const& value, boost::contract::virtual_* v = 0) + = 0; + +protected: + virtual unsigned capacity() const = 0; + virtual unsigned max_size() const = 0; +}; + +template<typename T> +void pushable<T>::push_back(T const& value, boost::contract::virtual_* v) { + boost::contract::old_ptr<unsigned> old_capacity = + BOOST_CONTRACT_OLDOF(v, capacity()); + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(capacity() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + }) + ; + assert(false); +} + +//[access +template<typename T> +class vector + #define BASES public pushable<T> + : BASES +{ // Private section of the class. + friend class boost::contract::access; // Friend `access` class so... + + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // ...private bases. + #undef BASES + + void invariant() const { // ...private invariants. + BOOST_CONTRACT_ASSERT(size() <= capacity()); + } + + BOOST_CONTRACT_OVERRIDE(push_back) // ...private overrides. + +public: // Public section of the class. + void push_back(T const& value, boost::contract::virtual_* v = 0) + /* override */ { + boost::contract::old_ptr<unsigned> old_size = + BOOST_CONTRACT_OLDOF(v, size()); + boost::contract::check c = boost::contract::public_function< + override_push_back>(v, &vector::push_back, this, value) + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + ; + + vect_.push_back(value); + } + + /* ... */ +//] + + unsigned size() const { return vect_.size(); } + unsigned max_size() const { return vect_.max_size(); } + unsigned capacity() const { return vect_.capacity(); } + +private: // Another private section. + std::vector<T> vect_; +}; + +int main() { + vector<int> vect; + vect.push_back(123); + assert(vect.size() == 1); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/assertion_level.cpp b/src/boost/libs/contract/example/features/assertion_level.cpp new file mode 100644 index 00000000..c347b19c --- /dev/null +++ b/src/boost/libs/contract/example/features/assertion_level.cpp @@ -0,0 +1,135 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <algorithm> +#include <iostream> +#include <cassert> + +//[assertion_level_no_impl +// If valid iterator range (cannot implement in C++ but OK to use in AXIOM). +template<typename Iter> +bool valid(Iter first, Iter last); // Only declared, not actually defined. +//] + +//[assertion_level_class_begin +template<typename T> +class vector { +//] + +public: + typedef typename std::vector<T>::iterator iterator; + + // Could program class invariants and contracts for the following. + iterator begin() { return vect_.begin(); } + iterator end() { return vect_.end(); } + unsigned capacity() const { return vect_.capacity(); } + bool operator==(vector const& other) { return vect_ == other.vect_; } + +//[assertion_level_axiom +public: + iterator insert(iterator where, T const& value) { + iterator result; + boost::contract::old_ptr<unsigned> old_capacity = + BOOST_CONTRACT_OLDOF(capacity()); + boost::contract::check c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + if(capacity() > *old_capacity) { + BOOST_CONTRACT_ASSERT_AXIOM(!valid(begin(), end())); + } else { + BOOST_CONTRACT_ASSERT_AXIOM(!valid(where, end())); + } + }) + ; + + return result = vect_.insert(where, value); + } +//] + +//[assertion_level_audit_old +public: + void swap(vector& other) { + boost::contract::old_ptr<vector> old_me, old_other; + #ifdef BOOST_CONTRACT_AUDITS + old_me = BOOST_CONTRACT_OLDOF(*this); + old_other = BOOST_CONTRACT_OLDOF(other); + #endif // Else, skip old value copies... + boost::contract::check c = boost::contract::public_function(this) + .postcondition([&] { + // ...and also skip related assertions. + BOOST_CONTRACT_ASSERT_AUDIT(*this == *old_other); + BOOST_CONTRACT_ASSERT_AUDIT(other == *old_me); + }) + ; + + vect_.swap(other.vect_); + } +//] + +//[assertion_level_class_end + /* ... */ + +private: + std::vector<T> vect_; +}; +//] + +//[assertion_level_audit +template<typename RandomIter, typename T> +RandomIter random_binary_search(RandomIter first, RandomIter last, + T const& value) { + RandomIter result; + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(first <= last); // Default, not expensive. + // Expensive O(n) assertion (use AXIOM if prohibitive instead). + BOOST_CONTRACT_ASSERT_AUDIT(std::is_sorted(first, last)); + }) + .postcondition([&] { + if(result != last) BOOST_CONTRACT_ASSERT(*result == value); + }) + ; + + /* ... */ +//] + + RandomIter begin = first, end = last; + while(begin < end) { + RandomIter middle = begin + ((end - begin) >> 1); + BOOST_CONTRACT_CHECK(*begin <= *middle || value < *middle || + *middle < value); + + if(value < *middle) end = middle; + else if(value > *middle) begin = middle + 1; + else return result = middle; + } + return result = last; +} + +int main() { + vector<char> v; + v.insert(v.begin() + 0, 'a'); + v.insert(v.begin() + 1, 'b'); + v.insert(v.begin() + 2, 'c'); + + vector<char>::iterator i = random_binary_search(v.begin(), v.end(), 'b'); + assert(i != v.end()); + assert(*i == 'b'); + + vector<char> w; + w.insert(w.begin() + 0, 'x'); + w.insert(w.begin() + 1, 'y'); + + w.swap(v); + assert(*(w.begin() + 0) == 'a'); + assert(*(w.begin() + 1) == 'b'); + assert(*(w.begin() + 2) == 'c'); + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/base_types.cpp b/src/boost/libs/contract/example/features/base_types.cpp new file mode 100644 index 00000000..56efcbfe --- /dev/null +++ b/src/boost/libs/contract/example/features/base_types.cpp @@ -0,0 +1,188 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <algorithm> +#include <cassert> + +template<typename T> +class pushable { +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(capacity() <= max_size()); + } + + virtual void push_back(T x, boost::contract::virtual_* v = 0) = 0; + +protected: + virtual unsigned capacity() const = 0; + virtual unsigned max_size() const = 0; +}; + +template<typename T> +void pushable<T>::push_back(T x, boost::contract::virtual_* v) { + boost::contract::old_ptr<unsigned> old_capacity = + BOOST_CONTRACT_OLDOF(v, capacity()); + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(capacity() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + }) + ; + assert(false); // Shall never execute this body. +} + +struct has_size { virtual unsigned size() const = 0; }; +struct has_empty { virtual bool empty() const = 0; }; + +class unique_chars + : private boost::contract::constructor_precondition<unique_chars> +{ +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(size() >= 0); + } + + unique_chars(char from, char to) : + boost::contract::constructor_precondition<unique_chars>([&] { + BOOST_CONTRACT_ASSERT(from <= to); + }) + { + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(int(size()) == (to - from + 1)); + }) + ; + + for(char x = from; x <= to; ++x) vect_.push_back(x); + } + + virtual ~unique_chars() { + boost::contract::check c = boost::contract::destructor(this); + } + + unsigned size() const { + boost::contract::check c = boost::contract::public_function(this); + return vect_.size(); + } + + bool find(char x) const { + bool result; + boost::contract::check c = boost::contract::public_function(this) + .postcondition([&] { + if(size() == 0) BOOST_CONTRACT_ASSERT(!result); + }) + ; + + return result = std::find(vect_.begin(), vect_.end(), x) != vect_.end(); + } + + virtual void push_back(char x, boost::contract::virtual_* v = 0) { + boost::contract::old_ptr<bool> old_find = + BOOST_CONTRACT_OLDOF(v, find(x)); + boost::contract::old_ptr<unsigned> old_size = + BOOST_CONTRACT_OLDOF(v, size()); + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!find(x)); + }) + .postcondition([&] { + if(!*old_find) { + BOOST_CONTRACT_ASSERT(find(x)); + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + } + }) + ; + + vect_.push_back(x); + } + +protected: + unique_chars() {} + + std::vector<char> const& vect() const { return vect_; } + +private: + std::vector<char> vect_; +}; + +//[base_types +class chars + #define BASES /* local macro (for convenience) */ \ + private boost::contract::constructor_precondition<chars>, \ + public unique_chars, \ + public virtual pushable<char>, \ + virtual protected has_size, \ + private has_empty + : BASES // Bases of this class. +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Bases typedef. + #undef BASES // Undefine local macro. + + /* ... */ +//] + + void invariant() const { + BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); + } + + chars(char from, char to) : unique_chars(from, to) { + boost::contract::check c = boost::contract::constructor(this); + } + + chars(char const* const c_str) : + boost::contract::constructor_precondition<chars>([&] { + BOOST_CONTRACT_ASSERT(c_str[0] != '\0'); + }) + { + boost::contract::check c = boost::contract::constructor(this); + + for(unsigned i = 0; c_str[i] != '\0'; ++i) push_back(c_str[i]); + } + + void push_back(char x, boost::contract::virtual_* v = 0) /* override */ { + boost::contract::old_ptr<bool> old_find = + BOOST_CONTRACT_OLDOF(v, find(x)); + boost::contract::old_ptr<unsigned> old_size = + BOOST_CONTRACT_OLDOF(v, size()); + boost::contract::check c = boost::contract::public_function< + override_push_back>(v, &chars::push_back, this, x) + .precondition([&] { + BOOST_CONTRACT_ASSERT(find(x)); + }) + .postcondition([&] { + if(*old_find) BOOST_CONTRACT_ASSERT(size() == *old_size); + }) + ; + + if(!find(x)) unique_chars::push_back(x); + } + BOOST_CONTRACT_OVERRIDE(push_back); + + bool empty() const { + boost::contract::check c = boost::contract::public_function(this); + return size() == 0; + } + + unsigned size() const { return unique_chars::size(); } + +protected: + unsigned max_size() const { return vect().max_size(); } + unsigned capacity() const { return vect().capacity(); } +}; + +int main() { + chars s("abc"); + assert(s.find('a')); + assert(s.find('b')); + assert(!s.find('x')); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/base_types_no_macro.cpp b/src/boost/libs/contract/example/features/base_types_no_macro.cpp new file mode 100644 index 00000000..f9add687 --- /dev/null +++ b/src/boost/libs/contract/example/features/base_types_no_macro.cpp @@ -0,0 +1,188 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <algorithm> +#include <cassert> + +template<typename T> +class pushable { +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(capacity() <= max_size()); + } + + virtual void push_back(T x, boost::contract::virtual_* v = 0) = 0; + +protected: + virtual unsigned capacity() const = 0; + virtual unsigned max_size() const = 0; +}; + +template<typename T> +void pushable<T>::push_back(T x, boost::contract::virtual_* v) { + boost::contract::old_ptr<unsigned> old_capacity = + BOOST_CONTRACT_OLDOF(v, capacity()); + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(capacity() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + }) + ; + assert(false); // Shall never execute this body. +} + +struct has_size { virtual unsigned size() const = 0; }; +struct has_empty { virtual bool empty() const = 0; }; + +class unique_chars + : private boost::contract::constructor_precondition<unique_chars> +{ +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(size() >= 0); + } + + unique_chars(char from, char to) : + boost::contract::constructor_precondition<unique_chars>([&] { + BOOST_CONTRACT_ASSERT(from <= to); + }) + { + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(int(size()) == (to - from + 1)); + }) + ; + + for(char x = from; x <= to; ++x) vect_.push_back(x); + } + + virtual ~unique_chars() { + boost::contract::check c = boost::contract::destructor(this); + } + + unsigned size() const { + boost::contract::check c = boost::contract::public_function(this); + return vect_.size(); + } + + bool find(char x) const { + bool result; + boost::contract::check c = boost::contract::public_function(this) + .postcondition([&] { + if(size() == 0) BOOST_CONTRACT_ASSERT(!result); + }) + ; + + return result = std::find(vect_.begin(), vect_.end(), x) != vect_.end(); + } + + virtual void push_back(char x, boost::contract::virtual_* v = 0) { + boost::contract::old_ptr<bool> old_find = + BOOST_CONTRACT_OLDOF(v, find(x)); + boost::contract::old_ptr<unsigned> old_size = + BOOST_CONTRACT_OLDOF(v, size()); + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!find(x)); + }) + .postcondition([&] { + if(!*old_find) { + BOOST_CONTRACT_ASSERT(find(x)); + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + } + }) + ; + + vect_.push_back(x); + } + +protected: + unique_chars() {} + + std::vector<char> const& vect() const { return vect_; } + +private: + std::vector<char> vect_; +}; + +//[base_types_no_macro +#include <boost/mpl/vector.hpp> + +class chars : + private boost::contract::constructor_precondition<chars>, + public unique_chars, + public virtual pushable<char>, + virtual protected has_size, + private has_empty +{ +public: + // Program `base_types` without macros (list only public bases). + typedef boost::mpl::vector<unique_chars, pushable<char> > base_types; + + /* ... */ +//] + + void invariant() const { + BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); + } + + chars(char from, char to) : unique_chars(from, to) { + boost::contract::check c = boost::contract::constructor(this); + } + + chars(char const* const c_str) : + boost::contract::constructor_precondition<chars>([&] { + BOOST_CONTRACT_ASSERT(c_str[0] != '\0'); + }) + { + boost::contract::check c = boost::contract::constructor(this); + + for(unsigned i = 0; c_str[i] != '\0'; ++i) push_back(c_str[i]); + } + + void push_back(char x, boost::contract::virtual_* v = 0) /* override */ { + boost::contract::old_ptr<bool> old_find = + BOOST_CONTRACT_OLDOF(v, find(x)); + boost::contract::old_ptr<unsigned> old_size = + BOOST_CONTRACT_OLDOF(v, size()); + boost::contract::check c = boost::contract::public_function< + override_push_back>(v, &chars::push_back, this, x) + .precondition([&] { + BOOST_CONTRACT_ASSERT(find(x)); + }) + .postcondition([&] { + if(*old_find) BOOST_CONTRACT_ASSERT(size() == *old_size); + }) + ; + + if(!find(x)) unique_chars::push_back(x); + } + BOOST_CONTRACT_OVERRIDE(push_back); + + bool empty() const { + boost::contract::check c = boost::contract::public_function(this); + return size() == 0; + } + + unsigned size() const { return unique_chars::size(); } + +protected: + unsigned max_size() const { return vect().max_size(); } + unsigned capacity() const { return vect().capacity(); } +}; + +int main() { + chars s("abc"); + assert(s.find('a')); + assert(s.find('b')); + assert(!s.find('x')); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/call_if_cxx14.cpp b/src/boost/libs/contract/example/features/call_if_cxx14.cpp new file mode 100644 index 00000000..bdf4f424 --- /dev/null +++ b/src/boost/libs/contract/example/features/call_if_cxx14.cpp @@ -0,0 +1,92 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract/call_if.hpp> +#include <type_traits> +#include <iterator> +#include <functional> // std::bind for generic lambdas. +#include <vector> +#include <list> +#include <sstream> + +template<typename Iter> +struct is_random_access_iterator : std::is_same< + typename std::iterator_traits<Iter>::iterator_category, + std::random_access_iterator_tag +> {}; + +template<typename Iter> +struct is_bidirectional_iterator : std::is_same< + typename std::iterator_traits<Iter>::iterator_category, + std::bidirectional_iterator_tag +> {}; + +template<typename Iter> +struct is_input_iterator : std::is_same< + typename std::iterator_traits<Iter>::iterator_category, + std::input_iterator_tag +> {}; + +//[call_if_cxx14 +template<typename Iter, typename Dist> +void myadvance(Iter& i, Dist n) { + Iter* p = &i; // So captures change actual pointed iterator value. + boost::contract::call_if<is_random_access_iterator<Iter> >( + std::bind([] (auto p, auto n) { // C++14 generic lambda. + *p += n; + }, p, n) + ).template else_if<is_bidirectional_iterator<Iter> >( + std::bind([] (auto p, auto n) { + if(n >= 0) while(n--) ++*p; + else while(n++) --*p; + }, p, n) + ).template else_if<is_input_iterator<Iter> >( + std::bind([] (auto p, auto n) { + while(n--) ++*p; + }, p, n) + ).else_( + std::bind([] (auto false_) { + static_assert(false_, "requires at least input iterator"); + }, std::false_type()) // Use constexpr value. + ); +} +//] + +struct x {}; // Test not an iterator (static_assert failure in else_ above). + +namespace std { + template<> + struct iterator_traits<x> { + typedef void iterator_category; + }; +} + +int main() { + std::vector<char> v; + v.push_back('a'); + v.push_back('b'); + v.push_back('c'); + v.push_back('d'); + std::vector<char>::iterator r = v.begin(); // Random iterator. + myadvance(r, 1); + assert(*r == 'b'); + + std::list<char> l(v.begin(), v.end()); + std::list<char>::iterator b = l.begin(); // Bidirectional iterator. + myadvance(b, 2); + assert(*b == 'c'); + + std::istringstream s("a b c d"); + std::istream_iterator<char> i(s); + myadvance(i, 3); + assert(*i == 'd'); + + // x j; + // myadvance(j, 0); // Error (correctly because x not even input iter). + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/check.cpp b/src/boost/libs/contract/example/features/check.cpp new file mode 100644 index 00000000..36aa9da3 --- /dev/null +++ b/src/boost/libs/contract/example/features/check.cpp @@ -0,0 +1,41 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> + +int gcd(int const a, int const b) { + int result; + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(a > 0); + BOOST_CONTRACT_ASSERT(b > 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result <= a); + BOOST_CONTRACT_ASSERT(result <= b); + }) + ; + + int x = a, y = b; + while(x != y) { + if(x > y) x = x - y; + else y = y - x; + } + return result = x; +} + +//[check +int main() { + // Implementation checks (via nullary functor). + boost::contract::check c = [] { + BOOST_CONTRACT_ASSERT(gcd(12, 28) == 4); + BOOST_CONTRACT_ASSERT(gcd(4, 14) == 2); + }; + + return 0; +} +//] + diff --git a/src/boost/libs/contract/example/features/check_macro.cpp b/src/boost/libs/contract/example/features/check_macro.cpp new file mode 100644 index 00000000..80d9c66c --- /dev/null +++ b/src/boost/libs/contract/example/features/check_macro.cpp @@ -0,0 +1,39 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> + +int gcd(int const a, int const b) { + int result; + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(a > 0); + BOOST_CONTRACT_ASSERT(b > 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result <= a); + BOOST_CONTRACT_ASSERT(result <= b); + }) + ; + + int x = a, y = b; + while(x != y) { + if(x > y) x = x - y; + else y = y - x; + } + return result = x; +} + +//[check_macro +int main() { + // Implementation checks (via macro, disable run-/compile-time overhead). + BOOST_CONTRACT_CHECK(gcd(12, 28) == 4); + BOOST_CONTRACT_CHECK(gcd(4, 14) == 2); + + return 0; +} +//] + diff --git a/src/boost/libs/contract/example/features/code_block.cpp b/src/boost/libs/contract/example/features/code_block.cpp new file mode 100644 index 00000000..2ec434aa --- /dev/null +++ b/src/boost/libs/contract/example/features/code_block.cpp @@ -0,0 +1,43 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <algorithm> +#include <limits> + +int main() { + std::vector<int> v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + int total = 10; + + //[code_block + /* ... */ + + // Contract for a code block. + { // Code block entry (check preconditions). + boost::contract::old_ptr<int> old_total = BOOST_CONTRACT_OLDOF(total); + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(v.size() == 3); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(total == *old_total + v[0] + v[1] + v[2]); + }) + ; + + total += v[0] + v[1] + v[2]; // Code block body. + } // Code block exit (check postconditions and exceptions guarantees). + + /* ... */ + //] + + assert(total == 16); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/condition_if.cpp b/src/boost/libs/contract/example/features/condition_if.cpp new file mode 100644 index 00000000..c8ecb964 --- /dev/null +++ b/src/boost/libs/contract/example/features/condition_if.cpp @@ -0,0 +1,58 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <boost/type_traits/has_equal_to.hpp> +#include <boost/bind.hpp> +#include <vector> +#include <functional> +#include <cassert> + +//[condition_if +template<typename T> +class vector { +public: + void push_back(T const& value) { + boost::contract::check c = boost::contract::public_function(this) + .postcondition([&] { + // Instead of `ASSERT(back() == value)` for T without `==`. + BOOST_CONTRACT_ASSERT( + boost::contract::condition_if<boost::has_equal_to<T> >( + boost::bind(std::equal_to<T>(), + boost::cref(back()), + boost::cref(value) + ) + ) + ); + }) + ; + + vect_.push_back(value); + } + + /* ... */ +//] + + T const& back() const { return vect_.back(); } + +private: + std::vector<T> vect_; +}; + +int main() { + vector<int> v; + v.push_back(1); // Type `int` has `==` so check postcondition. + assert(v.back() == 1); + + struct i { int value; } j; + j.value = 10; + vector<i> w; + w.push_back(j); // Type `i` has no `==` so skip postcondition. + assert(j.value == 10); + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/friend.cpp b/src/boost/libs/contract/example/features/friend.cpp new file mode 100644 index 00000000..215cfa6d --- /dev/null +++ b/src/boost/libs/contract/example/features/friend.cpp @@ -0,0 +1,69 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <string> +#include <cassert> + +//[friend_byte +class buffer; + +class byte { + friend bool operator==(buffer const& left, byte const& right); + +private: + char value_; + + /* ... */ +//] + +public: + // Could program invariants and contracts for following too. + explicit byte(char value) : value_(value) {} + bool empty() const { return value_ == '\0'; } +}; + +//[friend_buffer +class buffer { + // Friend functions are not member functions... + friend bool operator==(buffer const& left, byte const& right) { + // ...so check contracts via `function` (which won't check invariants). + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(!left.empty()); + BOOST_CONTRACT_ASSERT(!right.empty()); + }) + ; + + for(char const* x = left.values_.c_str(); *x != '\0'; ++x) { + if(*x != right.value_) return false; + } + return true; + } + +private: + std::string values_; + + /* ... */ +//] + +public: + // Could program invariants and contracts for following too. + explicit buffer(std::string const& values) : values_(values) {} + bool empty() const { return values_ == ""; } +}; + +int main() { + buffer p("aaa"); + byte a('a'); + assert(p == a); + + buffer q("aba"); + assert(!(q == a)); // No operator!=. + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/friend_invariant.cpp b/src/boost/libs/contract/example/features/friend_invariant.cpp new file mode 100644 index 00000000..b9f69bbe --- /dev/null +++ b/src/boost/libs/contract/example/features/friend_invariant.cpp @@ -0,0 +1,59 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <cassert> + +//[friend_invariant +template<typename T> +class positive { +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(value() > 0); + } + + // Can be considered an extension of enclosing class' public interface... + friend void swap(positive& object, T& value) { + boost::contract::old_ptr<T> old_object_value = + BOOST_CONTRACT_OLDOF(object.value()); + boost::contract::old_ptr<T> old_value = BOOST_CONTRACT_OLDOF(value); + // ...so it can be made to check invariants via `public_function`. + boost::contract::check c = boost::contract::public_function(&object) + .precondition([&] { + BOOST_CONTRACT_ASSERT(value > 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(object.value() == *old_value); + BOOST_CONTRACT_ASSERT(value == *old_object_value); + }) + ; + + T saved = object.value_; + object.value_ = value; + value = saved; + } + +private: + T value_; + + /* ... */ +//] + +public: + // Could program contracts for following too. + explicit positive(T const& value) : value_(value) {} + T value() const { return value_; } +}; + +int main() { + positive<int> i(123); + int x = 456; + swap(i, x); + assert(i.value() == 456); + assert(x == 123); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/if_constexpr.cpp b/src/boost/libs/contract/example/features/if_constexpr.cpp new file mode 100644 index 00000000..f4561f14 --- /dev/null +++ b/src/boost/libs/contract/example/features/if_constexpr.cpp @@ -0,0 +1,113 @@ + +// Copyright (C) 2008-2019 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <boost/type_traits/has_equal_to.hpp> +#include <utility> +#include <cassert> + +//[if_constexpr +template<typename T> +void swap(T& x, T& y) { + constexpr bool b = boost::contract::is_old_value_copyable<T>::value && + boost::has_equal_to<T>::value; + boost::contract::old_ptr<T> old_x, old_y; + if constexpr(b) { // Contract requires copyable T... + old_x = BOOST_CONTRACT_OLDOF(x); + old_y = BOOST_CONTRACT_OLDOF(y); + } + boost::contract::check c = boost::contract::function() + .postcondition([&] { + if constexpr(b) { // ... and T with `==`... + BOOST_CONTRACT_ASSERT(x == *old_y); + BOOST_CONTRACT_ASSERT(y == *old_x); + } + }) + ; + + T t = std::move(x); // ...but body only requires movable T. + x = std::move(y); + y = std::move(t); +} +//] + +struct i { // Non-copyable but has operator==. + explicit i(int n) : n_(n) {} + + i(i const&) = delete; // Non-copyable. + i& operator=(i const&) = delete; + + i(i const&& o) : n_(o.n_) {} + i& operator=(i const&& o) { n_ = o.n_; return *this; } + + friend bool operator==(i const& l, i const& r) { // Operator==. + return l.n_ == r.n_; + } + +private: + int n_; +}; + +struct j { // Copyable but no operator==. + explicit j(int n) : n_(n) {} + + j(j const& o) : n_(o.n_) {} // Copyable. + j& operator=(j const& o) { n_ = o.n_; return *this; } + + j(j const&& o) : n_(o.n_) {} + j& operator=(j const&& o) { n_ = o.n_; return *this; } + + // No operator==. + +private: + int n_; +}; + +struct k { // Non-copyable and no operator==. + explicit k(int n) : n_(n) {} + + k(k const&) = delete; // Non-copyable. + k& operator=(k const&) = delete; + + k(k const&& o) : n_(o.n_) {} + k& operator=(k const&& o) { n_ = o.n_; return *this; } + + // No operator==. + +private: + int n_; +}; + +int main() { + { // Copyable and operator== (so checks postconditions). + int x = 123, y = 456; + swap(x, y); + assert(x == 456); + assert(y == 123); + } + + { // Non-copyable (so does not check postconditions). + i x{123}, y{456}; + swap(x, y); + assert(x == i{456}); + assert(y == i{123}); + } + + { // No operator== (so does not check postconditions). + j x{123}, y{456}; + swap(x, y); + // Cannot assert x and y because no operator==. + } + + { // Non-copyable and no operator== (so does not check postconditions). + k x{123}, y{456}; + swap(x, y); + // Cannot assert x and y because no operator==. + } + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/ifdef.cpp b/src/boost/libs/contract/example/features/ifdef.cpp new file mode 100644 index 00000000..74e74ee9 --- /dev/null +++ b/src/boost/libs/contract/example/features/ifdef.cpp @@ -0,0 +1,213 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <vector> +#include <limits> +#include <cassert> + +//[ifdef_function +// Use #ifdef to completely disable contract code compilation. +#include <boost/contract/core/config.hpp> +#ifndef BOOST_CONTRACT_NO_ALL + #include <boost/contract.hpp> +#endif + +int inc(int& x) { + int result; + #ifndef BOOST_CONTRACT_NO_OLDS + boost::contract::old_ptr<int> old_x = BOOST_CONTRACT_OLDOF(x); + #endif + #ifndef BOOST_CONTRACT_NO_FUNCTIONS + boost::contract::check c = boost::contract::function() + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + .precondition([&] { + BOOST_CONTRACT_ASSERT(x < std::numeric_limits<int>::max()); + }) + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + .postcondition([&] { + BOOST_CONTRACT_ASSERT(x == *old_x + 1); + BOOST_CONTRACT_ASSERT(result == *old_x); + }) + #endif + ; + #endif + + return result = x++; +} +//] + +template<typename T> +class pushable { + #ifndef BOOST_CONTRACT_NO_ALL + friend class boost::contract::access; + #endif + + #ifndef BOOST_CONTRACT_NO_INVARIANTS + void invariant() const { + BOOST_CONTRACT_ASSERT(capacity() <= max_size()); + } + #endif + +public: + virtual void push_back( + T const& x + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + , boost::contract::virtual_* v = 0 + #endif + ) = 0; + +protected: + virtual unsigned capacity() const = 0; + virtual unsigned max_size() const = 0; +}; + +template<typename T> +void pushable<T>::push_back( + T const& x + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + , boost::contract::virtual_* v + #endif +) { + #ifndef BOOST_CONTRACT_NO_OLDS + boost::contract::old_ptr<unsigned> old_capacity = + BOOST_CONTRACT_OLDOF(v, capacity()); + #endif + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + boost::contract::check c = boost::contract::public_function(v, this) + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + .precondition([&] { + BOOST_CONTRACT_ASSERT(capacity() < max_size()); + }) + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + }) + #endif + ; + #endif + assert(false); // Shall never execute this body. +} + +//[ifdef_class +class integers + #define BASES public pushable<int> + : + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + private boost::contract::constructor_precondition<integers>, BASES + #else + BASES + #endif +{ + #ifndef BOOST_CONTRACT_NO_ALL + friend class boost::contract::access; + #endif + + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #endif + #undef BASES + + #ifndef BOOST_CONTRACT_NO_INVARIANTS + void invariant() const { + BOOST_CONTRACT_ASSERT(size() <= capacity()); + } + #endif + +public: + integers(int from, int to) : + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + boost::contract::constructor_precondition<integers>([&] { + BOOST_CONTRACT_ASSERT(from <= to); + }), + #endif + vect_(to - from + 1) + { + #ifndef BOOST_CONTRACT_NO_CONSTRUCTORS + boost::contract::check c = boost::contract::constructor(this) + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + .postcondition([&] { + BOOST_CONTRACT_ASSERT(int(size()) == (to - from + 1)); + }) + #endif + ; + #endif + + for(int x = from; x <= to; ++x) vect_.at(x - from) = x; + } + + virtual ~integers() { + #ifndef BOOST_CONTRACT_NO_DESTRUCTORS + // Check invariants. + boost::contract::check c = boost::contract::destructor(this); + #endif + } + + virtual void push_back( + int const& x + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + , boost::contract::virtual_* v = 0 + #endif + ) /* override */ { + #ifndef BOOST_CONTRACT_NO_OLDS + boost::contract::old_ptr<unsigned> old_size; + #endif + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + boost::contract::check c = boost::contract::public_function< + override_push_back>(v, &integers::push_back, this, x) + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() < max_size()); + }) + #endif + #ifndef BOOST_CONTRACT_NO_OLDS + .old([&] { + old_size = BOOST_CONTRACT_OLDOF(v, size()); + }) + #endif + #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + #endif + #ifndef BOOST_CONTRACT_NO_EXCEPTS + .except([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size); + }) + #endif + ; + #endif + + vect_.push_back(x); + } + +private: + #ifndef BOOST_CONTRACT_NO_PUBLIC_FUNCTIONS + BOOST_CONTRACT_OVERRIDE(push_back) + #endif + + /* ... */ +//] + +public: // Could program contracts for these too... + unsigned size() const { return vect_.size(); } + unsigned max_size() const { return vect_.max_size(); } + unsigned capacity() const { return vect_.capacity(); } + +private: + std::vector<int> vect_; +}; + +int main() { + integers i(1, 10); + int x = 123; + i.push_back(inc(x)); + assert(x == 124); + assert(i.size() == 11); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/ifdef_macro.cpp b/src/boost/libs/contract/example/features/ifdef_macro.cpp new file mode 100644 index 00000000..cc979bfd --- /dev/null +++ b/src/boost/libs/contract/example/features/ifdef_macro.cpp @@ -0,0 +1,150 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <vector> +#include <limits> +#include <cassert> + +//[ifdef_macro_function +// Use macro interface to completely disable contract code compilation. +#include <boost/contract_macro.hpp> + +int inc(int& x) { + int result; + BOOST_CONTRACT_OLD_PTR(int)(old_x, x); + BOOST_CONTRACT_FUNCTION() + BOOST_CONTRACT_PRECONDITION([&] { + BOOST_CONTRACT_ASSERT(x < std::numeric_limits<int>::max()); + }) + BOOST_CONTRACT_POSTCONDITION([&] { + BOOST_CONTRACT_ASSERT(x == *old_x + 1); + BOOST_CONTRACT_ASSERT(result == *old_x); + }) + ; + + return result = x++; +} +//] + +template<typename T> +class pushable { + friend class boost::contract::access; // Left in code (almost no overhead). + + BOOST_CONTRACT_INVARIANT({ + BOOST_CONTRACT_ASSERT(capacity() <= max_size()); + }) + +public: + virtual void push_back( + T const& x, + boost::contract::virtual_* v = 0 // Left in code (almost no overhead). + ) = 0; + +protected: + virtual unsigned capacity() const = 0; + virtual unsigned max_size() const = 0; +}; + +template<typename T> +void pushable<T>::push_back(T const& x, boost::contract::virtual_* v) { + BOOST_CONTRACT_OLD_PTR(unsigned)(v, old_capacity, capacity()); + BOOST_CONTRACT_PUBLIC_FUNCTION(v, this) + BOOST_CONTRACT_PRECONDITION([&] { + BOOST_CONTRACT_ASSERT(capacity() < max_size()); + }) + BOOST_CONTRACT_POSTCONDITION([&] { + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + }) + ; + assert(false); // Shall never execute this body. +} + +//[ifdef_macro_class +class integers + #define BASES public pushable<int> + : + // Left in code (almost no overhead). + private boost::contract::constructor_precondition<integers>, + BASES +{ + // Followings left in code (almost no overhead). + friend class boost::contract::access; + + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + BOOST_CONTRACT_INVARIANT({ + BOOST_CONTRACT_ASSERT(size() <= capacity()); + }) + +public: + integers(int from, int to) : + BOOST_CONTRACT_CONSTRUCTOR_PRECONDITION(integers)([&] { + BOOST_CONTRACT_ASSERT(from <= to); + }), + vect_(to - from + 1) + { + BOOST_CONTRACT_CONSTRUCTOR(this) + BOOST_CONTRACT_POSTCONDITION([&] { + BOOST_CONTRACT_ASSERT(int(size()) == (to - from + 1)); + }) + ; + + for(int x = from; x <= to; ++x) vect_.at(x - from) = x; + } + + virtual ~integers() { + BOOST_CONTRACT_DESTRUCTOR(this); // Check invariants. + } + + virtual void push_back( + int const& x, + boost::contract::virtual_* v = 0 // Left in code (almost no overhead). + ) /* override */ { + BOOST_CONTRACT_OLD_PTR(unsigned)(old_size); + BOOST_CONTRACT_PUBLIC_FUNCTION_OVERRIDE(override_push_back)( + v, &integers::push_back, this, x) + BOOST_CONTRACT_PRECONDITION([&] { + BOOST_CONTRACT_ASSERT(size() < max_size()); + }) + BOOST_CONTRACT_OLD([&] { + old_size = BOOST_CONTRACT_OLDOF(v, size()); + }) + BOOST_CONTRACT_POSTCONDITION([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + BOOST_CONTRACT_EXCEPT([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size); + }) + ; + + vect_.push_back(x); + } + +private: + BOOST_CONTRACT_OVERRIDE(push_back) // Left in code (almost no overhead). + + /* ... */ +//] + +public: // Could program contracts for these too... + unsigned size() const { return vect_.size(); } + unsigned max_size() const { return vect_.max_size(); } + unsigned capacity() const { return vect_.capacity(); } + +private: + std::vector<int> vect_; +}; + +int main() { + integers i(1, 10); + int x = 123; + i.push_back(inc(x)); + assert(x == 124); + assert(i.size() == 11); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/introduction.cpp b/src/boost/libs/contract/example/features/introduction.cpp new file mode 100644 index 00000000..25baf10f --- /dev/null +++ b/src/boost/libs/contract/example/features/introduction.cpp @@ -0,0 +1,34 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <limits> +#include <cassert> + +//[introduction +#include <boost/contract.hpp> + +void inc(int& x) { + boost::contract::old_ptr<int> old_x = BOOST_CONTRACT_OLDOF(x); // Old value. + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(x < std::numeric_limits<int>::max()); // Line 17. + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(x == *old_x + 1); // Line 20. + }) + ; + + ++x; // Function body. +} +//] + +int main() { + int x = 10; + inc(x); + assert(x == 11); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/introduction_comments.cpp b/src/boost/libs/contract/example/features/introduction_comments.cpp new file mode 100644 index 00000000..3eba12f8 --- /dev/null +++ b/src/boost/libs/contract/example/features/introduction_comments.cpp @@ -0,0 +1,24 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <cassert> + +//[introduction_comments +void inc(int& x) + // Precondition: x < std::numeric_limit<int>::max() + // Postcondition: x == oldof(x) + 1 +{ + ++x; // Function body. +} +//] + +int main() { + int x = 10; + inc(x); + assert(x == 11); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/introduction_public.cpp b/src/boost/libs/contract/example/features/introduction_public.cpp new file mode 100644 index 00000000..2206bcab --- /dev/null +++ b/src/boost/libs/contract/example/features/introduction_public.cpp @@ -0,0 +1,89 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <cassert> + +template<typename T> +class pushable { // Somewhat arbitrary base (used just to show subcontracting). +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(capacity() <= max_size()); + } + + virtual void push_back(T const& value, + boost::contract::virtual_* v = 0) = 0; // Pure virtual function. + +protected: + virtual unsigned capacity() const = 0; + virtual unsigned max_size() const = 0; +}; + +template<typename T> // Contract for pure virtual function. +void pushable<T>::push_back(T const& value, boost::contract::virtual_* v) { + boost::contract::old_ptr<unsigned> old_capacity = + BOOST_CONTRACT_OLDOF(v, capacity()); + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(capacity() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + }) + ; + assert(false); // Shall never execute this body. +} + +//[introduction_public +template<typename T> +class vector + #define BASES public pushable<T> + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // For subcontracting. + #undef BASES + + void invariant() const { // Checked in AND with base class invariants. + BOOST_CONTRACT_ASSERT(size() <= capacity()); + } + + virtual void push_back(T const& value, + boost::contract::virtual_* v = 0) /* override */ { // For virtuals. + boost::contract::old_ptr<unsigned> old_size = + BOOST_CONTRACT_OLDOF(v, size()); // Old values for virtuals. + boost::contract::check c = boost::contract::public_function< // For overrides. + override_push_back>(v, &vector::push_back, this, value) + .precondition([&] { // Checked in OR with base preconditions. + BOOST_CONTRACT_ASSERT(size() < max_size()); + }) + .postcondition([&] { // Checked in AND with base postconditions. + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + ; + + vect_.push_back(value); + } + BOOST_CONTRACT_OVERRIDE(push_back) // Define `override_push_back` above. + + // Could program contracts for those as well. + unsigned size() const { return vect_.size(); } + unsigned max_size() const { return vect_.max_size(); } + unsigned capacity() const { return vect_.capacity(); } + +private: + std::vector<T> vect_; +}; +//] + +int main() { + vector<int> vect; + vect.push_back(123); + assert(vect.size() == 1); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/lambda.cpp b/src/boost/libs/contract/example/features/lambda.cpp new file mode 100644 index 00000000..6eb99980 --- /dev/null +++ b/src/boost/libs/contract/example/features/lambda.cpp @@ -0,0 +1,43 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <algorithm> +#include <limits> + +int main() { + std::vector<int> v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + + //[lambda + int total = 0; + std::for_each(v.cbegin(), v.cend(), + // Contract for a lambda function. + [&total] (int const x) { + boost::contract::old_ptr<int> old_total = + BOOST_CONTRACT_OLDOF(total); + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT( + total < std::numeric_limits<int>::max() - x); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(total == *old_total + x); + }) + ; + + total += x; // Lambda function body. + } + ); + //] + + assert(total == 6); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/loop.cpp b/src/boost/libs/contract/example/features/loop.cpp new file mode 100644 index 00000000..1d8acdd7 --- /dev/null +++ b/src/boost/libs/contract/example/features/loop.cpp @@ -0,0 +1,40 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <algorithm> +#include <limits> + +int main() { + std::vector<int> v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + + //[loop + int total = 0; + // Contract for a for-loop (same for while- and all other loops). + for(std::vector<int>::const_iterator i = v.begin(); i != v.end(); ++i) { + boost::contract::old_ptr<int> old_total = BOOST_CONTRACT_OLDOF(total); + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT( + total < std::numeric_limits<int>::max() - *i); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(total == *old_total + *i); + }) + ; + + total += *i; // For-loop body. + } + //] + + assert(total == 6); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/move.cpp b/src/boost/libs/contract/example/features/move.cpp new file mode 100644 index 00000000..de54d16a --- /dev/null +++ b/src/boost/libs/contract/example/features/move.cpp @@ -0,0 +1,201 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <utility> +#include <cassert> + +//[move +class circular_buffer : + private boost::contract::constructor_precondition<circular_buffer> { +public: + void invariant() const { + if(!moved()) { // Do not check (some) invariants for moved-from objects. + BOOST_CONTRACT_ASSERT(index() < size()); + } + // More invariants here that hold also for moved-from objects (e.g., + // all assertions necessary to successfully destroy moved-from objects). + } + + // Move constructor. + circular_buffer(circular_buffer&& other) : + boost::contract::constructor_precondition<circular_buffer>([&] { + BOOST_CONTRACT_ASSERT(!other.moved()); + }) + { + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!moved()); + BOOST_CONTRACT_ASSERT(other.moved()); + }) + ; + + move(std::forward<circular_buffer>(other)); + } + + // Move assignment. + circular_buffer& operator=(circular_buffer&& other) { + // Moved-from can be (move) assigned (so no pre `!moved()` here). + boost::contract::check c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!other.moved()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!moved()); + BOOST_CONTRACT_ASSERT(other.moved()); + }) + ; + + return move(std::forward<circular_buffer>(other)); + } + + ~circular_buffer() { + // Moved-from can always be destroyed (in fact no preconditions). + boost::contract::check c = boost::contract::destructor(this); + } + + bool moved() const { + boost::contract::check c = boost::contract::public_function(this); + return moved_; + } + +private: + bool moved_; + + /* ... */ +//] + +public: + explicit circular_buffer(std::vector<char> const& data, + unsigned start = 0) : + boost::contract::constructor_precondition<circular_buffer>([&] { + BOOST_CONTRACT_ASSERT(start < data.size()); + }), + moved_(false), + data_(data), + index_(start) + { + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!moved()); + }) + ; + } + + // Copy constructor. + circular_buffer(circular_buffer const& other) : + boost::contract::constructor_precondition<circular_buffer>([&] { + BOOST_CONTRACT_ASSERT(!other.moved()); + }) + { + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!moved()); + }) + ; + + copy(other); + } + + // Copy assignment. + circular_buffer& operator=(circular_buffer const& other) { + // Moved-from can be (copy) assigned (so no pre `!moved()` here). + boost::contract::check c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!other.moved()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!moved()); + }) + ; + + return copy(other); + } + + char read() { + boost::contract::check c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!moved()); + }) + ; + + unsigned i = index_++; + if(index_ == data_.size()) index_ = 0; // Circular. + return data_.at(i); + } + +private: + circular_buffer& copy(circular_buffer const& other) { + data_ = other.data_; + index_ = other.index_; + moved_ = false; + return *this; + } + + circular_buffer& move(circular_buffer&& other) { + data_ = std::move(other.data_); + index_ = std::move(other.index_); + moved_ = false; + other.moved_ = true; // Mark moved-from object. + return *this; + } + + std::vector<char> data_; + unsigned index_; + +public: + unsigned index() const { + boost::contract::check c = boost::contract::public_function(this); + return index_; + } + + unsigned size() const { + boost::contract::check c = boost::contract::public_function(this); + return data_.size(); + } +}; + +int main() { + struct err {}; + boost::contract::set_precondition_failure( + [] (boost::contract::from) { throw err(); }); + + { + circular_buffer x({'a', 'b', 'c', 'd'}, 2); + assert(x.read() == 'c'); + + circular_buffer y1 = x; // Copy constructor. + assert(y1.read() == 'd'); + assert(x.read() == 'd'); + + circular_buffer y2({'h'}); + y2 = x; // Copy assignment. + assert(y2.read() == 'a'); + assert(x.read() == 'a'); + + circular_buffer z1 = std::move(x); // Move constructor. + assert(z1.read() == 'b'); + // Calling `x.read()` would fail `!moved()` precondition. + + x = y1; // Moved-from `x` can be copy assigned. + assert(x.read() == 'a'); + assert(y1.read() == 'a'); + + circular_buffer z2({'k'}); + z2 = std::move(x); // Move assignment. + assert(z2.read() == 'b'); + // Calling `x.read()` would fail `!moved()` precondition. + + x = std::move(y2); // Moved-from `x` can be move assigned. + assert(x.read() == 'b'); + // Calling `y2.read()` would fail `!moved()` precondition. + + } // Moved-from `y2` can be destroyed. + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/named_override.cpp b/src/boost/libs/contract/example/features/named_override.cpp new file mode 100644 index 00000000..9afc5f60 --- /dev/null +++ b/src/boost/libs/contract/example/features/named_override.cpp @@ -0,0 +1,104 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <boost/optional.hpp> +#include <cassert> + +//[named_override_pure_virtual_assert_false +template<typename T> +class generic_unary_pack { +public: + virtual void _1(T const& value, boost::contract::virtual_* v = 0) = 0; + virtual T _1(boost::contract::virtual_* v = 0) const = 0; +}; + +template<typename T> +void generic_unary_pack<T>::_1(T const& value, boost::contract::virtual_* v) { + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(false); // Defer preconditions to overrides. + }) + ; + assert(false); +} + +/* ... */ +//] + +template<typename T> +T generic_unary_pack<T>::_1(boost::contract::virtual_* v) const { + boost::optional<T> result; // Do not assume T has default constructor. + boost::contract::check c = boost::contract::public_function(v, result, this) + .postcondition([&] (boost::optional<T const&> const& result) { + BOOST_CONTRACT_ASSERT(*result == _1()); + }) + ; + + assert(false); + return *result; +} + +//[named_override +template<typename T> +class positive_unary_pack + #define BASES public generic_unary_pack<T> + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + // BOOST_CONTRACT_OVERRIDE(_1) would generate reserved name `override__1`. + BOOST_CONTRACT_NAMED_OVERRIDE(override1, _1) // Generate `override1`. + + virtual void _1(T const& value, boost::contract::virtual_* v = 0) + /* override */ { + // Use `override1` generated by BOOST_CONTRACT_NAMED_OVERRIDE above. + boost::contract::check c = boost::contract::public_function<override1>( + v, + static_cast<void (positive_unary_pack::*)(T const&, + boost::contract::virtual_*)>(&positive_unary_pack::_1), + this, + value + ) + .precondition([&] { + BOOST_CONTRACT_ASSERT(value > 0); + }) + ; + value1_ = value; + } + + /* ... */ +//] + + virtual T _1(boost::contract::virtual_* v = 0) const /* override */ { + T result; // Class default constructor already used T's default ctor. + boost::contract::check c = boost::contract::public_function<override1>( + v, + result, + static_cast<T (positive_unary_pack::*)(boost::contract::virtual_*) + const>(&positive_unary_pack::_1), + this + ) + .postcondition([&] (T const& result) { + BOOST_CONTRACT_ASSERT(result > 0); + }) + ; + return result = value1_; + } + +private: + T value1_; +}; + +int main() { + positive_unary_pack<int> u; + u._1(123); + assert(u._1() == 123); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/no_lambdas.cpp b/src/boost/libs/contract/example/features/no_lambdas.cpp new file mode 100644 index 00000000..783adce5 --- /dev/null +++ b/src/boost/libs/contract/example/features/no_lambdas.cpp @@ -0,0 +1,92 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include "no_lambdas.hpp" +#include <boost/bind.hpp> +#include <cassert> + +//[no_lambdas_cpp +iarray::iarray(unsigned max, unsigned count) : + boost::contract::constructor_precondition<iarray>(boost::bind( + &iarray::constructor_precondition, max, count)), + values_(new int[max]), // Member initializations can be here. + capacity_(max) +{ + boost::contract::old_ptr<int> old_instances; + boost::contract::check c = boost::contract::constructor(this) + .old(boost::bind(&iarray::constructor_old, boost::ref(old_instances))) + .postcondition(boost::bind( + &iarray::constructor_postcondition, + this, + boost::cref(max), + boost::cref(count), + boost::cref(old_instances) + )) + ; + + for(unsigned i = 0; i < count; ++i) values_[i] = int(); + size_ = count; + ++instances_; +} + +iarray::~iarray() { + boost::contract::old_ptr<int> old_instances; + boost::contract::check c = boost::contract::destructor(this) + .old(boost::bind(&iarray::destructor_old, this, + boost::ref(old_instances))) + .postcondition(boost::bind(&iarray::destructor_postcondition, + boost::cref(old_instances))) + ; + + delete[] values_; + --instances_; +} + +void iarray::push_back(int value, boost::contract::virtual_* v) { + boost::contract::old_ptr<unsigned> old_size; + boost::contract::check c = boost::contract::public_function(v, this) + .precondition(boost::bind(&iarray::push_back_precondition, this)) + .old(boost::bind(&iarray::push_back_old, this, boost::cref(v), + boost::ref(old_size))) + .postcondition(boost::bind(&iarray::push_back_postcondition, this, + boost::cref(old_size))) + ; + + values_[size_++] = value; +} + +unsigned iarray::capacity() const { + // Check invariants. + boost::contract::check c = boost::contract::public_function(this); + return capacity_; +} + +unsigned iarray::size() const { + // Check invariants. + boost::contract::check c = boost::contract::public_function(this); + return size_; +} + +int iarray::instances() { + // Check static invariants. + boost::contract::check c = boost::contract::public_function<iarray>(); + return instances_; +} + +int iarray::instances_ = 0; +//] + +int main() { + iarray a(3, 2); + assert(a.capacity() == 3); + assert(a.size() == 2); + + a.push_back(-123); + assert(a.size() == 3); + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/no_lambdas.hpp b/src/boost/libs/contract/example/features/no_lambdas.hpp new file mode 100644 index 00000000..5f0dbe72 --- /dev/null +++ b/src/boost/libs/contract/example/features/no_lambdas.hpp @@ -0,0 +1,77 @@ + +#ifndef NO_LAMBDAS_HPP_ +#define NO_LAMBDAS_HPP_ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> + +//[no_lambdas_hpp +class iarray : + private boost::contract::constructor_precondition<iarray> { +public: + static void static_invariant() { + BOOST_CONTRACT_ASSERT(instances() >= 0); + } + + void invariant() const { + BOOST_CONTRACT_ASSERT(size() <= capacity()); + } + + explicit iarray(unsigned max, unsigned count = 0); + static void constructor_precondition(unsigned const max, + unsigned const count) { + BOOST_CONTRACT_ASSERT(count <= max); + } + static void constructor_old(boost::contract::old_ptr<int>& + old_instances) { + old_instances = BOOST_CONTRACT_OLDOF(instances()); + } + void constructor_postcondition(unsigned const max, unsigned const count, + boost::contract::old_ptr<int> const old_instances) const { + BOOST_CONTRACT_ASSERT(capacity() == max); + BOOST_CONTRACT_ASSERT(size() == count); + BOOST_CONTRACT_ASSERT(instances() == *old_instances + 1); + } + + virtual ~iarray(); + void destructor_old(boost::contract::old_ptr<int>& old_instances) + const { + old_instances = BOOST_CONTRACT_OLDOF(instances()); + } + static void destructor_postcondition(boost::contract::old_ptr<int> const + old_instances) { + BOOST_CONTRACT_ASSERT(instances() == *old_instances - 1); + } + + virtual void push_back(int value, boost::contract::virtual_* v = 0); + void push_back_precondition() const { + BOOST_CONTRACT_ASSERT(size() < capacity()); + } + void push_back_old(boost::contract::virtual_* v, + boost::contract::old_ptr<unsigned>& old_size) const { + old_size = BOOST_CONTRACT_OLDOF(v, size()); + } + void push_back_postcondition( + boost::contract::old_ptr<unsigned> const old_size) const { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + } + + unsigned capacity() const; + unsigned size() const; + + static int instances(); + +private: + int* values_; + unsigned capacity_; + unsigned size_; + static int instances_; +}; +//] + +#endif // #include guard + diff --git a/src/boost/libs/contract/example/features/no_lambdas_local_func.cpp b/src/boost/libs/contract/example/features/no_lambdas_local_func.cpp new file mode 100644 index 00000000..801e1639 --- /dev/null +++ b/src/boost/libs/contract/example/features/no_lambdas_local_func.cpp @@ -0,0 +1,119 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <boost/local_function.hpp> +#include <boost/bind.hpp> +#include <cassert> + +class iarray : + private boost::contract::constructor_precondition<iarray> { +public: + static void static_invariant() { + BOOST_CONTRACT_ASSERT(instances() >= 0); + } + + void invariant() const { + BOOST_CONTRACT_ASSERT(size() <= capacity()); + } + + static void constructor_pre(unsigned const max, unsigned const count) { + BOOST_CONTRACT_ASSERT(count <= max); + } + explicit iarray(unsigned max, unsigned count = 0) : + boost::contract::constructor_precondition<iarray>(boost::bind( + &iarray::constructor_pre, max, count)), + values_(new int[max]), + capacity_(max) + { + boost::contract::old_ptr<int> old_instances; + void BOOST_LOCAL_FUNCTION(bind& old_instances) { + old_instances = BOOST_CONTRACT_OLDOF(iarray::instances()); + } BOOST_LOCAL_FUNCTION_NAME(old) + void BOOST_LOCAL_FUNCTION(const bind this_, const bind& count, + const bind& old_instances) { + BOOST_CONTRACT_ASSERT(this_->size() == count); + BOOST_CONTRACT_ASSERT(this_->instances() == *old_instances + 1); + } BOOST_LOCAL_FUNCTION_NAME(post) + boost::contract::check c = boost::contract::constructor(this) + .old(old).postcondition(post); + + for(unsigned i = 0; i < count; ++i) values_[i] = int(); + size_ = count; + ++instances_; + } + + virtual ~iarray() { + boost::contract::old_ptr<int> old_instances; + void BOOST_LOCAL_FUNCTION(const bind this_, bind& old_instances) { + old_instances = BOOST_CONTRACT_OLDOF(this_->instances()); + } BOOST_LOCAL_FUNCTION_NAME(old) + void BOOST_LOCAL_FUNCTION(const bind& old_instances) { + BOOST_CONTRACT_ASSERT(iarray::instances() == *old_instances - 1); + } BOOST_LOCAL_FUNCTION_NAME(post) + boost::contract::check c = boost::contract::destructor(this) + .old(old).postcondition(post); + + delete[] values_; + --instances_; + } + + virtual void push_back(int value, boost::contract::virtual_* v = 0) { + boost::contract::old_ptr<unsigned> old_size; + void BOOST_LOCAL_FUNCTION(const bind this_) { + BOOST_CONTRACT_ASSERT(this_->size() < this_->capacity()); + } BOOST_LOCAL_FUNCTION_NAME(pre) + void BOOST_LOCAL_FUNCTION(const bind v, const bind this_, + bind& old_size) { + old_size = BOOST_CONTRACT_OLDOF(v, this_->size()); + } BOOST_LOCAL_FUNCTION_NAME(old) + void BOOST_LOCAL_FUNCTION(const bind this_, const bind& old_size) { + BOOST_CONTRACT_ASSERT(this_->size() == *old_size + 1); + } BOOST_LOCAL_FUNCTION_NAME(post) + boost::contract::check c = boost::contract::public_function(v, this) + .precondition(pre).old(old).postcondition(post); + + values_[size_++] = value; + } + + unsigned capacity() const { + // Check invariants. + boost::contract::check c = boost::contract::public_function(this); + return capacity_; + } + + unsigned size() const { + // Check invariants. + boost::contract::check c = boost::contract::public_function(this); + return size_; + } + + static int instances() { + // Check static invariants. + boost::contract::check c = boost::contract::public_function<iarray>(); + return instances_; + } + +private: + int* values_; + unsigned capacity_; + unsigned size_; + static int instances_; +}; + +int iarray::instances_ = 0; + +int main() { + iarray a(3, 2); + assert(a.capacity() == 3); + assert(a.size() == 2); + + a.push_back('x'); + assert(a.size() == 3); + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/non_member.cpp b/src/boost/libs/contract/example/features/non_member.cpp new file mode 100644 index 00000000..12224154 --- /dev/null +++ b/src/boost/libs/contract/example/features/non_member.cpp @@ -0,0 +1,40 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <limits> +#include <cassert> + +//[non_member +#include <boost/contract.hpp> + +// Contract for a non-member function. +int inc(int& x) { + int result; + boost::contract::old_ptr<int> old_x = BOOST_CONTRACT_OLDOF(x); + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(x < std::numeric_limits<int>::max()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(x == *old_x + 1); + BOOST_CONTRACT_ASSERT(result == *old_x); + }) + .except([&] { + BOOST_CONTRACT_ASSERT(x == *old_x); + }) + ; + + return result = x++; // Function body. +} +//] + +int main() { + int x = std::numeric_limits<int>::max() - 1; + assert(inc(x) == std::numeric_limits<int>::max() - 1); + assert(x == std::numeric_limits<int>::max()); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/old.cpp b/src/boost/libs/contract/example/features/old.cpp new file mode 100644 index 00000000..bdf8b8c6 --- /dev/null +++ b/src/boost/libs/contract/example/features/old.cpp @@ -0,0 +1,41 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <string> +#include <cassert> + +//[old +char replace(std::string& s, unsigned index, char x) { + char result; + boost::contract::old_ptr<char> old_char; // Null, old value copied later... + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(index < s.size()); + }) + .old([&] { // ...after preconditions (and invariants) checked. + old_char = BOOST_CONTRACT_OLDOF(s[index]); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(s[index] == x); + BOOST_CONTRACT_ASSERT(result == *old_char); + }) + ; + + result = s[index]; + s[index] = x; + return result; +} +//] + +int main() { + std::string s = "abc"; + char r = replace(s, 1, '_'); + assert(s == "a_c"); + assert(r == 'b'); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/old_if_copyable.cpp b/src/boost/libs/contract/example/features/old_if_copyable.cpp new file mode 100644 index 00000000..8cf1acc7 --- /dev/null +++ b/src/boost/libs/contract/example/features/old_if_copyable.cpp @@ -0,0 +1,133 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <boost/type_traits.hpp> +#include <boost/noncopyable.hpp> +#include <cassert> + +//[old_if_copyable_offset +template<typename T> // T might or might not be copyable. +void offset(T& x, int count) { + // No compiler error if T has no copy constructor... + boost::contract::old_ptr_if_copyable<T> old_x = BOOST_CONTRACT_OLDOF(x); + boost::contract::check c = boost::contract::function() + .postcondition([&] { + // ...but old value null if T has no copy constructor. + if(old_x) BOOST_CONTRACT_ASSERT(x == *old_x + count); + }) + ; + + x += count; +} +//] + +//[old_if_copyable_w_decl +// Copyable type but... +class w { +public: + w(w const&) { /* Some very expensive copy operation here... */ } + + /* ... */ +//] + w() : num_(0) {} + int operator+(int i) const { return num_ + i; } + w& operator+=(int i) { num_ += i; return *this; } + bool operator==(int i) const { return long(num_) == i; } +private: + unsigned long num_; +}; + +//[old_if_copyable_w_spec +// ...never copy old values for type `w` (because its copy is too expensive). +namespace boost { namespace contract { + template<> + struct is_old_value_copyable<w> : boost::false_type {}; +} } +//] + +//[old_if_copyable_p_decl +// Non-copyable type but... +class p : private boost::noncopyable { + int* num_; + + friend struct boost::contract::old_value_copy<p>; + + /* ... */ +//] +public: + p() : num_(new int(0)) {} + ~p() { delete num_; } + int operator+(int i) const { return *num_ + i; } + p& operator+=(int i) { *num_ += i; return *this; } + bool operator==(int i) const { return *num_ == i; } +}; + +//[old_if_copyable_p_spec +// ...still copy old values for type `p` (using a deep copy). +namespace boost { namespace contract { + template<> + struct old_value_copy<p> { + explicit old_value_copy(p const& old) { + *old_.num_ = *old.num_; // Deep copy pointed value. + } + + p const& old() const { return old_; } + + private: + p old_; + }; + + template<> + struct is_old_value_copyable<p> : boost::true_type {}; +} } +//] + +//[old_if_copyable_n_decl +class n { // Do not want to use boost::noncopyable but... + int num_; + +private: + n(n const&); // ...unimplemented private copy constructor (so non-copyable). + + /* ... */ +//] + +public: + n() : num_(0) {} + int operator+(int i) const { return num_ + i; } + n& operator+=(int i) { num_ += i; return *this; } + bool operator==(int i) const { return num_ == i; } +}; + +//[old_if_copyable_n_spec +// Specialize `boost::is_copy_constructible` (no need for this on C++11). +namespace boost { namespace contract { + template<> + struct is_old_value_copyable<n> : boost::false_type {}; +} } +//] + +int main() { + int i = 0; // Copy constructor, copy and check old values. + offset(i, 3); + assert(i == 3); + + w j; // Expensive copy constructor, so never copy or check old values. + offset(j, 3); + assert(j == 3); + + p k; // No copy constructor, but still copy and check old values. + offset(k, 3); + assert(k == 3); + + n h; // No copy constructor, no compiler error but no old value checks. + offset(h, 3); + assert(h == 3); + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/old_no_macro.cpp b/src/boost/libs/contract/example/features/old_no_macro.cpp new file mode 100644 index 00000000..29c06a68 --- /dev/null +++ b/src/boost/libs/contract/example/features/old_no_macro.cpp @@ -0,0 +1,46 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <cassert> +#include <vector> + +//[old_no_macro +template<typename T> +class vector { +public: + virtual void push_back(T const& value, boost::contract::virtual_* v = 0) { + // Program old value instead of using `OLD(size())` macro. + boost::contract::old_ptr<unsigned> old_size = + boost::contract::make_old(v, boost::contract::copy_old(v) ? + size() : boost::contract::null_old()) + ; + + boost::contract::check c = boost::contract::public_function(v, this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + ; + + vect_.push_back(value); + } + + /* ... */ +//] + + unsigned size() const { return vect_.size(); } + +private: + std::vector<T> vect_; +}; + +int main() { + vector<int> vect; + vect.push_back(123); + assert(vect.size() == 1); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/optional_result.cpp b/src/boost/libs/contract/example/features/optional_result.cpp new file mode 100644 index 00000000..330c780d --- /dev/null +++ b/src/boost/libs/contract/example/features/optional_result.cpp @@ -0,0 +1,41 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <boost/optional.hpp> +#include <vector> +#include <cassert> + +//[optional_result +template<unsigned Index, typename T> +T& get(std::vector<T>& vect) { + boost::optional<T&> result; // Result not initialized here... + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(Index < vect.size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(*result == vect[Index]); + }) + ; + + // Function body (executed after preconditions checked). + return *(result = vect[Index]); // ...result initialized here instead. +} +//] + +int main() { + std::vector<int> v; + v.push_back(123); + v.push_back(456); + v.push_back(789); + int& x = get<1>(v); + assert(x == 456); + x = -456; + assert(v[1] == -456); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/optional_result_virtual.cpp b/src/boost/libs/contract/example/features/optional_result_virtual.cpp new file mode 100644 index 00000000..724a1849 --- /dev/null +++ b/src/boost/libs/contract/example/features/optional_result_virtual.cpp @@ -0,0 +1,88 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <boost/optional.hpp> +#include <vector> +#include <cassert> + +template<typename T> +class accessible { +public: + virtual T& at(unsigned index, boost::contract::virtual_* v = 0) = 0; + + // Could program class invariants and contracts for following too. + virtual T const& operator[](unsigned index) const = 0; + virtual unsigned size() const = 0; +}; + +//[optional_result_virtual +template<typename T> +T& accessible<T>::at(unsigned index, boost::contract::virtual_* v) { + boost::optional<T&> result; + // Pass `result` right after `v`... + boost::contract::check c = boost::contract::public_function(v, result, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(index < size()); + }) + // ...plus postconditions take `result` as a parameter (not capture). + .postcondition([&] (boost::optional<T const&> const& result) { + BOOST_CONTRACT_ASSERT(*result == operator[](index)); + }) + ; + + assert(false); + return *result; +} +//] + +template<typename T> +class vector + #define BASES public accessible<T> + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + T& at(unsigned index, boost::contract::virtual_* v = 0) /* override */ { + boost::optional<T&> result; + // Pass `result` right after `v`... + boost::contract::check c = boost::contract::public_function< + override_at>(v, result, &vector::at, this, index) + // ...plus postconditions take `result` as parameter (not capture). + .postcondition([&] (boost::optional<T const&> const& result) { + if(index == 0) BOOST_CONTRACT_ASSERT(*result == front()); + }) + ; + + return *(result = vect_[index]); + } + + // Could program class invariants and contracts for following too. + T const& operator[](unsigned index) const { return vect_[index]; } + unsigned size() const { return vect_.size(); } + T const& front() const { return vect_.front(); } + void push_back(T const& value) { vect_.push_back(value); } + + BOOST_CONTRACT_OVERRIDE(at) + +private: + std::vector<T> vect_; +}; + +int main() { + vector<int> v; + v.push_back(123); + v.push_back(456); + v.push_back(789); + int& x = v.at(1); + assert(x == 456); + x = -456; + assert(v.at(1) == -456); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/overload.cpp b/src/boost/libs/contract/example/features/overload.cpp new file mode 100644 index 00000000..2feab347 --- /dev/null +++ b/src/boost/libs/contract/example/features/overload.cpp @@ -0,0 +1,202 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <boost/optional.hpp> +#include <string> +#include <sstream> +#include <cassert> + +class lines { +public: + virtual std::string str(boost::contract::virtual_* v = 0) const = 0; + virtual std::string& str(boost::contract::virtual_* v = 0) = 0; + + virtual void put(std::string const& x, + boost::contract::virtual_* v = 0) = 0; + + virtual void put(char x, boost::contract::virtual_* v = 0) = 0; + + virtual void put(int x, bool tab = false, + boost::contract::virtual_* v = 0) = 0; +}; + +std::string lines::str(boost::contract::virtual_* v) const { + std::string result; + boost::contract::check c = boost::contract::public_function(v, result, this) + .postcondition([&] (std::string const& result) { + if(result != "") BOOST_CONTRACT_ASSERT(*result.rbegin() == '\n'); + }) + ; + assert(false); + return result; +} + +std::string& lines::str(boost::contract::virtual_* v) { + boost::optional<std::string&> result; + boost::contract::check c = boost::contract::public_function(v, result, this) + .postcondition([&] (boost::optional<std::string const&> const& result) { + if(*result != "") BOOST_CONTRACT_ASSERT(*result->rbegin() == '\n'); + }) + ; + assert(false); + return *result; +} + +void lines::put(std::string const& x, boost::contract::virtual_* v) { + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(*x.rbegin() != '\n'); + }) + ; + assert(false); +} + +void lines::put(char x, boost::contract::virtual_* v) { + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(x != '\n'); + }) + ; + assert(false); +} + +void lines::put(int x, bool tab, + boost::contract::virtual_* v) { + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(x >= 0); + }) + ; + assert(false); +} + +//[overload +class string_lines + #define BASES public lines + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + BOOST_CONTRACT_OVERRIDES(str) // Invoked only once for all `str` overloads. + + std::string str(boost::contract::virtual_* v = 0) const /* override */ { + std::string result; + boost::contract::check c = boost::contract::public_function< + override_str>( + v, result, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast<std::string (string_lines::*)( + boost::contract::virtual_*) const>(&string_lines::str), + this + ); + + return result = str_; + } + + // Overload on (absence of) `const` qualifier. + std::string& str(boost::contract::virtual_* v = 0) /* override */ { + boost::contract::check c = boost::contract::public_function< + override_str>( + v, str_, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast<std::string& (string_lines::*)( + boost::contract::virtual_*)>(&string_lines::str), + this + ); + + return str_; + } + + BOOST_CONTRACT_OVERRIDES(put) // Invoked only once for all `put` overloads. + + void put(std::string const& x, + boost::contract::virtual_* v = 0) /* override */ { + boost::contract::old_ptr<std::string> old_str = + BOOST_CONTRACT_OLDOF(v, str()); + boost::contract::check c = boost::contract::public_function< + override_put>( + v, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast<void (string_lines::*)(std::string const&, + boost::contract::virtual_*)>(&string_lines::put), + this, x + ) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(str() == *old_str + x + '\n'); + }) + ; + + str_ = str_ + x + '\n'; + } + + // Overload on argument type. + void put(char x, boost::contract::virtual_* v = 0) /* override */ { + boost::contract::old_ptr<std::string> old_str = + BOOST_CONTRACT_OLDOF(v, str()); + boost::contract::check c = boost::contract::public_function< + override_put>( + v, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast<void (string_lines::*)(char, + boost::contract::virtual_*)>(&string_lines::put), + this, x + ) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(str() == *old_str + x + '\n'); + }) + ; + + str_ = str_ + x + '\n'; + } + + // Overload on argument type and arity (also with default parameter). + void put(int x, bool tab = false, + boost::contract::virtual_* v = 0) /* override */ { + boost::contract::old_ptr<std::string> old_str = + BOOST_CONTRACT_OLDOF(v, str()); + boost::contract::check c = boost::contract::public_function< + override_put>( + v, + // `static_cast` resolves overloaded function pointer ambiguities. + static_cast<void (string_lines::*)(int, bool, + boost::contract::virtual_*)>(&string_lines::put), + this, x, tab + ) + .postcondition([&] { + std::ostringstream s; + s << x; + BOOST_CONTRACT_ASSERT( + str() == *old_str + (tab ? "\t" : "") + s.str() + '\n'); + }) + ; + + std::ostringstream s; + s << str_ << (tab ? "\t" : "") << x << '\n'; + str_ = s.str(); + } + +private: + std::string str_; +}; +//] + +int main() { + string_lines s; + s.put("abc"); + assert(s.str() == "abc\n"); + s.put('x'); + assert(s.str() == "abc\nx\n"); + s.put(10); + assert(s.str() == "abc\nx\n10\n"); + s.put(20, true); + lines const& l = s; + assert(l.str() == "abc\nx\n10\n\t20\n"); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/private_protected.cpp b/src/boost/libs/contract/example/features/private_protected.cpp new file mode 100644 index 00000000..7651a925 --- /dev/null +++ b/src/boost/libs/contract/example/features/private_protected.cpp @@ -0,0 +1,77 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <limits> +#include <cassert> + +//[private_protected +class counter { +protected: // Protected functions use `function()` (like non-members). + void set(int n) { + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(n <= 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == n); + }) + ; + + n_ = n; + } + +private: // Private functions use `function()` (like non-members). + void dec() { + boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(get()); + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT( + get() + 1 >= std::numeric_limits<int>::min()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == *old_get - 1); + }) + ; + + set(get() - 1); + } + + int n_; + + /* ... */ +//] + +public: + int get() const { + int result; + boost::contract::check c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result <= 0); + BOOST_CONTRACT_ASSERT(result == n_); + }) + ; + + return result = n_; + } + + counter() : n_(0) {} // Should contract constructor and destructor too. + + void invariant() const { + BOOST_CONTRACT_ASSERT(get() <= 0); + } + + friend int main(); +}; + +int main() { + counter cnt; + assert(cnt.get() == 0); + cnt.dec(); + assert(cnt.get() == -1); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/private_protected_virtual.cpp b/src/boost/libs/contract/example/features/private_protected_virtual.cpp new file mode 100644 index 00000000..534da508 --- /dev/null +++ b/src/boost/libs/contract/example/features/private_protected_virtual.cpp @@ -0,0 +1,145 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <limits> +#include <cassert> + +//[private_protected_virtual_counter +class counter { + // Virtual private and protected functions still declare extra + // `virtual_* = 0` parameter (otherwise they cannot be overridden), but... +protected: + virtual void set(int n, boost::contract::virtual_* = 0) { + boost::contract::check c = boost::contract::function() // ...no `v`. + .precondition([&] { + BOOST_CONTRACT_ASSERT(n <= 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == n); + }) + ; + + n_ = n; + } + +private: + virtual void dec(boost::contract::virtual_* = 0) { + boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(get()); // ...no `v`. + boost::contract::check c = boost::contract::function() // ...no `v`. + .precondition([&] { + BOOST_CONTRACT_ASSERT( + get() + 1 >= std::numeric_limits<int>::min()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == *old_get - 1); + }) + ; + + set(get() - 1); + } + + int n_; + + /* ... */ +//] + +public: + virtual int get(boost::contract::virtual_* v = 0) const { + int result; + boost::contract::check c = boost::contract::public_function( + v, result, this) + .postcondition([&] (int const result) { + BOOST_CONTRACT_ASSERT(result <= 0); + BOOST_CONTRACT_ASSERT(result == n_); + }) + ; + + return result = n_; + } + + counter() : n_(0) {} // Should contract constructor and destructor too. + + void invariant() const { + BOOST_CONTRACT_ASSERT(get() <= 0); + } + + friend int main(); +}; + +//[private_protected_virtual_counter10 +class counter10 + #define BASES public counter + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + // Overriding from non-public members so no subcontracting, no override_... + + virtual void set(int n, boost::contract::virtual_* v = 0) /* override */ { + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(n % 10 == 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == n); + }) + ; + + counter::set(n); + } + + virtual void dec(boost::contract::virtual_* v = 0) /* override */ { + boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(v, get()); + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT( + get() + 10 >= std::numeric_limits<int>::min()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == *old_get - 10); + }) + ; + + set(get() - 10); + } + + /* ... */ +//] + + virtual int get(boost::contract::virtual_* v = 0) const { + int result; + boost::contract::check c = boost::contract::public_function< + override_get>(v, result, &counter10::get, this); + + return result = counter::get(); + } + BOOST_CONTRACT_OVERRIDE(get) + + // Should contract default constructor and destructor too. + + void invariant() const { + BOOST_CONTRACT_ASSERT(get() % 10 == 0); + } +}; + +int main() { + counter cnt; + assert(cnt.get() == 0); + cnt.dec(); + assert(cnt.get() == -1); + + counter10 cnt10; + counter& b = cnt10; // Polymorphic calls. + assert(b.get() == 0); + b.dec(); + assert(b.get() == -10); + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/private_protected_virtual_multi.cpp b/src/boost/libs/contract/example/features/private_protected_virtual_multi.cpp new file mode 100644 index 00000000..2ab875fb --- /dev/null +++ b/src/boost/libs/contract/example/features/private_protected_virtual_multi.cpp @@ -0,0 +1,209 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/config.hpp> +#ifdef BOOST_MSVC + +// WARNING: MSVC (at least up to VS 2015) gives a compile-time error if SFINAE +// cannot introspect a member because of its private or protected access level. +// That is incorrect, SFINAE should fail in these cases without generating +// compile-time errors like GCC and CLang do. Therefore, currently it is not +// possible to override a member that is public in one base but private or +// protected in other base using this library on MSVC (that can be done instead +// using this library on GCC or CLang). +int main() { return 0; } // Trivial program for MSVC. + +#else + +#include <boost/contract.hpp> +#include <limits> +#include <cassert> + +class counter { + // Virtual private and protected functions still declare extra + // `virtual_* = 0` parameter (otherwise they cannot be overridden). +protected: + virtual void set(int n, boost::contract::virtual_* = 0) { + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT(n <= 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == n); + }) + ; + + n_ = n; + } + +private: + virtual void dec(boost::contract::virtual_* = 0) { + boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(get()); + boost::contract::check c = boost::contract::function() + .precondition([&] { + BOOST_CONTRACT_ASSERT( + get() + 1 >= std::numeric_limits<int>::min()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == *old_get - 1); + }) + ; + + set(get() - 1); + } + + int n_; + +public: + virtual int get(boost::contract::virtual_* v = 0) const { + int result; + boost::contract::check c = boost::contract::public_function( + v, result, this) + .postcondition([&] (int const result) { + BOOST_CONTRACT_ASSERT(result <= 0); + BOOST_CONTRACT_ASSERT(result == n_); + }) + ; + + return result = n_; + } + + counter() : n_(0) {} // Should contract constructor and destructor too. + + void invariant() const { + BOOST_CONTRACT_ASSERT(get() <= 0); + } + + friend int main(); +}; + +//[private_protected_virtual_multi_countable +class countable { +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(get() <= 0); + } + + virtual void dec(boost::contract::virtual_* v = 0) = 0; + virtual void set(int n, boost::contract::virtual_* v = 0) = 0; + virtual int get(boost::contract::virtual_* v = 0) const = 0; +}; + +/* ... */ +//] + +void countable::dec(boost::contract::virtual_* v) { + boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(v, get()); + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(get() > std::numeric_limits<int>::min()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() < *old_get); + }) + ; + assert(false); // Never executed by this library. +} + +void countable::set(int n, boost::contract::virtual_* v) { + boost::contract::check c = boost::contract::public_function( + v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(n <= 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == n); + }) + ; + assert(false); // Never executed by this library. +} + +int countable::get(boost::contract::virtual_* v) const { + int result; + boost::contract::check c = boost::contract::public_function( + v, result, this); + assert(false); // Never executed by this library. +} + +//[private_protected_virtual_multi_counter10 +class counter10 + #define BASES public countable, public counter // Multiple inheritance. + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + // Overriding from public members from `countable` so use `override_...`. + + virtual void set(int n, boost::contract::virtual_* v = 0) /* override */ { + boost::contract::check c = boost::contract::public_function< + override_set>(v, &counter10::set, this, n) + .precondition([&] { + BOOST_CONTRACT_ASSERT(n % 10 == 0); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == n); + }) + ; + + counter::set(n); + } + + virtual void dec(boost::contract::virtual_* v = 0) /* override */ { + boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(v, get()); + boost::contract::check c = boost::contract::public_function< + override_dec>(v, &counter10::dec, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT( + get() + 10 >= std::numeric_limits<int>::min()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(get() == *old_get - 10); + }) + ; + + set(get() - 10); + } + + BOOST_CONTRACT_OVERRIDES(set, dec) + + /* ... */ +//] + + virtual int get(boost::contract::virtual_* v = 0) const { + int result; + boost::contract::check c = boost::contract::public_function< + override_get>(v, result, &counter10::get, this); + + return result = counter::get(); + } + BOOST_CONTRACT_OVERRIDE(get) + + // Should contract default constructor and destructor too. + + void invariant() const { + BOOST_CONTRACT_ASSERT(get() % 10 == 0); + } +}; + +int main() { + counter cnt; + assert(cnt.get() == 0); + cnt.dec(); + assert(cnt.get() == -1); + + counter10 cnt10; + countable& b = cnt10; // Polymorphic calls. + assert(b.get() == 0); + b.dec(); + assert(b.get() == -10); + + return 0; +} + +#endif // MSVC + diff --git a/src/boost/libs/contract/example/features/public.cpp b/src/boost/libs/contract/example/features/public.cpp new file mode 100644 index 00000000..a6d94aa7 --- /dev/null +++ b/src/boost/libs/contract/example/features/public.cpp @@ -0,0 +1,189 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <algorithm> +#include <cassert> + +//[public_class_begin +class unique_identifiers : + private boost::contract::constructor_precondition<unique_identifiers> +{ +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(size() >= 0); + } +//] + +//[public_constructor +public: + // Contract for a constructor. + unique_identifiers(int from, int to) : + boost::contract::constructor_precondition<unique_identifiers>([&] { + BOOST_CONTRACT_ASSERT(from >= 0); + BOOST_CONTRACT_ASSERT(to >= from); + }) + { + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == (to - from + 1)); + }) + ; + + // Constructor body. + for(int id = from; id <= to; ++id) vect_.push_back(id); + } +//] + +//[public_destructor +public: + // Contract for a destructor. + virtual ~unique_identifiers() { + // Following contract checks class invariants. + boost::contract::check c = boost::contract::destructor(this); + + // Destructor body here... (do nothing in this example). + } +//] + + int size() const { + // Following contract checks invariants. + boost::contract::check c = boost::contract::public_function(this); + return vect_.size(); + } + +//[public_function +public: + // Contract for a public function (but no static, virtual, or override). + bool find(int id) const { + bool result; + boost::contract::check c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(id >= 0); + }) + .postcondition([&] { + if(size() == 0) BOOST_CONTRACT_ASSERT(!result); + }) + ; + + // Function body. + return result = std::find(vect_.begin(), vect_.end(), id) != + vect_.end(); + } +//] + +//[public_virtual_function +public: + // Contract for a public virtual function (but no override). + virtual int push_back(int id, boost::contract::virtual_* v = 0) { // Extra `v`. + int result; + boost::contract::old_ptr<bool> old_find = + BOOST_CONTRACT_OLDOF(v, find(id)); // Pass `v`. + boost::contract::old_ptr<int> old_size = + BOOST_CONTRACT_OLDOF(v, size()); // Pass `v`. + boost::contract::check c = boost::contract::public_function( + v, result, this) // Pass `v` and `result`. + .precondition([&] { + BOOST_CONTRACT_ASSERT(id >= 0); + BOOST_CONTRACT_ASSERT(!find(id)); // ID cannot be already present. + }) + .postcondition([&] (int const result) { + if(!*old_find) { + BOOST_CONTRACT_ASSERT(find(id)); + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + } + BOOST_CONTRACT_ASSERT(result == id); + }) + ; + + // Function body. + vect_.push_back(id); + return result = id; + } +//] + +private: + std::vector<int> vect_; +//[public_class_end + /* ... */ +}; +//] + +//[public_derived_class_begin +class identifiers + #define BASES public unique_identifiers + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Bases typedef. + #undef BASES + + void invariant() const { // Check in AND with bases. + BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); + } +//] + +//[public_function_override +public: + // Contract for a public function override. + int push_back(int id, boost::contract::virtual_* v = 0) /* override */ { + int result; + boost::contract::old_ptr<bool> old_find = + BOOST_CONTRACT_OLDOF(v, find(id)); + boost::contract::old_ptr<int> old_size = + BOOST_CONTRACT_OLDOF(v, size()); + boost::contract::check c = boost::contract::public_function< + override_push_back // Pass override type plus below function pointer... + >(v, result, &identifiers::push_back, this, id) // ...and arguments. + .precondition([&] { // Check in OR with bases. + BOOST_CONTRACT_ASSERT(id >= 0); + BOOST_CONTRACT_ASSERT(find(id)); // ID can be already present. + }) + .postcondition([&] (int const result) { // Check in AND with bases. + if(*old_find) BOOST_CONTRACT_ASSERT(size() == *old_size); + }) + ; + + // Function body. + if(!find(id)) unique_identifiers::push_back(id); // Else, do nothing. + return result = id; + } + BOOST_CONTRACT_OVERRIDE(push_back) // Define `override_push_back`. +//] + + bool empty() const { + // Following contract checks invariants. + boost::contract::check c = boost::contract::public_function(this); + return size() == 0; + } + + identifiers(int from, int to) : unique_identifiers(from, to) { + // Following contract checks invariants. + boost::contract::check c = boost::contract::constructor(this); + } + +//[public_derived_class_end + /* ... */ +}; +//] + +int main() { + unique_identifiers uids(1, 4); + assert(uids.find(2)); + assert(!uids.find(5)); + uids.push_back(5); + assert(uids.find(5)); + + identifiers ids(10, 40); + assert(!ids.find(50)); + ids.push_back(50); + ids.push_back(50); + assert(ids.find(50)); + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/pure_virtual_public.cpp b/src/boost/libs/contract/example/features/pure_virtual_public.cpp new file mode 100644 index 00000000..917a6c71 --- /dev/null +++ b/src/boost/libs/contract/example/features/pure_virtual_public.cpp @@ -0,0 +1,89 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <vector> +#include <cassert> + +//[pure_virtual_public_base_begin +template<typename Iterator> +class range { +public: + // Pure virtual function declaration (contract in definition below). + virtual Iterator begin(boost::contract::virtual_* v = 0) = 0; +//] + + // Could program class invariants and contracts for the following too. + virtual Iterator end() = 0; + virtual bool empty() const = 0; + +//[pure_virtual_public_base_end + /* ... */ +}; +//] + +//[pure_virtual_public_base_impl +// Pure virtual function default implementation (out-of-line in C++). +template<typename Iterator> +Iterator range<Iterator>::begin(boost::contract::virtual_* v) { + Iterator result; // As usual, virtual pass `result` right after `v`... + boost::contract::check c = boost::contract::public_function(v, result, this) + .postcondition([&] (Iterator const& result) { + if(empty()) BOOST_CONTRACT_ASSERT(result == end()); + }) + ; + + // Pure function body (never executed by this library). + assert(false); + return result; +} +//] + +template<typename T> +class vector + #define BASES public range<typename std::vector<T>::iterator> + : BASES +{ +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + typedef typename std::vector<T>::iterator iterator; + + iterator begin(boost::contract::virtual_* v = 0) /* override */ { + iterator result; + // Again, pass result right after `v`... + boost::contract::check c = boost::contract::public_function< + override_begin>(v, result, &vector::begin, this) + // ...plus postconditions take `result` as parameter (not capture). + .postcondition([&] (iterator const& result) { + if(!empty()) BOOST_CONTRACT_ASSERT(*result == front()); + }) + ; + + return result = vect_.begin(); + } + BOOST_CONTRACT_OVERRIDE(begin) + + // Could program class invariants and contracts for the following too. + iterator end() { return vect_.end(); } + bool empty() const { return vect_.empty(); } + T const& front() const { return vect_.front(); } + void push_back(T const& value) { vect_.push_back(value); } + +private: + std::vector<T> vect_; +}; + +int main() { + vector<int> v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + range<std::vector<int>::iterator>& r = v; + assert(*(r.begin()) == 1); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/separate_body.cpp b/src/boost/libs/contract/example/features/separate_body.cpp new file mode 100644 index 00000000..10e05b2e --- /dev/null +++ b/src/boost/libs/contract/example/features/separate_body.cpp @@ -0,0 +1,36 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include "separate_body.hpp" +#include <cassert> + +//[separate_body_cpp +void iarray::constructor_body(unsigned max, unsigned count) { + for(unsigned i = 0; i < count; ++i) values_[i] = int(); + size_ = count; +} + +void iarray::destructor_body() { delete[] values_; } + +void iarray::push_back_body(int value) { values_[size_++] = value; } + +/* ... */ +//] + +unsigned iarray::capacity_body() const { return capacity_; } +unsigned iarray::size_body() const { return size_; } + +int main() { + iarray a(3, 2); + assert(a.capacity() == 3); + assert(a.size() == 2); + + a.push_back(-123); + assert(a.size() == 3); + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/separate_body.hpp b/src/boost/libs/contract/example/features/separate_body.hpp new file mode 100644 index 00000000..6b83afd5 --- /dev/null +++ b/src/boost/libs/contract/example/features/separate_body.hpp @@ -0,0 +1,88 @@ + +#ifndef SEPARATE_BODY_HPP_ +#define SEPARATE_BODY_HPP_ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> + +//[separate_body_hpp +class iarray : + private boost::contract::constructor_precondition<iarray> { +public: + void invariant() const { + BOOST_CONTRACT_ASSERT(size() <= capacity()); + } + + explicit iarray(unsigned max, unsigned count = 0) : + boost::contract::constructor_precondition<iarray>([&] { + BOOST_CONTRACT_ASSERT(count <= max); + }), + // Still, member initializations must be here. + values_(new int[max]), + capacity_(max) + { + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() == max); + BOOST_CONTRACT_ASSERT(size() == count); + }) + ; + constructor_body(max, count); // Separate constructor body impl. + } + + virtual ~iarray() { + boost::contract::check c = boost::contract::destructor(this); // Inv. + destructor_body(); // Separate destructor body implementation. + } + + virtual void push_back(int value, boost::contract::virtual_* v = 0) { + boost::contract::old_ptr<unsigned> old_size = + BOOST_CONTRACT_OLDOF(v, size()); + boost::contract::check c = boost::contract::public_function(v, this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() < capacity()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + }) + ; + push_back_body(value); // Separate member function body implementation. + } + +private: + // Contracts in class declaration (above), but body implementations are not. + void constructor_body(unsigned max, unsigned count); + void destructor_body(); + void push_back_body(int value); + + /* ... */ +//] + +public: + unsigned capacity() const { + // Check invariants. + boost::contract::check c = boost::contract::public_function(this); + return capacity_body(); + } + + unsigned size() const { + // Check invariants. + boost::contract::check c = boost::contract::public_function(this); + return size_body(); + } + +private: + unsigned size_body() const; + unsigned capacity_body() const; + + int* values_; + unsigned capacity_; + unsigned size_; +}; + +#endif // #include guard + diff --git a/src/boost/libs/contract/example/features/static_public.cpp b/src/boost/libs/contract/example/features/static_public.cpp new file mode 100644 index 00000000..146de0fa --- /dev/null +++ b/src/boost/libs/contract/example/features/static_public.cpp @@ -0,0 +1,69 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <cassert> + +//[static_public +template<class C> +class make { +public: + static void static_invariant() { // Static class invariants. + BOOST_CONTRACT_ASSERT(instances() >= 0); + } + + // Contract for a static public function. + static int instances() { + // Explicit template parameter `make` (check static invariants). + boost::contract::check c = boost::contract::public_function<make>(); + + return instances_; // Function body. + } + + /* ... */ +//] + + make() : object() { + boost::contract::old_ptr<int> old_instances = + BOOST_CONTRACT_OLDOF(instances()); + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(instances() == *old_instances + 1); + }) + ; + + ++instances_; + } + + ~make() { + boost::contract::old_ptr<int> old_instances = + BOOST_CONTRACT_OLDOF(instances()); + boost::contract::check c = boost::contract::destructor(this) + .postcondition([&] { // (An example of destructor postconditions.) + BOOST_CONTRACT_ASSERT(instances() == *old_instances - 1); + }) + ; + + --instances_; + } + + C object; + +private: + static int instances_; +}; + +template<class C> +int make<C>::instances_ = 0; + +int main() { + struct x {}; + make<x> x1, x2, x3; + assert(make<x>::instances() == 3); + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/throw_on_failure.cpp b/src/boost/libs/contract/example/features/throw_on_failure.cpp new file mode 100644 index 00000000..4cff315f --- /dev/null +++ b/src/boost/libs/contract/example/features/throw_on_failure.cpp @@ -0,0 +1,145 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <iostream> +#include <cstring> +#include <cassert> + +//[throw_on_failure_class_begin +struct too_large_error {}; + +template<unsigned MaxSize> +class cstring + #define BASES private boost::contract::constructor_precondition<cstring< \ + MaxSize> > + : BASES +{ +//] +public: + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + +//[throw_on_failure_ctor +public: + /* implicit */ cstring(char const* chars) : + boost::contract::constructor_precondition<cstring>([&] { + BOOST_CONTRACT_ASSERT(chars); // Throw `assertion_failure`. + // Or, throw user-defined exception. + if(std::strlen(chars) > MaxSize) throw too_large_error(); + }) + { +//] + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == std::strlen(chars)); + }) + ; + + size_ = std::strlen(chars); + for(unsigned i = 0; i < size_; ++i) chars_[i] = chars[i]; + chars_[size_] = '\0'; + } + +//[throw_on_failure_dtor +public: + void invariant() const { + if(size() > MaxSize) throw too_large_error(); // Throw user-defined ex. + BOOST_CONTRACT_ASSERT(chars_); // Or, throw `assertion_failure`. + BOOST_CONTRACT_ASSERT(chars_[size()] == '\0'); + } + + ~cstring() noexcept { // Exception specifiers apply to contract code. + // Check invariants. + boost::contract::check c = boost::contract::destructor(this); + } +//] + + unsigned size() const { + // Check invariants. + boost::contract::check c = boost::contract::public_function(this); + return size_; + } + +private: + char chars_[MaxSize + 1]; + unsigned size_; +//[throw_on_failure_class_end + /* ... */ +}; +//] + +void bad_throwing_handler() { // For docs only (not actually used here). + //[throw_on_failure_bad_handler + /* ... */ + + // Warning... might cause destructors to throw (unless declared noexcept). + boost::contract::set_invariant_failure( + [] (boost::contract::from) { + throw; // Throw no matter if from destructor, etc. + } + ); + + /* ... */ + //] +} + +//[throw_on_failure_handlers +int main() { + boost::contract::set_precondition_failure( + boost::contract::set_postcondition_failure( + boost::contract::set_invariant_failure( + boost::contract::set_old_failure( + [] (boost::contract::from where) { + if(where == boost::contract::from_destructor) { + // Shall not throw from C++ destructors. + std::clog << "ignored destructor contract failure" << std::endl; + } else throw; // Re-throw (assertion_failure, user-defined, etc.). + } + )))); + boost::contract::set_except_failure( + [] (boost::contract::from) { + // Already an active exception so shall not throw another... + std::clog << "ignored exception guarantee failure" << std::endl; + } + ); + boost::contract::set_check_failure( + [] { + // But now CHECK shall not be used in destructor implementations. + throw; // Re-throw (assertion_failure, user-defined, etc.). + } + ); + + /* ... */ +//] + + { + cstring<3> s("abc"); + assert(s.size() == 3); + } + + #ifndef BOOST_CONTRACT_NO_PRECONDITIONS + // These failures properly handled only when preconditions checked. + + try { + char* c = 0; + cstring<3> s(c); + assert(false); + } catch(boost::contract::assertion_failure const& error) { + // OK (expected). + std::clog << "ignored: " << error.what() << std::endl; + } catch(...) { assert(false); } + + try { + cstring<3> s("abcd"); + assert(false); + } catch(too_large_error const&) {} // OK (expected). + catch(...) { assert(false); } + #endif + + return 0; +} + diff --git a/src/boost/libs/contract/example/features/union.cpp b/src/boost/libs/contract/example/features/union.cpp new file mode 100644 index 00000000..0681c774 --- /dev/null +++ b/src/boost/libs/contract/example/features/union.cpp @@ -0,0 +1,134 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <boost/config.hpp> +#include <cassert> + +#ifdef BOOST_GCC // G++ does not support static union members yet. + int instances_ = 0; +#endif + +//[union +union positive { +public: + static void static_invariant() { // Static class invariants (as usual). + BOOST_CONTRACT_ASSERT(instances() >= 0); + } + + void invariant() const { // Class invariants (as usual). + BOOST_CONTRACT_ASSERT(i_ > 0); + BOOST_CONTRACT_ASSERT(d_ > 0); + } + + // Contracts for constructor, as usual but... + explicit positive(int x) : d_(0) { + // ...unions cannot have bases so constructor preconditions here. + boost::contract::constructor_precondition<positive> pre([&] { + BOOST_CONTRACT_ASSERT(x > 0); + }); + boost::contract::old_ptr<int> old_instances = + BOOST_CONTRACT_OLDOF(instances()); + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + { int y; get(y); BOOST_CONTRACT_ASSERT(y == x); } + BOOST_CONTRACT_ASSERT(instances() == *old_instances + 1); + }) + ; + + i_ = x; + ++instances_; + } + + // Contracts for destructor (as usual). + ~positive() { + boost::contract::old_ptr<int> old_instances = + BOOST_CONTRACT_OLDOF(instances()); + boost::contract::check c = boost::contract::destructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(instances() == *old_instances - 1); + }) + ; + + --instances_; + } + + // Contracts for public function (as usual, but no virtual or override). + void get(int& x) const { + boost::contract::check c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(x > 0); + }) + ; + + x = i_; + } + + // Contracts for static public function (as usual). + static int instances() { + boost::contract::check c = boost::contract::public_function<positive>(); + return instances_; + } + +private: + int i_; + double d_; + + /* ... */ +//] + +public: + explicit positive(double x) : d_(0) { + // Unions cannot have bases so constructor preconditions here. + boost::contract::constructor_precondition<positive> pre([&] { + BOOST_CONTRACT_ASSERT(x > 0); + }); + boost::contract::old_ptr<int> old_instances = + BOOST_CONTRACT_OLDOF(instances()); + boost::contract::check c = boost::contract::constructor(this) + .postcondition([&] { + { double y; get(y); BOOST_CONTRACT_ASSERT(y == x); } + BOOST_CONTRACT_ASSERT(instances() == *old_instances + 1); + }) + ; + + d_ = x; + ++instances_; + } + + void get(double& x) const { + boost::contract::check c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(x > 0); + }) + ; + + x = d_; + } + + #ifndef BOOST_GCC // G++ does not support static union members yet. + static int instances_; + #endif +}; + +#ifndef BOOST_GCC // G++ does not support static union members yet. + int positive::instances_ = 0; +#endif + +int main() { + { + positive p(123); + assert(p.instances() == 1); + { int y = -456; p.get(y); assert(y == 123); } + + positive q(1.23); + assert(q.instances() == 2); + { double y = -4.56; q.get(y); assert(y == 1.23); } + } + assert(positive::instances() == 0); + return 0; +} + diff --git a/src/boost/libs/contract/example/features/volatile.cpp b/src/boost/libs/contract/example/features/volatile.cpp new file mode 100644 index 00000000..eb9b2e71 --- /dev/null +++ b/src/boost/libs/contract/example/features/volatile.cpp @@ -0,0 +1,102 @@ + +// Copyright (C) 2008-2018 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 (see accompanying +// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). +// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html + +#include <boost/contract.hpp> +#include <cassert> + +//[volatile +class u { +public: + static void static_invariant(); // Static invariants. + void invariant() const volatile; // Volatile invariants. + void invariant() const; // Const invariants. + + u() { // Check static, volatile, and const invariants. + boost::contract::check c= boost::contract::constructor(this); + } + + ~u() { // Check static, volatile, and const invariants. + boost::contract::check c = boost::contract::destructor(this); + } + + void nc() { // Check static and const invariants. + boost::contract::check c = boost::contract::public_function(this); + } + + void c() const { // Check static and const invariants. + boost::contract::check c = boost::contract::public_function(this); + } + + void v() volatile { // Check static and volatile invariants. + boost::contract::check c = boost::contract::public_function(this); + } + + void cv() const volatile { // Check static and volatile invariants. + boost::contract::check c = boost::contract::public_function(this); + } + + static void s() { // Check static invariants only. + boost::contract::check c = boost::contract::public_function<u>(); + } +}; +//] + +bool static_inv_checked, cv_inv_checked, const_inv_checked; +void u::static_invariant() { static_inv_checked = true; } +void u::invariant() const volatile { cv_inv_checked = true; } +void u::invariant() const { const_inv_checked = true; } + +int main() { + #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS + { + static_inv_checked = cv_inv_checked = const_inv_checked = false; + u x; + assert(static_inv_checked); + assert(cv_inv_checked); + assert(const_inv_checked); + + static_inv_checked = cv_inv_checked = const_inv_checked = false; + x.nc(); + assert(static_inv_checked); + assert(!cv_inv_checked); + assert(const_inv_checked); + + static_inv_checked = cv_inv_checked = const_inv_checked = false; + x.c(); + assert(static_inv_checked); + assert(!cv_inv_checked); + assert(const_inv_checked); + + static_inv_checked = cv_inv_checked = const_inv_checked = false; + x.v(); + assert(static_inv_checked); + assert(cv_inv_checked); + assert(!const_inv_checked); + + static_inv_checked = cv_inv_checked = const_inv_checked = false; + x.cv(); + assert(static_inv_checked); + assert(cv_inv_checked); + assert(!const_inv_checked); + + static_inv_checked = cv_inv_checked = const_inv_checked = false; + x.s(); + assert(static_inv_checked); + assert(!cv_inv_checked); + assert(!const_inv_checked); + + static_inv_checked = cv_inv_checked = const_inv_checked = false; + } // Call destructor. + #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS + assert(static_inv_checked); + assert(cv_inv_checked); + assert(const_inv_checked); + #endif + #endif + + return 0; +} + |