diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index b8960a4..6ee4a03 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -1280,7 +1280,9 @@ And they also can receive additional options: provides a bucket length that is not power of two. Default: `power_2_buckets`. -* [*`cache_begin`]: Due to its internal structure, finding the first +* [*`cache_begin`]: + [*Note: this option is not compatible with `auto_unlink` hooks]. + Due to its internal structure, finding the first element of an unordered container (`begin()` operation) is amortized constant-time. It's possible to speed up `begin()` and other operations related to it (like `clear()`) if the container caches internally the position @@ -3701,6 +3703,13 @@ all the objects to be inserted in intrusive containers in containers like `std:: [section:release_notes Release Notes] +[section:release_notes_boost_1_39_00 Boost 1.39 Release] + +* Optimized `list::merge` and `slist::merge` +* `list::sort` and `slist::sort` are now stable. + +[endsect] + [section:release_notes_boost_1_38_00 Boost 1.38 Release] * New treap-based containers: treap, treap_set, treap_multiset. diff --git a/example/doc_any_hook.cpp b/example/doc_any_hook.cpp index 15220dc..11991aa 100644 --- a/example/doc_any_hook.cpp +++ b/example/doc_any_hook.cpp @@ -34,7 +34,7 @@ int main() typedef any_to_slist_hook < base_hook< any_base_hook<> > > BaseSlistOption; typedef slist BaseSList; - //Define a member hook option that converts any_base_hook to a list hook + //Define a member hook option that converts any_member_hook to a list hook typedef any_to_list_hook< member_hook < MyClass, any_member_hook<>, &MyClass::member_hook_> > MemberListOption; typedef list MemberList; diff --git a/include/boost/intrusive/detail/ebo_functor_holder.hpp b/include/boost/intrusive/detail/ebo_functor_holder.hpp index 43cc975..35628f2 100644 --- a/include/boost/intrusive/detail/ebo_functor_holder.hpp +++ b/include/boost/intrusive/detail/ebo_functor_holder.hpp @@ -26,18 +26,18 @@ class ebo_functor_holder_impl ebo_functor_holder_impl() {} ebo_functor_holder_impl(const T& t) - : t(t) + : t_(t) {} template ebo_functor_holder_impl(const Arg1& arg1, const Arg2& arg2) - : t(arg1, arg2) + : t_(arg1, arg2) {} - T& get(){return t;} - const T& get()const{return t;} + T& get(){return t_;} + const T& get()const{return t_;} private: - T t; + T t_; }; template diff --git a/include/boost/intrusive/detail/parent_from_member.hpp b/include/boost/intrusive/detail/parent_from_member.hpp index c99ac6c..c750ad8 100644 --- a/include/boost/intrusive/detail/parent_from_member.hpp +++ b/include/boost/intrusive/detail/parent_from_member.hpp @@ -15,7 +15,8 @@ #include #include -#if defined(BOOST_MSVC) || (defined (BOOST_WINDOWS) && defined(BOOST_INTEL)) +#if defined(BOOST_MSVC) || ((defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && defined(BOOST_INTEL)) + #define BOOST_INTRUSIVE_MSVC_COMPLIANT_PTR_TO_MEMBER #include #endif diff --git a/include/boost/intrusive/detail/tree_node.hpp b/include/boost/intrusive/detail/tree_node.hpp index be3c976..146f758 100644 --- a/include/boost/intrusive/detail/tree_node.hpp +++ b/include/boost/intrusive/detail/tree_node.hpp @@ -99,8 +99,8 @@ class tree_iterator : members_ (0, 0) {} - explicit tree_iterator(node_ptr node, const Container *cont_ptr) - : members_ (node, cont_ptr) + explicit tree_iterator(node_ptr nodeptr, const Container *cont_ptr) + : members_ (nodeptr, cont_ptr) {} tree_iterator(tree_iterator const& other) @@ -110,8 +110,8 @@ class tree_iterator const node_ptr &pointed_node() const { return members_.nodeptr_; } - tree_iterator &operator=(const node_ptr &node) - { members_.nodeptr_ = node; return static_cast(*this); } + tree_iterator &operator=(const node_ptr &nodeptr) + { members_.nodeptr_ = nodeptr; return static_cast(*this); } public: tree_iterator& operator++() diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index 0db5f23..d8605aa 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -718,6 +718,8 @@ class hashtable_impl //Constant-time size is incompatible with auto-unlink hooks! BOOST_STATIC_ASSERT(!(constant_time_size && ((int)real_value_traits::link_mode == (int)auto_unlink))); + //Cache begin is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(cache_begin && ((int)real_value_traits::link_mode == (int)auto_unlink))); template node_cast_adaptor > @@ -871,7 +873,7 @@ class hashtable_impl //! Effects: Returns true if the container is empty. //! - //! Complexity: if constant-time size and cache_last options are disabled, + //! Complexity: if constant-time size and cache_begin options are disabled, //! average constant time (worst case, with empty() == true: O(this->bucket_count()). //! Otherwise constant. //! diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index b1f944a..d38d960 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -978,7 +978,8 @@ class list_impl carry.splice(carry.cbegin(), *this, this->cbegin()); int i = 0; while(i < fill && !counter[i].empty()) { - carry.merge(counter[i++], p); + counter[i].merge(carry, p); + carry.swap(counter[i++]); } carry.swap(counter[i]); if(i == fill) @@ -1021,21 +1022,26 @@ class list_impl template void merge(list_impl& x, Predicate p) { - const_iterator e(this->end()); - const_iterator bx(x.begin()); - const_iterator ex(x.end()); - - for (const_iterator b = this->cbegin(); b != e; ++b) { - size_type n(0); - const_iterator ix(bx); - while(ix != ex && p(*ix, *b)){ - ++ix; ++n; + const_iterator e(this->cend()), ex(x.cend()); + const_iterator b(this->cbegin()); + while(!x.empty()){ + const_iterator ix(x.cbegin()); + while (b != e && !p(*ix, *b)){ + ++b; + } + if(b == e){ + //Now transfer the rest to the end of the container + this->splice(e, x); + break; + } + else{ + size_type n(0); + do{ + ++ix; ++n; + } while(ix != ex && p(*ix, *b)); + this->splice(b, x, x.begin(), ix, n); } - this->splice(b, x, bx, ix, n); - bx = ix; } - //Now transfer the rest at the end of the container - this->splice(e, x); } //! Effects: Reverses the order of elements in the list. diff --git a/include/boost/intrusive/rbtree.hpp b/include/boost/intrusive/rbtree.hpp index fa7aa4a..572b545 100644 --- a/include/boost/intrusive/rbtree.hpp +++ b/include/boost/intrusive/rbtree.hpp @@ -513,9 +513,9 @@ class rbtree_impl template void insert_equal(Iterator b, Iterator e) { - iterator end(this->end()); + iterator iend(this->end()); for (; b != e; ++b) - this->insert_equal(end, *b); + this->insert_equal(iend, *b); } //! Requires: value must be an lvalue @@ -579,9 +579,9 @@ class rbtree_impl void insert_unique(Iterator b, Iterator e) { if(this->empty()){ - iterator end(this->end()); + iterator iend(this->end()); for (; b != e; ++b) - this->insert_unique(end, *b); + this->insert_unique(iend, *b); } else{ for (; b != e; ++b) diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index a08752e..e430fb1 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -598,7 +598,7 @@ class slist_impl void swap(slist_impl& other) { if(cache_last){ - this->priv_swap_cache_last(other); + priv_swap_cache_last(this, &other); } else{ this->priv_swap_lists(this->get_root_node(), other.get_root_node(), detail::bool_()); @@ -1264,6 +1264,7 @@ class slist_impl carry.splice_after(carry.cbefore_begin(), *this, this->cbefore_begin()); int i = 0; while(i < fill && !counter[i].empty()) { + carry.swap(counter[i]); last_inserted = carry.merge(counter[i++], p); } BOOST_INTRUSIVE_INVARIANT_ASSERT(counter[i].empty()); @@ -1340,24 +1341,26 @@ class slist_impl template iterator merge(slist_impl& x, Predicate p) { - const_iterator a(cbefore_begin()), e(cend()), ax(x.cbefore_begin()), ex(x.cend()); - const_iterator last_inserted(e); - const_iterator a_next; - while(++(a_next = a) != e && !x.empty()) { - const_iterator ix(ax); - const_iterator cx; - size_type n(0); - while(++(cx = ix) != ex && p(*cx, *a_next)){ - ++ix; ++n; + const_iterator e(this->cend()), ex(x.cend()), bb(this->cbefore_begin()), + bb_next, last_inserted(e); + while(!x.empty()){ + const_iterator ibx_next(x.cbefore_begin()), ibx(ibx_next++); + while (++(bb_next = bb) != e && !p(*ibx_next, *bb_next)){ + bb = bb_next; } - if(ax != ix){ - this->splice_after(a, x, ax, ix, n); - last_inserted = ix; + if(bb_next == e){ + //Now transfer the rest to the end of the container + last_inserted = this->splice_after(bb, x); + break; + } + else{ + size_type n(0); + do{ + ibx = ibx_next; ++n; + } while(++(ibx_next = ibx) != ex && p(*ibx_next, *bb_next)); + this->splice_after(bb, x, x.before_begin(), ibx, n); + last_inserted = ibx; } - a = a_next; - } - if (!x.empty()){ - last_inserted = this->splice_after(a, x); } return last_inserted.unconst(); } @@ -1711,22 +1714,40 @@ class slist_impl } } - void priv_swap_cache_last(slist_impl &other) + static void priv_swap_cache_last(slist_impl *this_impl, slist_impl *other_impl) { - node_ptr other_last(other.get_last_node()); - node_ptr this_last(this->get_last_node()); - node_ptr other_bfirst(other.get_root_node()); - node_ptr this_bfirst(this->get_root_node()); - node_algorithms::transfer_after(this_bfirst, other_bfirst, other_last); - node_algorithms::transfer_after(other_bfirst, other_last != other_bfirst? other_last : this_bfirst, this_last); - node_ptr tmp(this->get_last_node()); - this->set_last_node(other.get_last_node()); - other.set_last_node(tmp); - if(this->get_last_node() == other_bfirst){ - this->set_last_node(this_bfirst); + bool other_was_empty = false; + if(this_impl->empty()){ + //Check if both are empty or + if(other_impl->empty()) + return; + //If this is empty swap pointers + slist_impl *tmp = this_impl; + this_impl = other_impl; + other_impl = tmp; + other_was_empty = true; } - if(other.get_last_node() == this_bfirst){ - other.set_last_node(other_bfirst); + else{ + other_was_empty = other_impl->empty(); + } + + //Precondition: this is not empty + node_ptr other_old_last(other_impl->get_last_node()); + node_ptr other_bfirst(other_impl->get_root_node()); + node_ptr this_bfirst(this_impl->get_root_node()); + node_ptr this_old_last(this_impl->get_last_node()); + + //Move all nodes from this to other's beginning + node_algorithms::transfer_after(other_bfirst, this_bfirst, this_old_last); + other_impl->set_last_node(this_old_last); + + if(other_was_empty){ + this_impl->set_last_node(this_bfirst); + } + else{ + //Move trailing nodes from other to this + node_algorithms::transfer_after(this_bfirst, this_old_last, other_old_last); + this_impl->set_last_node(other_old_last); } } diff --git a/proj/vc7ide/any_test/any_test.vcproj b/proj/vc7ide/any_test/any_test.vcproj index b053349..e99365d 100644 --- a/proj/vc7ide/any_test/any_test.vcproj +++ b/proj/vc7ide/any_test/any_test.vcproj @@ -27,7 +27,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" - DisableLanguageExtensions="FALSE" + DisableLanguageExtensions="TRUE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/custom_bucket_traits/custom_bucket_traits.vcproj b/proj/vc7ide/custom_bucket_traits/custom_bucket_traits.vcproj index a396174..2c873b8 100644 --- a/proj/vc7ide/custom_bucket_traits/custom_bucket_traits.vcproj +++ b/proj/vc7ide/custom_bucket_traits/custom_bucket_traits.vcproj @@ -27,7 +27,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" - DisableLanguageExtensions="FALSE" + DisableLanguageExtensions="TRUE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/default_hook/default_hook.vcproj b/proj/vc7ide/default_hook/default_hook.vcproj index 9c26fb7..e6c1b7f 100644 --- a/proj/vc7ide/default_hook/default_hook.vcproj +++ b/proj/vc7ide/default_hook/default_hook.vcproj @@ -27,7 +27,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" - DisableLanguageExtensions="FALSE" + DisableLanguageExtensions="TRUE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/external_value_traits/external_value_traits.vcproj b/proj/vc7ide/external_value_traits/external_value_traits.vcproj index 87ebd51..6f0b875 100644 --- a/proj/vc7ide/external_value_traits/external_value_traits.vcproj +++ b/proj/vc7ide/external_value_traits/external_value_traits.vcproj @@ -27,7 +27,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" - DisableLanguageExtensions="FALSE" + DisableLanguageExtensions="TRUE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/list/list.vcproj b/proj/vc7ide/list/list.vcproj index e5e510b..8f5817b 100644 --- a/proj/vc7ide/list/list.vcproj +++ b/proj/vc7ide/list/list.vcproj @@ -27,7 +27,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" - DisableLanguageExtensions="FALSE" + DisableLanguageExtensions="TRUE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/make_functions/make_functions.vcproj b/proj/vc7ide/make_functions/make_functions.vcproj index cf926ce..572aa02 100644 --- a/proj/vc7ide/make_functions/make_functions.vcproj +++ b/proj/vc7ide/make_functions/make_functions.vcproj @@ -27,7 +27,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" - DisableLanguageExtensions="FALSE" + DisableLanguageExtensions="TRUE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/stateful_value_traits/stateful_value_traits.vcproj b/proj/vc7ide/stateful_value_traits/stateful_value_traits.vcproj index 72cbe3b..a5b898e 100644 --- a/proj/vc7ide/stateful_value_traits/stateful_value_traits.vcproj +++ b/proj/vc7ide/stateful_value_traits/stateful_value_traits.vcproj @@ -27,7 +27,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" - DisableLanguageExtensions="FALSE" + DisableLanguageExtensions="TRUE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/to-do.txt b/proj/vc7ide/to-do.txt index f62414d..534314c 100644 --- a/proj/vc7ide/to-do.txt +++ b/proj/vc7ide/to-do.txt @@ -24,3 +24,5 @@ -> revise strong exception safety concepts for treap::erase functions. What happens with range deletions? -> Assure stable order for optimize_multikey and inverse order otherwise +-> linear slist's splice_after(..., slist &x) can be optimized if *this is empty +-> optimize slist::merge like list::merge diff --git a/proj/vc7ide/virtual_base/virtual_base.vcproj b/proj/vc7ide/virtual_base/virtual_base.vcproj index b5f6f66..7d87163 100644 --- a/proj/vc7ide/virtual_base/virtual_base.vcproj +++ b/proj/vc7ide/virtual_base/virtual_base.vcproj @@ -27,7 +27,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" - DisableLanguageExtensions="FALSE" + DisableLanguageExtensions="TRUE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 569c1ae..ff0bd7f 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -417,6 +417,28 @@ void test_slist { int init_values [] = { 2 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist2.begin() ); } } + { //Now test swap when testlist2 is empty + list_type testlist1 (&values[0], &values[0] + 2); + list_type testlist2; + testlist1.swap(testlist2); + BOOST_TEST (testlist1.empty()); + { int init_values [] = { 1, 2 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist2.begin() ); } + } + { //Now test swap when testlist1 is empty + list_type testlist2 (&values[0], &values[0] + 2); + list_type testlist1; + testlist1.swap(testlist2); + BOOST_TEST (testlist2.empty()); + { int init_values [] = { 1, 2 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } + } + { //Now test when both are empty + list_type testlist1, testlist2; + testlist2.swap(testlist1); + BOOST_TEST (testlist1.empty() && testlist2.empty()); + } + if(!list_type::linear) { list_type testlist1 (&values[0], &values[0] + 2); diff --git a/test/unordered_multiset_test.cpp b/test/unordered_multiset_test.cpp index 868d264..206605d 100644 --- a/test/unordered_multiset_test.cpp +++ b/test/unordered_multiset_test.cpp @@ -719,7 +719,6 @@ class test_main_template , false , Incremental >::test_all(data); - return 0; } }; @@ -740,7 +739,7 @@ class test_main_template < value_type , typename hooks::base_hook_type >::type - , true + , false , false , Incremental >::test_all(data); @@ -752,7 +751,7 @@ class test_main_template , &value_type::node_ > >::type - , false + , true , false , Incremental >::test_all(data); @@ -761,8 +760,8 @@ class test_main_template < value_type , typename hooks::auto_base_hook_type >::type - , true - , true + , false + , false , Incremental >::test_all(data); diff --git a/test/unordered_set_test.cpp b/test/unordered_set_test.cpp index b84414b..f6b5e48 100644 --- a/test/unordered_set_test.cpp +++ b/test/unordered_set_test.cpp @@ -623,7 +623,7 @@ class test_main_template < value_type , typename hooks::auto_base_hook_type >::type - , true + , false , true , incremental >::test_all(data);