diff --git a/include/boost/intrusive/detail/utilities.hpp b/include/boost/intrusive/detail/utilities.hpp index f190c92..19b6628 100644 --- a/include/boost/intrusive/detail/utilities.hpp +++ b/include/boost/intrusive/detail/utilities.hpp @@ -391,7 +391,11 @@ struct link_dispatch template void destructor_impl(Hook &hook, detail::link_dispatch) -{ (void)hook; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!hook.is_linked()); } +{ //If this assertion raises, you might have destroyed an object + //while it was still inserted in a container that is alive. + //If so, remove the object from the container before destroying it. + (void)hook; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!hook.is_linked()); +} template void destructor_impl(Hook &hook, detail::link_dispatch) diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index b621894..8ae0968 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -343,7 +343,7 @@ struct uset_defaults //! is used to construct intrusive unordered_set and unordered_multiset containers. The //! no-throw guarantee holds only, if the Equal object and Hasher don't throw. //! -//! hashtable is a pseudo-intrusive container: each object to be stored in the +//! hashtable is a semi-intrusive container: each object to be stored in the //! container must contain a proper hook, but the container also needs //! additional auxiliary memory to work: hashtable needs a pointer to an array //! of type `bucket_type` to be passed in the constructor. This bucket array must diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index ca7f7f6..2b28923 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -586,7 +586,7 @@ class list_impl iterator erase(iterator i) { return this->erase_and_dispose(i, detail::null_disposer()); } - //! Requires: first and last must be valid iterator to elements in *this. + //! Requires: b and e must be valid iterators to elements in *this. //! //! Effects: Erases the element range pointed by b and e //! No destructors are called. @@ -596,8 +596,8 @@ class list_impl //! //! Throws: Nothing. //! - //! Complexity: Linear to the number of elements erased if it's a safe-mode - //! or auto-unlink value. Constant time otherwise. + //! Complexity: Linear to the number of erased elements if it's a safe-mode + //! or auto-unlink value, or constant-time size is enabled. Constant-time otherwise. //! //! Note: Invalidates the iterators (but not the references) to the //! erased elements. @@ -612,6 +612,37 @@ class list_impl } } + //! Requires: b and e must be valid iterators to elements in *this. + //! n must be std::distance(b, e). + //! + //! Effects: Erases the element range pointed by b and e + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of erased elements if it's a safe-mode + //! or auto-unlink value is enabled. Constant-time otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased elements. + iterator erase(iterator b, iterator e, difference_type n) + { + BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(b, e) == difference_type(n)); + if(safemode_or_autounlink || constant_time_size){ + return this->erase_and_dispose(b, e, detail::null_disposer()); + } + else{ + if(constant_time_size){ + this->priv_size_traits().set_size(this->priv_size_traits().get_size() - n); + } + node_algorithms::unlink(b.pointed_node(), e.pointed_node()); + return e; + } + } + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the element pointed by i of the list. diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index 3527bfe..14c614f 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -778,12 +778,64 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Lineal to the elements (last - before_first + 1). + //! Complexity: Linear to the number of erased elements if it's a safe-mode + //! , auto-unlink value or constant-time size is activated. Constant time otherwise. //! //! Note: Invalidates the iterators (but not the references) to the //! erased element. iterator erase_after(iterator before_first, iterator last) - { return this->erase_after_and_dispose(before_first, last, detail::null_disposer()); } + { + if(safemode_or_autounlink || constant_time_size){ + return this->erase_after_and_dispose(before_first, last, detail::null_disposer()); + } + else{ + node_ptr bfp = before_first.pointed_node(); + node_ptr lp = last.pointed_node(); + if(cache_last){ + if((lp == this->get_end_node())){ + this->set_last_node(bfp); + } + } + node_algorithms::unlink_after(bfp, lp); + return last; + } + } + + //! Effects: Erases the range (before_first, last) from + //! the list. n must be std::distance(before_first, last) - 1. + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: constant-time if link_mode is normal_link. + //! Linear to the elements (last - before_first) otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + iterator erase_after(iterator before_first, iterator last, difference_type n) + { + BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(++iterator(before_first), last) == difference_type(n)); + if(safemode_or_autounlink){ + return this->erase_after(before_first, last); + } + else{ + node_ptr bfp = before_first.pointed_node(); + node_ptr lp = last.pointed_node(); + if(cache_last){ + if((lp == this->get_end_node())){ + this->set_last_node(bfp); + } + } + node_algorithms::unlink_after(bfp, lp); + if(constant_time_size){ + this->priv_size_traits().set_size(this->priv_size_traits().get_size() - n); + } + return last; + } + } //! Effects: Erases the element pointed by i of the list. //! No destructors are called. @@ -810,14 +862,30 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Linear to the number of elements erased plus linear - //! to the elements before first. + //! Complexity: Linear to the elements before last. //! //! Note: Invalidates the iterators (but not the references) to the //! erased elements. iterator erase(iterator first, iterator last) { return this->erase_after(this->previous(first), last); } + //! Effects: Erases the range [first, last) from + //! the list. n must be std::distance(first, last). + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: linear to the elements before first if link_mode is normal_link + //! and constant_time_size is activated. Linear to the elements before last otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + iterator erase(iterator first, iterator last, difference_type n) + { return this->erase_after(this->previous(first), last, n); } + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the element after the element pointed by prev of @@ -885,7 +953,7 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Lineal to the elements (last - before_first). + //! Complexity: Lineal to the elements (last - before_first + 1). //! //! Note: Invalidates the iterators to the erased element. template @@ -939,7 +1007,7 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Linear to the number of elements erased plus linear + //! Complexity: Linear to the number of erased elements plus linear //! to the elements before first. //! //! Note: Invalidates the iterators (but not the references) to the @@ -1047,10 +1115,7 @@ class slist_impl void splice_after(iterator prev_pos, slist_impl &x, iterator prev_ele) { iterator elem = prev_ele; - ++elem; - if (elem != prev_pos && prev_ele != prev_pos){ - this->splice_after(prev_pos, x, prev_ele, elem, 1); - } + this->splice_after(prev_pos, x, prev_ele, ++elem, 1); } //! Requires: prev_pos must be a dereferenceable iterator in *this or be @@ -1588,15 +1653,18 @@ class slist_impl private: void priv_splice_after(node_ptr prev_pos_n, slist_impl &x, node_ptr before_first_n, node_ptr before_last_n) { - if(cache_last){ - if(node_traits::get_next(prev_pos_n) == this->get_end_node()){ - this->set_last_node(before_last_n); - } - if(node_traits::get_next(before_last_n) == x.get_end_node()){ - x.set_last_node(before_first_n); + if (before_first_n != before_last_n && prev_pos_n != before_first_n && prev_pos_n != before_last_n) + { + if(cache_last){ + if(node_traits::get_next(prev_pos_n) == this->get_end_node()){ + this->set_last_node(before_last_n); + } + if(node_traits::get_next(before_last_n) == x.get_end_node()){ + x.set_last_node(before_first_n); + } } + node_algorithms::transfer_after(prev_pos_n, before_first_n, before_last_n); } - node_algorithms::transfer_after(prev_pos_n, before_first_n, before_last_n); } void priv_reverse(detail::bool_) diff --git a/include/boost/intrusive/unordered_set.hpp b/include/boost/intrusive/unordered_set.hpp index d35eef4..342e2a6 100644 --- a/include/boost/intrusive/unordered_set.hpp +++ b/include/boost/intrusive/unordered_set.hpp @@ -24,7 +24,7 @@ namespace intrusive { //! The class template unordered_set is an intrusive container, that mimics most of //! the interface of std::tr1::unordered_set as described in the C++ TR1. //! -//! unordered_set is a pseudo-intrusive container: each object to be stored in the +//! unordered_set is a semi-intrusive container: each object to be stored in the //! container must contain a proper hook, but the container also needs //! additional auxiliary memory to work: unordered_set needs a pointer to an array //! of type `bucket_type` to be passed in the constructor. This bucket array must @@ -1019,7 +1019,7 @@ class unordered_set //! The class template unordered_multiset is an intrusive container, that mimics most of //! the interface of std::tr1::unordered_multiset as described in the C++ TR1. //! -//! unordered_multiset is a pseudo-intrusive container: each object to be stored in the +//! unordered_multiset is a semi-intrusive container: each object to be stored in the //! container must contain a proper hook, but the container also needs //! additional auxiliary memory to work: unordered_multiset needs a pointer to an array //! of type `bucket_type` to be passed in the constructor. This bucket array must