Merge branch 'develop' into node-checkers

This commit is contained in:
Matei David
2014-08-14 12:34:25 -04:00
20 changed files with 344 additions and 135 deletions

View File

@@ -3780,6 +3780,7 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std
* [@https://svn.boost.org/trac/boost/ticket/9948 #9948: remove use of const_cast in intrusive containers] * [@https://svn.boost.org/trac/boost/ticket/9948 #9948: remove use of const_cast in intrusive containers]
* [@https://svn.boost.org/trac/boost/ticket/9949 #9949: clear header node hooks upon intrusive container destruction] * [@https://svn.boost.org/trac/boost/ticket/9949 #9949: clear header node hooks upon intrusive container destruction]
* [@https://svn.boost.org/trac/boost/ticket/9961 #9961: tests for hooks not derived frorm generic_hook] * [@https://svn.boost.org/trac/boost/ticket/9961 #9961: tests for hooks not derived frorm generic_hook]
* [@https://github.com/boostorg/intrusive/pull/12 GitHub #12: ['Fix MSVC14 warning C4456: declaration of 'x_parent_right' hides previous local declaration]]
* Optimized tree rebalancing code to avoid redundant assignments. * Optimized tree rebalancing code to avoid redundant assignments.

View File

@@ -450,7 +450,9 @@ class avltree_algorithms
static void rebalance_after_erasure(const node_ptr & header, node_ptr x, node_ptr x_parent) static void rebalance_after_erasure(const node_ptr & header, node_ptr x, node_ptr x_parent)
{ {
for (node_ptr root = NodeTraits::get_parent(header); x != root; root = NodeTraits::get_parent(header)) { for ( node_ptr root = NodeTraits::get_parent(header)
; x != root
; root = NodeTraits::get_parent(header), x_parent = NodeTraits::get_parent(x)) {
const balance x_parent_balance = NodeTraits::get_balance(x_parent); const balance x_parent_balance = NodeTraits::get_balance(x_parent);
//Don't cache x_is_leftchild or similar because x can be null and //Don't cache x_is_leftchild or similar because x can be null and
//equal to both x_parent_left and x_parent_right //equal to both x_parent_left and x_parent_right
@@ -492,7 +494,6 @@ class avltree_algorithms
} }
else { else {
// x is left child (x_parent_right is the right child) // x is left child (x_parent_right is the right child)
const node_ptr x_parent_right(NodeTraits::get_right(x_parent));
BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_right); BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_right);
if (NodeTraits::get_balance(x_parent_right) == NodeTraits::negative()) { if (NodeTraits::get_balance(x_parent_right) == NodeTraits::negative()) {
// x_parent_right MUST have then a left child // x_parent_right MUST have then a left child
@@ -512,7 +513,6 @@ class avltree_algorithms
else{ else{
BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached
} }
x_parent = NodeTraits::get_parent(x);
} }
} }

View File

@@ -77,7 +77,7 @@ struct bstbase3
static const bool safemode_or_autounlink = is_safe_autounlink<value_traits::link_mode>::value; static const bool safemode_or_autounlink = is_safe_autounlink<value_traits::link_mode>::value;
static const bool stateful_value_traits = detail::is_stateful_value_traits<value_traits>::value; static const bool stateful_value_traits = detail::is_stateful_value_traits<value_traits>::value;
static const bool has_container_from_iterator = static const bool has_container_from_iterator =
boost::is_same< header_holder_type, detail::default_header_holder< node_traits > >::value; detail::is_same< header_holder_type, detail::default_header_holder< node_traits > >::value;
struct holder_t : public ValueTraits struct holder_t : public ValueTraits
{ {

View File

@@ -64,8 +64,9 @@ class circular_list_algorithms
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
static void init(const node_ptr &this_node) static void init(const node_ptr &this_node)
{ {
NodeTraits::set_next(this_node, node_ptr()); const node_ptr null_node((node_ptr()));
NodeTraits::set_previous(this_node, node_ptr()); NodeTraits::set_next(this_node, null_node);
NodeTraits::set_previous(this_node, null_node);
} }
//! <b>Effects</b>: Returns true is "this_node" is in a non-used state //! <b>Effects</b>: Returns true is "this_node" is in a non-used state
@@ -135,15 +136,10 @@ class circular_list_algorithms
static node_ptr unlink(const node_ptr &this_node) static node_ptr unlink(const node_ptr &this_node)
{ {
node_ptr next(NodeTraits::get_next(this_node)); node_ptr next(NodeTraits::get_next(this_node));
if(next){ node_ptr prev(NodeTraits::get_previous(this_node));
node_ptr prev(NodeTraits::get_previous(this_node)); NodeTraits::set_next(prev, next);
NodeTraits::set_next(prev, next); NodeTraits::set_previous(next, prev);
NodeTraits::set_previous(next, prev); return next;
return next;
}
else{
return this_node;
}
} }
//! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range. //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.
@@ -404,6 +400,70 @@ class circular_list_algorithms
} }
link_after(last, p); link_after(last, p);
} }
struct stable_partition_info
{
std::size_t num_1st_partition;
std::size_t num_2nd_partition;
node_ptr beg_2st_partition;
};
template<class Pred>
static void stable_partition(node_ptr beg, const node_ptr &end, Pred pred, stable_partition_info &info)
{
node_ptr bcur = node_traits::get_previous(beg);
node_ptr cur = beg;
node_ptr new_f = end;
std::size_t num1 = 0, num2 = 0;
while(cur != end){
if(pred(cur)){
++num1;
bcur = cur;
cur = node_traits::get_next(cur);
}
else{
++num2;
node_ptr last_to_remove = bcur;
new_f = cur;
bcur = cur;
cur = node_traits::get_next(cur);
BOOST_TRY{
//Main loop
while(cur != end){
if(pred(cur)){ //Might throw
++num1;
//Process current node
node_traits::set_next (last_to_remove, cur);
node_traits::set_previous(cur, last_to_remove);
last_to_remove = cur;
node_ptr nxt = node_traits::get_next(cur);
node_traits::set_next (bcur, nxt);
node_traits::set_previous(nxt, bcur);
cur = nxt;
}
else{
++num2;
bcur = cur;
cur = node_traits::get_next(cur);
}
}
}
BOOST_CATCH(...){
node_traits::set_next (last_to_remove, new_f);
node_traits::set_previous(new_f, last_to_remove);
throw;
}
BOOST_CATCH_END
node_traits::set_next(last_to_remove, new_f);
node_traits::set_previous(new_f, last_to_remove);
break;
}
}
info.num_1st_partition = num1;
info.num_2nd_partition = num2;
info.beg_2st_partition = new_f;
}
}; };
/// @cond /// @cond

View File

@@ -280,7 +280,7 @@ class any_algorithms
any_algorithms<VoidPointer>::template function_not_available_for_any_hooks<node_ptr>(); any_algorithms<VoidPointer>::template function_not_available_for_any_hooks<node_ptr>();
} }
static void swap_nodes(const node_ptr & l, const node_ptr & r) static void swap_nodes(const node_ptr &, const node_ptr &)
{ {
//Any nodes have no swap_nodes capability because they don't know //Any nodes have no swap_nodes capability because they don't know
//what algorithm they must use to unlink the node from the container //what algorithm they must use to unlink the node from the container

View File

@@ -16,6 +16,7 @@
#include <boost/intrusive/detail/config_begin.hpp> #include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp> #include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/assert.hpp> #include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <cstddef> #include <cstddef>
namespace boost { namespace boost {
@@ -88,9 +89,83 @@ class common_slist_algorithms
NodeTraits::set_next(bp, next_b); NodeTraits::set_next(bp, next_b);
} }
} }
struct stable_partition_info
{
std::size_t num_1st_partition;
std::size_t num_2nd_partition;
node_ptr beg_2st_partition;
node_ptr new_last_node;
};
template<class Pred>
static void stable_partition(node_ptr before_beg, const node_ptr &end, Pred pred, stable_partition_info &info)
{
node_ptr bcur = before_beg;
node_ptr cur = node_traits::get_next(bcur);
node_ptr new_f = end;
std::size_t num1 = 0, num2 = 0;
while(cur != end){
if(pred(cur)){
++num1;
bcur = cur;
cur = node_traits::get_next(cur);
}
else{
++num2;
node_ptr last_to_remove = bcur;
new_f = cur;
bcur = cur;
cur = node_traits::get_next(cur);
BOOST_TRY{
//Main loop
while(cur != end){
if(pred(cur)){ //Might throw
++num1;
//Process current node
node_traits::set_next(last_to_remove, cur);
last_to_remove = cur;
node_ptr nxt = node_traits::get_next(cur);
node_traits::set_next(bcur, nxt);
cur = nxt;
}
else{
++num2;
bcur = cur;
cur = node_traits::get_next(cur);
}
}
}
BOOST_CATCH(...){
node_traits::set_next(last_to_remove, new_f);
throw;
}
BOOST_CATCH_END
node_traits::set_next(last_to_remove, new_f);
break;
}
}
info.num_1st_partition = num1;
info.num_2nd_partition = num2;
info.beg_2st_partition = new_f;
info.new_last_node = bcur;
}
}; };
/// @endcond
} //namespace detail } //namespace detail
/// @cond
template<class NodeTraits>
struct get_algo<CommonSListAlgorithms, NodeTraits>
{
typedef detail::common_slist_algorithms<NodeTraits> type;
};
} //namespace intrusive } //namespace intrusive
} //namespace boost } //namespace boost

View File

@@ -177,8 +177,11 @@ class generic_hook
void unlink() void unlink()
{ {
BOOST_STATIC_ASSERT(( (int)hooktags::link_mode == (int)auto_unlink )); BOOST_STATIC_ASSERT(( (int)hooktags::link_mode == (int)auto_unlink ));
node_algorithms::unlink(this->this_ptr()); node_ptr n(this->this_ptr());
node_algorithms::init(this->this_ptr()); if(!node_algorithms::inited(n)){
node_algorithms::unlink(n);
node_algorithms::init(n);
}
} }
}; };

View File

@@ -205,7 +205,7 @@ struct get_slist_impl
< typename NodeTraits::node < typename NodeTraits::node
, boost::intrusive::value_traits<trivial_traits> , boost::intrusive::value_traits<trivial_traits>
, boost::intrusive::constant_time_size<false> , boost::intrusive::constant_time_size<false>
, boost::intrusive::size_type<std::size_t> , boost::intrusive::size_type<std::size_t>
>::type >::type
{}; {};
}; };

View File

@@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// (C) Copyright Ion Gaztanaga 2006-2014 // (C) Copyright Ion Gaztanaga 2006-2014
// (C) Copyright Microsoft Corporation 2014 // (C) Copyright Microsoft Corporation 2014
// //
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.

View File

@@ -31,7 +31,6 @@
#include <boost/detail/no_exceptions_support.hpp> #include <boost/detail/no_exceptions_support.hpp>
#include <functional> #include <functional>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <boost/tti/tti.hpp>
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
@@ -41,6 +40,7 @@ enum algo_types
CircularListAlgorithms, CircularListAlgorithms,
CircularSListAlgorithms, CircularSListAlgorithms,
LinearSListAlgorithms, LinearSListAlgorithms,
CommonSListAlgorithms,
BsTreeAlgorithms, BsTreeAlgorithms,
RbTreeAlgorithms, RbTreeAlgorithms,
AvlTreeAlgorithms, AvlTreeAlgorithms,
@@ -223,6 +223,10 @@ struct key_nodeptr_comp
bool operator()(const KeyType &key1, const KeyType2 &key2) const bool operator()(const KeyType &key1, const KeyType2 &key2) const
{ return base_t::get()(this->key_forward(key1), this->key_forward(key2)); } { return base_t::get()(this->key_forward(key1), this->key_forward(key2)); }
template<class KeyType>
bool operator()(const KeyType &key1) const
{ return base_t::get()(this->key_forward(key1)); }
const ValueTraits *const traits_; const ValueTraits *const traits_;
}; };
@@ -403,7 +407,7 @@ void destructor_impl(Hook &, detail::link_dispatch<normal_link>)
#define BOOST_INTRUSIVE_BSR_INTRINSIC_64_BIT #define BOOST_INTRUSIVE_BSR_INTRINSIC_64_BIT
#endif #endif
#ifndef __INTRIN_H_ // Avoid including any windows system header #ifndef __INTRIN_H_ // Avoid including any windows system header
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif // __cplusplus #endif // __cplusplus
@@ -798,108 +802,108 @@ class array_initializer
template<class It> template<class It>
class reverse_iterator class reverse_iterator
: public std::iterator< : public std::iterator<
typename std::iterator_traits<It>::iterator_category, typename std::iterator_traits<It>::iterator_category,
typename std::iterator_traits<It>::value_type, typename std::iterator_traits<It>::value_type,
typename std::iterator_traits<It>::difference_type, typename std::iterator_traits<It>::difference_type,
typename std::iterator_traits<It>::pointer, typename std::iterator_traits<It>::pointer,
typename std::iterator_traits<It>::reference> typename std::iterator_traits<It>::reference>
{ {
public: public:
typedef typename std::iterator_traits<It>::pointer pointer; typedef typename std::iterator_traits<It>::pointer pointer;
typedef typename std::iterator_traits<It>::reference reference; typedef typename std::iterator_traits<It>::reference reference;
typedef typename std::iterator_traits<It>::difference_type difference_type; typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It iterator_type; typedef It iterator_type;
reverse_iterator(){} reverse_iterator(){}
explicit reverse_iterator(It r) explicit reverse_iterator(It r)
: m_current(r) : m_current(r)
{} {}
template<class OtherIt> template<class OtherIt>
reverse_iterator(const reverse_iterator<OtherIt>& r) reverse_iterator(const reverse_iterator<OtherIt>& r)
: m_current(r.base()) : m_current(r.base())
{} {}
It base() const It base() const
{ return m_current; } { return m_current; }
reference operator*() const reference operator*() const
{ It temp(m_current); --temp; return *temp; } { It temp(m_current); --temp; return *temp; }
pointer operator->() const pointer operator->() const
{ It temp(m_current); --temp; return temp.operator->(); } { It temp(m_current); --temp; return temp.operator->(); }
reference operator[](difference_type off) const reference operator[](difference_type off) const
{ return this->m_current[-off]; } { return this->m_current[-off]; }
reverse_iterator& operator++() reverse_iterator& operator++()
{ --m_current; return *this; } { --m_current; return *this; }
reverse_iterator operator++(int) reverse_iterator operator++(int)
{ {
reverse_iterator temp = *this; reverse_iterator temp = *this;
--m_current; --m_current;
return temp; return temp;
}
reverse_iterator& operator--()
{
++m_current;
return *this;
} }
reverse_iterator operator--(int) reverse_iterator& operator--()
{ {
reverse_iterator temp(*this); ++m_current;
++m_current; return *this;
return temp; }
}
friend bool operator==(const reverse_iterator& l, const reverse_iterator& r) reverse_iterator operator--(int)
{ return l.m_current == r.m_current; } {
reverse_iterator temp(*this);
++m_current;
return temp;
}
friend bool operator!=(const reverse_iterator& l, const reverse_iterator& r) friend bool operator==(const reverse_iterator& l, const reverse_iterator& r)
{ return l.m_current != r.m_current; } { return l.m_current == r.m_current; }
friend bool operator<(const reverse_iterator& l, const reverse_iterator& r) friend bool operator!=(const reverse_iterator& l, const reverse_iterator& r)
{ return l.m_current < r.m_current; } { return l.m_current != r.m_current; }
friend bool operator<=(const reverse_iterator& l, const reverse_iterator& r) friend bool operator<(const reverse_iterator& l, const reverse_iterator& r)
{ return l.m_current <= r.m_current; } { return l.m_current < r.m_current; }
friend bool operator>(const reverse_iterator& l, const reverse_iterator& r) friend bool operator<=(const reverse_iterator& l, const reverse_iterator& r)
{ return l.m_current > r.m_current; } { return l.m_current <= r.m_current; }
friend bool operator>=(const reverse_iterator& l, const reverse_iterator& r) friend bool operator>(const reverse_iterator& l, const reverse_iterator& r)
{ return l.m_current >= r.m_current; } { return l.m_current > r.m_current; }
reverse_iterator& operator+=(difference_type off) friend bool operator>=(const reverse_iterator& l, const reverse_iterator& r)
{ m_current -= off; return *this; } { return l.m_current >= r.m_current; }
friend reverse_iterator operator+(const reverse_iterator & l, difference_type off) reverse_iterator& operator+=(difference_type off)
{ { m_current -= off; return *this; }
friend reverse_iterator operator+(const reverse_iterator & l, difference_type off)
{
reverse_iterator tmp(l.m_current); reverse_iterator tmp(l.m_current);
tmp.m_current -= off; tmp.m_current -= off;
return tmp; return tmp;
} }
reverse_iterator& operator-=(difference_type off) reverse_iterator& operator-=(difference_type off)
{ m_current += off; return *this; } { m_current += off; return *this; }
friend reverse_iterator operator-(const reverse_iterator & l, difference_type off) friend reverse_iterator operator-(const reverse_iterator & l, difference_type off)
{ {
reverse_iterator tmp(l.m_current); reverse_iterator tmp(l.m_current);
tmp.m_current += off; tmp.m_current += off;
return tmp; return tmp;
} }
friend difference_type operator-(const reverse_iterator& l, const reverse_iterator& r) friend difference_type operator-(const reverse_iterator& l, const reverse_iterator& r)
{ return r.m_current - l.m_current; } { return r.m_current - l.m_current; }
private: private:
It m_current; // the wrapped iterator It m_current; // the wrapped iterator
}; };
template<class ConstNodePtr> template<class ConstNodePtr>

View File

@@ -88,7 +88,7 @@ class list_impl
static const bool constant_time_size = ConstantTimeSize; static const bool constant_time_size = ConstantTimeSize;
static const bool stateful_value_traits = detail::is_stateful_value_traits<value_traits>::value; static const bool stateful_value_traits = detail::is_stateful_value_traits<value_traits>::value;
static const bool has_container_from_iterator = static const bool has_container_from_iterator =
boost::is_same< header_holder_type, detail::default_header_holder< node_traits > >::value; detail::is_same< header_holder_type, detail::default_header_holder< node_traits > >::value;
/// @cond /// @cond
@@ -1081,7 +1081,17 @@ class list_impl
//! and iterators to elements that are not removed remain valid. //! and iterators to elements that are not removed remain valid.
template<class Pred> template<class Pred>
void remove_if(Pred pred) void remove_if(Pred pred)
{ this->remove_and_dispose_if(pred, detail::null_disposer()); } {
const node_ptr root_node = this->get_root_node();
typename node_algorithms::stable_partition_info info;
node_algorithms::stable_partition
(node_traits::get_next(root_node), root_node, detail::key_nodeptr_comp<Pred, value_traits>(pred, &this->priv_value_traits()), info);
//Invariants preserved by stable_partition so erase can be safely called
//The first element might have changed so calculate it again
this->erase( const_iterator(node_traits::get_next(root_node), this->priv_value_traits_ptr())
, const_iterator(info.beg_2st_partition, this->priv_value_traits_ptr())
, info.num_1st_partition);
}
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw. //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//! //!
@@ -1098,16 +1108,15 @@ class list_impl
template<class Pred, class Disposer> template<class Pred, class Disposer>
void remove_and_dispose_if(Pred pred, Disposer disposer) void remove_and_dispose_if(Pred pred, Disposer disposer)
{ {
const_iterator cur(this->cbegin()); const node_ptr root_node = this->get_root_node();
const_iterator last(this->cend()); typename node_algorithms::stable_partition_info info;
while(cur != last) { node_algorithms::stable_partition
if(pred(*cur)){ (node_traits::get_next(root_node), root_node, detail::key_nodeptr_comp<Pred, value_traits>(pred, &this->priv_value_traits()), info);
cur = this->erase_and_dispose(cur, disposer); //Invariants preserved by stable_partition so erase can be safely called
} //The first element might have changed so calculate it again
else{ this->erase_and_dispose( const_iterator(node_traits::get_next(root_node), this->priv_value_traits_ptr())
++cur; , const_iterator(info.beg_2st_partition, this->priv_value_traits_ptr())
} , disposer);
}
} }
//! <b>Effects</b>: Removes adjacent duplicate elements or adjacent //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent

View File

@@ -62,7 +62,7 @@ struct pointer_traits
//!Ptr::reference if such a type exists (non-standard extension); otherwise, element_type & //!Ptr::reference if such a type exists (non-standard extension); otherwise, element_type &
//! //!
typedef element_type &reference; typedef unspecified_type reference;
#else #else
typedef Ptr pointer; typedef Ptr pointer;
// //
@@ -190,12 +190,12 @@ struct pointer_traits
static pointer priv_dynamic_cast_from(boost::intrusive::detail::false_, const UPtr &uptr) static pointer priv_dynamic_cast_from(boost::intrusive::detail::false_, const UPtr &uptr)
{ {
element_type *p = dynamic_cast<element_type*>(&*uptr); element_type *p = dynamic_cast<element_type*>(&*uptr);
if(!p){ if(!p){
return pointer(); return pointer();
} }
else{ else{
return pointer_to(*p); return pointer_to(*p);
} }
} }
///@endcond ///@endcond
}; };

View File

@@ -25,9 +25,9 @@ template <class T>
struct priority_compare struct priority_compare
{ {
//Compatibility with std::binary_function //Compatibility with std::binary_function
typedef T first_argument_type; typedef T first_argument_type;
typedef T second_argument_type; typedef T second_argument_type;
typedef bool result_type; typedef bool result_type;
bool operator()(const T &val, const T &val2) const bool operator()(const T &val, const T &val2) const
{ {

View File

@@ -25,6 +25,7 @@
#include <boost/intrusive/link_mode.hpp> #include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/options.hpp> #include <boost/intrusive/options.hpp>
#include <boost/intrusive/detail/utilities.hpp> #include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <iterator> #include <iterator>
#include <functional> #include <functional>
#include <algorithm> #include <algorithm>
@@ -123,7 +124,7 @@ class slist_impl
static const bool linear = 0 != (BoolFlags & slist_bool_flags::linear_pos); static const bool linear = 0 != (BoolFlags & slist_bool_flags::linear_pos);
static const bool cache_last = 0 != (BoolFlags & slist_bool_flags::cache_last_pos); static const bool cache_last = 0 != (BoolFlags & slist_bool_flags::cache_last_pos);
static const bool has_container_from_iterator = static const bool has_container_from_iterator =
boost::is_same< header_holder_type, detail::default_header_holder< node_traits > >::value; detail::is_same< header_holder_type, detail::default_header_holder< node_traits > >::value;
typedef typename detail::if_c typedef typename detail::if_c
< linear < linear
@@ -1537,7 +1538,20 @@ class slist_impl
//! and iterators to elements that are not removed remain valid. //! and iterators to elements that are not removed remain valid.
template<class Pred> template<class Pred>
void remove_if(Pred pred) void remove_if(Pred pred)
{ this->remove_and_dispose_if(pred, detail::null_disposer()); } {
const node_ptr bbeg = this->get_root_node();
typename node_algorithms::stable_partition_info info;
node_algorithms::stable_partition
(bbeg, this->get_end_node(), detail::key_nodeptr_comp<Pred, value_traits>(pred, &this->priv_value_traits()), info);
//After cache last is set, slist invariants are preserved...
if(cache_last){
this->set_last_node(info.new_last_node);
}
//...so erase can be safely called
this->erase_after( const_iterator(bbeg, this->priv_value_traits_ptr())
, const_iterator(info.beg_2st_partition, this->priv_value_traits_ptr())
, info.num_1st_partition);
}
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw. //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//! //!
@@ -1554,20 +1568,18 @@ class slist_impl
template<class Pred, class Disposer> template<class Pred, class Disposer>
void remove_and_dispose_if(Pred pred, Disposer disposer) void remove_and_dispose_if(Pred pred, Disposer disposer)
{ {
const_iterator bcur(this->before_begin()), cur(this->begin()), e(this->end()); const node_ptr bbeg = this->get_root_node();
typename node_algorithms::stable_partition_info info;
while(cur != e){ node_algorithms::stable_partition
if (pred(*cur)){ (bbeg, this->get_end_node(), detail::key_nodeptr_comp<Pred, value_traits>(pred, &this->priv_value_traits()), info);
cur = this->erase_after_and_dispose(bcur, disposer); //After cache last is set, slist invariants are preserved...
}
else{
bcur = cur;
++cur;
}
}
if(cache_last){ if(cache_last){
this->set_last_node(bcur.pointed_node()); this->set_last_node(info.new_last_node);
} }
//...so erase can be safely called
this->erase_after_and_dispose( const_iterator(bbeg, this->priv_value_traits_ptr())
, const_iterator(info.beg_2st_partition, this->priv_value_traits_ptr())
, disposer);
} }
//! <b>Effects</b>: Removes adjacent duplicate elements or adjacent //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent

View File

@@ -38,7 +38,7 @@ class bounded_pointer
typedef void (bounded_pointer::*unspecified_bool_type)() const; typedef void (bounded_pointer::*unspecified_bool_type)() const;
public: public:
typedef typename boost::remove_const< T >::type mut_val_t; typedef typename boost::intrusive::detail::remove_const< T >::type mut_val_t;
typedef const mut_val_t const_val_t; typedef const mut_val_t const_val_t;
typedef bounded_reference<T> reference; typedef bounded_reference<T> reference;
@@ -140,7 +140,7 @@ template < typename T >
class bounded_reference class bounded_reference
{ {
public: public:
typedef typename boost::remove_const< T >::type mut_val_t; typedef typename boost::intrusive::detail::remove_const< T >::type mut_val_t;
typedef const mut_val_t const_val_t; typedef const mut_val_t const_val_t;
typedef bounded_pointer< T > pointer; typedef bounded_pointer< T > pointer;
static const unsigned char max_offset = pointer::max_offset; static const unsigned char max_offset = pointer::max_offset;

View File

@@ -15,7 +15,6 @@
#define BOOST_INTRUSIVE_BPTR_VALUE_HPP #define BOOST_INTRUSIVE_BPTR_VALUE_HPP
#include <cassert> #include <cassert>
#include <boost/intrusive/list.hpp>
#include "bounded_pointer.hpp" #include "bounded_pointer.hpp"
#include "common_functors.hpp" #include "common_functors.hpp"
@@ -39,7 +38,6 @@ struct BPtr_Value
{ {
if (is_linked()) if (is_linked())
{ {
std::cerr << "BPtr_Value dtor: destructing linked value: &=" << (void*)this << "\n";
assert(false); assert(false);
} }
} }
@@ -50,7 +48,6 @@ struct BPtr_Value
{ {
if (is_linked()) if (is_linked())
{ {
std::cerr << "BPtr_Value asop: assigning to linked value: &=" << (void*)this << ", src=" << (void*)&src << "\n";
assert(false); assert(false);
} }
value_ = src.value_; value_ = src.value_;
@@ -99,11 +96,6 @@ struct BPtr_Value
friend bool operator!= (const BPtr_Value &other1, int other2) friend bool operator!= (const BPtr_Value &other1, int other2)
{ return !(other1.value_ == other2); } { return !(other1.value_ == other2); }
friend std::ostream& operator << (std::ostream& os, const BPtr_Value& v)
{
os << v.value_;
return os;
}
}; // class BPtr_Value }; // class BPtr_Value
template < typename Node_Algorithms > template < typename Node_Algorithms >

View File

@@ -50,6 +50,14 @@ class new_default_factory
{ return new T(); } { return new T(); }
}; };
class empty_disposer
{
public:
template<class T>
void operator()(const T &)
{}
};
} //namespace test { } //namespace test {
} //namespace intrusive { } //namespace intrusive {
} //namespace boost { } //namespace boost {

View File

@@ -163,6 +163,14 @@ struct is_even
{ return ((&v1)->value_ & 1) == 0; } { return ((&v1)->value_ & 1) == 0; }
}; };
struct is_odd
{
template <typename value_type>
bool operator()
(const value_type& v1) const
{ return ((&v1)->value_ & 1) != 0; }
};
template <typename> template <typename>
struct Value_Container; struct Value_Container;

View File

@@ -21,7 +21,6 @@
#include <boost/detail/lightweight_test.hpp> #include <boost/detail/lightweight_test.hpp>
#include "test_macros.hpp" #include "test_macros.hpp"
#include "test_container.hpp" #include "test_container.hpp"
#include <boost/tti/tti.hpp>
#include <typeinfo> #include <typeinfo>
using namespace boost::intrusive; using namespace boost::intrusive;
@@ -38,8 +37,7 @@ struct hooks
typedef list_member_hook< link_mode<auto_unlink> typedef list_member_hook< link_mode<auto_unlink>
, void_pointer<VoidPointer> > auto_member_hook_type; , void_pointer<VoidPointer> > auto_member_hook_type;
typedef nonhook_node_member< list_node_traits< VoidPointer >, typedef nonhook_node_member< list_node_traits< VoidPointer >,
circular_list_algorithms circular_list_algorithms > nonhook_node_member_type;
> nonhook_node_member_type;
}; };
@@ -145,7 +143,26 @@ void test_list< List_Type, Value_Container >
TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() ); TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() );
} }
{ {
Value_Container values2(values); // NOTE: problematic copy of value container list_type list(values.begin(), values.end());
list.remove_if(is_odd());
int init_values [] = { 2, 4 };
TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() );
}
{
list_type list(values.begin(), values.end());
list.remove_and_dispose_if(is_even(), test::empty_disposer());
int init_values [] = { 1, 3, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() );
}
{
list_type list(values.begin(), values.end());
list.remove_and_dispose_if(is_odd(), test::empty_disposer());
int init_values [] = { 2, 4 };
typename list_type::iterator i = list.begin(), e = list.end();
TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() );
}
{
Value_Container values2(values);
list_type list(values.begin(), values.end()); list_type list(values.begin(), values.end());
list.insert(list.end(), values2.begin(), values2.end()); list.insert(list.end(), values2.begin(), values2.end());
list.sort(); list.sort();

View File

@@ -159,6 +159,26 @@ void test_slist< List_Type, Value_Container >
int init_values [] = { 1, 3, 5 }; int init_values [] = { 1, 3, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() ); TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() );
} }
{
list_type list(values.begin(), values.end());
list.remove_if(is_odd());
int init_values [] = { 2, 4 };
TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() );
}
{
list_type list(values.begin(), values.end());
list.remove_and_dispose_if(is_even(), test::empty_disposer());
int init_values [] = { 1, 3, 5 };
typename list_type::iterator i = list.begin(), e = list.end();
TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() );
}
{
list_type list(values.begin(), values.end());
list.remove_and_dispose_if(is_odd(), test::empty_disposer());
int init_values [] = { 2, 4 };
typename list_type::iterator i = list.begin(), e = list.end();
TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() );
}
{ {
Value_Container values2(values); Value_Container values2(values);
list_type list(values.begin(), values.end()); list_type list(values.begin(), values.end());