From f6333c31269557ec6aefc46a2a627a31df33d149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 1 Aug 2014 10:58:30 +0200 Subject: [PATCH 1/8] Replaced tabs with spaces. Removed unneeded TTI include in utilities --- .../boost/intrusive/detail/hashtable_node.hpp | 2 +- include/boost/intrusive/detail/mpl.hpp | 2 +- include/boost/intrusive/detail/utilities.hpp | 129 +++++++++--------- include/boost/intrusive/pointer_traits.hpp | 12 +- include/boost/intrusive/priority_compare.hpp | 6 +- 5 files changed, 75 insertions(+), 76 deletions(-) diff --git a/include/boost/intrusive/detail/hashtable_node.hpp b/include/boost/intrusive/detail/hashtable_node.hpp index f00b0bf..68122f0 100644 --- a/include/boost/intrusive/detail/hashtable_node.hpp +++ b/include/boost/intrusive/detail/hashtable_node.hpp @@ -205,7 +205,7 @@ struct get_slist_impl < typename NodeTraits::node , boost::intrusive::value_traits , boost::intrusive::constant_time_size - , boost::intrusive::size_type + , boost::intrusive::size_type >::type {}; }; diff --git a/include/boost/intrusive/detail/mpl.hpp b/include/boost/intrusive/detail/mpl.hpp index 9dc0d52..1ac762a 100644 --- a/include/boost/intrusive/detail/mpl.hpp +++ b/include/boost/intrusive/detail/mpl.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2014 +// (C) Copyright Ion Gaztanaga 2006-2014 // (C) Copyright Microsoft Corporation 2014 // // Distributed under the Boost Software License, Version 1.0. diff --git a/include/boost/intrusive/detail/utilities.hpp b/include/boost/intrusive/detail/utilities.hpp index b893d22..01b84ba 100644 --- a/include/boost/intrusive/detail/utilities.hpp +++ b/include/boost/intrusive/detail/utilities.hpp @@ -31,7 +31,6 @@ #include #include #include -#include namespace boost { namespace intrusive { @@ -388,7 +387,7 @@ void destructor_impl(Hook &, detail::link_dispatch) #define BOOST_INTRUSIVE_BSR_INTRINSIC_64_BIT #endif - #ifndef __INTRIN_H_ // Avoid including any windows system header + #ifndef __INTRIN_H_ // Avoid including any windows system header #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -783,108 +782,108 @@ class array_initializer template class reverse_iterator - : public std::iterator< - typename std::iterator_traits::iterator_category, - typename std::iterator_traits::value_type, - typename std::iterator_traits::difference_type, - typename std::iterator_traits::pointer, - typename std::iterator_traits::reference> + : public std::iterator< + typename std::iterator_traits::iterator_category, + typename std::iterator_traits::value_type, + typename std::iterator_traits::difference_type, + typename std::iterator_traits::pointer, + typename std::iterator_traits::reference> { public: - typedef typename std::iterator_traits::pointer pointer; - typedef typename std::iterator_traits::reference reference; - typedef typename std::iterator_traits::difference_type difference_type; - typedef It iterator_type; + typedef typename std::iterator_traits::pointer pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It iterator_type; - reverse_iterator(){} + reverse_iterator(){} - explicit reverse_iterator(It r) - : m_current(r) + explicit reverse_iterator(It r) + : m_current(r) {} - template - reverse_iterator(const reverse_iterator& r) - : m_current(r.base()) - {} + template + reverse_iterator(const reverse_iterator& r) + : m_current(r.base()) + {} - It base() const + It base() const { return m_current; } - reference operator*() const + reference operator*() const { It temp(m_current); --temp; return *temp; } - pointer operator->() const + pointer operator->() const { It temp(m_current); --temp; return temp.operator->(); } - reference operator[](difference_type off) const - { return this->m_current[-off]; } + reference operator[](difference_type off) const + { return this->m_current[-off]; } - reverse_iterator& operator++() + reverse_iterator& operator++() { --m_current; return *this; } - reverse_iterator operator++(int) - { - reverse_iterator temp = *this; - --m_current; - return temp; - } - - reverse_iterator& operator--() - { - ++m_current; - return *this; + reverse_iterator operator++(int) + { + reverse_iterator temp = *this; + --m_current; + return temp; } - reverse_iterator operator--(int) - { - reverse_iterator temp(*this); - ++m_current; - return temp; - } + reverse_iterator& operator--() + { + ++m_current; + return *this; + } - friend bool operator==(const reverse_iterator& l, const reverse_iterator& r) - { return l.m_current == r.m_current; } + reverse_iterator operator--(int) + { + reverse_iterator temp(*this); + ++m_current; + return temp; + } - friend bool operator!=(const reverse_iterator& l, const reverse_iterator& r) - { return l.m_current != r.m_current; } + friend bool operator==(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current == r.m_current; } - friend bool operator<(const reverse_iterator& l, const reverse_iterator& r) - { return l.m_current < r.m_current; } + friend bool operator!=(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current != r.m_current; } - friend bool operator<=(const reverse_iterator& l, const reverse_iterator& r) - { return l.m_current <= r.m_current; } + friend bool operator<(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current < r.m_current; } - friend bool operator>(const reverse_iterator& l, const reverse_iterator& r) - { return l.m_current > r.m_current; } + friend bool operator<=(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current <= r.m_current; } - friend bool operator>=(const reverse_iterator& l, const reverse_iterator& r) - { return l.m_current >= r.m_current; } + friend bool operator>(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current > r.m_current; } - reverse_iterator& operator+=(difference_type off) - { m_current -= off; return *this; } + friend bool operator>=(const reverse_iterator& l, const reverse_iterator& r) + { 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); tmp.m_current -= off; return tmp; } - reverse_iterator& operator-=(difference_type off) - { m_current += off; return *this; } + reverse_iterator& operator-=(difference_type off) + { 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); tmp.m_current += off; return tmp; } - friend difference_type operator-(const reverse_iterator& l, const reverse_iterator& r) - { return r.m_current - l.m_current; } + friend difference_type operator-(const reverse_iterator& l, const reverse_iterator& r) + { return r.m_current - l.m_current; } private: - It m_current; // the wrapped iterator + It m_current; // the wrapped iterator }; template diff --git a/include/boost/intrusive/pointer_traits.hpp b/include/boost/intrusive/pointer_traits.hpp index fe898f6..d16471c 100644 --- a/include/boost/intrusive/pointer_traits.hpp +++ b/include/boost/intrusive/pointer_traits.hpp @@ -190,12 +190,12 @@ struct pointer_traits static pointer priv_dynamic_cast_from(boost::intrusive::detail::false_, const UPtr &uptr) { element_type *p = dynamic_cast(&*uptr); - if(!p){ - return pointer(); - } - else{ - return pointer_to(*p); - } + if(!p){ + return pointer(); + } + else{ + return pointer_to(*p); + } } ///@endcond }; diff --git a/include/boost/intrusive/priority_compare.hpp b/include/boost/intrusive/priority_compare.hpp index f6beee1..e2f4495 100644 --- a/include/boost/intrusive/priority_compare.hpp +++ b/include/boost/intrusive/priority_compare.hpp @@ -25,9 +25,9 @@ template struct priority_compare { //Compatibility with std::binary_function - typedef T first_argument_type; - typedef T second_argument_type; - typedef bool result_type; + typedef T first_argument_type; + typedef T second_argument_type; + typedef bool result_type; bool operator()(const T &val, const T &val2) const { From a6a65cff8da7aa31fa9ad28066bd9e669c9453f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 1 Aug 2014 11:05:56 +0200 Subject: [PATCH 2/8] GitHub #12: Fix MSVC14 warning C4456: declaration of 'x_parent_right' hides previous local declaration --- doc/intrusive.qbk | 7 +++++++ include/boost/intrusive/avltree_algorithms.hpp | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 6f72da3..913b6dd 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -3761,6 +3761,13 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std [section:release_notes Release Notes] +[section:release_notes_boost_1_57_00 Boost 1.57 Release] + +* Fixed bugs: + * [@https://github.com/boostorg/intrusive/pull/12 GitHub #12: ['Fix MSVC14 warning C4456: declaration of 'x_parent_right' hides previous local declaration]] + +[endsect] + [section:release_notes_boost_1_56_00 Boost 1.56 Release] * Improved Doxygen generated reference and updated and fixed forward-declaration header. diff --git a/include/boost/intrusive/avltree_algorithms.hpp b/include/boost/intrusive/avltree_algorithms.hpp index e6127b8..f63e9ae 100644 --- a/include/boost/intrusive/avltree_algorithms.hpp +++ b/include/boost/intrusive/avltree_algorithms.hpp @@ -411,7 +411,9 @@ class avltree_algorithms 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); //Don't cache x_is_leftchild or similar because x can be null and //equal to both x_parent_left and x_parent_right @@ -453,7 +455,6 @@ class avltree_algorithms } else { // 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); if (NodeTraits::get_balance(x_parent_right) == NodeTraits::negative()) { // x_parent_right MUST have then a left child @@ -473,7 +474,6 @@ class avltree_algorithms else{ BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached } - x_parent = NodeTraits::get_parent(x); } } From c8f0271ab38f59c054d6fff78f9869fb3546842a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 1 Aug 2014 11:26:42 +0200 Subject: [PATCH 3/8] Removed warning about unused arguments --- include/boost/intrusive/detail/any_node_and_algorithms.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/intrusive/detail/any_node_and_algorithms.hpp b/include/boost/intrusive/detail/any_node_and_algorithms.hpp index 8b51099..455546c 100644 --- a/include/boost/intrusive/detail/any_node_and_algorithms.hpp +++ b/include/boost/intrusive/detail/any_node_and_algorithms.hpp @@ -280,7 +280,7 @@ class any_algorithms any_algorithms::template function_not_available_for_any_hooks(); } - 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 //what algorithm they must use to unlink the node from the container From ddafb2d4efa38352fe0c457771f4cf3a61b43f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 2 Aug 2014 10:13:54 +0200 Subject: [PATCH 4/8] Use intrusive utilities instead of boost utilities to limit dependencies. --- include/boost/intrusive/bstree.hpp | 2 +- include/boost/intrusive/list.hpp | 2 +- include/boost/intrusive/slist.hpp | 3 ++- test/bounded_pointer.hpp | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/boost/intrusive/bstree.hpp b/include/boost/intrusive/bstree.hpp index 2af42cc..054b4b5 100644 --- a/include/boost/intrusive/bstree.hpp +++ b/include/boost/intrusive/bstree.hpp @@ -77,7 +77,7 @@ struct bstbase3 static const bool safemode_or_autounlink = is_safe_autounlink::value; static const bool stateful_value_traits = detail::is_stateful_value_traits::value; 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 { diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index c22e3af..cea73fe 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -88,7 +88,7 @@ class list_impl static const bool constant_time_size = ConstantTimeSize; static const bool stateful_value_traits = detail::is_stateful_value_traits::value; 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 diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index 74d14c1..39837f4 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -123,7 +124,7 @@ class slist_impl 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 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 < linear diff --git a/test/bounded_pointer.hpp b/test/bounded_pointer.hpp index b584def..d2672b5 100644 --- a/test/bounded_pointer.hpp +++ b/test/bounded_pointer.hpp @@ -38,7 +38,7 @@ class bounded_pointer typedef void (bounded_pointer::*unspecified_bool_type)() const; 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 bounded_reference reference; @@ -140,7 +140,7 @@ template < typename T > class bounded_reference { 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 bounded_pointer< T > pointer; static const unsigned char max_offset = pointer::max_offset; From 59d31fefe73189c6e11c38b7ec1a57a670a2be46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 3 Aug 2014 10:14:55 +0200 Subject: [PATCH 5/8] Backport changes to 1.56 as some of them are needed to avoid a broken release on 1.56. --- doc/intrusive.qbk | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 913b6dd..ec6513e 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -3761,13 +3761,6 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std [section:release_notes Release Notes] -[section:release_notes_boost_1_57_00 Boost 1.57 Release] - -* Fixed bugs: - * [@https://github.com/boostorg/intrusive/pull/12 GitHub #12: ['Fix MSVC14 warning C4456: declaration of 'x_parent_right' hides previous local declaration]] - -[endsect] - [section:release_notes_boost_1_56_00 Boost 1.56 Release] * Improved Doxygen generated reference and updated and fixed forward-declaration header. @@ -3787,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/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://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. From 4a4b0edae41da8a883b58e8276a75c604d180bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 14 Aug 2014 00:12:18 +0200 Subject: [PATCH 6/8] Removed unneeded include and operator. --- test/bptr_value.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/bptr_value.hpp b/test/bptr_value.hpp index 17c3638..2a1a12a 100644 --- a/test/bptr_value.hpp +++ b/test/bptr_value.hpp @@ -15,7 +15,6 @@ #define BOOST_INTRUSIVE_BPTR_VALUE_HPP #include -#include #include "bounded_pointer.hpp" #include "common_functors.hpp" @@ -39,7 +38,6 @@ struct BPtr_Value { if (is_linked()) { - std::cerr << "BPtr_Value dtor: destructing linked value: &=" << (void*)this << "\n"; assert(false); } } @@ -50,7 +48,6 @@ struct BPtr_Value { if (is_linked()) { - std::cerr << "BPtr_Value asop: assigning to linked value: &=" << (void*)this << ", src=" << (void*)&src << "\n"; assert(false); } value_ = src.value_; @@ -99,11 +96,6 @@ struct BPtr_Value friend bool operator!= (const BPtr_Value &other1, int other2) { return !(other1.value_ == other2); } - friend std::ostream& operator << (std::ostream& os, const BPtr_Value& v) - { - os << v.value_; - return os; - } }; // class BPtr_Value template < typename Node_Algorithms > From 1afec2c7163b3d16e2c1926d128ef7261147ebce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 14 Aug 2014 00:19:34 +0200 Subject: [PATCH 7/8] Corrected documentation for "reference". --- include/boost/intrusive/pointer_traits.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/intrusive/pointer_traits.hpp b/include/boost/intrusive/pointer_traits.hpp index d16471c..4face3e 100644 --- a/include/boost/intrusive/pointer_traits.hpp +++ b/include/boost/intrusive/pointer_traits.hpp @@ -62,7 +62,7 @@ struct pointer_traits //!Ptr::reference if such a type exists (non-standard extension); otherwise, element_type & //! - typedef element_type &reference; + typedef unspecified_type reference; #else typedef Ptr pointer; // From 0a03aa599a71559c88792e9c758447ec545f1739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 14 Aug 2014 00:22:19 +0200 Subject: [PATCH 8/8] Reimplemented remove family for lists using new stable_partition algorithm. This allows less code duplication between lists with different options (constant_time_size, cache_list, safe/non-safe hooks, etc.). --- .../intrusive/circular_list_algorithms.hpp | 82 ++++++++++++++++--- .../detail/common_slist_algorithms.hpp | 75 +++++++++++++++++ .../boost/intrusive/detail/generic_hook.hpp | 7 +- include/boost/intrusive/detail/utilities.hpp | 5 ++ include/boost/intrusive/list.hpp | 31 ++++--- include/boost/intrusive/slist.hpp | 37 ++++++--- test/common_functors.hpp | 8 ++ test/itestvalue.hpp | 8 ++ test/list_test.cpp | 25 +++++- test/slist_test.cpp | 20 +++++ 10 files changed, 257 insertions(+), 41 deletions(-) diff --git a/include/boost/intrusive/circular_list_algorithms.hpp b/include/boost/intrusive/circular_list_algorithms.hpp index 9d6213a..3253f15 100644 --- a/include/boost/intrusive/circular_list_algorithms.hpp +++ b/include/boost/intrusive/circular_list_algorithms.hpp @@ -64,8 +64,9 @@ class circular_list_algorithms //! Throws: Nothing. static void init(const node_ptr &this_node) { - NodeTraits::set_next(this_node, node_ptr()); - NodeTraits::set_previous(this_node, node_ptr()); + const node_ptr null_node((node_ptr())); + NodeTraits::set_next(this_node, null_node); + NodeTraits::set_previous(this_node, null_node); } //! Effects: 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) { node_ptr next(NodeTraits::get_next(this_node)); - if(next){ - node_ptr prev(NodeTraits::get_previous(this_node)); - NodeTraits::set_next(prev, next); - NodeTraits::set_previous(next, prev); - return next; - } - else{ - return this_node; - } + node_ptr prev(NodeTraits::get_previous(this_node)); + NodeTraits::set_next(prev, next); + NodeTraits::set_previous(next, prev); + return next; } //! Requires: 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); } + + struct stable_partition_info + { + std::size_t num_1st_partition; + std::size_t num_2nd_partition; + node_ptr beg_2st_partition; + }; + + template + 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 diff --git a/include/boost/intrusive/detail/common_slist_algorithms.hpp b/include/boost/intrusive/detail/common_slist_algorithms.hpp index 0adbd50..316e5a1 100644 --- a/include/boost/intrusive/detail/common_slist_algorithms.hpp +++ b/include/boost/intrusive/detail/common_slist_algorithms.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include namespace boost { @@ -88,9 +89,83 @@ class common_slist_algorithms 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 + 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 + +/// @cond + +template +struct get_algo +{ + typedef detail::common_slist_algorithms type; +}; + + } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/detail/generic_hook.hpp b/include/boost/intrusive/detail/generic_hook.hpp index 835a8c7..a827678 100644 --- a/include/boost/intrusive/detail/generic_hook.hpp +++ b/include/boost/intrusive/detail/generic_hook.hpp @@ -177,8 +177,11 @@ class generic_hook void unlink() { BOOST_STATIC_ASSERT(( (int)hooktags::link_mode == (int)auto_unlink )); - node_algorithms::unlink(this->this_ptr()); - node_algorithms::init(this->this_ptr()); + node_ptr n(this->this_ptr()); + if(!node_algorithms::inited(n)){ + node_algorithms::unlink(n); + node_algorithms::init(n); + } } }; diff --git a/include/boost/intrusive/detail/utilities.hpp b/include/boost/intrusive/detail/utilities.hpp index 01b84ba..124e2ab 100644 --- a/include/boost/intrusive/detail/utilities.hpp +++ b/include/boost/intrusive/detail/utilities.hpp @@ -40,6 +40,7 @@ enum algo_types CircularListAlgorithms, CircularSListAlgorithms, LinearSListAlgorithms, + CommonSListAlgorithms, BsTreeAlgorithms, RbTreeAlgorithms, AvlTreeAlgorithms, @@ -219,6 +220,10 @@ struct key_nodeptr_comp bool operator()(const KeyType &key1, const KeyType2 &key2) const { return base_t::get()(this->key_forward(key1), this->key_forward(key2)); } + template + bool operator()(const KeyType &key1) const + { return base_t::get()(this->key_forward(key1)); } + const ValueTraits *const traits_; }; diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index cea73fe..3271dbf 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -1081,7 +1081,17 @@ class list_impl //! and iterators to elements that are not removed remain valid. template 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, &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); + } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1098,16 +1108,15 @@ class list_impl template void remove_and_dispose_if(Pred pred, Disposer disposer) { - const_iterator cur(this->cbegin()); - const_iterator last(this->cend()); - while(cur != last) { - if(pred(*cur)){ - cur = this->erase_and_dispose(cur, disposer); - } - else{ - ++cur; - } - } + 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, &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_and_dispose( const_iterator(node_traits::get_next(root_node), this->priv_value_traits_ptr()) + , const_iterator(info.beg_2st_partition, this->priv_value_traits_ptr()) + , disposer); } //! Effects: Removes adjacent duplicate elements or adjacent diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index 39837f4..9755919 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -1538,7 +1538,20 @@ class slist_impl //! and iterators to elements that are not removed remain valid. template 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, &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); + } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1555,20 +1568,18 @@ class slist_impl template void remove_and_dispose_if(Pred pred, Disposer disposer) { - const_iterator bcur(this->before_begin()), cur(this->begin()), e(this->end()); - - while(cur != e){ - if (pred(*cur)){ - cur = this->erase_after_and_dispose(bcur, disposer); - } - else{ - bcur = cur; - ++cur; - } - } + 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, &this->priv_value_traits()), info); + //After cache last is set, slist invariants are preserved... 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); } //! Effects: Removes adjacent duplicate elements or adjacent diff --git a/test/common_functors.hpp b/test/common_functors.hpp index a6af9fb..9500a52 100644 --- a/test/common_functors.hpp +++ b/test/common_functors.hpp @@ -50,6 +50,14 @@ class new_default_factory { return new T(); } }; +class empty_disposer +{ + public: + template + void operator()(const T &) + {} +}; + } //namespace test { } //namespace intrusive { } //namespace boost { diff --git a/test/itestvalue.hpp b/test/itestvalue.hpp index 427bfaf..7935040 100644 --- a/test/itestvalue.hpp +++ b/test/itestvalue.hpp @@ -163,6 +163,14 @@ struct is_even { return ((&v1)->value_ & 1) == 0; } }; +struct is_odd +{ + template + bool operator() + (const value_type& v1) const + { return ((&v1)->value_ & 1) != 0; } +}; + template struct Value_Container; diff --git a/test/list_test.cpp b/test/list_test.cpp index 397165c..b962bc8 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -21,7 +21,6 @@ #include #include "test_macros.hpp" #include "test_container.hpp" -#include #include using namespace boost::intrusive; @@ -38,8 +37,7 @@ struct hooks typedef list_member_hook< link_mode , void_pointer > auto_member_hook_type; typedef nonhook_node_member< list_node_traits< VoidPointer >, - circular_list_algorithms - > nonhook_node_member_type; + circular_list_algorithms > nonhook_node_member_type; }; @@ -145,7 +143,26 @@ void test_list< List_Type, Value_Container > 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.insert(list.end(), values2.begin(), values2.end()); list.sort(); diff --git a/test/slist_test.cpp b/test/slist_test.cpp index f455243..228c3e0 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -159,6 +159,26 @@ void test_slist< List_Type, Value_Container > int init_values [] = { 1, 3, 5 }; 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); list_type list(values.begin(), values.end());