mirror of
https://github.com/boostorg/contract.git
synced 2026-02-27 04:52:22 +00:00
fixed a bug with old value copies from .old(...) by storing them in a queue instead of a stack (same was already done for old value copies from init code outside .old(...))
This commit is contained in:
@@ -21,7 +21,6 @@ Facility to declare virtual public functions with contracts.
|
||||
!defined(BOOST_CONTRACT_NO_EXCEPTS)
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
@@ -84,10 +83,13 @@ class virtual_ : private boost::noncopyable { // Avoid copy queue, stack, etc.
|
||||
#endif
|
||||
#if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
|
||||
!defined(BOOST_CONTRACT_NO_EXCEPTS)
|
||||
push_old_init,
|
||||
call_old_copy,
|
||||
push_old_copy,
|
||||
pop_old_copy,
|
||||
// For outside .old(...).
|
||||
push_old_init_copy,
|
||||
// pop_old_init_copy as static function below.
|
||||
// For inside .old(...).
|
||||
call_old_ftor,
|
||||
push_old_ftor_copy,
|
||||
pop_old_ftor_copy,
|
||||
#endif
|
||||
#ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
|
||||
check_post,
|
||||
@@ -100,7 +102,7 @@ class virtual_ : private boost::noncopyable { // Avoid copy queue, stack, etc.
|
||||
#if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
|
||||
!defined(BOOST_CONTRACT_NO_EXCEPTS)
|
||||
// Not just an enum value because the logical combination of two values.
|
||||
inline static bool pop_old_init(action_enum a) {
|
||||
inline static bool pop_old_init_copy(action_enum a) {
|
||||
return
|
||||
#ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
|
||||
a == check_post
|
||||
@@ -139,8 +141,8 @@ class virtual_ : private boost::noncopyable { // Avoid copy queue, stack, etc.
|
||||
#endif
|
||||
#if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
|
||||
!defined(BOOST_CONTRACT_NO_EXCEPTS)
|
||||
std::queue<boost::shared_ptr<void> > old_inits_;
|
||||
std::stack<boost::shared_ptr<void> > old_copies_;
|
||||
std::queue<boost::shared_ptr<void> > old_init_copies_;
|
||||
std::queue<boost::shared_ptr<void> > old_ftor_copies_;
|
||||
#endif
|
||||
#ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
|
||||
boost::any result_ptr_; // Result for virtual and overriding functions.
|
||||
|
||||
@@ -203,7 +203,7 @@ protected:
|
||||
#ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
|
||||
void init_subcontracted_old() {
|
||||
// Old values of overloaded func on stack (so no `f` param here).
|
||||
exec_and(boost::contract::virtual_::push_old_init);
|
||||
exec_and(boost::contract::virtual_::push_old_init_copy);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -227,7 +227,7 @@ protected:
|
||||
#if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
|
||||
!defined(BOOST_CONTRACT_NO_EXCEPTS)
|
||||
void copy_subcontracted_old() {
|
||||
exec_and(boost::contract::virtual_::call_old_copy,
|
||||
exec_and(boost::contract::virtual_::call_old_ftor,
|
||||
&cond_with_subcontracting::copy_virtual_old);
|
||||
}
|
||||
#endif
|
||||
@@ -277,7 +277,7 @@ private:
|
||||
boost::contract::virtual_::action_enum a;
|
||||
if(base_call_) {
|
||||
a = v_->action_;
|
||||
v_->action_ = boost::contract::virtual_::push_old_copy;
|
||||
v_->action_ = boost::contract::virtual_::push_old_ftor_copy;
|
||||
}
|
||||
this->copy_old();
|
||||
if(base_call_) v_->action_ = a;
|
||||
@@ -286,7 +286,7 @@ private:
|
||||
void pop_base_old() {
|
||||
if(base_call_) {
|
||||
boost::contract::virtual_::action_enum a = v_->action_;
|
||||
v_->action_ = boost::contract::virtual_::pop_old_copy;
|
||||
v_->action_ = boost::contract::virtual_::pop_old_ftor_copy;
|
||||
this->copy_old();
|
||||
v_->action_ = a;
|
||||
} // Else, do nothing (for base calls only).
|
||||
|
||||
@@ -24,6 +24,7 @@ Facilities to support old values.
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/preprocessor/control/expr_iif.hpp>
|
||||
#include <boost/preprocessor/config/config.hpp>
|
||||
#include <queue>
|
||||
|
||||
#if !BOOST_PP_VARIADICS
|
||||
|
||||
@@ -321,7 +322,6 @@ public:
|
||||
)
|
||||
#if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
|
||||
!defined(BOOST_CONTRACT_NO_EXCEPTS)
|
||||
// TODO: Will this shared_ptr<void> destroy old_value_copy given its type is erased to void*?? Test it!
|
||||
: untyped_copy_(new old_value_copy<T>(old))
|
||||
#endif // Else, leave ptr_ null (thus no copy of T).
|
||||
{}
|
||||
@@ -420,28 +420,36 @@ private:
|
||||
boost::static_pointer_cast<copied_type>(untyped_copy_);
|
||||
BOOST_CONTRACT_DETAIL_DEBUG(typed_copy);
|
||||
return Ptr(typed_copy);
|
||||
} else if(v_->action_ == boost::contract::virtual_::push_old_init ||
|
||||
v_->action_ == boost::contract::virtual_::push_old_copy) {
|
||||
} else if(
|
||||
v_->action_ == boost::contract::virtual_::push_old_init_copy ||
|
||||
v_->action_ == boost::contract::virtual_::push_old_ftor_copy
|
||||
) {
|
||||
BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy_);
|
||||
if(v_->action_ == boost::contract::virtual_::push_old_init) {
|
||||
v_->old_inits_.push(untyped_copy_);
|
||||
} else {
|
||||
v_->old_copies_.push(untyped_copy_);
|
||||
}
|
||||
return Ptr(); // Push (so return null).
|
||||
} else if(boost::contract::virtual_::pop_old_init(v_->action_) ||
|
||||
v_->action_ == boost::contract::virtual_::pop_old_copy) {
|
||||
BOOST_CONTRACT_DETAIL_DEBUG(!untyped_copy_); // Copy not null...
|
||||
boost::shared_ptr<void> untyped_copy; // ...but still pop this.
|
||||
if(boost::contract::virtual_::pop_old_init(v_->action_)) {
|
||||
untyped_copy = v_->old_inits_.front();
|
||||
BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy);
|
||||
v_->old_inits_.pop();
|
||||
} else {
|
||||
untyped_copy = v_->old_copies_.top();
|
||||
BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy);
|
||||
v_->old_copies_.pop();
|
||||
}
|
||||
std::queue<boost::shared_ptr<void> >& copies = v_->action_ ==
|
||||
boost::contract::virtual_::push_old_ftor_copy ?
|
||||
v_->old_ftor_copies_
|
||||
:
|
||||
v_->old_init_copies_
|
||||
;
|
||||
copies.push(untyped_copy_);
|
||||
return Ptr(); // Pushed (so return null).
|
||||
} else if(
|
||||
boost::contract::virtual_::pop_old_init_copy(v_->action_) ||
|
||||
v_->action_ == boost::contract::virtual_::pop_old_ftor_copy
|
||||
) {
|
||||
// Copy not null, but still pop it from the queue.
|
||||
BOOST_CONTRACT_DETAIL_DEBUG(!untyped_copy_);
|
||||
|
||||
std::queue<boost::shared_ptr<void> >& copies = v_->action_ ==
|
||||
boost::contract::virtual_::pop_old_ftor_copy ?
|
||||
v_->old_ftor_copies_
|
||||
:
|
||||
v_->old_init_copies_
|
||||
;
|
||||
boost::shared_ptr<void> untyped_copy = copies.front();
|
||||
BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy);
|
||||
copies.pop();
|
||||
|
||||
typedef old_value_copy<typename Ptr::element_type> copied_type;
|
||||
boost::shared_ptr<copied_type> typed_copy = // Un-erase type.
|
||||
boost::static_pointer_cast<copied_type>(untyped_copy);
|
||||
@@ -549,8 +557,8 @@ bool copy_old(virtual_* v) {
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
return v->action_ == boost::contract::virtual_::push_old_init ||
|
||||
v->action_ == boost::contract::virtual_::push_old_copy;
|
||||
return v->action_ == boost::contract::virtual_::push_old_init_copy ||
|
||||
v->action_ == boost::contract::virtual_::push_old_ftor_copy;
|
||||
#else
|
||||
return false; // No post checking, so never copy old values.
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user