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:
U-CODE1\310206419
2016-11-26 19:09:03 -08:00
parent e7a64edfb2
commit 58b8b96a2a
8 changed files with 262 additions and 326 deletions

View File

@@ -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.

View File

@@ -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).

View File

@@ -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