diff --git a/example/push_back.cpp b/example/push_back.cpp index a31b515..102070d 100644 --- a/example/push_back.cpp +++ b/example/push_back.cpp @@ -5,7 +5,7 @@ template struct pusahble { void push_back(T const& value, boost::contract::virtual_body v = 0) { - boost::contract::type contract = boost::contract::public_member(this, v) + auto contract = boost::contract::public_member(v, this) .precondition([&] { BOOST_CONTRACT_ASSERT(false); // Force check derived precond. }) @@ -25,21 +25,23 @@ protected: virtual T const& back() const = 0; }; -#define BASES public ushable template -class vecotr : BASES { +class vector + #define BASES public ushable + : BASES +{ public: typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; -# undef BASES + #undef BASES void invariant() const { BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); } - void push_back(T const& value) { - unsigned const old_size = size(); + void push_back(T const& value, boost::contract::virtual_body v = 0) { + auto old_size = BOOST_CONTRACT_OLDOF(v, size()); boost::contract::type contract = boost::contract::public_member< - introspect_push_back>(this, &vector::push_back, value) + introspect_push_back>(v, this, &vector::push_back, value) .precondition([&]() { BOOST_CONTRACT_ASSERT(this->size() < this->max_size()); }) @@ -49,7 +51,7 @@ public: ; push_back_body(value); } - void push_back_body(T const& value) { vector_.push_back(value); } + virtual void push_back_body(T const& value) { vector_.push_back(value); } bool empty() const { return vector_.empty(); } unsigned size() const { return vector_.size(); } @@ -62,7 +64,3 @@ private: BOOST_CONTRACT_INTROSPECT(push_back) }; -call_if, bool>( - bind(equal_to(), cref(back()), cref(value)) -).else_(always(true)) - diff --git a/example/vector.cpp b/example/vector.cpp index dcb3e8d..50d2fa0 100644 --- a/example/vector.cpp +++ b/example/vector.cpp @@ -7,9 +7,10 @@ class vector : #define BASES private boost::contract::constructor_precondition BASES { +public: typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES -public: + void invariant() const { BOOST_CONTRACT_ASSERT(emtpy() == (size() == 0)); BOOST_CONTRACT_ASSERT(std::distance(begin(), end()) == int(size())); @@ -19,16 +20,16 @@ public: } vector() : vector_() { - boost::contract::type c = boost::contract::constructor(this) - .postcondition([&] () { + auto c = boost::contract::constructor(this) + .postcondition([&] { BOOST_CONTRACT_ASSERT(empty()); }) ; } explicit vector(Allocator const& allocator) : vector_(allocator) { - boost::contract::type c = boost::contract::constructor(this) - .postcondition([&] () { + auto c = boost::contract::constructor(this) + .postcondition([&] { BOOST_CONTRACT_ASSERT(empty()); BOOST_CONTRACT_ASSERT(get_allocator() == allocator); }) @@ -36,13 +37,13 @@ public: } explicit vector(size_type const count) : - boost::contract::constructor_precondition([&] () { + boost::contract::constructor_precondition([&] { BOOST_CONTRACT_ASSERT(count >= 0); }), vector_(count) { - boost::contract::type c = boost::contract::constructor(this) - .postcondition([&] () { + auto c = boost::contract::constructor(this) + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == count); BOOST_CONTRACT_ASSERT( boost::contract::check_if >( @@ -54,13 +55,13 @@ public: } vector(size_type const count, T const& value) : - boost::contract::constructor_precondition([&] () { + boost::contract::constructor_precondition([&] { BOOST_CONTRACT_ASSERT(count >= 0); }), vector_(count, value) { - boost::contract::type c = boost::contract::constructor(this) - .postcondition([&] () { + auto c = boost::contract::constructor(this) + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == count); BOOST_CONTRACT_ASSERT( boost::contract::check_if >( @@ -73,16 +74,16 @@ public: template vector(Iterator first, Iterator last) : vector_(first, last) { - boost::contract::type c = boost::contract::constructor(this) - .postcondition([&] () { + auto c = boost::contract::constructor(this) + .postcondition([&] { BOOST_CONTRACT_ASSERT(std::distance(first, lat) == int(size())); }) ; } vector(vector const& other) { - boost::contract::type c = boost::contract::constructor(this) - .postcondition([&] () { + auto c = boost::contract::constructor(this) + .postcondition([&] { BOOST_CONTRACT_ASSERT( boost::contract::check_if >( &std::equal_to, other, *this @@ -93,120 +94,107 @@ public: } vector& operator=(vector const& other) { - vector* result = 0; - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { + vector& result = *this; + auto c = boost::contract::public_member(this) + .postcondition([&] { BOOST_CONTRACT_ASSERT( boost::contract::check_if >( - &std::equal_to, *result, *this + &std::equal_to, result, *this ) ); BOOST_CONTRACT_ASSERT( boost::contract::check_if >( - &std::equal_to, *result, other + &std::equal_to, result, other ) ); }) ; vector_ = right.vector_; - return *(result = this); + return result; } virtual ~vector() { // No pre/post, but still contract so to check invariants. - boost::contract::type c = boost::contract::destructor(this); + auto c = boost::contract::destructor(this); } size_type capacity() const { - size_type* result = 0; - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { - BOOST_CONTRACT_ASSERT(*result >= size()); + size_type result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result >= size()); }) ; - size_type r = vector_.capacity(); - // TODO: This might not work... does r get destructored before c, and - // so before post are called? If so, must either default construct and - // then copy just before return, or must use shared_ptr. Same for all - // other similar returns. - return *(result = &r); + return result = vector_.capacity(); } iterator begin() { - iterator* result; - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { - if(empty()) BOOST_CONTRACT_ASSERTION(*result == end()); + iterator result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + if(empty()) BOOST_CONTRACT_ASSERTION(result == end()); }) ; - iterator r = vector_.begin(); - return *(result = &r); + return result = vector_.begin(); } const_iterator begin() const { - const_iterator* result; - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { - if(empty()) BOOST_CONTRACT_ASSERTION(*result == end()); + const_iterator result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + if(empty()) BOOST_CONTRACT_ASSERTION(result == end()); }) ; - const_iterator r = vector_.begin(); - return *(result = &r); + return result = vector_.begin(); } interator end() { - // No pre/post, but still contract so to check invariants. - boost::contract::type c = boost::contract::public_member(this); + auto c = boost::contract::public_member(this); // To check invariants. return vector_.end(); } const_interator end() const { - boost::contract::type c = boost::contract::public_member(this); + auto c = boost::contract::public_member(this); return vector_.end(); } iterator rbegin() { - iterator* result; - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { - if(empty()) BOOST_CONTRACT_ASSERTION(*result == end()); + iterator result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + if(empty()) BOOST_CONTRACT_ASSERTION(result == end()); }) ; - iterator r = vector_.rbegin(); - return *(result = &r); + return result = vector_.rbegin(); } const_iterator rbegin() const { - const_iterator* result; - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { - if(empty()) BOOST_CONTRACT_ASSERTION(*result == end()); + const_iterator result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + if(empty()) BOOST_CONTRACT_ASSERTION(result == end()); }) ; - const_iterator r = vector_.rbegin(); - return *(result = &r); + return result = vector_.rbegin(); } interator rend() { - boost::contract::type c = boost::contract::public_member(this); + auto c = boost::contract::public_member(this); return vector_.end(); } const_interator rend() const { - boost::contract::type c = boost::contract::public_member(this); + auto c = boost::contract::public_member(this); return vector_.end(); } void resize(size_type const new_size) { - // TODO: Using this oldof_ (and an overload oldof_(v, ...)) I should be - // able to remove copy overhead when post disabled... actually I - // might need to use a macro otherwise size() is alwasy evaluated... - size_type const old_size = boost::contract::oldof_(size()); - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(new_size >= 0); }) - .postcondition([&] () { + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == new_size); if(new_size > old_size) BOOST_CONTRACT_ASSERT( boost::contract::check_if >( @@ -220,12 +208,12 @@ public: } void resize(size_type const new_size, T const& value) { - size_type const old_size = BOOST_CONTRACT_OLDOF(size()); - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(new_size >= 0); }) - .postcondition([&] () { + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == new_size); if(new_size > old_size) BOOST_CONTRACT_ASSERT( boost::contract::check_if >( @@ -238,46 +226,43 @@ public: } size_type size() const { - size_type* result = 0; - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { - BOOST_CONTRACT_ASSERT(*result >= capacity()); + size_type result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result >= capacity()); }) ; - size_type r = vector_.size(); - return *(result = &r); + return result = vector_.size(); } size_type max_size() const { - size_type* result = 0; - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { - BOOST_CONTRACT_ASSERT(*result >= capacity()); + size_type result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result >= capacity()); }) ; - size_type r = vector_.max_size(); - return *(result = &r); + return result = vector_.max_size(); } bool empty() const { - bool* result = 0; - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { - BOOST_CONTRACT_ASSERT(*result == (size() == 0)); + bool result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result == (size() == 0)); }) ; - bool r = vector_.empty(); - return *(result = &r); + return result = vector_.empty(); } Allocator get_allocator() const { - boost::contract::type c = boost::contract::public_member(this); + auto c = boost::contract::public_member(this); return vector_.get_allocator(); } reference at(size_type const index) { - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(index < size()); }) ; @@ -285,8 +270,8 @@ public: } const_reference at(size_type const index) const { - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(index < size()); }) ; @@ -294,8 +279,8 @@ public: } reference operator[](size_type const index) { - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(index < size()); }) ; @@ -303,8 +288,8 @@ public: } const_reference operator[](size_type const index) const { - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(index < size()); }) ; @@ -312,17 +297,17 @@ public: } reference front() { - boost::contract::type c = booost::contract::public_member(this) - .precondition([&] () { + auto c = booost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(!emtpy()); - } + }) ; return vector_.front(); } const_reference front() const { - boost::contract::type c = booost::contract::public_member(this) - .precondition([&] () { + auto c = booost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(!emtpy()); } ; @@ -330,8 +315,8 @@ public: } reference back() { - boost::contract::type c = booost::contract::public_member(this) - .precondition([&] () { + auto c = booost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(!emtpy()); } ; @@ -339,8 +324,8 @@ public: } const_reference back() const { - boost::contract::type c = booost::contract::public_member(this) - .precondition([&] () { + auto c = booost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(!emtpy()); } ; @@ -348,15 +333,13 @@ public: } void push_back(T const& value) { - #if BOOST_CONTRACT_OLDOF - size_type const old_size = size()); - size_type const old_capacity = capacity(); - #endif - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(size() < max_size()); }) - .postcondition([&] () { + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == old_size + 1); BOOST_CONTRACT_ASSERT(capacity() >= old_capacity); BOOST_CONTRACT_ASSERT( @@ -369,21 +352,23 @@ public: } void pop_back() { - BOOST_CONTRACT_OLDOF(size_type const old_size = size()); - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { BOOST_CONTRACT_ASSERT(!empty()); }) - .postcondition([&] () { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto = boost::contract::public_member(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == old_size - 1); - ) + }) ; vector_.pop_back(); } template void assign(Iterator const first, Iterator const last) { - boost::contract::type c = boost::contract::public_member(this) + auto c = boost::contract::public_member(this) // precondition: [begin(), end()) does not contain [first, last) - .postcondition([&] () { + .postcondition([&] { BOOST_CONTRACT_ASSERT(std::distance(first, last) == int(size())); }) @@ -392,9 +377,11 @@ public: } void assign(size_type const count, T const& value) { - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { BOOST_CONTRACT_ASSERT(count <= max_size()); } - .postcondition([&] () { + auto c = boost::contract::public_member(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(count <= max_size()); + } + .postcondition([&] { BOOST_CONTRACT_ASSERT( boost::contract::check_if >( &boost::algorithm::all_of_equal, begin(), end(), value @@ -406,37 +393,34 @@ public: } iterator insert(iterator const where, T const& value) { - iterator* result = 0; - BOOST_CONTRACT_OLDOF(size_type const old_size = size()); - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + iterator result; + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(size() < max_size()); }) - .postcondition([&] () { + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == old_size + 1); BOOST_CONTRACT_ASSERT(boost::contract::check_if >(&std::equal_to, *result, value)); + has_equal_to >(&std::equal_to, result, value)); // if(capacity() > oldof capacity()) // [begin(), end()) is invalid // else // [where, end()) is invalid }) ; - iterator r = vector_.insert(where, value); - return *(result = &r); + return result = vector_.insert(where, value); } void insert(iterator where, size_type const count, T const& value) { - BOOST_CONTRACT_OLDOF( - size_type const old_size = size(); - size_type const old_capacity = capacity(); - iterator const old_where = where; - ) - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); + auto old_where = BOOST_CONTRACT_OLDOF(where); + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(size() + count < max_size()); }) - .postcondition([&] () { + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == old_size + count); BOOST_CONTRACT_ASSERT(capacity() >= old_capacity); if(capacity() == old_capacity) @@ -459,17 +443,15 @@ public: template void insert(Iterator where, Iterator first, Iterator last) { - BOOST_CONTRACT_OLDOF( - size_type const old_size = size(); - size_type const old_capacity = capacity(); - ) - boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); + auto c = boost::contract::public_member(this) + .precondition([&] { BOOST_CONTRACT_ASSERT(size() + std::distance(first, lat) < max_size()); // [first, last) is not contained in [begin(), end()) }) - .postcondition([&] () { + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == old_size + std::distance(first, last)); BOOST_CONTRACT_ASSERT(capacity() >= old_capacity); @@ -479,35 +461,34 @@ public: } iterator erase(iterator where) { - BOOST_CONTRACT_OLDOF(size_type const old_size = size()); + iterator result; + auto old_size = BOOST_CONTRACT_OLDOF(size()); boost::contract::type c = boost::contract::public_member(this) - .precondition([&] () { + .precondition([&] { BOOST_CONTRACT_ASSERT(!empty()); BOOST_CONTRACT_ASSERT(where != end()); }) - .postcondition([&] () { + .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == old_size - 1); - if(empty()) BOOST_CONTRACT_ASSERT(*result == end()); + if(empty()) BOOST_CONTRACT_ASSERT(result == end()); // [where, end()) is invalid }) ; - return vector_.erase(first, last); + return result = vector_.erase(first, last); } void clear() { boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { BOOST_CONTRACT_ASSERT(empty()); }) + .postcondition([&] { BOOST_CONTRACT_ASSERT(empty()); }) ; vector_.clear(); } void swap(vector& other) { - BOOST_CONTRACT_OLDOF( - vector const old_self = *this; - vector const old_other = other; - ) - boost::contract::type c = boost::contract::public_member(this) - .postcondition([&] () { + auto old_self = BOOST_CONTRACT_OLDOF(*this); + auto old_other = BOOST_CONTRACT_OLDOF(other); + auto = boost::contract::public_member(this) + .postcondition([&] { BOOST_CONTRACT_ASSERT( boost::contract::check_if >( &std::equal_to, other, old_self) diff --git a/include/boost/contract/assert.hpp b/include/boost/contract/assert.hpp index 518043e..2c0c457 100644 --- a/include/boost/contract/assert.hpp +++ b/include/boost/contract/assert.hpp @@ -2,30 +2,14 @@ #ifndef BOOST_CONTRACT_ASSERT_HPP_ #define BOOST_CONTRACT_ASSERT_HPP_ -#include -#include +#include #include -#include -#include /* PUBLIC */ -#if BOOST_PP_VARIADICS -# define BOOST_CONTRACT_ASSERT(...) BOOST_CONTRACT_ASSERT_((__VA_ARGS__)) -#else -# define BOOST_CONTRACT_ASSERT(cond) BOOST_CONTRACT_ASSERT_((cond)) -#endif - -/* PRIVATE */ - -#define BOOST_CONTRACT_ASSERT_(cond) \ - if(!cond) { \ - std::ostringstream BOOST_CONTRACT_AUX_NAME1(error); \ - BOOST_CONTRACT_AUX_NAME1(error) << "failed \"" << BOOST_PP_STRINGIZE( \ - cond) << "\" at " << __FILE__ << ":" << __LINE__; \ - throw boost::contract::aux::assertion_failure( \ - BOOST_CONTRACT_AUX_NAME1(error.str().c_str())); \ - } +#define BOOST_CONTRACT_ASSERT(condition) \ + if(!(condition)) throw boost::contract::assertion_failure( \ + __FILE__, __LINE__, BOOST_PP_STRINGIZE(condition)); #endif // #include guard diff --git a/include/boost/contract/aux_/check/pre_post_inv.hpp b/include/boost/contract/aux_/check/pre_post_inv.hpp index af6a8b3..d17773f 100644 --- a/include/boost/contract/aux_/check/pre_post_inv.hpp +++ b/include/boost/contract/aux_/check/pre_post_inv.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace boost { namespace contract { namespace aux { namespace check { diff --git a/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp b/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp index c032e3c..1689bfa 100644 --- a/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp +++ b/include/boost/contract/aux_/check/subcontracted_pre_post_inv.hpp @@ -28,14 +28,6 @@ #include #include -// TODO: Modelling after Clang message for assert() failure: -// assertion "(Key != boost::contract::aux::constructor)" failed: file "..\include/boost/contract/aux_/function.hpp", line 156 -// This library should say: -// precondition/postcondition/invariant/... "..." failed: file "...", line ... -// for exception classes precondition/postcondition/..._failure (inheriting from -// assertion_failure base exception to be thrown by CONTRACT_ASSERT) and failure -// handlers [set_]precondition_failed. - namespace boost { namespace contract { namespace aux { namespace check { template< diff --git a/include/boost/contract/aux_/exception.hpp b/include/boost/contract/aux_/exception.hpp index c75be94..26cfe34 100644 --- a/include/boost/contract/aux_/exception.hpp +++ b/include/boost/contract/aux_/exception.hpp @@ -2,19 +2,9 @@ #ifndef BOOST_CONTRACT_AUX_EXCEPTION_HPP_ #define BOOST_CONTRACT_AUX_EXCEPTION_HPP_ -#include -#include - namespace boost { namespace contract { namespace aux { -struct no_error {}; - -struct assertion_failure { - explicit assertion_failure ( char const* const what ) : what_(what) {} - const char* what ( ) const { return what_; } -private: - const char* const what_; -}; +struct no_error {}; // Do not inherit from anything (this is internal only). } } } // namespace diff --git a/include/boost/contract/aux_/set/nothing.hpp b/include/boost/contract/aux_/set/nothing.hpp deleted file mode 100644 index b197278..0000000 --- a/include/boost/contract/aux_/set/nothing.hpp +++ /dev/null @@ -1,31 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_SET_NOTHING_HPP_ -#define BOOST_CONTRACT_AUX_SET_NOTHING_HPP_ - -#include -#include - -namespace boost { - namespace contract { - class type; - } -} - -namespace boost { namespace contract { namespace aux { namespace set { - -class nothing { -public: - explicit nothing(boost::shared_ptr - const contract) : contract_(contract) {} - - // Allow to set nothing (neither pre, nor post). - -private: - friend class boost::contract::type; - boost::shared_ptr contract_; -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/set/post_only.hpp b/include/boost/contract/aux_/set/post_only.hpp deleted file mode 100644 index 6187e7a..0000000 --- a/include/boost/contract/aux_/set/post_only.hpp +++ /dev/null @@ -1,36 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_SET_POST_ONLY_HPP_ -#define BOOST_CONTRACT_AUX_SET_POST_ONLY_HPP_ - -#include -#include -#include - -namespace boost { - namespace contract { - class type; - } -} - -namespace boost { namespace contract { namespace aux { namespace set { - -class post_only { -public: - explicit post_only(boost::shared_ptr - const contract) : contract_(contract) {} - - template - boost::contract::aux::set::nothing postcondition(Pre const& post) { - contract_->set_post(post); - return boost::contract::aux::set::nothing(contract_); - } - -private: - friend class boost::contract::type; - boost::shared_ptr contract_; -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/set/pre_only.hpp b/include/boost/contract/aux_/set/pre_only.hpp deleted file mode 100644 index 2a2b0c5..0000000 --- a/include/boost/contract/aux_/set/pre_only.hpp +++ /dev/null @@ -1,36 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_SET_PRE_ONLY_HPP_ -#define BOOST_CONTRACT_AUX_SET_PRE_ONLY_HPP_ - -#include -#include -#include - -namespace boost { - namespace contract { - class type; - } -} - -namespace boost { namespace contract { namespace aux { namespace set { - -class pre_only { -public: - explicit pre_only(boost::shared_ptr - const contract) : contract_(contract) {} - - template - boost::contract::aux::set::nothing precondition(Pre const& pre) { - contract_->set_pre(pre); - return boost::contract::aux::set::nothing(contract_); - } - -private: - friend class boost::contract::type; - boost::shared_ptr contract_; -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/set/pre_post.hpp b/include/boost/contract/aux_/set/pre_post.hpp deleted file mode 100644 index c058cae..0000000 --- a/include/boost/contract/aux_/set/pre_post.hpp +++ /dev/null @@ -1,43 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_SET_PRE_POST_HPP_ -#define BOOST_CONTRACT_AUX_SET_PRE_POST_HPP_ - -#include -#include -#include -#include - -namespace boost { - namespace contract { - class type; - } -} - -namespace boost { namespace contract { namespace aux { namespace set { - -class pre_post { -public: - explicit pre_post(boost::shared_ptr - const contract) : contract_(contract) {} - - template - boost::contract::aux::set::post_only precondition(Pre const& pre) { - contract_->set_pre(pre); - return boost::contract::aux::set::post_only(contract_); - } - - template - boost::contract::aux::set::pre_only postcondition(Post const& post) { - contract_->set_post(post); - return boost::contract::aux::set::pre_only(contract_); - } - -private: - friend class boost::contract::type; - boost::shared_ptr contract_; -}; - -} } } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/base_types.hpp b/include/boost/contract/base_types.hpp index 4327d86..6595cab 100644 --- a/include/boost/contract/base_types.hpp +++ b/include/boost/contract/base_types.hpp @@ -4,7 +4,9 @@ #include #if !BOOST_PP_VARIADICS -# define BOOST_CONTRACT_BASE_TYPES ERROR_variadic_macros_required_by_BOOST_CONTRACT_BASE_TYPES_otherwise_manually_program_base_types + +#define BOOST_CONTRACT_BASE_TYPES BOOST_CONTRACT_ERROR_variadic_macros_required_by_BOOST_CONTRACT_BASE_TYPES_otherwise_manually_program_base_types + #else #include @@ -47,9 +49,6 @@ BOOST_CONTRACT_BASE_TYPES_ERR_ \ )(bases_tuple, bases_seq) -// TODO: Make sure all compile-time error names read BOOST_CONTRACT_ERROR_... -// (not just ERROR_... because that's not reserved for this library use). - #define BOOST_CONTRACT_BASE_TYPES_ERR_(bases_tuple, bases_seq) \ BOOST_CONTRACT_ERROR_all_bases_must_explicitly_specify_public_protected_or_private base_tuple diff --git a/include/boost/contract/config.hpp b/include/boost/contract/config.hpp index ef5a8dc..2c78594 100644 --- a/include/boost/contract/config.hpp +++ b/include/boost/contract/config.hpp @@ -2,6 +2,8 @@ #ifndef BOOST_CONTRACT_CONFIG_HPP_ #define BOOST_CONTRACT_CONFIG_HPP_ +// TODO: Implement NO_... macros to disable pre/post/inv-entry/inv-exit/etc. + // The name of the invariant member function ("invariant" by default). #ifndef BOOST_CONTRACT_CONFIG_INVARIANT # define BOOST_CONTRACT_CONFIG_INVARIANT invariant diff --git a/include/boost/contract/constructor.hpp b/include/boost/contract/constructor.hpp index d056725..78202a6 100644 --- a/include/boost/contract/constructor.hpp +++ b/include/boost/contract/constructor.hpp @@ -2,15 +2,15 @@ #ifndef BOOST_CONTRACT_CONSTRUCTOR_HPP_ #define BOOST_CONTRACT_CONSTRUCTOR_HPP_ +#include #include -#include #include namespace boost { namespace contract { template -boost::contract::aux::set::post_only constructor(Class* const object) { - return boost::contract::aux::set::post_only(boost::make_shared< +boost::contract::set::postcondition_only constructor(Class* const object) { + return boost::contract::set::postcondition_only(boost::make_shared< boost::contract::aux::function::constructor >(object)); } diff --git a/include/boost/contract/destructor.hpp b/include/boost/contract/destructor.hpp index 6bc7965..8dbbaf3 100644 --- a/include/boost/contract/destructor.hpp +++ b/include/boost/contract/destructor.hpp @@ -2,15 +2,15 @@ #ifndef BOOST_CONTRACT_DESTRUCTOR_HPP_ #define BOOST_CONTRACT_DESTRUCTOR_HPP_ +#include #include -#include #include namespace boost { namespace contract { template -boost::contract::aux::set::post_only destructor(Class* const object) { - return boost::contract::aux::set::post_only(boost::make_shared< +boost::contract::set::postcondition_only destructor(Class* const object) { + return boost::contract::set::postcondition_only(boost::make_shared< boost::contract::aux::function::destructor >(object)); } diff --git a/include/boost/contract/exception.hpp b/include/boost/contract/exception.hpp new file mode 100644 index 0000000..5e7ee43 --- /dev/null +++ b/include/boost/contract/exception.hpp @@ -0,0 +1,166 @@ + +#ifndef BOOST_CONTRACT_EXCEPTION_HPP_ +#define BOOST_CONTRACT_EXCEPTION_HPP_ + +#include +#include +#include +#include + +// TODO: Implement set_precondition/postcondition/invariant/entry_invariant/ +// exit_invariant_failed handlers. + +namespace boost { namespace contract { + +// Exceptions. + +struct assertion_failure : public std::exception { + explicit assertion_failure(char const* const file = "", + unsigned long const line = 0, char const* const code = "") : + file_(file), line_(line), code_(code) + { init(); } + + explicit assertion_failure(char const* const code) : + file_(""), line_(0), code_(code) + { init(); } + + virtual ~assertion_failue() {} + + // Return `assertion "XYZ" failed: file "ABC", line 123`. + virtual char const* const what() const { return what_.c_str(); } + + char const* const file() const { return file_; } + unsigned long line() const { return line_; } + char const* const code() const { return code_; } + +private: + void init() { + what_ = "assertion"; + if(std::string(code_) != "") what_ += " \"" + code_ + "\""; + what_ += " failed"; + if(std::string(file_) != "") { + what_ += ": \"" + file_ + "\""; + if(line != 0) what_ += ", line " + std::string(line_); + } + } + + char const* const file_; + unsigned long const line_; + char const* const code_; + std::string what_; +}; + +struct precondition_failure : public assertion_failure { + explicit precondition_failure(assertion_failure const& failure) : + assertion_failure(failure) { + what_ = "precondition " + assertion_failure::what(); + } + virtual char const* const what() const { return what_.c_str(); } +private: + std::string what_; +}; + +struct postcondition_failure : public assertion_failure { + explicit postcondition_failure(assertion_failure const& failure) : + assertion_failure(failure) { + what_ = "postcondition " + assertion_failure::what(); + } + virtual char const* const what() const { return what_.c_str(); } +private: + std::string what_; +}; + +struct invariant_failure : public assertion_failure {}; + +struct entry_invariant_failure : public assertion_failure { + explicit entry_invariant_failure(assertion_failure const& failure) : + assertion_failure(failure) { + what_ = "exit invariant " + assertion_failure::what(); + } + virtual char const* const what() const { return what_.c_str(); } +private: + std::string what_; +}; + +struct exit_invariant_failure : public assertion_failure { + explicit exit_invariant_failure(assertion_failure const& failure) : + assertion_failure(failure) { + what_ = "exit invariant " + assertion_failure::what(); + } + virtual char const* const what() const { return what_.c_str(); } +private: + std::string what_; +}; + +// Handlers. + +enum from { + from_constructor, + from_destructor, + from_public_member, + from_protected_member, + from_private_member, + from_free_function +}; + +typedef void (*failure_handler)(from); + +// TODO: These are part of the lib state. They should prob be put in a .cpp and +// exported (so they are the same across DLL, etc.), plus they should be +// protected by mutexes. +namespace aux { + void default_handler(from const) { + try { + throw; + } catch(boost::contract::failure const& error) { + std::cerr << error.what() << std::endl; + std::terminate(); + } catch(...) { + std::terminate(); + } + } + + failure_hander precondition_failure_handler = &default_handler; + failure_hander postcondition_failure_handler = &default_handler; + failure_hander entry_invariant_failure_handler = &default_handler; + failure_hander exit_invariant_failure_handler = &default_handler; +} + +failure_handler set_precondition_failure(failure_handler f) + BOOST_NOEXCEPT_OR_NOTHROW { + failure_handler result = boost::contract::aux::precondition_failure_handler; + boost::contract::aux::precondition_failure_handler = f; + return result; +} + +failure_handler set_postcondition_failure(failure_handler f) + BOOST_NOEXCEPT_OR_NOTHROW { + failure_handler result = boost::contract::aux:: + postcondition_failure_handler; + boost::contract::aux::postcondition_failure_handler = f; + return result; +} + +failure_handler set_entry_invariant_failure(failure_handler f) + BOOST_NOEXCEPT_OR_NOTHROW { + failure_handler result = boost::contract::aux:: + entry_invariant_failure_handler; + boost::contract::aux::entry_invariant_failure_handler = f; + return result; +} + +failure_handler set_exit_invariant_failure(failure_handler f) + BOOST_NOEXCEPT_OR_NOTHROW { + failure_handler result = boost::contract::aux:: + exit_invariant_failure_handler; + boost::contract::aux::exit_invariant_failure_handler = f; + return result; +} + +void set_invariant_failure(failure_handler f) BOOST_NOEXCEPT_OR_NOTHROW { + set_entry_invariant_failure(f); + set_exit_invariant_failure(f); +} + +} } // namespace + diff --git a/include/boost/contract/free_function.hpp b/include/boost/contract/free_function.hpp index 09935cd..4d634b4 100644 --- a/include/boost/contract/free_function.hpp +++ b/include/boost/contract/free_function.hpp @@ -2,14 +2,14 @@ #ifndef BOOST_CONTRACT_FREE_FUNCTION_HPP_ #define BOOST_CONTRACT_FREE_FUNCTION_HPP_ +#include #include -#include #include namespace boost { namespace contract { -boost::contract::aux::set::pre_post free_function() { - return boost::contract::aux::set::pre_post(boost::make_shared< +boost::contract::set::precondition_postcondition free_function() { + return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::free_function>()); } diff --git a/include/boost/contract/oldof.hpp b/include/boost/contract/oldof.hpp new file mode 100644 index 0000000..25c44a1 --- /dev/null +++ b/include/boost/contract/oldof.hpp @@ -0,0 +1,136 @@ + +#ifndef BOOST_CONTRACT_OLDOF_HPP_ +#define BOOST_CONTRACT_OLDOF_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// IMPORTANT: Following old-of templates and macros ensure that: +// 1. Old-value expressions are evaluated only once and only when old-of +// should not be skipped. +// 2. Old-values are copied only once (using old-value type copy constructor) +// and only when old-of should not be skipped. +// Old-of are skipped if either postconditions are disabled all together (see +// also CONFIG_NO_POSTCONDITONS), or if virtual-body functions are called to +// not check postconditions (as controlled by the "v" extra parameter). + +#if !BOOST_PP_VARIADICS + +#define BOOST_CONTRACT_OLDOF BOOST_CONTRACT_ERROR_variadic_macros_required_by_BOOST_CONTRACT_OLDOF_otherwise_manually_program_old_values + +#else + +#include +#include + +/* PUBLIC */ + +#define BOOST_CONTRACT_OLDOF(...) \ + BOOST_PP_OVERLOAD( \ +BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_, \ + __VA_ARGS__)(__VA_ARGS__) + +/* PRIVATE */ + +#ifdef BOOST_NO_CXX11_AUTO_DECLARATIONS +# define BOOST_CONTRACT_OLDOF_TYPEOF_(value) /* nothing */ +#else +# include +# define BOOST_CONTRACT_OLDOF_TYPEOF_(value) BOOST_TYPEOF(value) +#endif + +// NOTE: Following are not local macros, do NOT #undef them. These macro names +// are use so all variadic macro argument numbers > 2 will generate appropriate +// ERROR symbols. + +#define \ +BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_2( \ + v_opt, value) \ + (boost::contract::skip_oldof(v_opt) ? boost::contract::oldof< \ + BOOST_CONTRACT_OLDOF_TYPEOF_((value))>() : (value)) + +#define \ +BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_1( \ + value) \ +BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_2( \ + BOOST_PP_EMPTY(), value) + +#endif // VARIADICS + +/* CODE */ + +namespace boost { namespace contract { + +template class oldof; + +// Used on compilers that do not support auto decl./type-of to erase old-value +// type T (and later un-erase it via pointer cast in oldof template below). +template<> +class oldof { +public: + oldof() : ptr_() {} + + template // This make_shared calls T's copy ctor. + oldof(T const& value) : ptr_(boost::make_shared(value)) {} + +private: + boost::shared_ptr ptr_; + + template friend class oldof; // Within same template family. +}; + +template +class oldof { +public: + oldof() : ptr_() {} + + // This make_shared calls T's copy ctor. + oldof(T const& value) : ptr_(boost::make_shared(value)) {} + + // This casts the pointer (to un-erase the type), so no T copy here. + oldof(oldof const& old) : + ptr_(boost::static_pointer_cast(old.ptr_)) {} + + // Add const because contracts should not modify old-values. + + typename boost::add_const::type& operator*() const { return *ptr_; } + + typename boost::add_const::type* const operator->() const { + return ptr_.get(); + } + +private: + boost::shared_ptr ptr_; +}; + +bool skip_oldof(boost::contract::virtual_body const v) { +#ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS + return true; // Never check post, so old-of never needed. +#else + if(v == boost::contract::virtual_body::user_call || + v == boost::contract::virtual_body::check_post_only) { + return false; // Checking post, so old-of needed. + } + return true; // Not checking post, so old-of not needed. +#endif +} + +bool skip_oldof() { +#ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS + return true; // Never check post, so old-of never needed. +#else + return false; // Contracts of virtual-body functions, always check post. +#endif +} + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/private_member.hpp b/include/boost/contract/private_member.hpp index c051bfb..762fb17 100644 --- a/include/boost/contract/private_member.hpp +++ b/include/boost/contract/private_member.hpp @@ -2,16 +2,16 @@ #ifndef BOOST_CONTRACT_PRIVATE_MEMBER_HPP_ #define BOOST_CONTRACT_PRIVATE_MEMBER_HPP_ +#include #include -#include #include // TOOD: On C++11 Clang... these could static_assert enclosing func is not pub? namespace boost { namespace contract { -boost::contract::aux::set::pre_post private_member() { - return boost::contract::aux::set::pre_post(boost::make_shared< +boost::contract::set::precondition_postcondition private_member() { + return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::private_member>()); } diff --git a/include/boost/contract/protected_member.hpp b/include/boost/contract/protected_member.hpp index e12281d..b5c44fe 100644 --- a/include/boost/contract/protected_member.hpp +++ b/include/boost/contract/protected_member.hpp @@ -2,16 +2,16 @@ #ifndef BOOST_CONTRACT_PROTECTED_MEMBER_HPP_ #define BOOST_CONTRACT_PROTECTED_MEMBER_HPP_ +#include #include -#include #include // TOOD: On C++11 Clang... these could static_assert enclosing func is not pub? namespace boost { namespace contract { -boost::contract::aux::set::pre_post protected_member() { - return boost::contract::aux::set::pre_post(boost::make_shared< +boost::contract::set::precondition_postcondition protected_member() { + return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::protected_member>()); } diff --git a/include/boost/contract/public_member.hpp b/include/boost/contract/public_member.hpp index f5b6aca..be7b57c 100644 --- a/include/boost/contract/public_member.hpp +++ b/include/boost/contract/public_member.hpp @@ -2,10 +2,10 @@ #ifndef BOOST_CONTRACT_PUBLIC_MEMBER_HPP_ #define BOOST_CONTRACT_PUBLIC_MEMBER_HPP_ +#include #include #include #include -#include #include // TODO: On C++11 Clang... these could static_assert enclosing func is pub? @@ -40,23 +40,24 @@ namespace boost { namespace contract { // also if there are no base classes). template -boost::contract::aux::set::pre_post public_member(Class* const object, Function - const&, Argument0 argument0, boost::contract::virtual_body const v) { - return boost::contract::aux::set::pre_post(boost::make_shared< +boost::contract::set::precondition_postcondition public_member( + Class* const object, Function const&, Argument0 argument0, + boost::contract::virtual_body const v +) { + return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_member >(v, object, argument0) ); } - // Contract for public member functions with a non-virtual body and members of a // class that inherits from one or more base classes (optionally, it can be used // also if there are no base classes). template -boost::contract::aux::set::pre_post public_member(Class* const object, Function - const&, Argument0 argument0) { - return boost::contract::aux::set::pre_post(boost::make_shared< +boost::contract::set::precondition_postcondition public_member( + Class* const object, Function const&, Argument0 argument0) { + return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_member >(object, argument0) ); @@ -65,24 +66,25 @@ boost::contract::aux::set::pre_post public_member(Class* const object, Function // Contract for public member functions with a virtual body and members of a // class that does not inherits from any base class. template -boost::contract::aux::set::pre_post public_member(Class* const object, - boost::contract::virtual_body const v) { - return boost::contract::aux::set::pre_post(boost::make_shared< +boost::contract::set::precondition_postcondition public_member( + Class* const object, boost::contract::virtual_body const v) { + return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_member >(v, object)); } // Contract for public member functions with a non-virtual body and members of a // class that does not inherits from any base class. template -boost::contract::aux::set::pre_post public_member(Class* const object) { - return boost::contract::aux::set::pre_post(boost::make_shared< +boost::contract::set::precondition_postcondition public_member( + Class* const object) { + return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_member >(object)); } // Contract for public static member functions. template -boost::contract::aux::set::pre_post public_member() { - return boost::contract::aux::set::pre_post(boost::make_shared< +boost::contract::set::precondition_postcondition public_member() { + return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_static_member >()); } diff --git a/include/boost/contract/set/nothing.hpp b/include/boost/contract/set/nothing.hpp new file mode 100644 index 0000000..9df1775 --- /dev/null +++ b/include/boost/contract/set/nothing.hpp @@ -0,0 +1,45 @@ + +#ifndef BOOST_CONTRACT_SET_NOTHING_HPP_ +#define BOOST_CONTRACT_SET_NOTHING_HPP_ + +#include +#include + +namespace boost { + namespace contract { + class type; + + namespace set { + class precondition_only; + class postcondition_only; + } + } +} + +namespace boost { namespace contract { namespace set { + +class nothing { +public: + // Allow to set nothing (neither precondition, nor postcondition). + +private: + explicit nothing(boost::shared_ptr + const contract) : contract_(contract) {} + + /* implicit */ nothing(nothing const& other) : contract_(other.contract_) {} + nothing& operator=(nothing const&) /* = delete */; + nothing() /* = delete */; + + boost::shared_ptr contract_; + + // Use friendship and deleted constructors to limit public API. + + friend class boost::contract::type; + friend class boost::contract::set::precondition_only; + friend class boost::contract::set::postcondition_only; +}; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/set/postcondition_only.hpp b/include/boost/contract/set/postcondition_only.hpp new file mode 100644 index 0000000..d5a0d31 --- /dev/null +++ b/include/boost/contract/set/postcondition_only.hpp @@ -0,0 +1,61 @@ + +#ifndef BOOST_CONTRACT_SET_POSTCONDITION_ONLY_HPP_ +#define BOOST_CONTRACT_SET_POSTCONDITION_ONLY_HPP_ + +#include +#include +#include + +namespace boost { + namespace contract { + class type; + + template + boost::contract::set::postcondition_only constructor(Class* const); + + template + boost::contract::set::postcondition_only destructor(Class* const); + + namespace set { + class precondition_postcondition; + } + } +} + +namespace boost { namespace contract { namespace set { + +class postcondition_only { +public: + template + boost::contract::set::nothing postcondition(Postcondition const& f) { + contract_->set_post(f); + return boost::contract::set::nothing(contract_); + } + +private: + explicit postcondition_only(boost::shared_ptr const contract) : contract_(contract) {} + + /* implicit */ postcondition_only(postcondition_only const& other) : + contract_(other.contract_) {} + postcondition_only& operator=(postcondition_only const&) /* = delete */; + postcondition_only() /* = delete */; + + boost::shared_ptr contract_; + + // Use friendship and deleted constructors to limit public API. + + friend class boost::contract::type; + friend class boost::contract::set::precondition_postcondition; + + template + friend postcondition_only boost::contract::constructor(Class* const); + + template + friend postcondition_only boost::contract::destructor(Class* const); +}; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/set/precondition_only.hpp b/include/boost/contract/set/precondition_only.hpp new file mode 100644 index 0000000..1006952 --- /dev/null +++ b/include/boost/contract/set/precondition_only.hpp @@ -0,0 +1,49 @@ + +#ifndef BOOST_CONTRACT_SET_PRECONDITION_ONLY_HPP_ +#define BOOST_CONTRACT_SET_PRECONDITION_ONLY_HPP_ + +#include +#include +#include + +namespace boost { + namespace contract { + class type; + + namespace set { + class precondition_postcondition; + } + } +} + +namespace boost { namespace contract { namespace set { + +class precondition_only { +public: + template + boost::contract::set::nothing precondition(Precondition const& f) { + contract_->set_pre(f); + return boost::contract::set::nothing(contract_); + } + +private: + explicit precondition_only(boost::shared_ptr const contract) : contract_(contract) {} + + /* implicit */ precondition_only(precondition_only const& other) : + contract_(other.contract_) {} + precondition_only& operator=(precondition_only const&) /* = delete */; + precondition_only() /* = delete */; + + boost::shared_ptr contract_; + + // Use friendship and deleted constructors to limit public API. + + friend class boost::contract::type; + friend class boost::contract::set::precondition_postcondition; +}; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/set/precondition_postcondition.hpp b/include/boost/contract/set/precondition_postcondition.hpp new file mode 100644 index 0000000..e76aa38 --- /dev/null +++ b/include/boost/contract/set/precondition_postcondition.hpp @@ -0,0 +1,109 @@ + +#ifndef BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ +#define BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ + +#include +#include +#include +#include + +namespace boost { + namespace contract { + class type; + class virtual_body; + + template + boost::contract::set::precondition_postcondition public_member( + Class* const, Function const&, Argument0, + boost::contract::virtual_body const + ); + + template + boost::contract::set::precondition_postcondition public_member( + Class* const, Function const&, Argument0); + + template + boost::contract::set::precondition_postcondition public_member( + Class* const, boost::contract::virtual_body const); + + template + boost::contract::set::precondition_postcondition public_member( + Class* const); + + template + boost::contract::set::precondition_postcondition public_member(); + + boost::contract::set::precondition_postcondition protected_member(); + boost::contract::set::precondition_postcondition private_member(); + boost::contract::set::precondition_postcondition free_function(); + } +} + +namespace boost { namespace contract { namespace set { + +class precondition_postcondition { +public: + template + boost::contract::set::postcondition_only precondition( + Precondition const& f) { + contract_->set_pre(f); + return boost::contract::set::postcondition_only(contract_); + } + + template + boost::contract::set::precondition_only postcondition( + Postcondition const& f) { + contract_->set_post(f); + return boost::contract::set::precondition_only(contract_); + } + +private: + explicit precondition_postcondition(boost::shared_ptr const contract) : contract_(contract) {} + + /* implicit */ precondition_postcondition(precondition_postcondition const& + other) : contract_(other.contract_) {} + precondition_postcondition& operator=(precondition_postcondition const&) + /* = delete */; + precondition_postcondition() /* = delete */; + + boost::shared_ptr contract_; + + // Use friendship and deleted constructors to limit public API. + + friend class boost::contract::type; + + template + friend precondition_postcondition boost::contract::public_member( + Class* const, Function const&, Argument0, + boost::contract::virtual_body const + ); + + template + friend precondition_postcondition boost::contract::public_member( + Class* const, Function const&, Argument0); + + template + friend precondition_postcondition boost::contract::public_member( + Class* const, boost::contract::virtual_body const); + + template + friend precondition_postcondition boost::contract::public_member( + Class* const); + + template + friend precondition_postcondition boost::contract::public_member(); + + friend precondition_postcondition boost::contract::protected_member(); + friend precondition_postcondition boost::contract::private_member(); + friend precondition_postcondition boost::contract::free_function(); +}; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/type.hpp b/include/boost/contract/type.hpp index a5b1f4f..df02319 100644 --- a/include/boost/contract/type.hpp +++ b/include/boost/contract/type.hpp @@ -2,28 +2,28 @@ #ifndef BOOST_CONTRACT_TYPE_HPP_ #define BOOST_CONTRACT_TYPE_HPP_ -#include -#include -#include -#include +#include +#include +#include +#include #include #include namespace boost { namespace contract { -class type { // This can be copied (as shallow smart pointer copy). +class type { // Must allow copy for `type c = ...` (shallow smart ptr copy). public: - /* implicit */ type(boost::contract::aux::set::pre_post const& pre_post) : - contract_(pre_post.contract_) {} + /* implicit */ type(boost::contract::set::precondition_postcondition const& + c) : contract_(c.contract_) {} - /* implicit */ type(boost::contract::aux::set::pre_only const& pre_only) : - contract_(pre_only.contract_) {} + /* implicit */ type(boost::contract::set::precondition_only const& + c) : contract_(c.contract_) {} - /* implicit */ type(boost::contract::aux::set::post_only const& post_only) : - contract_(post_only.contract_) {} + /* implicit */ type(boost::contract::set::postcondition_only const& + c) : contract_(c.contract_) {} - /* implicit */ type(boost::contract::aux::set::nothing const& nothing) : - contract_(nothing.contract_) {} + /* implicit */ type(boost::contract::set::nothing const& + c) : contract_(c.contract_) {} private: boost::shared_ptr contract_; diff --git a/include/boost/contract/virtual_body.hpp b/include/boost/contract/virtual_body.hpp index f0d4b2c..69bbad8 100644 --- a/include/boost/contract/virtual_body.hpp +++ b/include/boost/contract/virtual_body.hpp @@ -20,19 +20,11 @@ namespace boost { namespace boost { namespace contract { // Must be efficient to pass this as value param (to limit user API verbosity). -struct virtual_body { +class virtual_body { +public: /* implicit */ virtual_body(int const) : action(user_call) {} - // TODO: Fix old-of... but how? - template - T const oldof_(T const& value) const { return value; } - private: - template friend class - boost::contract::aux::check::subcontracted_pre_post_inv; - template friend class - boost::contract::aux::function::public_member; - enum action_type { user_call, check_inv_only, @@ -44,6 +36,16 @@ private: action(an_action) {} action_type action; + + // Use friendship to limit public API. + + template + friend class boost::contract::aux::check::subcontracted_pre_post_inv; + + template + friend class boost::contract::aux::function::public_member; + + friend bool skip_oldof(virtual_body const); }; } } // namespace diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 3e6bf4b..96611c4 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -15,5 +15,12 @@ run public_member_bases_static.cpp ; run protected_member_bases.cpp ; run private_member_bases.cpp ; -run free_function.cpp ; +run free_function/call.cpp ; +run free_function/set.cpp ; +compile-fail free_function/set_pre_pre_error.cpp ; +compile-fail free_function/set_pre_post_pre_error.cpp ; +compile-fail free_function/set_post_pre_pre_error.cpp ; +compile-fail free_function/set_post_post_error.cpp ; +compile-fail free_function/set_post_pre_post_error.cpp ; +compile-fail free_function/set_pre_post_post_error.cpp ; diff --git a/test/constructor/Jamfile.v2 b/test/constructor/Jamfile.v2 new file mode 100644 index 0000000..4c0e50c --- /dev/null +++ b/test/constructor/Jamfile.v2 @@ -0,0 +1,9 @@ + +import testing ; + +run with_bases.cpp ; +run set.cpp ; +compile-fail set_pre_error.cpp ; +compile-fail set_post_pre_error.cpp ; +compile-fail set_post_post_error.cpp ; + diff --git a/test/constructor/set.cpp b/test/constructor/set.cpp new file mode 100644 index 0000000..ed5649d --- /dev/null +++ b/test/constructor/set.cpp @@ -0,0 +1,95 @@ + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +// Test all possible orders in which pre/post can be set. + +boost::contract::aux::test::oteststream out; + +struct nothing { + void invariant() const { out << "inv" << std::endl; } + static void static_invariant() { out << "static_inv" << std::endl; } + + explicit nothing() { + boost::contract::type c = boost::contract::constructor(this); + out << "body" << std::endl; + } +}; + +struct pre_only : private boost::contract::constructor_precondition { + void invariant() const { out << "inv" << std::endl; } + static void static_invariant() { out << "static_inv" << std::endl; } + + explicit pre_only() : + boost::contract::constructor_precondition([&] { + out << "pre" << std::endl; + }) + { + boost::contract::type c = boost::contract::constructor(this); + out << "body" << std::endl; + } +}; + +struct post_only { + void invariant() const { out << "inv" << std::endl; } + static void static_invariant() { out << "static_inv" << std::endl; } + + explicit post_only() { + boost::contract::type c = boost::contract::constructor(this) + .postcondition([&] { out << "post" << std::endl; }) + ; + out << "body" << std::endl; + } +}; + +struct pre_post : private boost::contract::constructor_precondition { + void invariant() const { out << "inv" << std::endl; } + static void static_invariant() { out << "static_inv" << std::endl; } + + explicit pre_post() : + boost::contract::constructor_precondition([&] { + out << "pre" << std::endl; + }) + { + boost::contract::type c = boost::contract::constructor(this) + .postcondition([&] { out << "post" << std::endl; }) + ; + out << "body" << std::endl; + } +}; + +int main() { + std::ostringstream ok; + + out.str(""); + nothing n; + ok.str(""); ok << "static_inv" << std::endl << "body" << std::endl << + "static_inv" << std::endl << "inv" << std::endl; + BOOST_TEST(out.check(ok.str())); + + out.str(""); + pre_only e; + ok.str(""); ok << "pre" << std::endl << "static_inv" << std::endl << "body" + << std::endl << "static_inv" << std::endl << "inv" << std::endl; + BOOST_TEST(out.check(ok.str())); + + out.str(""); + post_only o; + ok.str(""); ok << "static_inv" << std::endl << "body" << std::endl << + "static_inv" << std::endl << "inv" << std::endl << "post" << + std::endl; + BOOST_TEST(out.check(ok.str())); + + out.str(""); + pre_post pp; + ok.str(""); ok << "pre" << std::endl << "static_inv" << std::endl << "body" + << std::endl << "static_inv" << std::endl << "inv" << std::endl << + "post" << std::endl; + BOOST_TEST(out.check(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/constructor/set_post_post_error.cpp b/test/constructor/set_post_post_error.cpp new file mode 100644 index 0000000..e3cceb8 --- /dev/null +++ b/test/constructor/set_post_post_error.cpp @@ -0,0 +1,20 @@ + +#include +#include + +// Test double post error. + +struct a { + explicit a() { + boost::contract::type c = boost::contract::constructor(this) + .postcondition([&] {}) + .postcondition([&] {}) + ; + } +}; + +int main() { + a aa; + return 0; +} + diff --git a/test/constructor/set_post_pre_error.cpp b/test/constructor/set_post_pre_error.cpp new file mode 100644 index 0000000..79c0e13 --- /dev/null +++ b/test/constructor/set_post_pre_error.cpp @@ -0,0 +1,20 @@ + +#include +#include + +// Test pre after post error (must use constructor_precondition instead). + +struct a { + explicit a() { + boost::contract::type c = boost::contract::constructor(this) + .postcondition([&] {}) + .precondition([&] {}) + ; + } +}; + +int main() { + a aa; + return 0; +} + diff --git a/test/constructor/set_pre_error.cpp b/test/constructor/set_pre_error.cpp new file mode 100644 index 0000000..a47eebf --- /dev/null +++ b/test/constructor/set_pre_error.cpp @@ -0,0 +1,19 @@ + +#include +#include + +// Test pre error (must use constructor_precondition instead). + +struct a { + explicit a() { + boost::contract::type c = boost::contract::constructor(this) + .precondition([&] {}) + ; + } +}; + +int main() { + a aa; + return 0; +} + diff --git a/test/constructor_bases.cpp b/test/constructor/with_bases.cpp similarity index 99% rename from test/constructor_bases.cpp rename to test/constructor/with_bases.cpp index b4f2b9b..4b0d668 100644 --- a/test/constructor_bases.cpp +++ b/test/constructor/with_bases.cpp @@ -1,5 +1,5 @@ -#include "aux_/oteststream.hpp" +#include "../aux_/oteststream.hpp" #include #include #include diff --git a/test/free_function/Jamfile.v2 b/test/free_function/Jamfile.v2 new file mode 100644 index 0000000..d455828 --- /dev/null +++ b/test/free_function/Jamfile.v2 @@ -0,0 +1,12 @@ + +import testing ; + +run call.cpp ; +run set.cpp ; +compile-fail set_pre_pre_error.cpp ; +compile-fail set_pre_post_pre_error.cpp ; +compile-fail set_post_pre_pre_error.cpp ; +compile-fail set_post_post_error.cpp ; +compile-fail set_post_pre_post_error.cpp ; +compile-fail set_pre_post_post_error.cpp ; + diff --git a/test/free_function.cpp b/test/free_function/call.cpp similarity index 95% rename from test/free_function.cpp rename to test/free_function/call.cpp index 3a685cb..1fe9685 100644 --- a/test/free_function.cpp +++ b/test/free_function/call.cpp @@ -1,5 +1,5 @@ -#include "aux_/oteststream.hpp" +#include "../aux_/oteststream.hpp" #include #include #include diff --git a/test/free_function/set.cpp b/test/free_function/set.cpp new file mode 100644 index 0000000..dd724f6 --- /dev/null +++ b/test/free_function/set.cpp @@ -0,0 +1,81 @@ + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +// Test free-function with neither pre nor post set. +void nothing() { + boost::contract::type c = boost::contract::free_function(); + out << "body" << std::endl; +} + +// Test free-function with only pre set. +void pre_only() { + boost::contract::type c = boost::contract::free_function() + .precondition([&] { out << "pre" << std::endl; }) + ; + out << "body" << std::endl; +} + +// Test free-function with only post set. +void post_only() { + boost::contract::type c = boost::contract::free_function() + .postcondition([&] { out << "post" << std::endl; }) + ; + out << "body" << std::endl; +} + +// Test free-function with pre set before post. +void pre_post() { + boost::contract::type c = boost::contract::free_function() + .precondition([&] { out << "pre" << std::endl; }) + .postcondition([&] { out << "post" << std::endl; }) + ; + out << "body" << std::endl; +} + +// Test free-function with post set before pre. +void post_pre() { + boost::contract::type c = boost::contract::free_function() + .postcondition([&] { out << "post" << std::endl; }) + .precondition([&] { out << "pre" << std::endl; }) + ; + out << "body" << std::endl; +} + +int main() { + std::ostringstream ok; + + out.str(""); + nothing(); + ok.str(""); ok << "body" << std::endl; + BOOST_TEST(out.check(ok.str())); + + out.str(""); + pre_only(); + ok.str(""); ok << "pre" << std::endl << "body" << std::endl; + BOOST_TEST(out.check(ok.str())); + + out.str(""); + post_only(); + ok.str(""); ok << "body" << std::endl << "post" << std::endl; + BOOST_TEST(out.check(ok.str())); + + ok.str(""); ok << "pre" << std::endl << "body" << std::endl << "post" << + std::endl; + + out.str(""); + pre_post(); + BOOST_TEST(out.check(ok.str())); + + out.str(""); + post_pre(); + BOOST_TEST(out.check(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/free_function/set_post_post_error.cpp b/test/free_function/set_post_post_error.cpp new file mode 100644 index 0000000..cf21cdb --- /dev/null +++ b/test/free_function/set_post_post_error.cpp @@ -0,0 +1,12 @@ + +#include +#include + +int main() { + boost::contract::type c = boost::contract::free_function() + .postcondition([&] {}) + .postcondition([&] {}) + ; + return 0; +} + diff --git a/test/free_function/set_post_pre_post_error.cpp b/test/free_function/set_post_pre_post_error.cpp new file mode 100644 index 0000000..bde2186 --- /dev/null +++ b/test/free_function/set_post_pre_post_error.cpp @@ -0,0 +1,13 @@ + +#include +#include + +int main() { + boost::contract::type c = boost::contract::free_function() + .postcondition([&] {}) + .precondition([&] {}) + .postcondition([&] {}) + ; + return 0; +} + diff --git a/test/free_function/set_post_pre_pre_error.cpp b/test/free_function/set_post_pre_pre_error.cpp new file mode 100644 index 0000000..27d9d5f --- /dev/null +++ b/test/free_function/set_post_pre_pre_error.cpp @@ -0,0 +1,13 @@ + +#include +#include + +int main() { + boost::contract::type c = boost::contract::free_function() + .postcondition([&] {}) + .precondition([&] {}) + .precondition([&] {}) + ; + return 0; +} + diff --git a/test/free_function/set_pre_post_post_error.cpp b/test/free_function/set_pre_post_post_error.cpp new file mode 100644 index 0000000..f137048 --- /dev/null +++ b/test/free_function/set_pre_post_post_error.cpp @@ -0,0 +1,13 @@ + +#include +#include + +int main() { + boost::contract::type c = boost::contract::free_function() + .precondition([&] {}) + .postcondition([&] {}) + .postcondition([&] {}) + ; + return 0; +} + diff --git a/test/free_function/set_pre_post_pre_error.cpp b/test/free_function/set_pre_post_pre_error.cpp new file mode 100644 index 0000000..fa59bfe --- /dev/null +++ b/test/free_function/set_pre_post_pre_error.cpp @@ -0,0 +1,13 @@ + +#include +#include + +int main() { + boost::contract::type c = boost::contract::free_function() + .precondition([&] {}) + .postcondition([&] {}) + .precondition([&] {}) + ; + return 0; +} + diff --git a/test/free_function/set_pre_pre_error.cpp b/test/free_function/set_pre_pre_error.cpp new file mode 100644 index 0000000..f8db4c5 --- /dev/null +++ b/test/free_function/set_pre_pre_error.cpp @@ -0,0 +1,12 @@ + +#include +#include + +int main() { + boost::contract::type c = boost::contract::free_function() + .precondition([&] {}) + .precondition([&] {}) + ; + return 0; +} +