From 08b525b49b80c72a6e178f82dd00c4f00f016a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Sch=C3=B6pflin?= Date: Thu, 26 Jun 2008 06:54:42 +0000 Subject: [PATCH 01/14] For compilers checking the full source code at compile time, regardless of whether the code is instantiated or not, turn the expected compile time error into a link time error. [SVN r46707] --- .../boost/intrusive/detail/any_node_and_algorithms.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/intrusive/detail/any_node_and_algorithms.hpp b/include/boost/intrusive/detail/any_node_and_algorithms.hpp index 6b75f57..9662138 100644 --- a/include/boost/intrusive/detail/any_node_and_algorithms.hpp +++ b/include/boost/intrusive/detail/any_node_and_algorithms.hpp @@ -269,6 +269,14 @@ class any_algorithms static bool unique(const_node_ptr node) { return 0 == node->node_ptr_1; } + +#if defined(__EDG__) && defined(__STD_STRICT_ANSI) + // For compilers checking the full source code at compile time, regardless + // of whether the code is instantiated or not, we turn the compile error + // below into a link error. + static void unlink(node_ptr); + static void swap_nodes(node_ptr l, node_ptr r); +#else static void unlink(node_ptr) { //Auto-unlink hooks and unlink() call for safe hooks are not @@ -282,6 +290,7 @@ class any_algorithms //what algorithm they must use from unlink them from the container any_algorithms::swap_nodes_not_available_for_any_hooks(); } +#endif }; } //namespace intrusive From 1f6958076f49cea0a9b1d334b50afcb81ba95eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 27 Jun 2008 18:19:38 +0000 Subject: [PATCH 02/14] Some fixes for inspection report, Run Date: 15:00:47 UTC, Friday 27 June 2008 [SVN r46786] --- include/boost/intrusive/detail/utilities.hpp | 2 +- include/boost/intrusive/slist.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/intrusive/detail/utilities.hpp b/include/boost/intrusive/detail/utilities.hpp index 743f329..7a92449 100644 --- a/include/boost/intrusive/detail/utilities.hpp +++ b/include/boost/intrusive/detail/utilities.hpp @@ -506,7 +506,7 @@ inline std::size_t floor_log2 (std::size_t x) for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ std::size_t tmp = n >> shift; if (tmp) - log2 += shift, n = tmp; + log2 += shift, n = tmp; } return log2; diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index 14c614f..bab8308 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -1653,7 +1653,7 @@ 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 (before_first_n != before_last_n && prev_pos_n != before_first_n && prev_pos_n != before_last_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()){ From 04883b48c3a5e3a2cc47b3cc81d8c1f1ea21c72a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 27 Jun 2008 18:20:47 +0000 Subject: [PATCH 03/14] Some fixes for inspection report, Run Date: 15:00:47 UTC, Friday 27 June 2008 [SVN r46787] --- index.html | 9 +++++++-- proj/vc7ide/to-do.txt | 37 ------------------------------------- 2 files changed, 7 insertions(+), 39 deletions(-) delete mode 100644 proj/vc7ide/to-do.txt diff --git a/index.html b/index.html index 8c018f9..de9100d 100644 --- a/index.html +++ b/index.html @@ -1,9 +1,14 @@ + - + Automatic redirection failed, please go to -../../doc/html/intrusive +../../doc/html/intrusive.html diff --git a/proj/vc7ide/to-do.txt b/proj/vc7ide/to-do.txt deleted file mode 100644 index 747f679..0000000 --- a/proj/vc7ide/to-do.txt +++ /dev/null @@ -1,37 +0,0 @@ -Implement incremental hashing: - -bucket_len is power of two -cur_idx is always at least, half of bucket_len - -find bucket from value: - size_type bucket_num = hash(val) &(bucket_len - 1); - if (bucket_num >= cur_idx) - bucket_num -= bucket_len/2; - -incremental_rehash: - - iterator _Plist, _Where; - if (load_factor > LoadFactorLimit) - { // too dense, need to grow hash table - if (cur_idx >= (bucket_len - 1)) - { // table full, request doubling - return false; - } - else if (cur_idx >= bucket_len) - bucket_len*=2; - - size_type bucket_num = cur_idx - bucket_len/2; - // rehash elements from bucket_num - ++cur_idx; - } - -insert from value: - - size_type bucket_num = hash(val) & (bucket_len - 1); - if (bucket_num >= cur_idx) - bucket_num -= bucket_len/2; - insert in bucket - -rehash: - - From cb7715bf446933abaa2aeee03a23bf95b4158693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 5 Jul 2008 22:45:31 +0000 Subject: [PATCH 04/14] Ticket #2073: slist::swap doesn't work properly under certain conditions [SVN r47121] --- include/boost/intrusive/detail/common_slist_algorithms.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/intrusive/detail/common_slist_algorithms.hpp b/include/boost/intrusive/detail/common_slist_algorithms.hpp index ada51a9..d837ad0 100644 --- a/include/boost/intrusive/detail/common_slist_algorithms.hpp +++ b/include/boost/intrusive/detail/common_slist_algorithms.hpp @@ -76,7 +76,7 @@ class common_slist_algorithms static void transfer_after(node_ptr p, node_ptr b, node_ptr e) { - if (p != b && p != e) { + if (p != b && p != e && b != e) { node_ptr next_b = NodeTraits::get_next(b); node_ptr next_e = NodeTraits::get_next(e); node_ptr next_p = NodeTraits::get_next(p); From 2d24b82cdfb12064cf360ce21d93d41e7854515b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 8 Jul 2008 16:57:56 +0000 Subject: [PATCH 05/14] Convert link error to compile-time error when using swap_nodes() and unlink() with any_hooks [SVN r47238] --- .../detail/any_node_and_algorithms.hpp | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/include/boost/intrusive/detail/any_node_and_algorithms.hpp b/include/boost/intrusive/detail/any_node_and_algorithms.hpp index 9662138..6a3d955 100644 --- a/include/boost/intrusive/detail/any_node_and_algorithms.hpp +++ b/include/boost/intrusive/detail/any_node_and_algorithms.hpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace boost { namespace intrusive { @@ -238,6 +239,10 @@ class any_node_traits template class any_algorithms { + template + static void function_not_available_for_any_hooks(typename detail::enable_if >::type) + {} + public: typedef any_node node; typedef typename boost::pointer_to_other @@ -269,28 +274,18 @@ class any_algorithms static bool unique(const_node_ptr node) { return 0 == node->node_ptr_1; } - -#if defined(__EDG__) && defined(__STD_STRICT_ANSI) - // For compilers checking the full source code at compile time, regardless - // of whether the code is instantiated or not, we turn the compile error - // below into a link error. - static void unlink(node_ptr); - static void swap_nodes(node_ptr l, node_ptr r); -#else static void unlink(node_ptr) { - //Auto-unlink hooks and unlink() call for safe hooks are not - //available for any hooks!!! - any_algorithms::unlink_not_available_for_any_hooks(); + //Auto-unlink hooks and unlink() are not available for any hooks + any_algorithms::template function_not_available_for_any_hooks(); } static void swap_nodes(node_ptr l, node_ptr r) { //Any nodes have no swap_nodes capability because they don't know - //what algorithm they must use from unlink them from the container - any_algorithms::swap_nodes_not_available_for_any_hooks(); + //what algorithm they must use to unlink the node from the container + any_algorithms::template function_not_available_for_any_hooks(); } -#endif }; } //namespace intrusive From cff3efe68983de4692f7cadb3eb582ea204a6687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 8 Jul 2008 17:00:24 +0000 Subject: [PATCH 06/14] Added operator==() to solve comeau errors [SVN r47239] --- test/itestvalue.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/itestvalue.hpp b/test/itestvalue.hpp index b45bdd8..4fd6750 100644 --- a/test/itestvalue.hpp +++ b/test/itestvalue.hpp @@ -380,6 +380,9 @@ struct testvalue bool operator==(const testvalue &other) const { return value_ == other.value_; } + bool operator!=(const testvalue &other) const + { return value_ != other.value_; } + friend bool operator< (int other1, const testvalue &other2) { return other1 < other2.value_; } @@ -391,6 +394,12 @@ struct testvalue friend bool operator== (const testvalue &other1, int other2) { return other1.value_ == other2; } + + friend bool operator!= (int other1, const testvalue &other2) + { return other1 != other2.value_; } + + friend bool operator!= (const testvalue &other1, int other2) + { return other1.value_ != other2; } }; template From d7b03e5f031e61f452e0f787c18a2671cec7859a Mon Sep 17 00:00:00 2001 From: John Maddock Date: Fri, 10 Oct 2008 16:10:00 +0000 Subject: [PATCH 07/14] Change includes of to . Previously if Boost.TR1 was in the include path then including pulls in all the new TR1 math functions, which in turn also requires linking to an external library. With auto-linking support this requires that library to have been built and be present in the library search path, even if the actual library under use is header only. Fixes #2392. [SVN r49254] --- include/boost/intrusive/sgtree.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/intrusive/sgtree.hpp b/include/boost/intrusive/sgtree.hpp index 44ba705..70d4b61 100644 --- a/include/boost/intrusive/sgtree.hpp +++ b/include/boost/intrusive/sgtree.hpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include From d8641cd15c11966890077259ae220a01e64085fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 11 Oct 2008 13:14:49 +0000 Subject: [PATCH 08/14] Changes and fixes for Boost 1.37 [SVN r49276] --- include/boost/intrusive/any_hook.hpp | 46 +- include/boost/intrusive/avl_set.hpp | 114 ++- include/boost/intrusive/avl_set_hook.hpp | 42 +- include/boost/intrusive/avltree.hpp | 98 +- .../boost/intrusive/avltree_algorithms.hpp | 16 +- include/boost/intrusive/bs_set_hook.hpp | 62 +- .../intrusive/circular_slist_algorithms.hpp | 4 +- include/boost/intrusive/detail/assert.hpp | 18 +- include/boost/intrusive/detail/list_node.hpp | 3 + include/boost/intrusive/detail/mpl.hpp | 188 ++-- include/boost/intrusive/detail/slist_node.hpp | 3 + .../intrusive/detail/tree_algorithms.hpp | 4 +- include/boost/intrusive/detail/workaround.hpp | 30 + include/boost/intrusive/hashtable.hpp | 890 ++++++++++++------ include/boost/intrusive/intrusive_fwd.hpp | 152 ++- .../intrusive/linear_slist_algorithms.hpp | 4 +- include/boost/intrusive/list.hpp | 146 +-- include/boost/intrusive/list_hook.hpp | 44 +- include/boost/intrusive/options.hpp | 214 ++++- include/boost/intrusive/pointer_plus_bits.hpp | 7 +- include/boost/intrusive/rbtree.hpp | 106 ++- include/boost/intrusive/set.hpp | 116 ++- include/boost/intrusive/set_hook.hpp | 44 +- include/boost/intrusive/sg_set.hpp | 116 ++- include/boost/intrusive/sgtree.hpp | 96 +- include/boost/intrusive/sgtree_algorithms.hpp | 2 +- include/boost/intrusive/slist.hpp | 212 +++-- include/boost/intrusive/slist_hook.hpp | 44 +- include/boost/intrusive/splay_set.hpp | 115 ++- include/boost/intrusive/splay_set_hook.hpp | 44 +- include/boost/intrusive/splaytree.hpp | 109 ++- .../boost/intrusive/splaytree_algorithms.hpp | 2 +- include/boost/intrusive/unordered_set.hpp | 154 ++- .../boost/intrusive/unordered_set_hook.hpp | 44 +- 34 files changed, 2274 insertions(+), 1015 deletions(-) create mode 100644 include/boost/intrusive/detail/workaround.hpp diff --git a/include/boost/intrusive/any_hook.hpp b/include/boost/intrusive/any_hook.hpp index 148d41d..4690cef 100644 --- a/include/boost/intrusive/any_hook.hpp +++ b/include/boost/intrusive/any_hook.hpp @@ -34,7 +34,7 @@ struct get_any_node_algo //! Helper metafunction to define a \c \c any_base_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -43,8 +43,14 @@ struct make_any_base_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; - + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; + typedef detail::generic_hook < get_any_node_algo , typename packed_options::tag @@ -70,15 +76,21 @@ struct make_any_base_hook //! //! \c void_pointer<> is the pointer type that will be used internally in the hook //! and the the container configured to use this hook. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class any_base_hook - : public make_any_base_hook::type + : public make_any_base_hook + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) public: //! Effects: If link_mode is or \c safe_link //! initializes the node to an unlinked state. @@ -127,7 +139,7 @@ class any_base_hook //! Helper metafunction to define a \c \c any_member_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -136,7 +148,13 @@ struct make_any_member_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_any_node_algo @@ -158,15 +176,21 @@ struct make_any_member_hook //! //! \c void_pointer<> is the pointer type that will be used internally in the hook //! and the the container configured to use this hook. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class any_member_hook - : public make_any_member_hook::type + : public make_any_member_hook + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) public: //! Effects: If link_mode is or \c safe_link //! initializes the node to an unlinked state. diff --git a/include/boost/intrusive/avl_set.hpp b/include/boost/intrusive/avl_set.hpp index 8429f13..a550232 100644 --- a/include/boost/intrusive/avl_set.hpp +++ b/include/boost/intrusive/avl_set.hpp @@ -31,7 +31,7 @@ namespace intrusive { //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -323,18 +323,19 @@ class avl_set_impl { tree_.swap(other.tree_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const avl_set_impl &src, Cloner cloner, Disposer disposer) { tree_.clone_from(src.tree_, cloner, disposer); } @@ -996,65 +997,65 @@ class avl_set_impl /// @endcond }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avl_set_impl &x, const avl_set_impl &y) #else (const avl_set_impl &x, const avl_set_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avl_set_impl &x, const avl_set_impl &y) #else (const avl_set_impl &x, const avl_set_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avl_set_impl &x, const avl_set_impl &y) #else (const avl_set_impl &x, const avl_set_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avl_set_impl &x, const avl_set_impl &y) #else (const avl_set_impl &x, const avl_set_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (avl_set_impl &x, avl_set_impl &y) #else (avl_set_impl &x, avl_set_impl &y) @@ -1063,7 +1064,7 @@ inline void swap //! Helper metafunction to define a \c avl_set that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_avltree_opt + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class avl_set - : public make_avl_set::type + : public make_avl_set + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type { typedef typename make_avl_set - ::type Base; + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type Base; public: typedef typename Base::value_compare value_compare; @@ -1134,7 +1157,7 @@ class avl_set //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -1422,18 +1445,19 @@ class avl_multiset_impl { tree_.swap(other.tree_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. Basic guarantee. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const avl_multiset_impl &src, Cloner cloner, Disposer disposer) { tree_.clone_from(src.tree_, cloner, disposer); } @@ -2002,65 +2026,65 @@ class avl_multiset_impl /// @endcond }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avl_multiset_impl &x, const avl_multiset_impl &y) #else (const avl_multiset_impl &x, const avl_multiset_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avl_multiset_impl &x, const avl_multiset_impl &y) #else (const avl_multiset_impl &x, const avl_multiset_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avl_multiset_impl &x, const avl_multiset_impl &y) #else (const avl_multiset_impl &x, const avl_multiset_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avl_multiset_impl &x, const avl_multiset_impl &y) #else (const avl_multiset_impl &x, const avl_multiset_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (avl_multiset_impl &x, avl_multiset_impl &y) #else (avl_multiset_impl &x, avl_multiset_impl &y) @@ -2069,7 +2093,7 @@ inline void swap //! Helper metafunction to define a \c avl_multiset that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_avltree_opt + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class avl_multiset - : public make_avl_multiset::type + : public make_avl_multiset::type { typedef typename make_avl_multiset - ::type Base; + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type Base; public: typedef typename Base::value_compare value_compare; diff --git a/include/boost/intrusive/avl_set_hook.hpp b/include/boost/intrusive/avl_set_hook.hpp index 93a9a85..76fa739 100644 --- a/include/boost/intrusive/avl_set_hook.hpp +++ b/include/boost/intrusive/avl_set_hook.hpp @@ -34,7 +34,7 @@ struct get_avl_set_node_algo //! Helper metafunction to define a \c avl_set_base_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -43,7 +43,12 @@ struct make_avl_set_base_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3, O4>::type packed_options; + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type packed_options; typedef detail::generic_hook < get_avl_set_node_algo will tell the hook to optimize the hook for size instead //! of speed. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class avl_set_base_hook - : public make_avl_set_base_hook::type + : public make_avl_set_base_hook + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! @@ -153,7 +164,7 @@ class avl_set_base_hook //! Helper metafunction to define a \c avl_set_member_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -162,7 +173,12 @@ struct make_avl_set_member_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3, O4>::type packed_options; + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type packed_options; typedef detail::generic_hook < get_avl_set_node_algo will tell the hook to optimize the hook for size instead //! of speed. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class avl_set_member_hook - : public make_avl_set_member_hook::type + : public make_avl_set_member_hook + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! diff --git a/include/boost/intrusive/avltree.hpp b/include/boost/intrusive/avltree.hpp index afd6bd4..46038a8 100644 --- a/include/boost/intrusive/avltree.hpp +++ b/include/boost/intrusive/avltree.hpp @@ -36,20 +36,6 @@ namespace intrusive { /// @cond -template -struct internal_default_avl_set_hook -{ - template static detail::one test(...); - template static detail::two test(typename U::default_avl_set_hook* = 0); - static const bool value = sizeof(test(0)) == sizeof(detail::two); -}; - -template -struct get_default_avl_set_hook -{ - typedef typename T::default_avl_set_hook type; -}; - template struct avl_setopt { @@ -63,13 +49,7 @@ template struct avl_set_defaults : pack_options < none - , base_hook - < typename detail::eval_if_c - < internal_default_avl_set_hook::value - , get_default_avl_set_hook - , detail::identity - >::type - > + , base_hook , constant_time_size , size_type , compare > @@ -91,7 +71,7 @@ struct avl_set_defaults //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -1055,29 +1035,34 @@ class avltree_impl } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const avltree_impl &src, Cloner cloner, Disposer disposer) { this->clear_and_dispose(disposer); if(!src.empty()){ + detail::exception_disposer + rollback(*this, disposer); node_algorithms::clone (const_node_ptr(&src.priv_header()) ,node_ptr(&this->priv_header()) ,detail::node_cloner(cloner, this) ,detail::node_disposer(disposer, this)); this->priv_size_traits().set_size(src.priv_size_traits().get_size()); + this->priv_comp() = src.priv_comp(); + rollback.release(); } } @@ -1260,26 +1245,26 @@ class avltree_impl { return priv_container_from_end_iterator(it.end_iterator_from_it()); } }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator< -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avltree_impl &x, const avltree_impl &y) #else (const avltree_impl &x, const avltree_impl &y) #endif { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif bool operator== -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avltree_impl &x, const avltree_impl &y) #else (const avltree_impl &x, const avltree_impl &y) @@ -1311,65 +1296,65 @@ bool operator== } } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avltree_impl &x, const avltree_impl &y) #else (const avltree_impl &x, const avltree_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avltree_impl &x, const avltree_impl &y) #else (const avltree_impl &x, const avltree_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avltree_impl &x, const avltree_impl &y) #else (const avltree_impl &x, const avltree_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const avltree_impl &x, const avltree_impl &y) #else (const avltree_impl &x, const avltree_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (avltree_impl &x, avltree_impl &y) #else (avltree_impl &x, avltree_impl &y) @@ -1377,15 +1362,24 @@ inline void swap { x.swap(y); } /// @cond + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif struct make_avltree_opt { typedef typename pack_options - < avl_set_defaults, O1, O2, O3, O4>::type packed_options; + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + < avl_set_defaults, O1, O2, O3, O4> + #else + < avl_set_defaults, Options...> + #endif + ::type packed_options; + typedef typename detail::get_value_traits ::type value_traits; @@ -1400,7 +1394,7 @@ struct make_avltree_opt //! Helper metafunction to define a \c avltree that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + #else + < typename make_avltree_opt::type + #endif > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class avltree + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) : public make_avltree::type + #else + : public make_avltree::type + #endif { typedef typename make_avltree - ::type Base; + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type Base; public: typedef typename Base::value_compare value_compare; diff --git a/include/boost/intrusive/avltree_algorithms.hpp b/include/boost/intrusive/avltree_algorithms.hpp index dc4eed4..307dbc8 100644 --- a/include/boost/intrusive/avltree_algorithms.hpp +++ b/include/boost/intrusive/avltree_algorithms.hpp @@ -682,10 +682,10 @@ class avltree_algorithms // x is right child // a is left child node_ptr a = NodeTraits::get_left(x_parent); - assert(a); + BOOST_INTRUSIVE_INVARIANT_ASSERT(a); if (NodeTraits::get_balance(a) == NodeTraits::positive()) { // a MUST have a right child - assert(NodeTraits::get_right(a)); + BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(a)); rotate_left_right(x_parent, root); x = NodeTraits::get_parent(x_parent); @@ -714,10 +714,10 @@ class avltree_algorithms // x is left child // a is right child node_ptr a = NodeTraits::get_right(x_parent); - assert(a); + BOOST_INTRUSIVE_INVARIANT_ASSERT(a); if (NodeTraits::get_balance(a) == NodeTraits::negative()) { // a MUST have then a left child - assert(NodeTraits::get_left(a)); + BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(a)); rotate_right_left(x_parent, root); x = NodeTraits::get_parent(x_parent); @@ -735,7 +735,7 @@ class avltree_algorithms } } else{ - assert(false); // never reached + BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached } } NodeTraits::set_parent(header, root); @@ -784,7 +784,7 @@ class avltree_algorithms break; } else{ - assert(false); // never reached + BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached } } NodeTraits::set_parent(header, root); @@ -842,7 +842,7 @@ class avltree_algorithms NodeTraits::set_balance(b, NodeTraits::negative()); } else{ - assert(false); // never reached + BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached } NodeTraits::set_balance(c, NodeTraits::zero()); } @@ -899,7 +899,7 @@ class avltree_algorithms NodeTraits::set_balance(b, NodeTraits::zero()); } else{ - assert(false); + BOOST_INTRUSIVE_INVARIANT_ASSERT(false); } NodeTraits::set_balance(c, NodeTraits::zero()); } diff --git a/include/boost/intrusive/bs_set_hook.hpp b/include/boost/intrusive/bs_set_hook.hpp index bf55042..d4726b0 100644 --- a/include/boost/intrusive/bs_set_hook.hpp +++ b/include/boost/intrusive/bs_set_hook.hpp @@ -34,7 +34,7 @@ struct get_bs_set_node_algo //! Helper metafunction to define a \c bs_set_base_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -43,7 +43,12 @@ struct make_bs_set_base_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + < hook_defaults, O1, O2, O3> + #else + < hook_defaults, Options...> + #endif + ::type packed_options; //Scapegoat trees can't be auto unlink trees BOOST_STATIC_ASSERT(((int)packed_options::link_mode != (int)auto_unlink)); @@ -75,15 +80,22 @@ struct make_bs_set_base_hook //! //! \c link_mode<> will specify the linking mode of the hook (\c normal_link, //! \c auto_unlink or \c safe_link). -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class bs_set_base_hook - : public make_bs_set_base_hook::type + : public make_bs_set_base_hook + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type + { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! @@ -152,7 +164,7 @@ class bs_set_base_hook //! Helper metafunction to define a \c bs_set_member_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -161,7 +173,13 @@ struct make_bs_set_member_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + < hook_defaults, O1, O2, O3> + #else + < hook_defaults, Options...> + #endif + + ::type packed_options; //Scapegoat trees can't be auto unlink trees BOOST_STATIC_ASSERT(((int)packed_options::link_mode != (int)auto_unlink)); @@ -187,15 +205,21 @@ struct make_bs_set_member_hook //! //! \c link_mode<> will specify the linking mode of the hook (\c normal_link, //! \c auto_unlink or \c safe_link). -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class bs_set_member_hook - : public make_bs_set_member_hook::type + : public make_bs_set_member_hook + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! @@ -262,24 +286,6 @@ class bs_set_member_hook #endif }; -/// @cond - -template -struct internal_default_bs_set_hook -{ - template static detail::one test(...); - template static detail::two test(typename U::default_bs_set_hook* = 0); - static const bool value = sizeof(test(0)) == sizeof(detail::two); -}; - -template -struct get_default_bs_set_hook -{ - typedef typename T::default_bs_set_hook type; -}; - -/// @endcond - } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/circular_slist_algorithms.hpp b/include/boost/intrusive/circular_slist_algorithms.hpp index f74a641..5247f57 100644 --- a/include/boost/intrusive/circular_slist_algorithms.hpp +++ b/include/boost/intrusive/circular_slist_algorithms.hpp @@ -59,7 +59,7 @@ class circular_slist_algorithms typedef typename NodeTraits::const_node_ptr const_node_ptr; typedef NodeTraits node_traits; - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: Constructs an non-used list element, putting the next //! pointer to null: @@ -128,7 +128,7 @@ class circular_slist_algorithms //! Throws: Nothing. static void transfer_after(node_ptr p, node_ptr b, node_ptr e); - #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: Constructs an empty list, making this_node the only //! node of the circular list: diff --git a/include/boost/intrusive/detail/assert.hpp b/include/boost/intrusive/detail/assert.hpp index 076343e..e742b7e 100644 --- a/include/boost/intrusive/detail/assert.hpp +++ b/include/boost/intrusive/detail/assert.hpp @@ -18,18 +18,24 @@ #endif #if !defined(BOOST_INTRUSIVE_INVARIANT_ASSERT) -#include -#define BOOST_INTRUSIVE_INVARIANT_ASSERT BOOST_ASSERT + #include + #define BOOST_INTRUSIVE_INVARIANT_ASSERT BOOST_ASSERT +#elif defined(BOOST_INTRUSIVE_INVARIANT_ASSERT_INCLUDE) + #include BOOST_INTRUSIVE_INVARIANT_ASSERT_INCLUDE #endif #if !defined(BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT) -#include -#define BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT BOOST_ASSERT + #include + #define BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT BOOST_ASSERT +#elif defined(BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT_INCLUDE) + #include BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT_INCLUDE #endif #if !defined(BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT) -#include -#define BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT BOOST_ASSERT + #include + #define BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT BOOST_ASSERT +#elif defined(BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE) + #include BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE #endif #endif //BOOST_INTRUSIVE_DETAIL_ASSERT_HPP diff --git a/include/boost/intrusive/detail/list_node.hpp b/include/boost/intrusive/detail/list_node.hpp index 371224e..a0bc8ba 100644 --- a/include/boost/intrusive/detail/list_node.hpp +++ b/include/boost/intrusive/detail/list_node.hpp @@ -161,6 +161,9 @@ class list_iterator return 0; } + list_iterator unconst() const + { return list_iterator(this->pointed_node(), this->get_container()); } + private: struct members : public detail::select_constptr diff --git a/include/boost/intrusive/detail/mpl.hpp b/include/boost/intrusive/detail/mpl.hpp index ed68350..27e7f37 100644 --- a/include/boost/intrusive/detail/mpl.hpp +++ b/include/boost/intrusive/detail/mpl.hpp @@ -51,6 +51,12 @@ struct enable_if_c {}; template struct enable_if : public enable_if_c{}; +template +struct apply +{ + typedef typename F::template apply::type type; +}; + template class is_convertible { @@ -127,83 +133,127 @@ struct identity #define BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS #endif -no_type BOOST_INTRUSIVE_TT_DECL is_function_ptr_tester(...); - -template -yes_type is_function_ptr_tester(R (*)()); - -template -yes_type is_function_ptr_tester(R (*)( ...)); - -#ifdef BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS -template -yes_type is_function_ptr_tester(R (__stdcall*)()); -template -yes_type is_function_ptr_tester(R (__stdcall*)( ...)); - -template -yes_type is_function_ptr_tester(R (__fastcall*)()); -template -yes_type is_function_ptr_tester(R (__fastcall*)( ...)); - -template -yes_type is_function_ptr_tester(R (__cdecl*)()); -template -yes_type is_function_ptr_tester(R (__cdecl*)( ...)); -#endif - -template -yes_type is_function_ptr_tester(R (*)( T0)); - -template -yes_type is_function_ptr_tester(R (*)( T0 ...)); - -#ifdef BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS -template -yes_type is_function_ptr_tester(R (__stdcall*)( T0)); -template -yes_type is_function_ptr_tester(R (__stdcall*)( T0 ...)); - -template -yes_type is_function_ptr_tester(R (__fastcall*)( T0)); -template -yes_type is_function_ptr_tester(R (__fastcall*)( T0 ...)); - -template -yes_type is_function_ptr_tester(R (__cdecl*)( T0)); -#endif -template -yes_type is_function_ptr_tester(R (*)( T0 , T1)); - -#ifdef BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS -template -yes_type is_function_ptr_tester(R (__stdcall*)( T0 , T1)); - -template -yes_type is_function_ptr_tester(R (__fastcall*)( T0 , T1)); - -template -yes_type is_function_ptr_tester(R (__cdecl*)( T0 , T1)); -#endif - template struct is_unary_or_binary_function_impl -{ - static T* t; - static const bool value = sizeof(is_function_ptr_tester(t)) == sizeof(yes_type); -}; +{ static const bool value = false; }; +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; +/* +#ifdef BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; +#endif +*/ +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#ifdef BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; +/* +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; +*/ +#endif + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; +/* +#ifdef BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; +#endif +*/ template struct is_unary_or_binary_function_impl -{ - static const bool value = false; -}; +{ static const bool value = false; }; template struct is_unary_or_binary_function -{ - static const bool value = is_unary_or_binary_function_impl::value; -}; +{ static const bool value = is_unary_or_binary_function_impl::value; }; //boost::alignment_of yields to 10K lines of preprocessed code, so we //need an alternative diff --git a/include/boost/intrusive/detail/slist_node.hpp b/include/boost/intrusive/detail/slist_node.hpp index 8195e54..c0636e1 100644 --- a/include/boost/intrusive/detail/slist_node.hpp +++ b/include/boost/intrusive/detail/slist_node.hpp @@ -128,6 +128,9 @@ class slist_iterator return 0; } + slist_iterator unconst() const + { return slist_iterator(this->pointed_node(), this->get_container()); } + const real_value_traits *get_real_value_traits() const { if(store_container_ptr) diff --git a/include/boost/intrusive/detail/tree_algorithms.hpp b/include/boost/intrusive/detail/tree_algorithms.hpp index 65e673f..0aa06f7 100644 --- a/include/boost/intrusive/detail/tree_algorithms.hpp +++ b/include/boost/intrusive/detail/tree_algorithms.hpp @@ -1391,14 +1391,14 @@ class tree_algorithms //Taken from: //"Tree rebalancing in optimal time and space" //Quentin F. Stout and Bette L. Warren - std::size_t len; + std::size_t len = 0; subtree_to_vine(NodeTraits::get_parent(header), &len); vine_to_subtree(NodeTraits::get_parent(header), len); } static node_ptr rebalance_subtree(node_ptr old_root) { - std::size_t len; + std::size_t len = 0; node_ptr new_root = subtree_to_vine(old_root, &len); return vine_to_subtree(new_root, len); } diff --git a/include/boost/intrusive/detail/workaround.hpp b/include/boost/intrusive/detail/workaround.hpp new file mode 100644 index 0000000..a4c0974 --- /dev/null +++ b/include/boost/intrusive/detail/workaround.hpp @@ -0,0 +1,30 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_DETAIL_WRKRND_HPP +#define BOOST_INTRUSIVE_DETAIL_WRKRND_HPP + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) +// C++0x features are only enabled when -std=c++0x or -std=gnu++0x are +// passed on the command line, which in turn defines +// __GXX_EXPERIMENTAL_CXX0X__. Note: __GXX_EXPERIMENTAL_CPP0X__ is +// defined by some very early development versions of GCC 4.3; we will +// remove this part of the check in the near future. +# if defined(__GXX_EXPERIMENTAL_CPP0X__) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_INTRUSIVE_RVALUE_REFERENCE +# define BOOST_INTRUSIVE_VARIADIC_TEMPLATES +# endif +#endif + +#if defined(BOOST_INTRUSIVE_RVALUE_REFERENCE) && defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +#define BOOST_INTRUSIVE_PERFECT_FORWARDING +#endif + +#endif //#ifndef BOOST_INTRUSIVE_DETAIL_WRKRND_HPP diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index 2d51e79..c0ef630 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -43,6 +43,50 @@ namespace intrusive { namespace detail { +struct hash_bool_flags +{ + static const std::size_t unique_keys_pos = 1u; + static const std::size_t constant_time_size_pos = 2u; + static const std::size_t power_2_buckets_pos = 4u; + static const std::size_t cache_begin_pos = 8u; + static const std::size_t compare_hash_pos = 16u; + static const std::size_t incremental_pos = 32u; +}; + +template + < class ValueTraits + , class Hash + , class Equal + , class SizeType + , class BucketTraits + , std::size_t BoolFlags + > +struct usetopt +{ + typedef ValueTraits value_traits; + typedef Hash hash; + typedef Equal equal; + typedef SizeType size_type; + typedef BucketTraits bucket_traits; + static const std::size_t bool_flags = BoolFlags; +}; + +template + < class UsetOpt + , std::size_t BoolMask + > +struct usetopt_mask +{ + typedef usetopt + type; +}; + template struct hash_reduced_slist_node_traits { @@ -109,7 +153,6 @@ struct get_slist_impl_from_supposed_value_traits >::type type; }; - template struct unordered_bucket_impl { @@ -173,11 +216,11 @@ struct optimize_multikey_is_true template struct bucket_plus_size : public detail::size_holder - < Config::constant_time_size + < 0 != (Config::bool_flags & hash_bool_flags::constant_time_size_pos) , typename Config::size_type> { typedef detail::size_holder - < Config::constant_time_size + < 0 != (Config::bool_flags & hash_bool_flags::constant_time_size_pos) , typename Config::size_type> size_traits; typedef typename Config::bucket_traits bucket_traits; @@ -188,11 +231,12 @@ struct bucket_plus_size }; template -struct bucket_hash_t : public detail::ebo_functor_holder +struct bucket_hash_t + : public detail::ebo_functor_holder { typedef typename Config::hash hasher; typedef detail::size_holder - < Config::constant_time_size + < 0 != (Config::bool_flags & hash_bool_flags::constant_time_size_pos) , typename Config::size_type> size_traits; typedef typename Config::bucket_traits bucket_traits; @@ -236,6 +280,7 @@ struct bucket_hash_equal_t template struct hashtable_data_t : public Config::value_traits { + static const std::size_t bool_flags = Config::bool_flags; typedef typename Config::value_traits value_traits; typedef typename Config::equal equal; typedef typename Config::hash hasher; @@ -243,9 +288,27 @@ struct hashtable_data_t : public Config::value_traits hashtable_data_t( const bucket_traits &b_traits, const hasher & h , const equal &e, const value_traits &val_traits) - : Config::value_traits(val_traits), bucket_hash_equal_(b_traits, h, e) + : Config::value_traits(val_traits), internal_(b_traits, h, e) {} - bucket_hash_equal_t bucket_hash_equal_; + typedef typename detail::usetopt_mask + < Config + , detail::hash_bool_flags::constant_time_size_pos + | detail::hash_bool_flags::incremental_pos + >::type masked_config_t; + struct internal + : public detail::size_holder + < 0 != (Config::bool_flags & hash_bool_flags::incremental_pos) + , typename Config::size_type> + { + internal(const bucket_traits &b_traits, const hasher & h, const equal &e) + : bucket_hash_equal_(b_traits, h, e) + {} + + bucket_hash_equal_t + < masked_config_t + , 0 != (bool_flags & hash_bool_flags::cache_begin_pos) + > bucket_hash_equal_; + } internal_; }; struct insert_commit_data_impl @@ -253,12 +316,154 @@ struct insert_commit_data_impl std::size_t hash; }; -template -struct internal_default_uset_hook +template +struct group_functions { - template static detail::one test(...); - template static detail::two test(typename U::default_uset_hook* = 0); - static const bool value = sizeof(test(0)) == sizeof(detail::two); + typedef NodeTraits node_traits; + typedef unordered_group_adapter group_traits; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::node node; + typedef typename reduced_slist_node_traits + ::type reduced_node_traits; + typedef typename reduced_node_traits::node_ptr slist_node_ptr; + typedef typename reduced_node_traits::node slist_node; + typedef circular_slist_algorithms group_algorithms; + + static node_ptr dcast_bucket_ptr(slist_node_ptr p) + { return node_ptr(&static_cast(*p)); } + + static slist_node_ptr priv_get_bucket_before_begin + (slist_node_ptr bucket_beg, slist_node_ptr bucket_end, node_ptr p) + { + //First find the last node of p's group. + //This requires checking the first node of the next group or + //the bucket node. + node_ptr prev_node = p; + node_ptr nxt(node_traits::get_next(p)); + while(!(bucket_beg <= nxt && nxt <= bucket_end) && + (group_traits::get_next(nxt) == prev_node)){ + prev_node = nxt; + nxt = node_traits::get_next(nxt); + } + + //If we've reached the bucket node just return it. + if(bucket_beg <= nxt && nxt <= bucket_end){ + return nxt; + } + + //Otherwise, iterate using group links until the bucket node + node_ptr first_node_of_group = nxt; + node_ptr last_node_group = group_traits::get_next(first_node_of_group); + slist_node_ptr possible_end = node_traits::get_next(last_node_group); + + while(!(bucket_beg <= possible_end && possible_end <= bucket_end)){ + first_node_of_group = dcast_bucket_ptr(possible_end); + last_node_group = group_traits::get_next(first_node_of_group); + possible_end = node_traits::get_next(last_node_group); + } + return possible_end; + } + + static node_ptr priv_get_prev_to_first_in_group(slist_node_ptr bucket_node, node_ptr first_in_group) + { + //Just iterate using group links and obtain the node + //before "first_in_group)" + node_ptr prev_node = dcast_bucket_ptr(bucket_node); + node_ptr nxt(node_traits::get_next(prev_node)); + while(nxt != first_in_group){ + prev_node = group_traits::get_next(nxt); + nxt = node_traits::get_next(prev_node); + } + return prev_node; + } + + static node_ptr priv_get_first_in_group_of_last_in_group(node_ptr last_in_group) + { + //Just iterate using group links and obtain the node + //before "last_in_group" + node_ptr possible_first = group_traits::get_next(last_in_group); + node_ptr possible_first_prev = group_traits::get_next(possible_first); + // The deleted node is at the end of the group, so the + // node in the group pointing to it is at the beginning + // of the group. Find that to change its pointer. + while(possible_first_prev != last_in_group){ + possible_first = possible_first_prev; + possible_first_prev = group_traits::get_next(possible_first); + } + return possible_first; + } + + + static void priv_erase_from_group(slist_node_ptr end_ptr, node_ptr to_erase_ptr, detail::true_) + { + node_ptr nxt_ptr(node_traits::get_next(to_erase_ptr)); + node_ptr prev_in_group_ptr(group_traits::get_next(to_erase_ptr)); + bool last_in_group = (end_ptr == nxt_ptr) || + (group_traits::get_next(nxt_ptr) != to_erase_ptr); + bool first_in_group = node_traits::get_next(prev_in_group_ptr) != to_erase_ptr; + + if(first_in_group && last_in_group){ + group_algorithms::init(to_erase_ptr); + } + else if(first_in_group){ + group_algorithms::unlink_after(nxt_ptr); + } + else if(last_in_group){ + node_ptr first_in_group = + priv_get_first_in_group_of_last_in_group(to_erase_ptr); + group_algorithms::unlink_after(first_in_group); + } + else{ + group_algorithms::unlink_after(nxt_ptr); + } + } + + static void priv_erase_from_group(slist_node_ptr, node_ptr, detail::false_) + {} + + static node_ptr priv_get_last_in_group(node_ptr first_in_group, detail::true_) + { return group_traits::get_next(first_in_group); } + + static node_ptr priv_get_last_in_group(node_ptr n, detail::false_) + { return n; } +}; + +template +class incremental_rehash_rollback +{ + private: + typedef BucketType bucket_type; + typedef SplitTraits split_traits; + + incremental_rehash_rollback(); + incremental_rehash_rollback & operator=(const incremental_rehash_rollback &); + incremental_rehash_rollback (const incremental_rehash_rollback &); + + public: + incremental_rehash_rollback + (bucket_type &source_bucket, bucket_type &destiny_bucket, split_traits &split_traits) + : source_bucket_(source_bucket), destiny_bucket_(destiny_bucket) + , split_traits_(split_traits), released_(false) + {} + + void release() + { released_ = true; } + + ~incremental_rehash_rollback() + { + if(!released_){ + //If an exception is thrown, just put all moved nodes back in the old bucket + //and move back the split mark. + destiny_bucket_.splice_after(destiny_bucket_.before_begin(), source_bucket_); + split_traits_.decrement(); + } + } + + private: + bucket_type &source_bucket_; + bucket_type &destiny_bucket_; + split_traits &split_traits_; + bool released_; }; } //namespace detail { @@ -304,50 +509,13 @@ struct unordered_default_bucket_traits typedef implementation_defined type; }; -template -struct get_default_uset_hook -{ - typedef typename T::default_uset_hook type; -}; - -template < class ValueTraits - , bool UniqueKeys - , class Hash - , class Equal - , class SizeType - , bool ConstantTimeSize - , class BucketTraits - , bool Power2Buckets - , bool CacheBegin - , bool CompareHash - > -struct usetopt -{ - typedef ValueTraits value_traits; - typedef Hash hash; - typedef Equal equal; - typedef SizeType size_type; - typedef BucketTraits bucket_traits; - static const bool constant_time_size = ConstantTimeSize; - static const bool power_2_buckets = Power2Buckets; - static const bool unique_keys = UniqueKeys; - static const bool cache_begin = CacheBegin; - static const bool compare_hash = CompareHash; -}; - struct default_bucket_traits; template struct uset_defaults : pack_options < none - , base_hook - < typename detail::eval_if_c - < detail::internal_default_uset_hook::value - , get_default_uset_hook - , detail::identity - >::type - > + , base_hook , constant_time_size , size_type , equal > @@ -356,6 +524,7 @@ struct uset_defaults , power_2_buckets , cache_begin , compare_hash + , incremental >::type {}; @@ -380,7 +549,7 @@ struct uset_defaults //! The container supports the following options: //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<>, \c hash<> and \c equal<> -//! \c bucket_traits<>, power_2_buckets<> and cache_begin<>. +//! \c bucket_traits<>, power_2_buckets<>, cache_begin<> and incremental<>. //! //! hashtable only provides forward iterators but it provides 4 iterator types: //! iterator and const_iterator to navigate through the whole container and @@ -397,13 +566,12 @@ struct uset_defaults //! //! Since no automatic rehashing is done, iterators are never invalidated when //! inserting or erasing elements. Iterators are only invalidated when rehashing. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif class hashtable_impl - : private detail::hashtable_data_t { public: typedef typename Config::value_traits value_traits; @@ -455,18 +623,22 @@ class hashtable_impl ::type const_node_ptr; typedef typename slist_impl::node_algorithms node_algorithms; - static const bool constant_time_size = Config::constant_time_size; static const bool stateful_value_traits = detail::store_cont_ptr_on_it::value; static const bool store_hash = detail::store_hash_is_true::value; - static const bool unique_keys = Config::unique_keys; + + static const bool unique_keys = 0 != (Config::bool_flags & detail::hash_bool_flags::unique_keys_pos); + static const bool constant_time_size = 0 != (Config::bool_flags & detail::hash_bool_flags::constant_time_size_pos); + static const bool cache_begin = 0 != (Config::bool_flags & detail::hash_bool_flags::cache_begin_pos); + static const bool compare_hash = 0 != (Config::bool_flags & detail::hash_bool_flags::compare_hash_pos); + static const bool incremental = 0 != (Config::bool_flags & detail::hash_bool_flags::incremental_pos); + static const bool power_2_buckets = incremental || (0 != (Config::bool_flags & detail::hash_bool_flags::power_2_buckets_pos)); + static const bool optimize_multikey = detail::optimize_multikey_is_true::value && !unique_keys; - static const bool power_2_buckets = Config::power_2_buckets; - static const bool cache_begin = Config::cache_begin; - static const bool compare_hash = Config::compare_hash; /// @cond private: + //Configuration error: compare_hash<> can't be specified without store_hash<> //See documentation for more explanations BOOST_STATIC_ASSERT((!compare_hash || store_hash)); @@ -483,7 +655,17 @@ class hashtable_impl typedef detail::bool_ cache_begin_t; typedef detail::bool_ power_2_buckets_t; typedef detail::size_holder size_traits; - typedef detail::hashtable_data_t base_type; + typedef detail::size_holder split_traits; + typedef detail::group_functions group_functions_t; + + static const std::size_t hashtable_data_bool_flags_mask = + ( detail::hash_bool_flags::cache_begin_pos + | detail::hash_bool_flags::constant_time_size_pos + | detail::hash_bool_flags::incremental_pos + ); + typedef typename detail::usetopt_mask + ::type masked_config_t; + detail::hashtable_data_t data_; template struct downcast_node_to_value @@ -555,16 +737,16 @@ class hashtable_impl /// @cond const real_value_traits &get_real_value_traits(detail::bool_) const - { return *this; } + { return this->data_; } const real_value_traits &get_real_value_traits(detail::bool_) const - { return base_type::get_value_traits(*this); } + { return data_.get_value_traits(*this); } real_value_traits &get_real_value_traits(detail::bool_) - { return *this; } + { return this->data_; } real_value_traits &get_real_value_traits(detail::bool_) - { return base_type::get_value_traits(*this); } + { return data_.get_value_traits(*this); } /// @endcond @@ -593,14 +775,16 @@ class hashtable_impl , const hasher & hash_func = hasher() , const key_equal &equal_func = key_equal() , const value_traits &v_traits = value_traits()) - : base_type(b_traits, hash_func, equal_func, v_traits) + : data_(b_traits, hash_func, equal_func, v_traits) { priv_initialize_buckets(); this->priv_size_traits().set_size(size_type(0)); - BOOST_INTRUSIVE_INVARIANT_ASSERT(this->priv_buckets_len() != 0); + size_type bucket_size = this->priv_buckets_len(); + BOOST_INTRUSIVE_INVARIANT_ASSERT(bucket_size != 0); //Check power of two bucket array if the option is activated BOOST_INTRUSIVE_INVARIANT_ASSERT - (!power_2_buckets || (0 == (this->priv_buckets_len() & (this->priv_buckets_len()-1)))); + (!power_2_buckets || (0 == (bucket_size & (bucket_size-1)))); + priv_split_traits().set_size(bucket_size>>1); } //! Effects: Detaches all elements from this. The objects in the unordered_set @@ -620,10 +804,7 @@ class hashtable_impl //! //! Throws: Nothing. iterator begin() - { - size_type bucket_num; - return iterator(this->priv_begin(bucket_num), this); - } + { return iterator(this->priv_begin(), this); } //! Effects: Returns a const_iterator pointing to the beginning //! of the unordered_set. @@ -643,10 +824,7 @@ class hashtable_impl //! //! Throws: Nothing. const_iterator cbegin() const - { - size_type bucket_num; - return const_iterator(this->priv_begin(bucket_num), this); - } + { return const_iterator(this->priv_begin(), this); } //! Effects: Returns an iterator pointing to the end of the unordered_set. //! @@ -760,21 +938,32 @@ class hashtable_impl this->priv_size_traits().set_size(other.priv_size_traits().get_size()); other.priv_size_traits().set_size(backup); } + else if(incremental){ + size_type backup = this->priv_split_traits().get_size(); + this->priv_split_traits().set_size(other.priv_split_traits().get_size()); + other.priv_split_traits().set_size(backup); + } } - //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Requires: Disposer::operator()(pointer) shouldn't throw + //! Cloner should yield to nodes that compare equal and produce the same + //! hash than the original node. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. The hash function and the equality + //! predicate are copied from the source. //! - //! If cloner throws, all cloned elements are unlinked and disposed + //! If store_hash option is true, this method does not use the hash function. + //! + //! If any operation throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). - //! + //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. Basic guarantee. + //! Throws: If cloner or hasher throw or hash or equality predicate copying + //! throws. Basic guarantee. template void clone_from(const hashtable_impl &src, Cloner cloner, Disposer disposer) { @@ -789,7 +978,7 @@ class hashtable_impl (!power_2_buckets || (0 == (dst_bucket_count & (dst_bucket_count-1)))); //If src bucket count is bigger or equal, structural copy is possible - if(src_bucket_count >= dst_bucket_count){ + if(!incremental && (src_bucket_count >= dst_bucket_count)){ //First clone the first ones const bucket_ptr src_buckets = src.priv_buckets(); const bucket_ptr dst_buckets = this->priv_buckets(); @@ -813,7 +1002,7 @@ class hashtable_impl ; constructed < src_bucket_count ; ++constructed){ bucket_type &dst_b = - dst_buckets[priv_hash_to_bucket(constructed, dst_bucket_count)]; + dst_buckets[priv_hash_to_bucket(constructed, dst_bucket_count, dst_bucket_count)]; bucket_type &src_b = src_buckets[constructed]; for( siterator b(src_b.begin()), e(src_b.end()) ; b != e @@ -822,14 +1011,29 @@ class hashtable_impl } } } + this->priv_hasher() = src.priv_hasher(); + this->priv_equal() = src.priv_equal(); rollback.release(); this->priv_size_traits().set_size(src.priv_size_traits().get_size()); + this->priv_split_traits().set_size(dst_bucket_count); priv_insertion_update_cache(0u); priv_erasure_update_cache(); } + else if(store_hash){ + //Unlike previous cloning algorithm, this can throw + //if cloner, hasher or comparison functor throw + const_iterator b(src.begin()), e(src.end()); + detail::exception_disposer + rollback(*this, disposer); + for(; b != e; ++b){ + std::size_t hash_value = this->priv_stored_or_compute_hash(*b, store_hash_t());; + this->priv_insert_equal_with_hash(*cloner(*b), hash_value); + } + rollback.release(); + } else{ //Unlike previous cloning algorithm, this can throw - //if cloner, the hasher or comparison functor throw + //if cloner, hasher or comparison functor throw const_iterator b(src.begin()), e(src.end()); detail::exception_disposer rollback(*this, disposer); @@ -848,23 +1052,7 @@ class hashtable_impl siterator prev; siterator it = this->priv_find (value, this->priv_hasher(), this->priv_equal(), bucket_num, hash_value, prev); - bucket_type &b = this->priv_buckets()[bucket_num]; - bool found_equal = it != priv_invalid_local_it(); - node_ptr n = node_ptr(&priv_value_to_node(value)); - this->priv_store_hash(n, hash_value, store_hash_t()); - if(safemode_or_autounlink) - BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n)); - if(!found_equal){ - it = b.before_begin(); - } - if(optimize_multikey){ - node_ptr first_in_group = found_equal ? - dcast_bucket_ptr(it.pointed_node()) : node_ptr(0); - this->priv_insert_in_group(first_in_group, n, optimize_multikey_t()); - } - priv_insertion_update_cache(bucket_num); - this->priv_size_traits().increment(); - return iterator(b.insert_after(it, *n), this); + return priv_insert_equal_find(value, bucket_num, hash_value, it); } template @@ -968,7 +1156,7 @@ class hashtable_impl this->priv_find(key, hash_func, equal_func, bucket_num, commit_data.hash, prev); bool success = prev_pos == priv_invalid_local_it(); if(success){ - prev_pos = this->priv_buckets()[bucket_num].before_begin(); + prev_pos = prev; } return std::pair(iterator(prev_pos, this),success); } @@ -1177,8 +1365,8 @@ class hashtable_impl } else if(optimize_multikey){ siterator last = bucket_type::s_iterator_to - (*node_traits::get_next(priv_get_last_in_group - (dcast_bucket_ptr(it.pointed_node())))); + (*node_traits::get_next(group_functions_t::priv_get_last_in_group + (dcast_bucket_ptr(it.pointed_node()), optimize_multikey_t()))); this->priv_erase_range_impl(bucket_num, prev, last, disposer, count); } else{ @@ -1188,7 +1376,7 @@ class hashtable_impl slist_node_ptr n(it.pointed_node()); const value_type &v = priv_value_from_slist_node(n); if(compare_hash){ - std::size_t vh = this->priv_stored_hash(v, store_hash_t()); + std::size_t vh = this->priv_stored_or_compute_hash(v, store_hash_t()); if(h != vh || !equal_func(key, v)){ break; } @@ -1676,9 +1864,15 @@ class hashtable_impl //! or the same as the old bucket array. new_size is the length of the //! the array pointed by new_buckets. If new_buckets == this->bucket_pointer() //! n can be bigger or smaller than this->bucket_count(). + //! 'new_bucket_traits' copy constructor should not throw. //! //! Effects: Updates the internal reference with the new bucket erases - //! the values from the old bucket and inserts then in the new one. + //! the values from the old bucket and inserts then in the new one. + //! Bucket traits hold by *this is assigned from new_bucket_traits. + //! If the container is configured as incremental<>, the split bucket is set + //! to the new bucket_len(). + //! + //! If store_hash option is true, this method does not use the hash function. //! //! Complexity: Average case linear in this->size(), worst case quadratic. //! @@ -1698,7 +1892,7 @@ class hashtable_impl const bool same_buffer = old_buckets == new_buckets; //If the new bucket length is a common factor //of the old one we can avoid hash calculations. - const bool fast_shrink = (old_buckets_len > new_buckets_len) && + const bool fast_shrink = (!incremental) && (old_buckets_len > new_buckets_len) && (power_2_buckets ||(old_buckets_len % new_buckets_len) == 0); //If we are shrinking the same bucket array and it's //is a fast shrink, just rehash the last nodes @@ -1708,7 +1902,9 @@ class hashtable_impl new_first_bucket_num = priv_get_cache_bucket_num(); } - //Anti-exception stuff: they destroy the elements if something goes wrong + //Anti-exception stuff: they destroy the elements if something goes wrong. + //If the source and destination buckets are the same, the second rollback function + //is harmless, because all elements have been already unlinked and destroyed typedef detail::init_disposer NodeDisposer; NodeDisposer node_disp; detail::exception_array_disposer @@ -1733,12 +1929,13 @@ class hashtable_impl siterator i(old_bucket.begin()); for(;i != end; ++i){ const value_type &v = priv_value_from_slist_node(i.pointed_node()); - const std::size_t hash_value = this->priv_stored_hash(v, store_hash_t()); - const size_type new_n = priv_hash_to_bucket(hash_value, new_buckets_len); + const std::size_t hash_value = this->priv_stored_or_compute_hash(v, store_hash_t()); + const size_type new_n = priv_hash_to_bucket(hash_value, new_buckets_len, new_buckets_len); if(cache_begin && new_n < new_first_bucket_num) new_first_bucket_num = new_n; siterator last = bucket_type::s_iterator_to - (*priv_get_last_in_group(dcast_bucket_ptr(i.pointed_node()))); + (*group_functions_t::priv_get_last_in_group + (dcast_bucket_ptr(i.pointed_node()), optimize_multikey_t())); if(same_buffer && new_n == n){ before_i = last; } @@ -1750,7 +1947,7 @@ class hashtable_impl } } else{ - const size_type new_n = priv_hash_to_bucket(n, new_buckets_len); + const size_type new_n = priv_hash_to_bucket(n, new_buckets_len, new_buckets_len); if(cache_begin && new_n < new_first_bucket_num) new_first_bucket_num = new_n; bucket_type &new_b = new_buckets[new_n]; @@ -1764,14 +1961,148 @@ class hashtable_impl } this->priv_size_traits().set_size(size_backup); + this->priv_split_traits().set_size(new_buckets_len); this->priv_real_bucket_traits() = new_bucket_traits; priv_initialize_cache(); priv_insertion_update_cache(new_first_bucket_num); - //priv_erasure_update_cache(); rollback1.release(); rollback2.release(); } + //! Requires: + //! + //! Effects: + //! + //! Complexity: + //! + //! Throws: + //! + //! Note: this method is only available if incremental option is activated. + bool incremental_rehash(bool grow = true) + { + //This function is only available for containers with incremental hashing + BOOST_STATIC_ASSERT(( incremental && power_2_buckets )); + size_type split_idx = priv_split_traits().get_size(); + size_type bucket_len = priv_buckets_len(); + + if(grow){ + //Test if the split variable can be changed + if(split_idx >= bucket_len) + return false; + + size_type bucket_len = priv_buckets_len(); + size_type bucket_to_rehash = split_idx - bucket_len/2; + bucket_type &old_bucket = this->priv_buckets()[bucket_to_rehash]; + siterator before_i(old_bucket.before_begin()); + siterator end(old_bucket.end()); + siterator i(old_bucket.begin()); + priv_split_traits().increment(); + + //Anti-exception stuff: if an exception is thrown while + //moving elements from old_bucket to the target bucket, all moved + //elements are moved back to the original one. + detail::incremental_rehash_rollback rollback + ( this->priv_buckets()[split_idx], old_bucket, priv_split_traits()); + for(;i != end; ++i){ + const value_type &v = priv_value_from_slist_node(i.pointed_node()); + const std::size_t hash_value = this->priv_stored_or_compute_hash(v, store_hash_t()); + const size_type new_n = priv_hash_to_bucket(hash_value); + siterator last = bucket_type::s_iterator_to + (*group_functions_t::priv_get_last_in_group + (dcast_bucket_ptr(i.pointed_node()), optimize_multikey_t())); + if(new_n == bucket_to_rehash){ + before_i = last; + } + else{ + bucket_type &new_b = this->priv_buckets()[new_n]; + new_b.splice_after(new_b.before_begin(), old_bucket, before_i, last); + } + i = before_i; + } + rollback.release(); + priv_erasure_update_cache(); + return true; + } + else{ + //Test if the split variable can be changed + if(split_idx <= bucket_len/2) + return false; + const size_type target_bucket_num = split_idx - 1 - bucket_len/2; + bucket_type &target_bucket = this->priv_buckets()[target_bucket_num]; + bucket_type &source_bucket = this->priv_buckets()[split_idx-1]; + target_bucket.splice_after(target_bucket.cbefore_begin(), source_bucket); + priv_split_traits().decrement(); + priv_insertion_update_cache(target_bucket_num); + return true; + } + } + + //! Effects: If new_bucket_traits.bucket_count() is not + //! this->bucket_count()/2 or this->bucket_count()*2, or + //! this->split_bucket() != new_bucket_traits.bucket_count() returns false + //! and does nothing. + //! + //! Otherwise, copy assigns new_bucket_traits to the internal bucket_traits + //! and transfers all the objects from old buckets to the new ones. + //! + //! Complexity: Linear to size(). + //! + //! Throws: Nothing + //! + //! Note: this method is only available if incremental option is activated. + bool incremental_rehash(const bucket_traits &new_bucket_traits) + { + //This function is only available for containers with incremental hashing + BOOST_STATIC_ASSERT(( incremental && power_2_buckets )); + size_type new_bucket_traits_size = new_bucket_traits.bucket_count(); + size_type cur_bucket_traits = this->priv_buckets_len(); + if(new_bucket_traits_size/2 != cur_bucket_traits && new_bucket_traits_size != cur_bucket_traits/2){ + return false; + } + + const size_type split_idx = this->split_count(); + + if(new_bucket_traits_size/2 == cur_bucket_traits){ + //Test if the split variable can be changed + if(!(split_idx >= cur_bucket_traits)) + return false; + } + else{ + //Test if the split variable can be changed + if(!(split_idx <= cur_bucket_traits/2)) + return false; + } + + const size_type ini_n = priv_get_cache_bucket_num(); + const bucket_ptr old_buckets = this->priv_buckets(); + this->priv_real_bucket_traits() = new_bucket_traits; + if(new_bucket_traits.bucket_begin() != old_buckets){ + for(size_type n = ini_n; n < split_idx; ++n){ + bucket_type &new_bucket = new_bucket_traits.bucket_begin()[n]; + bucket_type &old_bucket = old_buckets[n]; + new_bucket.splice_after(new_bucket.cbefore_begin(), old_bucket); + } + //Put cache to safe position + priv_initialize_cache(); + priv_insertion_update_cache(ini_n); + } + return true; + } + + //! Requires: + //! + //! Effects: + //! + //! Complexity: + //! + //! Throws: + size_type split_count() const + { + //This function is only available if incremental hashing is activated + BOOST_STATIC_ASSERT(( incremental && power_2_buckets )); + return this->priv_split_traits().get_size(); + } + //! Effects: Returns the nearest new bucket count optimized for //! the container that is bigger than n. This suggestion can be used //! to create bucket arrays with a size that will usually improve @@ -1812,29 +2143,30 @@ class hashtable_impl /// @cond private: + std::size_t priv_hash_to_bucket(std::size_t hash_value) const - { return priv_hash_to_bucket(hash_value, power_2_buckets_t()); } + { return priv_hash_to_bucket(hash_value, this->priv_real_bucket_traits().bucket_count(), priv_split_traits().get_size()); } - std::size_t priv_hash_to_bucket(std::size_t hash_value, detail::bool_) const - { return hash_value % this->priv_real_bucket_traits().bucket_count(); } + std::size_t priv_hash_to_bucket(std::size_t hash_value, std::size_t bucket_len, std::size_t split) const + { + std::size_t bucket_number = priv_hash_to_bucket_impl(hash_value, bucket_len, power_2_buckets_t()); + if(incremental) + if(bucket_number >= split) + bucket_number -= bucket_len/2; + return bucket_number; + } - std::size_t priv_hash_to_bucket(std::size_t hash_value, detail::bool_) const - { return hash_value & (this->priv_real_bucket_traits().bucket_count() - 1); } - - std::size_t priv_hash_to_bucket(std::size_t hash_value, std::size_t bucket_len) const - { return priv_hash_to_bucket(hash_value, bucket_len, power_2_buckets_t()); } - - std::size_t priv_hash_to_bucket(std::size_t hash_value, std::size_t bucket_len, detail::bool_) const + std::size_t priv_hash_to_bucket_impl(std::size_t hash_value, std::size_t bucket_len, detail::bool_) const { return hash_value % bucket_len; } - std::size_t priv_hash_to_bucket(std::size_t hash_value, std::size_t bucket_len, detail::bool_) const + std::size_t priv_hash_to_bucket_impl(std::size_t hash_value, std::size_t bucket_len, detail::bool_) const { return hash_value & (bucket_len - 1); } const key_equal &priv_equal() const - { return static_cast(this->bucket_hash_equal_.get()); } + { return static_cast(this->data_.internal_.bucket_hash_equal_.get()); } key_equal &priv_equal() - { return static_cast(this->bucket_hash_equal_.get()); } + { return static_cast(this->data_.internal_.bucket_hash_equal_.get()); } value_type &priv_value_from_slist_node(slist_node_ptr n) { return *this->get_real_value_traits().to_value_ptr(dcast_bucket_ptr(n)); } @@ -1843,16 +2175,16 @@ class hashtable_impl { return *this->get_real_value_traits().to_value_ptr(dcast_bucket_ptr(n)); } const real_bucket_traits &priv_real_bucket_traits(detail::bool_) const - { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_; } + { return this->data_.internal_.bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_; } const real_bucket_traits &priv_real_bucket_traits(detail::bool_) const - { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_.get_bucket_traits(*this); } + { return this->data_.internal_.bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_.get_bucket_traits(*this); } real_bucket_traits &priv_real_bucket_traits(detail::bool_) - { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_; } + { return this->data_.internal_.bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_; } real_bucket_traits &priv_real_bucket_traits(detail::bool_) - { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_.get_bucket_traits(*this); } + { return this->data_.internal_.bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_.get_bucket_traits(*this); } const real_bucket_traits &priv_real_bucket_traits() const { return this->priv_real_bucket_traits(detail::bool_()); } @@ -1861,10 +2193,10 @@ class hashtable_impl { return this->priv_real_bucket_traits(detail::bool_()); } const hasher &priv_hasher() const - { return static_cast(this->bucket_hash_equal_.bucket_hash.get()); } + { return static_cast(this->data_.internal_.bucket_hash_equal_.bucket_hash.get()); } hasher &priv_hasher() - { return static_cast(this->bucket_hash_equal_.bucket_hash.get()); } + { return static_cast(this->data_.internal_.bucket_hash_equal_.bucket_hash.get()); } bucket_ptr priv_buckets() const { return this->priv_real_bucket_traits().bucket_begin(); } @@ -1882,10 +2214,16 @@ class hashtable_impl { return *this->get_real_value_traits().to_node_ptr(v); } size_traits &priv_size_traits() - { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_; } + { return this->data_.internal_.bucket_hash_equal_.bucket_hash.bucket_plus_size_; } const size_traits &priv_size_traits() const - { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_; } + { return this->data_.internal_.bucket_hash_equal_.bucket_hash.bucket_plus_size_; } + + split_traits &priv_split_traits() + { return this->data_.internal_; } + + const split_traits &priv_split_traits() const + { return this->data_.internal_; } template void priv_erase_range_impl @@ -1903,7 +2241,7 @@ class hashtable_impl ++to_erase; slist_node_ptr end_ptr = end.pointed_node(); while(to_erase != end){ - priv_erase_from_group(end_ptr, dcast_bucket_ptr(to_erase.pointed_node()), optimize_multikey_t()); + group_functions_t::priv_erase_from_group(end_ptr, dcast_bucket_ptr(to_erase.pointed_node()), optimize_multikey_t()); to_erase = b.erase_after_and_dispose(before_first_it, make_node_disposer(disposer)); ++num_erased; } @@ -1955,10 +2293,10 @@ class hashtable_impl static node_ptr dcast_bucket_ptr(typename slist_impl::node_ptr p) { return node_ptr(&static_cast(*p)); } - std::size_t priv_stored_hash(const value_type &v, detail::true_) const + std::size_t priv_stored_or_compute_hash(const value_type &v, detail::true_) const { return node_traits::get_hash(this->get_real_value_traits().to_node_ptr(v)); } - std::size_t priv_stored_hash(const value_type &v, detail::false_) const + std::size_t priv_stored_or_compute_hash(const value_type &v, detail::false_) const { return priv_hasher()(v); } std::size_t priv_stored_hash(slist_node_ptr n, detail::true_) const @@ -2002,10 +2340,10 @@ class hashtable_impl std::size_t priv_get_bucket_num_hash_dispatch(siterator it, detail::false_) { return priv_get_bucket_num_no_hash_store(it, optimize_multikey_t()); } - std::size_t priv_get_bucket_num_no_hash_store( siterator it, detail::true_) + std::size_t priv_get_bucket_num_no_hash_store(siterator it, detail::true_) { bucket_ptr f(priv_buckets()), l(f + priv_buckets_len() - 1); - slist_node_ptr bb = priv_get_bucket_before_begin + slist_node_ptr bb = group_functions_t::priv_get_bucket_before_begin ( f->end().pointed_node() , l->end().pointed_node() , dcast_bucket_ptr(it.pointed_node())); @@ -2016,7 +2354,7 @@ class hashtable_impl return static_cast(&b - &*f); } - std::size_t priv_get_bucket_num_no_hash_store( siterator it, detail::false_) + std::size_t priv_get_bucket_num_no_hash_store(siterator it, detail::false_) { bucket_ptr f(priv_buckets()), l(f + priv_buckets_len() - 1); slist_node_ptr first_ptr(f->cend().pointed_node()) @@ -2035,34 +2373,6 @@ class hashtable_impl return static_cast(&b - &*f); } - void priv_erase_from_group(slist_node_ptr end_ptr, node_ptr to_erase_ptr, detail::true_) - { - node_ptr nxt_ptr(node_traits::get_next(to_erase_ptr)); - node_ptr prev_in_group_ptr(group_traits::get_next(to_erase_ptr)); - bool last_in_group = (end_ptr == nxt_ptr) || - (group_traits::get_next(nxt_ptr) != to_erase_ptr); - bool first_in_group = node_traits::get_next(prev_in_group_ptr) != to_erase_ptr; - - if(first_in_group && last_in_group){ - group_algorithms::init(to_erase_ptr); - } - else if(first_in_group){ - group_algorithms::unlink_after(nxt_ptr); - } - else if(last_in_group){ - node_ptr first_in_group = //possible_first_in_group ? possible_first_in_group : - priv_get_first_in_group_of_last_in_group(to_erase_ptr); - group_algorithms::unlink_after(first_in_group); - //possible_first_in_group = 0; - } - else{ - group_algorithms::unlink_after(nxt_ptr); - } - } - - void priv_erase_from_group(slist_node_ptr, node_ptr, detail::false_) - {} - void priv_init_group(slist_node_ptr n, detail::true_) { group_algorithms::init(dcast_bucket_ptr(n)); } @@ -2083,79 +2393,9 @@ class hashtable_impl } } - static slist_node_ptr priv_get_bucket_before_begin - (slist_node_ptr bucket_beg, slist_node_ptr bucket_end, node_ptr p) - { - //First find the last node of p's group. - //This requires checking the first node of the next group or - //the bucket node. - node_ptr prev_node = p; - node_ptr nxt(node_traits::get_next(p)); - while(!(bucket_beg <= nxt && nxt <= bucket_end) && - (group_traits::get_next(nxt) == prev_node)){ - prev_node = nxt; - nxt = node_traits::get_next(nxt); - } - - //If we've reached the bucket node just return it. - if(bucket_beg <= nxt && nxt <= bucket_end){ - return nxt; - } - - //Otherwise, iterate using group links until the bucket node - node_ptr first_node_of_group = nxt; - node_ptr last_node_group = group_traits::get_next(first_node_of_group); - slist_node_ptr possible_end = node_traits::get_next(last_node_group); - - while(!(bucket_beg <= possible_end && possible_end <= bucket_end)){ - first_node_of_group = dcast_bucket_ptr(possible_end); - last_node_group = group_traits::get_next(first_node_of_group); - possible_end = node_traits::get_next(last_node_group); - } - return possible_end; - } - - static node_ptr priv_get_prev_to_first_in_group(slist_node_ptr bucket_node, node_ptr first_in_group) - { - //Just iterate using group links and obtain the node - //before "first_in_group)" - node_ptr prev_node = dcast_bucket_ptr(bucket_node); - node_ptr nxt(node_traits::get_next(prev_node)); - while(nxt != first_in_group){ - prev_node = group_traits::get_next(nxt); - nxt = node_traits::get_next(prev_node); - } - return prev_node; - } - - static node_ptr priv_get_first_in_group_of_last_in_group(node_ptr last_in_group) - { - //Just iterate using group links and obtain the node - //before "last_in_group" - node_ptr possible_first = group_traits::get_next(last_in_group); - node_ptr possible_first_prev = group_traits::get_next(possible_first); - // The deleted node is at the end of the group, so the - // node in the group pointing to it is at the beginning - // of the group. Find that to change its pointer. - while(possible_first_prev != last_in_group){ - possible_first = possible_first_prev; - possible_first_prev = group_traits::get_next(possible_first); - } - return possible_first; - } - void priv_insert_in_group(node_ptr, node_ptr, detail::false_) {} - static node_ptr priv_get_last_in_group(node_ptr first_in_group) - { return priv_get_last_in_group(first_in_group, optimize_multikey_t()); } - - static node_ptr priv_get_last_in_group(node_ptr first_in_group, detail::true_) - { return group_traits::get_next(first_in_group); } - - static node_ptr priv_get_last_in_group(node_ptr n, detail::false_) - { return n; } - siterator priv_get_previous (bucket_type &b, siterator i) { return priv_get_previous(b, i, optimize_multikey_t()); } @@ -2166,9 +2406,8 @@ class hashtable_impl node_ptr elem(dcast_bucket_ptr(i.pointed_node())); node_ptr prev_in_group(group_traits::get_next(elem)); bool first_in_group = node_traits::get_next(prev_in_group) != elem; - typename bucket_type::node &n = first_in_group - ? *priv_get_prev_to_first_in_group(b.end().pointed_node(), elem) + ? *group_functions_t::priv_get_prev_to_first_in_group(b.end().pointed_node(), elem) : *group_traits::get_next(elem) ; return bucket_type::s_iterator_to(n); @@ -2234,15 +2473,15 @@ class hashtable_impl ].before_begin().pointed_node(); } else{ - bucket_node = priv_get_bucket_before_begin + bucket_node = group_functions_t::priv_get_bucket_before_begin (first_end_ptr, last_end_ptr, start_pos); } prev = bucket_type::s_iterator_to - (*priv_get_prev_to_first_in_group(bucket_node, elem)); + (*group_functions_t::priv_get_prev_to_first_in_group(bucket_node, elem)); } else{ if(last_in_group){ - nxt_in_group = priv_get_first_in_group_of_last_in_group(elem); + nxt_in_group = group_functions_t::priv_get_first_in_group_of_last_in_group(elem); } else{ nxt_in_group = node_traits::get_next(elem); @@ -2283,32 +2522,29 @@ class hashtable_impl siterator priv_invalid_local_it() const { return priv_invalid_bucket()->end(); } - siterator priv_begin(size_type &bucket_num) const - { return priv_begin(bucket_num, cache_begin_t()); } + siterator priv_begin() const + { return priv_begin(cache_begin_t()); } - siterator priv_begin(size_type &bucket_num, detail::bool_) const + siterator priv_begin(detail::bool_) const { size_type n = 0; size_type buckets_len = this->priv_buckets_len(); for (n = 0; n < buckets_len; ++n){ bucket_type &b = this->priv_buckets()[n]; if(!b.empty()){ - bucket_num = n; return b.begin(); } } - bucket_num = n; return priv_invalid_local_it(); } - siterator priv_begin(size_type &bucket_num, detail::bool_) const + siterator priv_begin(detail::bool_) const { - bucket_num = this->bucket_hash_equal_.cached_begin_ - this->priv_buckets(); - if(this->bucket_hash_equal_.cached_begin_ == priv_invalid_bucket()){ + if(this->data_.internal_.bucket_hash_equal_.cached_begin_ == priv_invalid_bucket()){ return priv_invalid_local_it(); } else{ - return this->bucket_hash_equal_.cached_begin_->begin(); + return this->data_.internal_.bucket_hash_equal_.cached_begin_->begin(); } } @@ -2316,7 +2552,7 @@ class hashtable_impl { priv_initialize_cache(cache_begin_t()); } void priv_initialize_cache(detail::bool_) - { this->bucket_hash_equal_.cached_begin_ = priv_invalid_bucket(); } + { this->data_.internal_.bucket_hash_equal_.cached_begin_ = priv_invalid_bucket(); } void priv_initialize_cache(detail::bool_) {} @@ -2327,8 +2563,8 @@ class hashtable_impl void priv_insertion_update_cache(size_type insertion_bucket, detail::bool_) { bucket_ptr p = priv_buckets() + insertion_bucket; - if(p < this->bucket_hash_equal_.cached_begin_){ - this->bucket_hash_equal_.cached_begin_ = p; + if(p < this->data_.internal_.bucket_hash_equal_.cached_begin_){ + this->data_.internal_.bucket_hash_equal_.cached_begin_ = p; } } @@ -2361,11 +2597,11 @@ class hashtable_impl priv_initialize_cache(); } else{ - size_type current_n = this->bucket_hash_equal_.cached_begin_ - priv_buckets(); + size_type current_n = this->data_.internal_.bucket_hash_equal_.cached_begin_ - priv_buckets(); for( const size_type num_buckets = this->priv_buckets_len() ; current_n < num_buckets - ; ++current_n, ++this->bucket_hash_equal_.cached_begin_){ - if(!this->bucket_hash_equal_.cached_begin_->empty()){ + ; ++current_n, ++this->data_.internal_.bucket_hash_equal_.cached_begin_){ + if(!this->data_.internal_.bucket_hash_equal_.cached_begin_->empty()){ return; } } @@ -2378,8 +2614,8 @@ class hashtable_impl void priv_swap_cache(detail::bool_, hashtable_impl &other) { - std::swap( this->bucket_hash_equal_.cached_begin_ - , other.bucket_hash_equal_.cached_begin_); + std::swap( this->data_.internal_.bucket_hash_equal_.cached_begin_ + , other.data_.internal_.bucket_hash_equal_.cached_begin_); } void priv_swap_cache(detail::bool_, hashtable_impl &) @@ -2389,7 +2625,7 @@ class hashtable_impl { return priv_get_cache(cache_begin_t()); } bucket_ptr priv_get_cache(detail::bool_) - { return this->bucket_hash_equal_.cached_begin_; } + { return this->data_.internal_.bucket_hash_equal_.cached_begin_; } bucket_ptr priv_get_cache(detail::bool_) { return this->priv_buckets(); } @@ -2398,7 +2634,7 @@ class hashtable_impl { priv_set_cache(p, cache_begin_t()); } void priv_set_cache(bucket_ptr p, detail::bool_) - { this->bucket_hash_equal_.cached_begin_ = p; } + { this->data_.internal_.bucket_hash_equal_.cached_begin_ = p; } void priv_set_cache(bucket_ptr, detail::bool_) {} @@ -2407,7 +2643,7 @@ class hashtable_impl { return priv_get_cache_bucket_num(cache_begin_t()); } size_type priv_get_cache_bucket_num(detail::bool_) - { return this->bucket_hash_equal_.cached_begin_ - this->priv_buckets(); } + { return this->data_.internal_.bucket_hash_equal_.cached_begin_ - this->priv_buckets(); } size_type priv_get_cache_bucket_num(detail::bool_) { return 0u; } @@ -2420,10 +2656,7 @@ class hashtable_impl } void priv_initialize_buckets() - { - this->priv_clear_buckets - ( priv_buckets(), this->priv_buckets_len()); - } + { this->priv_clear_buckets(priv_buckets(), this->priv_buckets_len()); } void priv_clear_buckets(bucket_ptr buckets_ptr, size_type buckets_len) { @@ -2444,21 +2677,28 @@ class hashtable_impl ( const KeyType &key, KeyHasher hash_func , KeyValueEqual equal_func, size_type &bucket_number, std::size_t &h, siterator &previt) const { - bucket_number = priv_hash_to_bucket((h = hash_func(key))); + h = hash_func(key); + return priv_find_with_hash(key, equal_func, bucket_number, h, previt); + } + template + siterator priv_find_with_hash + ( const KeyType &key, KeyValueEqual equal_func, size_type &bucket_number, const std::size_t h, siterator &previt) const + { + bucket_number = priv_hash_to_bucket(h); + bucket_type &b = this->priv_buckets()[bucket_number]; + previt = b.before_begin(); if(constant_time_size && this->empty()){ return priv_invalid_local_it(); } - bucket_type &b = this->priv_buckets()[bucket_number]; - previt = b.before_begin(); siterator it = previt; ++it; while(it != b.end()){ const value_type &v = priv_value_from_slist_node(it.pointed_node()); if(compare_hash){ - std::size_t vh = this->priv_stored_hash(v, store_hash_t()); + std::size_t vh = this->priv_stored_or_compute_hash(v, store_hash_t()); if(h == vh && equal_func(key, v)){ return it; } @@ -2468,7 +2708,8 @@ class hashtable_impl } if(optimize_multikey){ previt = bucket_type::s_iterator_to - (*priv_get_last_in_group(dcast_bucket_ptr(it.pointed_node()))); + (*group_functions_t::priv_get_last_in_group + (dcast_bucket_ptr(it.pointed_node()), optimize_multikey_t())); it = previt; } else{ @@ -2476,10 +2717,45 @@ class hashtable_impl } ++it; } - + previt = b.before_begin(); return priv_invalid_local_it(); } + iterator priv_insert_equal_with_hash(reference value, std::size_t hash_value) + { + size_type bucket_num; + siterator prev; + siterator it = this->priv_find_with_hash + (value, this->priv_equal(), bucket_num, hash_value, prev); + return priv_insert_equal_find(value, bucket_num, hash_value, it); + } + + iterator priv_insert_equal_find(reference value, size_type bucket_num, std::size_t hash_value, siterator it) + { + bucket_type &b = this->priv_buckets()[bucket_num]; + bool found_equal = it != priv_invalid_local_it(); + if(!found_equal){ + it = b.before_begin(); + } + //Now store hash if needed + node_ptr n = node_ptr(&priv_value_to_node(value)); + this->priv_store_hash(n, hash_value, store_hash_t()); + //Checks for some modes + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n)); + //Shorcut for optimize_multikey cases + if(optimize_multikey){ + node_ptr first_in_group = found_equal ? + dcast_bucket_ptr(it.pointed_node()) : node_ptr(0); + this->priv_insert_in_group(first_in_group, n, optimize_multikey_t()); + } + //Update cache and increment size if needed + priv_insertion_update_cache(bucket_num); + this->priv_size_traits().increment(); + //Insert the element in the bucket after it + return iterator(b.insert_after(it, *n), this); + } + template std::pair priv_equal_range ( const KeyType &key @@ -2506,8 +2782,8 @@ class hashtable_impl siterator it = to_return.first; if(optimize_multikey){ to_return.second = bucket_type::s_iterator_to - (*node_traits::get_next(priv_get_last_in_group - (dcast_bucket_ptr(it.pointed_node())))); + (*node_traits::get_next(group_functions_t::priv_get_last_in_group + (dcast_bucket_ptr(it.pointed_node()), optimize_multikey_t()))); count = std::distance(it, to_return.second); if(to_return.second != b.end()){ bucket_number_second = bucket_number_first; @@ -2520,7 +2796,7 @@ class hashtable_impl while(it != b.end()){ const value_type &v = priv_value_from_slist_node(it.pointed_node()); if(compare_hash){ - std::size_t hv = this->priv_stored_hash(v, store_hash_t()); + std::size_t hv = this->priv_stored_or_compute_hash(v, store_hash_t()); if(hv != h || !equal_func(key, v)){ to_return.second = it; bucket_number_second = bucket_number_first; @@ -2556,18 +2832,28 @@ class hashtable_impl }; /// @cond +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template < class T , bool UniqueKeys , class O1 = none, class O2 = none , class O3 = none, class O4 = none , class O5 = none, class O6 = none , class O7 = none, class O8 = none - , class O9 = none + , class O9 = none, class O10= none > +#else +template +#endif struct make_hashtable_opt { typedef typename pack_options - < uset_defaults, O1, O2, O3, O4, O5, O6, O7, O8, O9>::type packed_options; + < uset_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4, O5, O6, O7, O8, O9, O10 + #else + Options... + #endif + >::type packed_options; //Real value traits must be calculated from options typedef typename detail::get_value_traits @@ -2598,31 +2884,32 @@ struct make_hashtable_opt , specified_bucket_traits >::type real_bucket_traits; - typedef usetopt + typedef detail::usetopt < value_traits - , UniqueKeys , typename packed_options::hash , typename packed_options::equal , typename packed_options::size_type - , packed_options::constant_time_size , real_bucket_traits - , packed_options::power_2_buckets - , packed_options::cache_begin - , packed_options::compare_hash + , (std::size_t(UniqueKeys)*detail::hash_bool_flags::unique_keys_pos) + | (std::size_t(packed_options::constant_time_size)*detail::hash_bool_flags::constant_time_size_pos) + | (std::size_t(packed_options::power_2_buckets)*detail::hash_bool_flags::power_2_buckets_pos) + | (std::size_t(packed_options::cache_begin)*detail::hash_bool_flags::cache_begin_pos) + | (std::size_t(packed_options::compare_hash)*detail::hash_bool_flags::compare_hash_pos) + | (std::size_t(packed_options::incremental)*detail::hash_bool_flags::incremental_pos) > type; }; /// @endcond //! Helper metafunction to define a \c hashtable that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif struct make_hashtable @@ -2630,20 +2917,42 @@ struct make_hashtable /// @cond typedef hashtable_impl < typename make_hashtable_opt - ::type + ::type > implementation_defined; /// @endcond typedef implementation_defined type; }; -#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED -template +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + +#if defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif class hashtable - : public make_hashtable::type + : public make_hashtable::type { - typedef typename make_hashtable - ::type Base; + typedef typename make_hashtable::type Base; public: typedef typename Base::value_traits value_traits; @@ -2669,7 +2978,6 @@ class hashtable #endif - } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/intrusive_fwd.hpp b/include/boost/intrusive/intrusive_fwd.hpp index 0642fff..38a622f 100644 --- a/include/boost/intrusive/intrusive_fwd.hpp +++ b/include/boost/intrusive/intrusive_fwd.hpp @@ -15,26 +15,12 @@ #include #include +#include /// @cond -//std predeclarations -namespace std{ - -template -struct equal_to; - -template -struct less; - -} //namespace std{ - namespace boost { -//Hash predeclaration -template -struct hash; - namespace intrusive { struct none; @@ -64,6 +50,7 @@ class rbtree_algorithms; //////////////////////////// //slist +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -72,46 +59,70 @@ template , class O4 = none , class O5 = none > +#else +template +#endif class slist; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class slist_base_hook; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class slist_member_hook; //list +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class list; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class list_base_hook; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class list_member_hook; //rbtree/set/multiset +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -119,8 +130,12 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class rbtree; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -128,8 +143,12 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class set; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -137,25 +156,37 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class multiset; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none , class O4 = none > +#else +template +#endif class set_base_hook; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none , class O4 = none > +#else +template +#endif class set_member_hook; //splaytree/splay_set/splay_multiset +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -163,8 +194,12 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class splaytree; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -172,8 +207,12 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class splay_set; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -181,23 +220,35 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class splay_multiset; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class splay_set_base_hook; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class splay_set_member_hook; //avltree/avl_set/avl_multiset +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -205,8 +256,12 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class avltree; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -214,8 +269,12 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class avl_set; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -223,25 +282,37 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class avl_multiset; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none , class O4 = none > +#else +template +#endif class avl_set_base_hook; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none , class O4 = none > +#else +template +#endif class avl_set_member_hook; //sgtree/sg_set/sg_multiset +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -249,8 +320,12 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class sgtree; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -258,8 +333,12 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class sg_set; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -267,23 +346,36 @@ template , class O3 = none , class O4 = none > +#else +template +#endif class sg_multiset; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class bs_set_base_hook; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class bs_set_member_hook; //hashtable/unordered_set/unordered_multiset + +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -295,9 +387,14 @@ template , class O7 = none , class O8 = none , class O9 = none + , class O10 = none > +#else +template +#endif class hashtable; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -309,9 +406,14 @@ template , class O7 = none , class O8 = none , class O9 = none + , class O10 = none > +#else +template +#endif class unordered_set; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class T , class O1 = none @@ -323,37 +425,57 @@ template , class O7 = none , class O8 = none , class O9 = none + , class O10 = none > +#else +template +#endif class unordered_multiset; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none , class O4 = none > +#else +template +#endif class unordered_set_base_hook; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none , class O4 = none > +#else +template +#endif class unordered_set_member_hook; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class any_base_hook; +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template < class O1 = none , class O2 = none , class O3 = none > +#else +template +#endif class any_member_hook; } //namespace intrusive { diff --git a/include/boost/intrusive/linear_slist_algorithms.hpp b/include/boost/intrusive/linear_slist_algorithms.hpp index b52a7ba..a181a51 100644 --- a/include/boost/intrusive/linear_slist_algorithms.hpp +++ b/include/boost/intrusive/linear_slist_algorithms.hpp @@ -58,7 +58,7 @@ class linear_slist_algorithms typedef typename NodeTraits::const_node_ptr const_node_ptr; typedef NodeTraits node_traits; - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: Constructs an non-used list element, putting the next //! pointer to null: @@ -127,7 +127,7 @@ class linear_slist_algorithms //! Throws: Nothing. static void transfer_after(node_ptr p, node_ptr b, node_ptr e); - #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: Constructs an empty list, making this_node the only //! node of the circular list: diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index 2b28923..c6d94f2 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -35,20 +35,6 @@ namespace intrusive { /// @cond -template -struct internal_default_list_hook -{ - template static detail::one test(...); - template static detail::two test(typename U::default_list_hook* = 0); - static const bool value = sizeof(test(0)) == sizeof(detail::two); -}; - -template -struct get_default_list_hook -{ - typedef typename T::default_list_hook type; -}; - template struct listopt { @@ -57,17 +43,12 @@ struct listopt static const bool constant_time_size = ConstantTimeSize; }; + template struct list_defaults : pack_options < none - , base_hook - < typename detail::eval_if_c - < internal_default_list_hook::value - , get_default_list_hook - , detail::identity - >::type - > + , base_hook , constant_time_size , size_type >::type @@ -85,7 +66,7 @@ struct list_defaults //! The container supports the following options: //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<> and \c size_type<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -225,7 +206,7 @@ class list_impl { this->priv_size_traits().set_size(size_type(0)); node_algorithms::init_header(this->get_root_node()); - this->insert(this->end(), b, e); + this->insert(this->cend(), b, e); } //! Effects: If it's not a safe-mode or an auto-unlink value_type @@ -583,7 +564,7 @@ class list_impl //! //! Note: Invalidates the iterators (but not the references) to the //! erased element. - iterator erase(iterator i) + iterator erase(const_iterator i) { return this->erase_and_dispose(i, detail::null_disposer()); } //! Requires: b and e must be valid iterators to elements in *this. @@ -601,14 +582,14 @@ class list_impl //! //! Note: Invalidates the iterators (but not the references) to the //! erased elements. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { if(safemode_or_autounlink || constant_time_size){ return this->erase_and_dispose(b, e, detail::null_disposer()); } else{ node_algorithms::unlink(b.pointed_node(), e.pointed_node()); - return e; + return e.unconst(); } } @@ -628,7 +609,7 @@ class list_impl //! //! Note: Invalidates the iterators (but not the references) to the //! erased elements. - iterator erase(iterator b, iterator e, difference_type n) + iterator erase(const_iterator b, const_iterator e, difference_type n) { BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(b, e) == difference_type(n)); if(safemode_or_autounlink || constant_time_size){ @@ -639,7 +620,7 @@ class list_impl this->priv_size_traits().set_size(this->priv_size_traits().get_size() - n); } node_algorithms::unlink(b.pointed_node(), e.pointed_node()); - return e; + return e.unconst(); } } @@ -658,7 +639,7 @@ class list_impl //! //! Note: Invalidates the iterators to the erased element. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { node_ptr to_erase(i.pointed_node()); ++i; @@ -667,7 +648,7 @@ class list_impl if(safemode_or_autounlink) node_algorithms::init(to_erase); disposer(this->get_real_value_traits().to_value_ptr(to_erase)); - return i; + return i.unconst(); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -685,7 +666,7 @@ class list_impl //! //! Note: Invalidates the iterators to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { node_ptr bp(b.pointed_node()), ep(e.pointed_node()); node_algorithms::unlink(bp, ep); @@ -697,7 +678,7 @@ class list_impl disposer(get_real_value_traits().to_value_ptr(to_erase)); this->priv_size_traits().decrement(); } - return e; + return e.unconst(); } //! Effects: Erases all the elements of the container. @@ -734,7 +715,7 @@ class list_impl template void clear_and_dispose(Disposer disposer) { - iterator it(this->begin()), itend(this->end()); + const_iterator it(this->begin()), itend(this->end()); while(it != itend){ node_ptr to_erase(it.pointed_node()); ++it; @@ -747,6 +728,7 @@ class list_impl } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the @@ -783,7 +765,7 @@ class list_impl //! Complexity: Constant time. No copy constructors are called. //! //! Note: Does not affect the validity of iterators and references. - iterator insert(iterator p, reference value) + iterator insert(const_iterator p, reference value) { node_ptr to_insert = this->get_real_value_traits().to_node_ptr(value); if(safemode_or_autounlink) @@ -805,7 +787,7 @@ class list_impl //! //! Note: Does not affect the validity of iterators and references. template - void insert(iterator p, Iterator b, Iterator e) + void insert(const_iterator p, Iterator b, Iterator e) { for (; b != e; ++b) this->insert(p, *b); @@ -830,7 +812,7 @@ class list_impl void assign(Iterator b, Iterator e) { this->clear(); - this->insert(this->end(), b, e); + this->insert(this->cend(), b, e); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -853,7 +835,7 @@ class list_impl void dispose_and_assign(Disposer disposer, Iterator b, Iterator e) { this->clear_and_dispose(disposer); - this->insert(this->end(), b, e); + this->insert(this->cend(), b, e); } //! Requires: p must be a valid iterator of *this. @@ -867,7 +849,7 @@ class list_impl //! //! Note: Iterators of values obtained from list x now point to elements of //! this list. Iterators of this list and all the references are not invalidated. - void splice(iterator p, list_impl& x) + void splice(const_iterator p, list_impl& x) { if(!x.empty()){ size_traits &thist = this->priv_size_traits(); @@ -892,7 +874,7 @@ class list_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(iterator p, list_impl&x, iterator new_ele) + void splice(const_iterator p, list_impl&x, const_iterator new_ele) { node_algorithms::transfer(p.pointed_node(), new_ele.pointed_node()); x.priv_size_traits().decrement(); @@ -912,7 +894,7 @@ class list_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(iterator p, list_impl&x, iterator start, iterator end) + void splice(const_iterator p, list_impl&x, const_iterator start, const_iterator end) { if(constant_time_size) this->splice(p, x, start, end, std::distance(start, end)); @@ -933,7 +915,7 @@ class list_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(iterator p, list_impl&x, iterator start, iterator end, difference_type n) + void splice(const_iterator p, list_impl&x, const_iterator start, const_iterator end, difference_type n) { if(n){ if(constant_time_size){ @@ -988,7 +970,7 @@ class list_impl list_impl counter[64]; int fill = 0; while(!this->empty()){ - carry.splice(carry.begin(), *this, this->begin()); + carry.splice(carry.cbegin(), *this, this->cbegin()); int i = 0; while(i < fill && !counter[i].empty()) { carry.merge(counter[i++], p); @@ -1034,13 +1016,13 @@ class list_impl template void merge(list_impl& x, Predicate p) { - iterator e(this->end()); - iterator bx(x.begin()); - iterator ex(x.end()); + const_iterator e(this->end()); + const_iterator bx(x.begin()); + const_iterator ex(x.end()); - for (iterator b = this->begin(); b != e; ++b) { + for (const_iterator b = this->cbegin(); b != e; ++b) { size_type n(0); - iterator ix(bx); + const_iterator ix(bx); while(ix != ex && p(*ix, *b)){ ++ix; ++n; } @@ -1116,8 +1098,8 @@ class list_impl template void remove_and_dispose_if(Pred pred, Disposer disposer) { - iterator cur(this->begin()); - iterator last(this->end()); + const_iterator cur(this->cbegin()); + const_iterator last(this->cend()); while(cur != last) { if(pred(*cur)){ cur = this->erase_and_dispose(cur, disposer); @@ -1185,11 +1167,11 @@ class list_impl template void unique_and_dispose(BinaryPredicate pred, Disposer disposer) { - iterator itend(this->end()); - iterator cur(this->begin()); + const_iterator itend(this->cend()); + const_iterator cur(this->cbegin()); if(cur != itend){ - iterator after(cur); + const_iterator after(cur); ++after; while(after != itend){ if(pred(*cur, *after)){ @@ -1284,26 +1266,26 @@ class list_impl /// @endcond }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator< -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const list_impl &x, const list_impl &y) #else (const list_impl &x, const list_impl &y) #endif { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif bool operator== -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const list_impl &x, const list_impl &y) #else (const list_impl &x, const list_impl &y) @@ -1336,65 +1318,65 @@ bool operator== } } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const list_impl &x, const list_impl &y) #else (const list_impl &x, const list_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const list_impl &x, const list_impl &y) #else (const list_impl &x, const list_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const list_impl &x, const list_impl &y) #else (const list_impl &x, const list_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const list_impl &x, const list_impl &y) #else (const list_impl &x, const list_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (list_impl &x, list_impl &y) #else (list_impl &x, list_impl &y) @@ -1403,7 +1385,7 @@ inline void swap //! Helper metafunction to define a \c list that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -1412,7 +1394,14 @@ struct make_list { /// @cond typedef typename pack_options - < list_defaults, O1, O2, O3>::type packed_options; + < list_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; + typedef typename detail::get_value_traits ::type value_traits; @@ -1430,12 +1419,29 @@ struct make_list #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class list - : public make_list::type + : public make_list::type { typedef typename make_list - ::type Base; + ::type Base; typedef typename Base::real_value_traits real_value_traits; //Assert if passed value traits are compatible with the type BOOST_STATIC_ASSERT((detail::is_same::value)); diff --git a/include/boost/intrusive/list_hook.hpp b/include/boost/intrusive/list_hook.hpp index 1133b4b..86745cf 100644 --- a/include/boost/intrusive/list_hook.hpp +++ b/include/boost/intrusive/list_hook.hpp @@ -35,7 +35,7 @@ struct get_list_node_algo //! Helper metafunction to define a \c \c list_base_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -44,7 +44,13 @@ struct make_list_base_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_list_node_algo @@ -72,15 +78,21 @@ struct make_list_base_hook //! //! \c void_pointer<> is the pointer type that will be used internally in the hook //! and the the container configured to use this hook. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class list_base_hook - : public make_list_base_hook::type + : public make_list_base_hook + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! @@ -149,7 +161,7 @@ class list_base_hook //! Helper metafunction to define a \c \c list_member_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -158,7 +170,13 @@ struct make_list_member_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_list_node_algo @@ -181,15 +199,21 @@ struct make_list_member_hook //! //! \c void_pointer<> is the pointer type that will be used internally in the hook //! and the the container configured to use this hook. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class list_member_hook - : public make_list_member_hook::type + : public make_list_member_hook + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + + #else + + #endif + ::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! diff --git a/include/boost/intrusive/options.hpp b/include/boost/intrusive/options.hpp index ab9535a..b937698 100644 --- a/include/boost/intrusive/options.hpp +++ b/include/boost/intrusive/options.hpp @@ -31,6 +31,26 @@ struct member_tag; namespace detail{ +struct default_hook_tag{}; + +#define BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER) \ +struct BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER : public default_hook_tag\ +{\ + template \ + struct apply\ + { typedef typename T::BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER type; };\ +}\ + +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_list_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_slist_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_set_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_uset_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_avl_set_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_splay_set_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_bs_set_hook); + +#undef BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION + template struct eval_value_traits { @@ -116,8 +136,12 @@ struct get_member_node_traits template struct get_value_traits { - typedef SupposedValueTraits supposed_value_traits; - //...if it's a base hook + typedef typename detail::eval_if_c + ::value + ,detail::apply + ,detail::identity + >::type supposed_value_traits; + //...if it's a default hook typedef typename detail::eval_if_c < internal_base_hook_bool_is_true::value //...get it's internal value traits using @@ -336,7 +360,7 @@ struct void_pointer }; //!This option setter specifies the type of -//!the tag of a base hook. A type can not have two +//!the tag of a base hook. A type cannot have two //!base hooks of the same type, so a tag can be used //!to differentiate two base hooks with otherwise same type template @@ -509,8 +533,29 @@ struct compare_hash /// @endcond }; +//!This option setter specifies if the hash container will use incremental +//!hashing. With incremental hashing the cost of hash table expansion is spread +//!out across each hash table insertion operation, as opposed to be incurred all at once. +//!Therefore linear hashing is well suited for interactive applications or real-time +//!appplications where the worst-case insertion time of non-incremental hash containers +//!(rehashing the whole bucket array) is not admisible. +template +struct incremental +{ + /// @cond + template + struct pack : Base + { + static const bool incremental = Enabled; + }; + /// @endcond +}; + /// @cond +//To-do: pass to variadic templates +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + template struct do_pack { @@ -525,7 +570,6 @@ struct do_pack typedef Prev type; }; - template < class DefaultOptions , class O1 = none @@ -537,7 +581,8 @@ template , class O7 = none , class O8 = none , class O9 = none - , class Option10 = none + , class O10 = none + , class O11 = none > struct pack_options { @@ -553,29 +598,164 @@ struct pack_options < typename do_pack < typename do_pack < typename do_pack - < DefaultOptions - , O1 + < typename do_pack + < DefaultOptions + , O1 + >::type + , O2 >::type - , O2 + , O3 >::type - , O3 + , O4 >::type - , O4 + , O5 >::type - , O5 + , O6 >::type - , O6 + , O7 >::type - , O7 + , O8 >::type - , O8 + , O9 >::type - , O9 - >::type - , Option10 + , O10 + >::type + , O11 >::type type; }; +#else + +//index_tuple +template +struct index_tuple{}; + +//build_number_seq +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + +template +struct typelist +{}; + +//invert_typelist +template +struct invert_typelist; + +template +struct typelist_element; + +template +struct typelist_element > +{ + typedef typename typelist_element >::type type; +}; + +template +struct typelist_element<0, typelist > +{ + typedef Head type; +}; + +template +typelist >::type...> + inverted_typelist(index_tuple, typelist) +{ + return typelist >::type...>(); +} + +//sizeof_typelist +template +struct sizeof_typelist; + +template +struct sizeof_typelist< typelist > +{ + static const std::size_t value = sizeof...(Types); +}; + +//invert_typelist_impl +template +struct invert_typelist_impl; + + +template +struct invert_typelist_impl< Typelist, index_tuple > +{ + static const std::size_t last_idx = sizeof_typelist::value - 1; + typedef typelist + ::type...> type; +}; + +template +struct invert_typelist_impl< Typelist, index_tuple > +{ + typedef Typelist type; +}; + +template +struct invert_typelist_impl< Typelist, index_tuple<> > +{ + typedef Typelist type; +}; + +//invert_typelist +template +struct invert_typelist; + +template +struct invert_typelist< typelist > +{ + typedef typelist typelist_t; + typedef typename build_number_seq::type indexes_t; + typedef typename invert_typelist_impl::type type; +}; + +//Do pack +template +struct do_pack; + +template<> +struct do_pack >; + +template +struct do_pack > +{ + typedef Prev type; +}; + +template +struct do_pack > +{ + typedef typename Prev::template pack type; +}; + +template +struct do_pack > +{ + typedef typename Prev::template pack + >::type> type; +}; + + +template +struct pack_options +{ + typedef typelist typelist_t; + typedef typename invert_typelist::type inverted_typelist; + typedef typename do_pack::type type; +}; + +#endif struct hook_defaults : public pack_options diff --git a/include/boost/intrusive/pointer_plus_bits.hpp b/include/boost/intrusive/pointer_plus_bits.hpp index 7c77e90..ec1fe51 100644 --- a/include/boost/intrusive/pointer_plus_bits.hpp +++ b/include/boost/intrusive/pointer_plus_bits.hpp @@ -14,6 +14,7 @@ #define BOOST_INTRUSIVE_POINTER_PLUS_BITS_HPP #include //ls_zeros +#include //BOOST_INTRUSIVE_INVARIANT_ASSERT namespace boost { namespace intrusive { @@ -28,7 +29,7 @@ struct max_pointer_plus_bits static const std::size_t value = 0; }; -//!This is an specialization for raw pointers. +//!This is a specialization for raw pointers. //!Raw pointers can embed extra bits in the lower bits //!if the alignment is multiple of 2pow(NumBits). template @@ -61,7 +62,7 @@ struct pointer_plus_bits static void set_pointer(pointer &n, pointer p) { - assert(0 == (std::size_t(p) & Mask)); + BOOST_INTRUSIVE_INVARIANT_ASSERT(0 == (std::size_t(p) & Mask)); n = pointer(std::size_t(p) | (std::size_t(n) & Mask)); } @@ -70,7 +71,7 @@ struct pointer_plus_bits static void set_bits(pointer &n, std::size_t c) { - assert(c <= Mask); + BOOST_INTRUSIVE_INVARIANT_ASSERT(c <= Mask); n = pointer(std::size_t(get_pointer(n)) | c); } }; diff --git a/include/boost/intrusive/rbtree.hpp b/include/boost/intrusive/rbtree.hpp index 4ec26ab..94d1a39 100644 --- a/include/boost/intrusive/rbtree.hpp +++ b/include/boost/intrusive/rbtree.hpp @@ -36,20 +36,6 @@ namespace intrusive { /// @cond -template -struct internal_default_set_hook -{ - template static detail::one test(...); - template static detail::two test(typename U::default_set_hook* = 0); - static const bool value = sizeof(test(0)) == sizeof(detail::two); -}; - -template -struct get_default_set_hook -{ - typedef typename T::default_set_hook type; -}; - template struct setopt { @@ -63,13 +49,7 @@ template struct set_defaults : pack_options < none - , base_hook - < typename detail::eval_if_c - < internal_default_set_hook::value - , get_default_set_hook - , detail::identity - >::type - > + , base_hook , constant_time_size , size_type , compare > @@ -91,7 +71,7 @@ struct set_defaults //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -1055,29 +1035,34 @@ class rbtree_impl } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const rbtree_impl &src, Cloner cloner, Disposer disposer) { this->clear_and_dispose(disposer); if(!src.empty()){ + detail::exception_disposer + rollback(*this, disposer); node_algorithms::clone (const_node_ptr(&src.priv_header()) ,node_ptr(&this->priv_header()) ,detail::node_cloner(cloner, this) ,detail::node_disposer(disposer, this)); this->priv_size_traits().set_size(src.priv_size_traits().get_size()); + this->priv_comp() = src.priv_comp(); + rollback.release(); } } @@ -1253,26 +1238,26 @@ class rbtree_impl { return priv_container_from_end_iterator(it.end_iterator_from_it()); } }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator< -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const rbtree_impl &x, const rbtree_impl &y) #else (const rbtree_impl &x, const rbtree_impl &y) #endif { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif bool operator== -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const rbtree_impl &x, const rbtree_impl &y) #else (const rbtree_impl &x, const rbtree_impl &y) @@ -1304,65 +1289,65 @@ bool operator== } } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const rbtree_impl &x, const rbtree_impl &y) #else (const rbtree_impl &x, const rbtree_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const rbtree_impl &x, const rbtree_impl &y) #else (const rbtree_impl &x, const rbtree_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const rbtree_impl &x, const rbtree_impl &y) #else (const rbtree_impl &x, const rbtree_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const rbtree_impl &x, const rbtree_impl &y) #else (const rbtree_impl &x, const rbtree_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (rbtree_impl &x, rbtree_impl &y) #else (rbtree_impl &x, rbtree_impl &y) @@ -1370,15 +1355,23 @@ inline void swap { x.swap(y); } /// @cond +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif struct make_rbtree_opt { typedef typename pack_options - < set_defaults, O1, O2, O3, O4>::type packed_options; + < set_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; typedef typename detail::get_value_traits ::type value_traits; @@ -1393,7 +1386,7 @@ struct make_rbtree_opt //! Helper metafunction to define a \c rbtree that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_rbtree_opt::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class rbtree - : public make_rbtree::type + : public make_rbtree::type { typedef typename make_rbtree - ::type Base; + ::type Base; public: typedef typename Base::value_compare value_compare; diff --git a/include/boost/intrusive/set.hpp b/include/boost/intrusive/set.hpp index de0b6c7..d2dff1e 100644 --- a/include/boost/intrusive/set.hpp +++ b/include/boost/intrusive/set.hpp @@ -32,7 +32,7 @@ namespace intrusive { //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -324,18 +324,19 @@ class set_impl { tree_.swap(other.tree_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const set_impl &src, Cloner cloner, Disposer disposer) { tree_.clone_from(src.tree_, cloner, disposer); } @@ -997,65 +998,65 @@ class set_impl /// @endcond }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const set_impl &x, const set_impl &y) #else (const set_impl &x, const set_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const set_impl &x, const set_impl &y) #else (const set_impl &x, const set_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const set_impl &x, const set_impl &y) #else (const set_impl &x, const set_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const set_impl &x, const set_impl &y) #else (const set_impl &x, const set_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (set_impl &x, set_impl &y) #else (set_impl &x, set_impl &y) @@ -1064,7 +1065,7 @@ inline void swap //! Helper metafunction to define a \c set that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_rbtree_opt::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class set - : public make_set::type + : public make_set::type { typedef typename make_set - ::type Base; + ::type Base; public: typedef typename Base::value_compare value_compare; @@ -1135,7 +1158,7 @@ class set //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -1423,18 +1446,19 @@ class multiset_impl { tree_.swap(other.tree_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. Basic guarantee. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const multiset_impl &src, Cloner cloner, Disposer disposer) { tree_.clone_from(src.tree_, cloner, disposer); } @@ -2018,65 +2042,65 @@ class multiset_impl /// @endcond }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const multiset_impl &x, const multiset_impl &y) #else (const multiset_impl &x, const multiset_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const multiset_impl &x, const multiset_impl &y) #else (const multiset_impl &x, const multiset_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const multiset_impl &x, const multiset_impl &y) #else (const multiset_impl &x, const multiset_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const multiset_impl &x, const multiset_impl &y) #else (const multiset_impl &x, const multiset_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (multiset_impl &x, multiset_impl &y) #else (multiset_impl &x, multiset_impl &y) @@ -2085,7 +2109,7 @@ inline void swap //! Helper metafunction to define a \c multiset that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_rbtree_opt::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class multiset - : public make_multiset::type + : public make_multiset::type { - typedef typename make_multiset - ::type Base; + typedef typename make_multiset::type Base; public: typedef typename Base::value_compare value_compare; diff --git a/include/boost/intrusive/set_hook.hpp b/include/boost/intrusive/set_hook.hpp index f439866..473dfe3 100644 --- a/include/boost/intrusive/set_hook.hpp +++ b/include/boost/intrusive/set_hook.hpp @@ -35,7 +35,7 @@ struct get_set_node_algo //! Helper metafunction to define a \c set_base_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -44,7 +44,13 @@ struct make_set_base_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3, O4>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_set_node_algo will tell the hook to optimize the hook for size instead //! of speed. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class set_base_hook - : public make_set_base_hook::type + : public make_set_base_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! @@ -154,7 +166,7 @@ class set_base_hook //! Helper metafunction to define a \c set_member_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -163,7 +175,13 @@ struct make_set_member_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3, O4>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_set_node_algo will tell the hook to optimize the hook for size instead //! of speed. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class set_member_hook - : public make_set_member_hook::type + : public make_set_member_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! diff --git a/include/boost/intrusive/sg_set.hpp b/include/boost/intrusive/sg_set.hpp index 66d461d..b3570fb 100644 --- a/include/boost/intrusive/sg_set.hpp +++ b/include/boost/intrusive/sg_set.hpp @@ -31,7 +31,7 @@ namespace intrusive { //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -323,18 +323,19 @@ class sg_set_impl { tree_.swap(other.tree_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const sg_set_impl &src, Cloner cloner, Disposer disposer) { tree_.clone_from(src.tree_, cloner, disposer); } @@ -1035,65 +1036,65 @@ class sg_set_impl /// @endcond }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sg_set_impl &x, const sg_set_impl &y) #else (const sg_set_impl &x, const sg_set_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sg_set_impl &x, const sg_set_impl &y) #else (const sg_set_impl &x, const sg_set_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sg_set_impl &x, const sg_set_impl &y) #else (const sg_set_impl &x, const sg_set_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sg_set_impl &x, const sg_set_impl &y) #else (const sg_set_impl &x, const sg_set_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (sg_set_impl &x, sg_set_impl &y) #else (sg_set_impl &x, sg_set_impl &y) @@ -1102,7 +1103,7 @@ inline void swap //! Helper metafunction to define a \c sg_set that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_sgtree_opt::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class sg_set - : public make_sg_set::type + : public make_sg_set::type { typedef typename make_sg_set - ::type Base; + ::type Base; public: typedef typename Base::value_compare value_compare; @@ -1173,7 +1197,7 @@ class sg_set //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -1461,18 +1485,19 @@ class sg_multiset_impl { tree_.swap(other.tree_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. Basic guarantee. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const sg_multiset_impl &src, Cloner cloner, Disposer disposer) { tree_.clone_from(src.tree_, cloner, disposer); } @@ -2080,65 +2105,65 @@ class sg_multiset_impl /// @endcond }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sg_multiset_impl &x, const sg_multiset_impl &y) #else (const sg_multiset_impl &x, const sg_multiset_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sg_multiset_impl &x, const sg_multiset_impl &y) #else (const sg_multiset_impl &x, const sg_multiset_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sg_multiset_impl &x, const sg_multiset_impl &y) #else (const sg_multiset_impl &x, const sg_multiset_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sg_multiset_impl &x, const sg_multiset_impl &y) #else (const sg_multiset_impl &x, const sg_multiset_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (sg_multiset_impl &x, sg_multiset_impl &y) #else (sg_multiset_impl &x, sg_multiset_impl &y) @@ -2147,7 +2172,7 @@ inline void swap //! Helper metafunction to define a \c sg_multiset that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_sgtree_opt::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class sg_multiset - : public make_sg_multiset::type + : public make_sg_multiset::type { typedef typename make_sg_multiset - ::type Base; + ::type Base; public: typedef typename Base::value_compare value_compare; diff --git a/include/boost/intrusive/sgtree.hpp b/include/boost/intrusive/sgtree.hpp index 70d4b61..63022a4 100644 --- a/include/boost/intrusive/sgtree.hpp +++ b/include/boost/intrusive/sgtree.hpp @@ -151,7 +151,7 @@ struct alpha_holder void set_alpha(float) { //alpha CAN't be changed. - assert(0); + BOOST_INTRUSIVE_INVARIANT_ASSERT(0); } h_alpha_t get_h_alpha_t() const @@ -176,13 +176,7 @@ template struct sg_set_defaults : pack_options < none - , base_hook - < typename detail::eval_if_c - < internal_default_bs_set_hook::value - , get_default_bs_set_hook - , detail::identity - >::type - > + , base_hook , floating_point , size_type , compare > @@ -204,7 +198,7 @@ struct sg_set_defaults //! \c base_hook<>/member_hook<>/value_traits<>, //! \c floating_point<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -1212,29 +1206,34 @@ class sgtree_impl } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const sgtree_impl &src, Cloner cloner, Disposer disposer) { this->clear_and_dispose(disposer); if(!src.empty()){ + detail::exception_disposer + rollback(*this, disposer); node_algorithms::clone (const_node_ptr(&src.priv_header()) ,node_ptr(&this->priv_header()) ,detail::node_cloner(cloner, this) ,detail::node_disposer(disposer, this)); this->priv_size_traits().set_size(src.priv_size_traits().get_size()); + this->priv_comp() = src.priv_comp(); + rollback.release(); } } @@ -1469,26 +1468,26 @@ class sgtree_impl { return priv_container_from_end_iterator(it.end_iterator_from_it()); } }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator< -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sgtree_impl &x, const sgtree_impl &y) #else (const sgtree_impl &x, const sgtree_impl &y) #endif { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif bool operator== -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sgtree_impl &x, const sgtree_impl &y) #else (const sgtree_impl &x, const sgtree_impl &y) @@ -1520,65 +1519,65 @@ bool operator== } } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sgtree_impl &x, const sgtree_impl &y) #else (const sgtree_impl &x, const sgtree_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sgtree_impl &x, const sgtree_impl &y) #else (const sgtree_impl &x, const sgtree_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sgtree_impl &x, const sgtree_impl &y) #else (const sgtree_impl &x, const sgtree_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const sgtree_impl &x, const sgtree_impl &y) #else (const sgtree_impl &x, const sgtree_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (sgtree_impl &x, sgtree_impl &y) #else (sgtree_impl &x, sgtree_impl &y) @@ -1586,15 +1585,22 @@ inline void swap { x.swap(y); } /// @cond +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template + , class O3 = none, class O4 = none> +#else +template +#endif struct make_sgtree_opt { typedef typename pack_options - < sg_set_defaults, O1, O2, O3, O4>::type packed_options; + < sg_set_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; typedef typename detail::get_value_traits ::type value_traits; @@ -1609,7 +1615,7 @@ struct make_sgtree_opt //! Helper metafunction to define a \c sgtree that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_sgtree_opt::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class sgtree - : public make_sgtree::type + : public make_sgtree::type { typedef typename make_sgtree - ::type Base; + ::type Base; public: typedef typename Base::value_compare value_compare; diff --git a/include/boost/intrusive/sgtree_algorithms.hpp b/include/boost/intrusive/sgtree_algorithms.hpp index 18c0884..c9af84f 100644 --- a/include/boost/intrusive/sgtree_algorithms.hpp +++ b/include/boost/intrusive/sgtree_algorithms.hpp @@ -683,7 +683,7 @@ class sgtree_algorithms for(std::size_t i = 1; true; ++i){ bool rebalance = false; if(i == depth){ - assert(tree_size == count(s)); + BOOST_INTRUSIVE_INVARIANT_ASSERT(tree_size == count(s)); rebalance = true; } else if(i > h_alpha(size)){ diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index bab8308..0577d71 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -36,18 +36,6 @@ namespace intrusive { /// @cond -template -struct internal_default_slist_hook -{ - template static detail::one test(...); - template static detail::two test(typename U::default_slist_hook* = 0); - static const bool value = sizeof(test(0)) == sizeof(detail::two); -}; - -template -struct get_default_slist_hook -{ typedef typename T::default_slist_hook type; }; - template struct slistopt { @@ -75,13 +63,7 @@ template struct slist_defaults : pack_options < none - , base_hook - < typename detail::eval_if_c - < internal_default_slist_hook::value - , get_default_slist_hook - , detail::identity - >::type - > + , base_hook , constant_time_size , linear , size_type @@ -114,7 +96,7 @@ struct slist_defaults //! the '*_after' functions, ++end() == begin() and previous(begin()) == end() //! are defined. An new special function "before_begin()" is defined, which returns //! an iterator that points one less the beginning of the list: ++before_begin() == begin() -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -300,7 +282,7 @@ class slist_impl : data_(v_traits) { this->set_default_constructed_state(); - this->insert_after(this->before_begin(), b, e); + this->insert_after(this->cbefore_begin(), b, e); } //! Effects: If it's a safe-mode @@ -346,7 +328,7 @@ class slist_impl template void clear_and_dispose(Disposer disposer) { - iterator it(this->begin()), itend(this->end()); + const_iterator it(this->begin()), itend(this->end()); while(it != itend){ node_ptr to_erase(it.pointed_node()); ++it; @@ -395,7 +377,7 @@ class slist_impl void push_back(reference value) { BOOST_STATIC_ASSERT((cache_last != 0)); - this->insert_after(iterator(this->get_last_node(), this), value); + this->insert_after(const_iterator(this->get_last_node(), this), value); } //! Effects: Erases the first element of the list. @@ -650,6 +632,7 @@ class slist_impl { this->priv_shift_forward(n, detail::bool_()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the @@ -668,7 +651,7 @@ class slist_impl this->clear_and_dispose(disposer); detail::exception_disposer rollback(*this, disposer); - iterator prev(this->before_begin()); + const_iterator prev(this->cbefore_begin()); const_iterator b(src.begin()), e(src.end()); for(; b != e; ++b){ prev = this->insert_after(prev, *cloner(*b)); @@ -689,7 +672,7 @@ class slist_impl //! Complexity: Constant. //! //! Note: Does not affect the validity of iterators and references. - iterator insert_after(iterator prev_p, reference value) + iterator insert_after(const_iterator prev_p, reference value) { node_ptr n = get_real_value_traits().to_node_ptr(value); if(safemode_or_autounlink) @@ -716,7 +699,7 @@ class slist_impl //! //! Note: Does not affect the validity of iterators and references. template - void insert_after(iterator prev_p, Iterator first, Iterator last) + void insert_after(const_iterator prev_p, Iterator first, Iterator last) { for (; first != last; ++first) prev_p = this->insert_after(prev_p, *first); @@ -734,7 +717,7 @@ class slist_impl //! Constant-time if cache_last<> is true and p == end(). //! //! Note: Does not affect the validity of iterators and references. - iterator insert(iterator p, reference value) + iterator insert(const_iterator p, reference value) { return this->insert_after(this->previous(p), value); } //! Requires: Dereferencing iterator must yield @@ -752,7 +735,7 @@ class slist_impl //! //! Note: Does not affect the validity of iterators and references. template - void insert(iterator p, Iterator b, Iterator e) + void insert(const_iterator p, Iterator b, Iterator e) { return this->insert_after(this->previous(p), b, e); } //! Effects: Erases the element after the element pointed by prev of @@ -767,7 +750,7 @@ class slist_impl //! //! Note: Invalidates the iterators (but not the references) to the //! erased element. - iterator erase_after(iterator prev) + iterator erase_after(const_iterator prev) { return this->erase_after_and_dispose(prev, detail::null_disposer()); } //! Effects: Erases the range (before_first, last) from @@ -783,7 +766,7 @@ class slist_impl //! //! Note: Invalidates the iterators (but not the references) to the //! erased element. - iterator erase_after(iterator before_first, iterator last) + iterator erase_after(const_iterator before_first, const_iterator last) { if(safemode_or_autounlink || constant_time_size){ return this->erase_after_and_dispose(before_first, last, detail::null_disposer()); @@ -797,7 +780,7 @@ class slist_impl } } node_algorithms::unlink_after(bfp, lp); - return last; + return last.unconst(); } } @@ -815,9 +798,9 @@ class slist_impl //! //! Note: Invalidates the iterators (but not the references) to the //! erased element. - iterator erase_after(iterator before_first, iterator last, difference_type n) + iterator erase_after(const_iterator before_first, const_iterator last, difference_type n) { - BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(++iterator(before_first), last) == difference_type(n)); + BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(++const_iterator(before_first), last) == difference_type(n)); if(safemode_or_autounlink){ return this->erase_after(before_first, last); } @@ -833,7 +816,7 @@ class slist_impl if(constant_time_size){ this->priv_size_traits().set_size(this->priv_size_traits().get_size() - n); } - return last; + return last.unconst(); } } @@ -849,7 +832,7 @@ class slist_impl //! //! Note: Invalidates the iterators (but not the references) to the //! erased element. - iterator erase(iterator i) + iterator erase(const_iterator i) { return this->erase_after(this->previous(i)); } //! Requires: first and last must be valid iterator to elements in *this. @@ -866,7 +849,7 @@ class slist_impl //! //! Note: Invalidates the iterators (but not the references) to the //! erased elements. - iterator erase(iterator first, iterator last) + iterator erase(const_iterator first, const_iterator last) { return this->erase_after(this->previous(first), last); } //! Effects: Erases the range [first, last) from @@ -883,7 +866,7 @@ class slist_impl //! //! Note: Invalidates the iterators (but not the references) to the //! erased element. - iterator erase(iterator first, iterator last, difference_type n) + iterator erase(const_iterator first, const_iterator last, difference_type n) { return this->erase_after(this->previous(first), last, n); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -901,9 +884,9 @@ class slist_impl //! //! Note: Invalidates the iterators to the erased element. template - iterator erase_after_and_dispose(iterator prev, Disposer disposer) + iterator erase_after_and_dispose(const_iterator prev, Disposer disposer) { - iterator it(prev); + const_iterator it(prev); ++it; node_ptr to_erase(it.pointed_node()); ++it; @@ -916,16 +899,16 @@ class slist_impl node_algorithms::init(to_erase); disposer(get_real_value_traits().to_value_ptr(to_erase)); this->priv_size_traits().decrement(); - return it; + return it.unconst(); } /// @cond template - static iterator s_erase_after_and_dispose(iterator prev, Disposer disposer) + static iterator s_erase_after_and_dispose(const_iterator prev, Disposer disposer) { BOOST_STATIC_ASSERT(((!cache_last)&&(!constant_time_size)&&(!stateful_value_traits))); - iterator it(prev); + const_iterator it(prev); ++it; node_ptr to_erase(it.pointed_node()); ++it; @@ -934,10 +917,10 @@ class slist_impl if(safemode_or_autounlink) node_algorithms::init(to_erase); disposer(real_value_traits::to_value_ptr(to_erase)); - return it; + return it.unconst(); } - static iterator s_erase_after(iterator prev) + static iterator s_erase_after(const_iterator prev) { return s_erase_after_and_dispose(prev, detail::null_disposer()); } /// @endcond @@ -957,7 +940,7 @@ class slist_impl //! //! Note: Invalidates the iterators to the erased element. template - iterator erase_after_and_dispose(iterator before_first, iterator last, Disposer disposer) + iterator erase_after_and_dispose(const_iterator before_first, const_iterator last, Disposer disposer) { node_ptr bfp(before_first.pointed_node()), lp(last.pointed_node()); node_ptr fp(node_traits::get_next(bfp)); @@ -973,7 +956,7 @@ class slist_impl if(cache_last && (node_traits::get_next(bfp) == this->get_end_node())){ this->set_last_node(bfp); } - return last; + return last.unconst(); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -992,7 +975,7 @@ class slist_impl //! Note: Invalidates the iterators (but not the references) to the //! erased element. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { return this->erase_after_and_dispose(this->previous(i), disposer); } //! Requires: first and last must be valid iterator to elements in *this. @@ -1013,7 +996,7 @@ class slist_impl //! Note: Invalidates the iterators (but not the references) to the //! erased elements. template - iterator erase_and_dispose(iterator first, iterator last, Disposer disposer) + iterator erase_and_dispose(const_iterator first, const_iterator last, Disposer disposer) { return this->erase_after_and_dispose(this->previous(first), last, disposer); } //! Requires: Dereferencing iterator must yield @@ -1035,7 +1018,7 @@ class slist_impl void assign(Iterator b, Iterator e) { this->clear(); - this->insert_after(this->before_begin(), b, e); + this->insert_after(this->cbefore_begin(), b, e); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1058,7 +1041,7 @@ class slist_impl void dispose_and_assign(Disposer disposer, Iterator b, Iterator e) { this->clear_and_dispose(disposer); - this->insert_after(this->before_begin(), b, e, disposer); + this->insert_after(this->cbefore_begin(), b, e, disposer); } //! Requires: prev is an iterator to an element or x.end()/x.before_begin() in x. @@ -1077,10 +1060,10 @@ class slist_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - iterator splice_after(iterator prev, slist_impl &x) + iterator splice_after(const_iterator prev, slist_impl &x) { if (!x.empty()){ - iterator last_x(x.previous(x.end())); //<- constant time if cache_last is active + const_iterator last_x(x.previous(x.end())); //<- constant time if cache_last is active node_ptr prev_n(prev.pointed_node()); node_ptr last_x_n(last_x.pointed_node()); if(cache_last){ @@ -1092,10 +1075,10 @@ class slist_impl node_algorithms::transfer_after( prev_n, x.before_begin().pointed_node(), last_x_n); this->priv_size_traits().set_size(this->priv_size_traits().get_size() + x.priv_size_traits().get_size()); x.priv_size_traits().set_size(size_type(0)); - return last_x; + return last_x.unconst(); } else{ - return prev; + return prev.unconst(); } } @@ -1112,9 +1095,9 @@ class slist_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice_after(iterator prev_pos, slist_impl &x, iterator prev_ele) + void splice_after(const_iterator prev_pos, slist_impl &x, const_iterator prev_ele) { - iterator elem = prev_ele; + const_iterator elem = prev_ele; this->splice_after(prev_pos, x, prev_ele, ++elem, 1); } @@ -1133,7 +1116,7 @@ class slist_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice_after(iterator prev_pos, slist_impl &x, iterator before_first, iterator before_last) + void splice_after(const_iterator prev_pos, slist_impl &x, const_iterator before_first, const_iterator before_last) { if(constant_time_size) this->splice_after(prev_pos, x, before_first, before_last, std::distance(before_first, before_last)); @@ -1156,7 +1139,7 @@ class slist_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice_after(iterator prev_pos, slist_impl &x, iterator before_first, iterator before_last, difference_type n) + void splice_after(const_iterator prev_pos, slist_impl &x, const_iterator before_first, const_iterator before_last, difference_type n) { if(n){ BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(before_first, before_last) == n); @@ -1188,7 +1171,7 @@ class slist_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - iterator splice(iterator it, slist_impl &x) + iterator splice(const_iterator it, slist_impl &x) { return this->splice_after(this->previous(it), x); } //! Requires: it p must be a valid iterator of *this. @@ -1205,7 +1188,7 @@ class slist_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(iterator pos, slist_impl &x, iterator elem) + void splice(const_iterator pos, slist_impl &x, const_iterator elem) { return this->splice_after(this->previous(pos), x, x.previous(elem)); } //! Requires: pos must be a dereferenceable iterator in *this @@ -1225,7 +1208,7 @@ class slist_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(iterator pos, slist_impl &x, iterator first, iterator last) + void splice(const_iterator pos, slist_impl &x, const_iterator first, const_iterator last) { return this->splice_after(this->previous(pos), x, x.previous(first), x.previous(last)); } //! Requires: pos must be a dereferenceable iterator in *this @@ -1244,7 +1227,7 @@ class slist_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(iterator pos, slist_impl &x, iterator first, iterator last, difference_type n) + void splice(const_iterator pos, slist_impl &x, const_iterator first, const_iterator last, difference_type n) { return this->splice_after(this->previous(pos), x, x.previous(first), x.previous(last), n); } //! Effects: This function sorts the list *this according to std::less. @@ -1266,10 +1249,10 @@ class slist_impl slist_impl carry; slist_impl counter[64]; int fill = 0; - iterator last_inserted; + const_iterator last_inserted; while(!this->empty()){ - last_inserted = this->begin(); - carry.splice_after(carry.before_begin(), *this, this->before_begin()); + last_inserted = this->cbegin(); + carry.splice_after(carry.cbefore_begin(), *this, this->cbefore_begin()); int i = 0; while(i < fill && !counter[i].empty()) { last_inserted = carry.merge(counter[i++], p); @@ -1277,16 +1260,16 @@ class slist_impl BOOST_INTRUSIVE_INVARIANT_ASSERT(counter[i].empty()); node_ptr p = node_algorithms::get_previous_node - (last_inserted.pointed_node(), carry.end().pointed_node()); - iterator last_element(p, this); + (last_inserted.pointed_node(), carry.cend().pointed_node()); + const_iterator last_element(p, this); if(constant_time_size){ - counter[i].splice_after( counter[i].before_begin(), carry - , carry.before_begin(), last_element + counter[i].splice_after( counter[i].cbefore_begin(), carry + , carry.cbefore_begin(), last_element , carry.size()); } else{ - counter[i].splice_after( counter[i].before_begin(), carry - , carry.before_begin(), last_element); + counter[i].splice_after( counter[i].cbefore_begin(), carry + , carry.cbefore_begin(), last_element); } if(i == fill) ++fill; @@ -1298,13 +1281,13 @@ class slist_impl node_ptr p = node_algorithms::get_previous_node (last_inserted.pointed_node(), counter[--fill].end().pointed_node()); - iterator last_element(p, this); + const_iterator last_element(p, this); if(constant_time_size){ - this->splice_after( before_begin(), counter[fill], counter[fill].before_begin() + this->splice_after( cbefore_begin(), counter[fill], counter[fill].cbefore_begin() , last_element, counter[fill].size()); } else{ - this->splice_after( before_begin(), counter[fill], counter[fill].before_begin() + this->splice_after( cbefore_begin(), counter[fill], counter[fill].cbefore_begin() , last_element); } } @@ -1348,12 +1331,12 @@ class slist_impl template iterator merge(slist_impl& x, Predicate p) { - iterator a(before_begin()), e(end()), ax(x.before_begin()), ex(x.end()); - iterator last_inserted(e); - iterator a_next; + 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()) { - iterator ix(ax); - iterator cx; + const_iterator ix(ax); + const_iterator cx; size_type n(0); while(++(cx = ix) != ex && p(*cx, *a_next)){ ++ix; ++n; @@ -1367,7 +1350,7 @@ class slist_impl if (!x.empty()){ last_inserted = this->splice_after(a, x); } - return last_inserted; + return last_inserted.unconst(); } //! Effects: This function removes all of x's elements and inserts them @@ -1455,7 +1438,7 @@ class slist_impl template void remove_and_dispose_if(Pred pred, Disposer disposer) { - iterator bcur(this->before_begin()), cur(this->begin()), e(this->end()); + const_iterator bcur(this->before_begin()), cur(this->begin()), e(this->end()); while(cur != e){ if (pred(*cur)){ @@ -1528,10 +1511,10 @@ class slist_impl template void unique_and_dispose(BinaryPredicate pred, Disposer disposer) { - iterator end_n(this->end()); - iterator bcur(this->begin()); + const_iterator end_n(this->cend()); + const_iterator bcur(this->cbegin()); if(bcur != end_n){ - iterator cur(bcur); + const_iterator cur(bcur); ++cur; while(cur != end_n) { if (pred(*bcur, *cur)){ @@ -1643,7 +1626,7 @@ class slist_impl const_iterator previous(const_iterator i) const { if(cache_last && (i.pointed_node() == this->get_end_node())){ - return iterator(uncast(this->get_last_node()), this); + return const_iterator(uncast(this->get_last_node()), this); } return const_iterator (node_algorithms::get_previous_node @@ -1760,26 +1743,26 @@ class slist_impl } }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator< -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const slist_impl &x, const slist_impl &y) #else (const slist_impl &x, const slist_impl &y) #endif { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif bool operator== -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const slist_impl &x, const slist_impl &y) #else (const slist_impl &x, const slist_impl &y) @@ -1812,65 +1795,65 @@ bool operator== } } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const slist_impl &x, const slist_impl &y) #else (const slist_impl &x, const slist_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const slist_impl &x, const slist_impl &y) #else (const slist_impl &x, const slist_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const slist_impl &x, const slist_impl &y) #else (const slist_impl &x, const slist_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const slist_impl &x, const slist_impl &y) #else (const slist_impl &x, const slist_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (slist_impl &x, slist_impl &y) #else (slist_impl &x, slist_impl &y) @@ -1879,7 +1862,7 @@ inline void swap //! Helper metafunction to define a \c slist that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -1888,7 +1871,13 @@ struct make_slist { /// @cond typedef typename pack_options - < slist_defaults, O1, O2, O3, O4, O5>::type packed_options; + < slist_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4, O5 + #else + Options... + #endif + >::type packed_options; typedef typename detail::get_value_traits ::type value_traits; typedef slist_impl @@ -1907,12 +1896,29 @@ struct make_slist #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class slist - : public make_slist::type + : public make_slist::type { typedef typename make_slist - ::type Base; + ::type Base; typedef typename Base::real_value_traits real_value_traits; //Assert if passed value traits are compatible with the type BOOST_STATIC_ASSERT((detail::is_same::value)); diff --git a/include/boost/intrusive/slist_hook.hpp b/include/boost/intrusive/slist_hook.hpp index b7d5344..8164d62 100644 --- a/include/boost/intrusive/slist_hook.hpp +++ b/include/boost/intrusive/slist_hook.hpp @@ -37,7 +37,7 @@ struct get_slist_node_algo //! Helper metafunction to define a \c slist_base_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -46,7 +46,13 @@ struct make_slist_base_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_slist_node_algo @@ -75,15 +81,21 @@ struct make_slist_base_hook //! //! \c void_pointer<> is the pointer type that will be used internally in the hook //! and the the container configured to use this hook. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class slist_base_hook - : public make_slist_base_hook::type + : public make_slist_base_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! @@ -152,7 +164,7 @@ class slist_base_hook //! Helper metafunction to define a \c slist_member_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -161,7 +173,13 @@ struct make_slist_member_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_slist_node_algo @@ -185,15 +203,21 @@ struct make_slist_member_hook //! //! \c void_pointer<> is the pointer type that will be used internally in the hook //! and the the container configured to use this hook. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class slist_member_hook - : public make_slist_member_hook::type + : public make_slist_member_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! diff --git a/include/boost/intrusive/splay_set.hpp b/include/boost/intrusive/splay_set.hpp index 104063a..f86ae8b 100644 --- a/include/boost/intrusive/splay_set.hpp +++ b/include/boost/intrusive/splay_set.hpp @@ -31,7 +31,7 @@ namespace intrusive { //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -323,18 +323,19 @@ class splay_set_impl { tree_.swap(other.tree_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const splay_set_impl &src, Cloner cloner, Disposer disposer) { tree_.clone_from(src.tree_, cloner, disposer); } @@ -1072,65 +1073,65 @@ class splay_set_impl /// @endcond }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splay_set_impl &x, const splay_set_impl &y) #else (const splay_set_impl &x, const splay_set_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splay_set_impl &x, const splay_set_impl &y) #else (const splay_set_impl &x, const splay_set_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splay_set_impl &x, const splay_set_impl &y) #else (const splay_set_impl &x, const splay_set_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splay_set_impl &x, const splay_set_impl &y) #else (const splay_set_impl &x, const splay_set_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (splay_set_impl &x, splay_set_impl &y) #else (splay_set_impl &x, splay_set_impl &y) @@ -1139,7 +1140,7 @@ inline void swap //! Helper metafunction to define a \c splay_set that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_splaytree_opt::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class splay_set - : public make_splay_set::type + : public make_splay_set::type { typedef typename make_splay_set - ::type Base; + ::type Base; public: typedef typename Base::value_compare value_compare; @@ -1210,7 +1233,7 @@ class splay_set //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -1498,18 +1521,19 @@ class splay_multiset_impl { tree_.swap(other.tree_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. Basic guarantee. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const splay_multiset_impl &src, Cloner cloner, Disposer disposer) { tree_.clone_from(src.tree_, cloner, disposer); } @@ -2154,65 +2178,65 @@ class splay_multiset_impl /// @endcond }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splay_multiset_impl &x, const splay_multiset_impl &y) #else (const splay_multiset_impl &x, const splay_multiset_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splay_multiset_impl &x, const splay_multiset_impl &y) #else (const splay_multiset_impl &x, const splay_multiset_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splay_multiset_impl &x, const splay_multiset_impl &y) #else (const splay_multiset_impl &x, const splay_multiset_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splay_multiset_impl &x, const splay_multiset_impl &y) #else (const splay_multiset_impl &x, const splay_multiset_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (splay_multiset_impl &x, splay_multiset_impl &y) #else (splay_multiset_impl &x, splay_multiset_impl &y) @@ -2221,7 +2245,7 @@ inline void swap //! Helper metafunction to define a \c splay_multiset that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_splaytree_opt::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class splay_multiset - : public make_splay_multiset::type + : public make_splay_multiset::type { typedef typename make_splay_multiset - ::type Base; + ::type Base; public: typedef typename Base::value_compare value_compare; diff --git a/include/boost/intrusive/splay_set_hook.hpp b/include/boost/intrusive/splay_set_hook.hpp index ddd7031..17f18bc 100644 --- a/include/boost/intrusive/splay_set_hook.hpp +++ b/include/boost/intrusive/splay_set_hook.hpp @@ -34,7 +34,7 @@ struct get_splay_set_node_algo //! Helper metafunction to define a \c splay_set_base_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -43,7 +43,13 @@ struct make_splay_set_base_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_splay_set_node_algo @@ -72,15 +78,21 @@ struct make_splay_set_base_hook //! //! \c link_mode<> will specify the linking mode of the hook (\c normal_link, //! \c auto_unlink or \c safe_link). -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class splay_set_base_hook - : public make_splay_set_base_hook::type + : public make_splay_set_base_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! @@ -149,7 +161,7 @@ class splay_set_base_hook //! Helper metafunction to define a \c splay_set_member_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -158,7 +170,13 @@ struct make_splay_set_member_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_splay_set_node_algo @@ -183,15 +201,21 @@ struct make_splay_set_member_hook //! //! \c link_mode<> will specify the linking mode of the hook (\c normal_link, //! \c auto_unlink or \c safe_link). -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class splay_set_member_hook - : public make_splay_set_member_hook::type + : public make_splay_set_member_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! diff --git a/include/boost/intrusive/splaytree.hpp b/include/boost/intrusive/splaytree.hpp index e356963..94a0985 100644 --- a/include/boost/intrusive/splaytree.hpp +++ b/include/boost/intrusive/splaytree.hpp @@ -35,20 +35,6 @@ namespace intrusive { /// @cond -template -struct internal_default_splay_set_hook -{ - template static detail::one test(...); - template static detail::two test(typename U::default_splay_set_hook* = 0); - static const bool value = sizeof(test(0)) == sizeof(detail::two); -}; - -template -struct get_default_splay_set_hook -{ - typedef typename T::default_splay_set_hook type; -}; - template struct splaysetopt { @@ -62,13 +48,7 @@ template struct splay_set_defaults : pack_options < none - , base_hook - < typename detail::eval_if_c - < internal_default_splay_set_hook::value - , get_default_splay_set_hook - , detail::identity - >::type - > + , base_hook , constant_time_size , size_type , compare > @@ -90,7 +70,7 @@ struct splay_set_defaults //! \c base_hook<>/member_hook<>/value_traits<>, //! \c constant_time_size<>, \c size_type<> and //! \c compare<>. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -1072,29 +1052,34 @@ class splaytree_impl } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. Copies the predicate from the source container. //! //! If cloner throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. template void clone_from(const splaytree_impl &src, Cloner cloner, Disposer disposer) { this->clear_and_dispose(disposer); if(!src.empty()){ + detail::exception_disposer + rollback(*this, disposer); node_algorithms::clone (const_node_ptr(&src.priv_header()) ,node_ptr(&this->priv_header()) ,detail::node_cloner(cloner, this) ,detail::node_disposer(disposer, this)); this->priv_size_traits().set_size(src.priv_size_traits().get_size()); + this->priv_comp() = src.priv_comp(); + rollback.release(); } } @@ -1339,26 +1324,26 @@ class splaytree_impl { return priv_container_from_end_iterator(it.end_iterator_from_it()); } }; -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator< -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splaytree_impl &x, const splaytree_impl &y) #else (const splaytree_impl &x, const splaytree_impl &y) #endif { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif bool operator== -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splaytree_impl &x, const splaytree_impl &y) #else (const splaytree_impl &x, const splaytree_impl &y) @@ -1390,65 +1375,65 @@ bool operator== } } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator!= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splaytree_impl &x, const splaytree_impl &y) #else (const splaytree_impl &x, const splaytree_impl &y) #endif { return !(x == y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator> -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splaytree_impl &x, const splaytree_impl &y) #else (const splaytree_impl &x, const splaytree_impl &y) #endif { return y < x; } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator<= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splaytree_impl &x, const splaytree_impl &y) #else (const splaytree_impl &x, const splaytree_impl &y) #endif { return !(y < x); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline bool operator>= -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (const splaytree_impl &x, const splaytree_impl &y) #else (const splaytree_impl &x, const splaytree_impl &y) #endif { return !(x < y); } -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template #endif inline void swap -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) (splaytree_impl &x, splaytree_impl &y) #else (splaytree_impl &x, splaytree_impl &y) @@ -1456,15 +1441,23 @@ inline void swap { x.swap(y); } /// @cond + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template + , class O3 = none, class O4 = none> +#else +template +#endif struct make_splaytree_opt { typedef typename pack_options - < splay_set_defaults, O1, O2, O3, O4>::type packed_options; + < splay_set_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; typedef typename detail::get_value_traits ::type value_traits; @@ -1479,7 +1472,7 @@ struct make_splaytree_opt //! Helper metafunction to define a \c splaytree that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template::type + < typename make_splaytree_opt::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template +#else +template +#endif class splaytree - : public make_splaytree::type + : public make_splaytree::type { typedef typename make_splaytree - ::type Base; + ::type Base; public: typedef typename Base::value_compare value_compare; diff --git a/include/boost/intrusive/splaytree_algorithms.hpp b/include/boost/intrusive/splaytree_algorithms.hpp index 409449f..e727ab6 100644 --- a/include/boost/intrusive/splaytree_algorithms.hpp +++ b/include/boost/intrusive/splaytree_algorithms.hpp @@ -870,7 +870,7 @@ class splaytree_algorithms if(NodeTraits::get_parent(g) == p) NodeTraits::set_parent(g, n); else{//must be ( g->right == p ) - assert(0); + BOOST_INTRUSIVE_INVARIANT_ASSERT(0); NodeTraits::set_right(g, n); } } diff --git a/include/boost/intrusive/unordered_set.hpp b/include/boost/intrusive/unordered_set.hpp index 6ec56fc..8f1f9d1 100644 --- a/include/boost/intrusive/unordered_set.hpp +++ b/include/boost/intrusive/unordered_set.hpp @@ -56,7 +56,7 @@ namespace intrusive { //! //! Since no automatic rehashing is done, iterators are never invalidated when //! inserting or erasing elements. Iterators are only invalidated when rehasing. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -268,18 +268,24 @@ class unordered_set_impl { table_.swap(other.table_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes that compare equal and produce the same + //! hash than the original node. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. The hash function and the equality + //! predicate are copied from the source. //! - //! If cloner throws, all cloned elements are unlinked and disposed + //! If store_hash option is true, this method does not use the hash function. + //! + //! If any operation throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. Basic guarantee. + //! Throws: If cloner or hasher throw or hash or equality predicate copying + //! throws. Basic guarantee. template void clone_from(const unordered_set_impl &src, Cloner cloner, Disposer disposer) { table_.clone_from(src.table_, cloner, disposer); } @@ -920,6 +926,8 @@ class unordered_set_impl //! //! Effects: Updates the internal reference with the new bucket erases //! the values from the old bucket and inserts then in the new one. + //! + //! If store_hash option is true, this method does not use the hash function. //! //! Complexity: Average case linear in this->size(), worst case quadratic. //! @@ -927,6 +935,32 @@ class unordered_set_impl void rehash(const bucket_traits &new_bucket_traits) { table_.rehash(new_bucket_traits); } + //! Requires: + //! + //! Effects: + //! + //! Complexity: + //! + //! Throws: + //! + //! Note: this method is only available if incremental option is activated. + bool incremental_rehash(bool grow = true) + { return table_.incremental_rehash(grow); } + + //! Note: this method is only available if incremental option is activated. + bool incremental_rehash(const bucket_traits &new_bucket_traits) + { return table_.incremental_rehash(new_bucket_traits); } + + //! Requires: + //! + //! Effects: + //! + //! Complexity: + //! + //! Throws: + size_type split_count() const + { return table_.split_count(); } + //! Effects: Returns the nearest new bucket count optimized for //! the container that is bigger than n. This suggestion can be used //! to create bucket arrays with a size that will usually improve @@ -954,14 +988,14 @@ class unordered_set_impl //! Helper metafunction to define an \c unordered_set that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif struct make_unordered_set @@ -969,19 +1003,42 @@ struct make_unordered_set /// @cond typedef unordered_set_impl < typename make_hashtable_opt - ::type + ::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED -template + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif class unordered_set - : public make_unordered_set::type + : public make_unordered_set::type { typedef typename make_unordered_set - ::type Base; + ::type Base; //Assert if passed value traits are compatible with the type BOOST_STATIC_ASSERT((detail::is_same::value)); @@ -1052,7 +1109,7 @@ class unordered_set //! //! Since no automatic rehashing is done, iterators are never invalidated when //! inserting or erasing elements. Iterators are only invalidated when rehasing. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template #else template @@ -1265,18 +1322,24 @@ class unordered_multiset_impl { table_.swap(other.table_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes that compare equal and produce the same + //! hash than the original node. //! //! Effects: Erases all the elements from *this //! calling Disposer::operator()(pointer), clones all the //! elements from src calling Cloner::operator()(const_reference ) - //! and inserts them on *this. + //! and inserts them on *this. The hash function and the equality + //! predicate are copied from the source. //! - //! If cloner throws, all cloned elements are unlinked and disposed + //! If store_hash option is true, this method does not use the hash function. + //! + //! If any operation throws, all cloned elements are unlinked and disposed //! calling Disposer::operator()(pointer). //! //! Complexity: Linear to erased plus inserted elements. //! - //! Throws: If cloner throws. + //! Throws: If cloner or hasher throw or hash or equality predicate copying + //! throws. Basic guarantee. template void clone_from(const unordered_multiset_impl &src, Cloner cloner, Disposer disposer) { table_.clone_from(src.table_, cloner, disposer); } @@ -1854,6 +1917,8 @@ class unordered_multiset_impl //! //! Effects: Updates the internal reference with the new bucket erases //! the values from the old bucket and inserts then in the new one. + //! + //! If store_hash option is true, this method does not use the hash function. //! //! Complexity: Average case linear in this->size(), worst case quadratic. //! @@ -1861,6 +1926,32 @@ class unordered_multiset_impl void rehash(const bucket_traits &new_bucket_traits) { table_.rehash(new_bucket_traits); } + //! Requires: + //! + //! Effects: + //! + //! Complexity: + //! + //! Throws: + //! + //! Note: this method is only available if incremental option is activated. + bool incremental_rehash(bool grow = true) + { return table_.incremental_rehash(grow); } + + //! Note: this method is only available if incremental option is activated. + bool incremental_rehash(const bucket_traits &new_bucket_traits) + { return table_.incremental_rehash(new_bucket_traits); } + + //! Requires: + //! + //! Effects: + //! + //! Complexity: + //! + //! Throws: + size_type split_count() const + { return table_.split_count(); } + //! Effects: Returns the nearest new bucket count optimized for //! the container that is bigger than n. This suggestion can be used //! to create bucket arrays with a size that will usually improve @@ -1888,14 +1979,14 @@ class unordered_multiset_impl //! Helper metafunction to define an \c unordered_multiset that yields to the same type when the //! same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif struct make_unordered_multiset @@ -1903,19 +1994,42 @@ struct make_unordered_multiset /// @cond typedef unordered_multiset_impl < typename make_hashtable_opt - ::type + ::type > implementation_defined; /// @endcond typedef implementation_defined type; }; #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED -template + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif class unordered_multiset - : public make_unordered_multiset::type + : public make_unordered_multiset::type { typedef typename make_unordered_multiset - ::type Base; + ::type Base; //Assert if passed value traits are compatible with the type BOOST_STATIC_ASSERT((detail::is_same::value)); diff --git a/include/boost/intrusive/unordered_set_hook.hpp b/include/boost/intrusive/unordered_set_hook.hpp index 7f6f5bd..0d5d4e8 100644 --- a/include/boost/intrusive/unordered_set_hook.hpp +++ b/include/boost/intrusive/unordered_set_hook.hpp @@ -153,7 +153,7 @@ struct get_uset_node_algo //! Helper metafunction to define a \c unordered_set_base_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -162,7 +162,13 @@ struct make_unordered_set_base_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3, O4>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_uset_node_algo will tell the hook to store a link to form a group //! with other value with the same value to speed up searches and insertions //! in unordered_multisets with a great number of with equivalent keys. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class unordered_set_base_hook - : public make_unordered_set_base_hook::type + : public make_unordered_set_base_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! @@ -279,7 +291,7 @@ class unordered_set_base_hook //! Helper metafunction to define a \c unordered_set_member_hook that yields to the same //! type when the same options (either explicitly or implicitly) are used. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template @@ -288,7 +300,13 @@ struct make_unordered_set_member_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3, O4>::type packed_options; + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; typedef detail::generic_hook < get_uset_node_algo< typename packed_options::void_pointer @@ -318,15 +336,21 @@ struct make_unordered_set_member_hook //! //! \c store_hash<> will tell the hook to store the hash of the value //! to speed up rehashings. -#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template #else template #endif class unordered_set_member_hook - : public make_unordered_set_member_hook::type + : public make_unordered_set_member_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type { - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! From be6ca1b7ec2292754ddee1eb58a44a243cb5c7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 11 Oct 2008 13:18:02 +0000 Subject: [PATCH 09/14] Changes and fixes for Boost 1.37 [SVN r49277] --- doc/intrusive.qbk | 52 ++- example/doc_window.cpp | 2 +- .../vc7ide/_intrusivelib/_intrusivelib.vcproj | 3 + proj/vc7ide/to-do.txt | 3 + .../vc7ide/unordered_set/unordered_set.vcproj | 5 +- test/default_hook_test.cpp | 37 +- test/list_test.cpp | 310 +++++++++++++- test/set_test.cpp | 1 - test/sg_multiset_test.cpp | 12 +- test/sg_set_test.cpp | 12 +- test/splay_multiset_test.cpp | 37 +- test/splay_set_test.cpp | 36 +- test/test_macros.hpp | 5 +- test/unordered_multiset_test.cpp | 380 ++++++++++++++---- test/unordered_set_test.cpp | 297 +++++++++++--- 15 files changed, 1012 insertions(+), 180 deletions(-) create mode 100644 proj/vc7ide/to-do.txt diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 2b410ed..b80d17e 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -596,7 +596,7 @@ Apart from that, [*Boost.Intrusive] offers additional features: be configured to use any type of pointer. This configuration information is also transmitted to the containers, so all the internal pointers used by intrusive containers configured with these hooks will be smart pointers. As an example, - [*Boost.Interprocess] defines an mart pointer compatible with shared memory, + [*Boost.Interprocess] defines a smart pointer compatible with shared memory, called `offset_ptr`. [*Boost.Intrusive] can be configured to use this smart pointer to allow shared memory intrusive containers. @@ -656,6 +656,15 @@ want to redefine intrusive safe-mode assertions without modifying the global used in hooks' destructors to check that the hook is in a default state. If any of these macros is not redefined, the assertion will default to `BOOST_ASSERT`. +If `BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT` or `BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT` +is defined and the programmer needs to include a file to configure that assertion, it can define +`BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE` or `BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT_INCLUDE` +with the name of the file to include: + +[c++] + + #define BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT MYASSERT + #define BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE [endsect] @@ -1032,8 +1041,9 @@ the same options explained in the section * [*`optimize_size`]: The hook will be optimized for size instead of speed. The hook will embed the color bit of the red-black tree node in the parent pointer if pointer alignment is even. - Optimizing the size will reduce speed performance a bit since masking - operations will be needed to access parent pointer and color attributes. + In some platforms, optimizing the size might reduce speed performance a bit + since masking operations will be needed to access parent pointer and color attributes, + in other platforms this option improves performance due to improved memory locality. Default: `optimize_size`. [endsect] @@ -1283,11 +1293,17 @@ And they also can receive additional options: (e.g. strings with a long common predicate) sometimes (specially when the load factor is high or we have many equivalent elements in an [classref boost::intrusive::unordered_multiset unordered_multiset] and - no `optimize_multikey<>` is activatedin the hook) + no `optimize_multikey<>` is activated in the hook) the equality function is a performance problem. Two equal values must have equal hashes, so comparing the hash values of two elements before using the comparison functor can speed up some implementations. +* [*`incremental`]: Activates incremental hashing (also known as Linear Hashing). + This option implies `power_2_buckets` and the container will require power of two buckets. + For more information on incremental hashing, see + [@http://en.wikipedia.org/wiki/Linear_hashing `Linear hash` on Wikipedia] + Default: `incremental` + [endsect] [section:unordered_set_unordered_multiset_example Example] @@ -1558,8 +1574,9 @@ the size of the node: * [*`optimize_size`]: The hook will be optimized for size instead of speed. The hook will embed the balance bits of the AVL tree node in the parent pointer if pointer alignment is multiple of 4. - Optimizing the size will reduce speed performance a bit since masking - operations will be needed to access parent pointer and balance factor attributes. + In some platforms, optimizing the size might reduce speed performance a bit + since masking operations will be needed to access parent pointer and balance factor attributes, + in other platforms this option improves performance due to improved memory locality. Default: `optimize_size`. [endsect] @@ -1890,7 +1907,7 @@ and [classref boost::intrusive::unordered_set unordered_set] reference for more With multiple ordered and unordered associative containers ([classref boost::intrusive::multiset multiset] and -[classref boost::intrusive::unordered_multiset unordered_multiset]) there's +[classref boost::intrusive::unordered_multiset unordered_multiset]) there is no need for these advanced insertion functions, since insertions are always succesful. [endsect] @@ -1982,7 +1999,7 @@ The cloning function works as follows: all the constructed elements are disposed using the disposer function object. -Here's an example of `clone_from`: +Here is an example of `clone_from`: [import ../example/doc_clone_from.cpp] [doc_clone_from] @@ -2116,7 +2133,7 @@ These hooks support these options: be inserted container. Additionally, these hooks don't support `unlink()` and `swap_nodes()` operations for the same reason. -Here's an example that creates a class with two any hooks, and uses one to insert the +Here is an example that creates a class with two any hooks, and uses one to insert the class in a [classref slist] and the other one in a [classref list]. [import ../example/doc_any_hook.cpp] @@ -2699,7 +2716,7 @@ used in node algorithms, since these types can be different. Apart from this, Instead of using [*Boost.Intrusive] predefined hooks a user might want to develop customized containers, for example, using nodes that are optimized for a specific -application or that are compatible with a a legacy ABI. A user might want +application or that are compatible with a legacy ABI. A user might want to have only two additional pointers in his class and insert the class in a doubly linked list sometimes and in a singly linked list in other situations. You can't achieve this using [*Boost.Intrusive] predefined hooks. Now, instead of using @@ -3459,7 +3476,7 @@ The disperse list is again the slowest. [section:performance_results_conclusions Conclusions] -Intrusive containers can offer performance benefits that can not be achieved with +Intrusive containers can offer performance benefits that cannot be achieved with equivalent non-intrusive containers. Memory locality improvements are noticeable when the objects to be inserted are small. Minimizing memory allocation/deallocation calls is also an important factor and intrusive containers make this simple if the user allocates @@ -3471,6 +3488,17 @@ all the objects to be inserted in intrusive containers in containers like `std:: [section:release_notes Release Notes] +[section:release_notes_boost_1_37_00 Boost 1.37 Release] + +* Intrusive now takes advantage of compilers with variadic templates. +* `clone_from` functions now copy predicates and hash functions of associative containers. +* Added incremental hashing to unordered containers via `incremental<>` option. +* Update some function parameters from `iterator` to `const_iterator` in containers + to keep up with the draft of the next standard. +* Added an option to specify include files for intrusive configurable assertion macros. + +[endsect] + [section:release_notes_boost_1_36_00 Boost 1.36 Release] * Added `linear<>` and `cache_last<>` options to singly linked lists. @@ -3512,7 +3540,7 @@ all the objects to be inserted in intrusive containers in containers like `std:: [endsect] -[section:acknowledgments Acknowledgements] +[section:acknowledgements Acknowledegements] [*Olaf Krzikalla] would like to thank: diff --git a/example/doc_window.cpp b/example/doc_window.cpp index 9f49e9e..7a0e12d 100644 --- a/example/doc_window.cpp +++ b/example/doc_window.cpp @@ -21,7 +21,7 @@ class Window : public list_base_hook<> //This is a container those value is an abstract class: you can't do this with std::list. typedef list win_list; - //An static intrusive list declaration + //A static intrusive list declaration static win_list all_windows; //Constructor. Includes this window in the list diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj index b42d957..c5a1d2e 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -267,6 +267,9 @@ + + Implement C++0x features (variadic templates & rvalue references) +-> Offer bidirectional iterator for hashtables +-> Non-array buckets diff --git a/proj/vc7ide/unordered_set/unordered_set.vcproj b/proj/vc7ide/unordered_set/unordered_set.vcproj index b7e9681..1496175 100644 --- a/proj/vc7ide/unordered_set/unordered_set.vcproj +++ b/proj/vc7ide/unordered_set/unordered_set.vcproj @@ -3,7 +3,7 @@ ProjectType="Visual C++" Version="7.10" Name="unordered_set" - ProjectGUID="{90E701E6-2C91-F4A7-BA6C-A9F3B0949279}" + ProjectGUID="{9101EE76-BB6C-2C91-F4B7-A27B94908F19}" Keyword="Win32Proj"> + UniqueIdentifier="{4F3C77F1-B78A-C745-4726-252AD75C322E}"> diff --git a/test/default_hook_test.cpp b/test/default_hook_test.cpp index 938095f..90f664d 100644 --- a/test/default_hook_test.cpp +++ b/test/default_hook_test.cpp @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include #include "smart_ptr.hpp" #include @@ -28,6 +31,12 @@ class MyClass < void_pointer >, link_mode > , public unordered_set_base_hook < void_pointer >, link_mode > +, public avl_set_base_hook + < void_pointer >, link_mode > +, public splay_set_base_hook + < void_pointer >, link_mode > +, public bs_set_base_hook + < void_pointer >, link_mode > { int int_; @@ -51,6 +60,9 @@ typedef list List; typedef slist Slist; typedef set Set; typedef unordered_set USet; +typedef avl_set AvlSet; +typedef splay_set SplaySet; +typedef sg_set SgSet; int main() { @@ -67,6 +79,9 @@ int main() Slist my_slist; Set my_set; USet my_uset(USet::bucket_traits(buckets, 100)); + AvlSet my_avlset; + SplaySet my_splayset; + SgSet my_sgset; //Now insert them in the reverse order //in the base hook intrusive list @@ -75,6 +90,9 @@ int main() my_slist.push_front(*it); my_set.insert(*it); my_uset.insert(*it); + my_avlset.insert(*it); + my_splayset.insert(*it); + my_sgset.insert(*it); } //Now test lists @@ -82,13 +100,24 @@ int main() List::const_iterator list_it(my_list.cbegin()); Slist::const_iterator slist_it(my_slist.cbegin()); Set::const_reverse_iterator set_rit(my_set.crbegin()); + AvlSet::const_reverse_iterator avl_set_rit(my_avlset.crbegin()); + SplaySet::const_reverse_iterator splay_set_rit(my_splayset.crbegin()); + SgSet::const_reverse_iterator sg_set_rit(my_sgset.crbegin()); + VectRit vect_it(values.rbegin()), vect_itend(values.rend()); //Test the objects inserted in the base hook list - for(; vect_it != vect_itend; ++vect_it, ++list_it, ++slist_it, ++set_rit){ - if(&*list_it != &*vect_it) return 1; - if(&*slist_it != &*vect_it) return 1; - if(&*set_rit != &*vect_it) return 1; + for(; vect_it != vect_itend + ; ++vect_it, ++list_it + , ++slist_it, ++set_rit + , ++avl_set_rit, ++splay_set_rit + , ++sg_set_rit){ + if(&*list_it != &*vect_it) return 1; + if(&*slist_it != &*vect_it) return 1; + if(&*set_rit != &*vect_it) return 1; + if(&*avl_set_rit != &*vect_it) return 1; + if(&*splay_set_rit != &*vect_it)return 1; + if(&*sg_set_rit != &*vect_it) return 1; if(my_uset.find(*set_rit) == my_uset.cend()) return 1; } } diff --git a/test/list_test.cpp b/test/list_test.cpp index 37998be..65cfa8b 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -13,6 +13,7 @@ #include #include + #include #include "itestvalue.hpp" #include "smart_ptr.hpp" @@ -446,13 +447,12 @@ class test_main_template > >::type >::test_all(data); -/* - test_list - , safe_link> - >::test_all(data); -*/ + +// test_list +// , safe_link> +// >::test_all(data); test_list < typename detail::get_base_value_traits < value_type , typename value_type::list_auto_base_hook_t @@ -467,13 +467,13 @@ class test_main_template > >::type >::test_all(data); -/* - test_list - , auto_unlink> - >::test_all(data); -*/ + +// test_list +// , auto_unlink> +// >::test_all(data); + return 0; } }; @@ -488,3 +488,285 @@ int main( int, char* [] ) return boost::report_errors(); } #include + + + + + + + + + + + + + +/* +#include + + +//////////////////////////////////////////////////// +// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will +// be used to "unpack" into comma-separated values +// in a function call. +//////////////////////////////////////////////////// + +template +struct index_tuple{}; + +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + +template +struct typelist +{}; + +template +struct invert_typelist; + +template +struct typelist_element; + +template +struct typelist_element > +{ + typedef typename typelist_element >::type type; +}; + +template +struct typelist_element<0, typelist > +{ + typedef Head type; +}; + +template +typelist >::type...> + inverted_typelist(index_tuple, typelist) +{ + return typelist >::type...>(); +} + + +template +struct sizeof_typelist; + +template +struct sizeof_typelist< typelist > +{ + static const std::size_t value = sizeof...(Types); +}; + +//invert_typelist_impl +template +struct invert_typelist_impl; + + +template +struct invert_typelist_impl< Typelist, index_tuple > +{ + static const std::size_t last_idx = sizeof_typelist::value - 1; + typedef typelist + ::type...> type; +}; + +template +struct invert_typelist_impl< Typelist, index_tuple > +{ + typedef Typelist type; +}; + +template +struct invert_typelist_impl< Typelist, index_tuple<> > +{ + typedef Typelist type; +}; + +//invert_typelist +template +struct invert_typelist; + +template +struct invert_typelist< typelist > +{ + typedef typelist typelist_t; + typedef typename build_number_seq::type indexes_t; + typedef typename invert_typelist_impl::type type; +}; + +struct none +{ + template + struct pack : Base + { }; +}; + +//!This option setter specifies the type of +//!a void pointer. This will instruct the hook +//!to use this type of pointer instead of the +//!default one +template +struct void_pointer +{ +/// @cond + template + struct pack : Base + { + typedef VoidPointer void_pointer; + }; +/// @endcond +}; + +//!This option setter specifies the type of +//!the tag of a base hook. A type cannot have two +//!base hooks of the same type, so a tag can be used +//!to differentiate two base hooks with otherwise same type +template +struct tag +{ +/// @cond + template + struct pack : Base + { + typedef Tag tag; + }; +/// @endcond +}; + + +//!This option setter specifies if the hook +//!should be optimized for size instead of for speed. +template +struct optimize_size +{ +/// @cond + template + struct pack : Base + { + static const bool optimize_size = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the list container should +//!use a linear implementation instead of a circular one. +template +struct linear +{ +/// @cond + template + struct pack : Base + { + static const bool linear = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the list container should +//!use a linear implementation instead of a circular one. +template +struct cache_last +{ +/// @cond + template + struct pack : Base + { + static const bool cache_last = Enabled; + }; +/// @endcond +}; + + + +template +struct do_pack; + +template<> +struct do_pack >; + +template +struct do_pack > +{ + typedef Prev type; +}; + +template +struct do_pack > +{ + typedef typename Prev::template pack type; +}; + +template +struct do_pack > +{ + typedef typename Prev::template pack + >::type> type; +}; + + +template +struct pack_options +{ + typedef typelist typelist_t; + typedef typename invert_typelist::type inverted_typelist; + typedef typename do_pack::type type; +}; + +struct hook_defaults + : public pack_options + < none + , void_pointer + , tag + , optimize_size + , linear + >::type +{}; + + +#include +#include + +struct S +{}; + +int main() +{ + { + typedef typelist typelist_t; + typedef invert_typelist::type inverted_typelist; + std::cout << "original: " << typeid(typelist_t).name() << std::endl; + std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl; + } + { + typedef typelist typelist_t; + typedef invert_typelist::type inverted_typelist; + std::cout << "original: " << typeid(typelist_t).name() << std::endl; + std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl; + } + { + typedef typelist<> typelist_t; + typedef invert_typelist::type inverted_typelist; + std::cout << "original: " << typeid(typelist_t).name() << std::endl; + std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl; + } + { + typedef pack_options::type options_t; + std::cout << "options_t " << typeid(options_t).name() << std::endl; + } + { + typedef pack_options::type options_t; + std::cout << "options_t " << typeid(options_t).name() << std::endl; + } + + hook_defaults h; + return 1; +} +*/ \ No newline at end of file diff --git a/test/set_test.cpp b/test/set_test.cpp index a6b214e..44a0141 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -108,7 +108,6 @@ class test_main_template int main( int, char* [] ) { - test_main_template()(); test_main_template, false>()(); test_main_template()(); diff --git a/test/sg_multiset_test.cpp b/test/sg_multiset_test.cpp index 48f15f4..e5bff6a 100644 --- a/test/sg_multiset_test.cpp +++ b/test/sg_multiset_test.cpp @@ -18,8 +18,18 @@ namespace boost { namespace intrusive { namespace test { +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_rebalance > +#else +template +#endif +struct has_rebalance > { static const bool value = true; }; diff --git a/test/sg_set_test.cpp b/test/sg_set_test.cpp index 9d85e32..df424cc 100644 --- a/test/sg_set_test.cpp +++ b/test/sg_set_test.cpp @@ -17,8 +17,18 @@ namespace boost { namespace intrusive { namespace test { +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_rebalance > +#else +template +#endif +struct has_rebalance > { static const bool value = true; }; diff --git a/test/splay_multiset_test.cpp b/test/splay_multiset_test.cpp index a8601ac..fbccdef 100644 --- a/test/splay_multiset_test.cpp +++ b/test/splay_multiset_test.cpp @@ -19,20 +19,51 @@ namespace boost { namespace intrusive { namespace test { +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_const_overloads > +#else +template +#endif +struct has_const_overloads +> { static const bool value = false; }; +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_splay > +#else +template +#endif +struct has_splay > { static const bool value = true; }; +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_rebalance > +#else +template +#endif +struct has_rebalance > { static const bool value = true; }; diff --git a/test/splay_set_test.cpp b/test/splay_set_test.cpp index b18b4e7..3f61609 100644 --- a/test/splay_set_test.cpp +++ b/test/splay_set_test.cpp @@ -17,20 +17,50 @@ namespace boost { namespace intrusive { namespace test { +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_const_overloads > +#else +template +#endif +struct has_const_overloads > { static const bool value = false; }; +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_splay > +#else +template +#endif +struct has_splay > { static const bool value = true; }; +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_rebalance > +#else +template +#endif +struct has_rebalance > { static const bool value = true; }; diff --git a/test/test_macros.hpp b/test/test_macros.hpp index d612b9f..3a76541 100644 --- a/test/test_macros.hpp +++ b/test/test_macros.hpp @@ -15,10 +15,7 @@ #define TEST_INTRUSIVE_SEQUENCE( INTVALUES, ITERATOR )\ { \ - const int init_values_size = sizeof(INTVALUES)/sizeof(INTVALUES[0]); \ - std::vector expected; \ - expected.assign(&INTVALUES[0], &INTVALUES[0] + init_values_size); \ - BOOST_TEST (std::equal(expected.begin(), expected.end(), ITERATOR) ); \ + BOOST_TEST (std::equal(&INTVALUES[0], &INTVALUES[0] + sizeof(INTVALUES)/sizeof(INTVALUES[0]), ITERATOR) ); \ } #define TEST_INTRUSIVE_SEQUENCE_EXPECTED( EXPECTEDVECTOR, ITERATOR )\ diff --git a/test/unordered_multiset_test.cpp b/test/unordered_multiset_test.cpp index e10efd2..1adab30 100644 --- a/test/unordered_multiset_test.cpp +++ b/test/unordered_multiset_test.cpp @@ -25,9 +25,9 @@ using namespace boost::intrusive; -static const std::size_t BucketSize = 11; +static const std::size_t BucketSize = 8; -template +template struct test_unordered_multiset { typedef typename ValueTraits::value_type value_type; @@ -35,14 +35,16 @@ struct test_unordered_multiset static void test_sort(std::vector& values); static void test_insert(std::vector& values); static void test_swap(std::vector& values); - static void test_rehash(std::vector& values); + static void test_rehash(std::vector& values, detail::true_); + static void test_rehash(std::vector& values, detail::false_); static void test_find(std::vector& values); static void test_impl(); static void test_clone(std::vector& values); }; -template -void test_unordered_multiset::test_all (std::vector& values) +template +void test_unordered_multiset:: + test_all (std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -51,6 +53,7 @@ void test_unordered_multiset::test_all (st , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; { typedef typename unordered_multiset_type::bucket_traits bucket_traits; @@ -71,15 +74,16 @@ void test_unordered_multiset::test_all (st test_sort(values); test_insert(values); test_swap(values); - test_rehash(values); + test_rehash(values, detail::bool_()); test_find(values); test_impl(); test_clone(values); } //test case due to an error in tree implementation: -template -void test_unordered_multiset::test_impl() +template +void test_unordered_multiset + ::test_impl() { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -88,6 +92,7 @@ void test_unordered_multiset::test_impl() , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; @@ -110,8 +115,9 @@ void test_unordered_multiset::test_impl() } //test: constructor, iterator, clear, reverse_iterator, front, back, size: -template -void test_unordered_multiset::test_sort(std::vector& values) +template +void test_unordered_multiset + ::test_sort(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -120,21 +126,29 @@ void test_unordered_multiset::test_sort(st , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; typename unordered_multiset_type::bucket_type buckets [BucketSize]; unordered_multiset_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize)); - { int init_values [] = { 1, 2, 2, 3, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + if(Incremental){ + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + else{ + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } testset1.clear(); BOOST_TEST (testset1.empty()); } - + //test: insert, const_iterator, const_reverse_iterator, erase, iterator_to: -template -void test_unordered_multiset::test_insert(std::vector& values) +template +void test_unordered_multiset + ::test_insert(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -143,54 +157,100 @@ void test_unordered_multiset::test_insert( , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::iterator iterator; - { - typename unordered_multiset_type::bucket_type buckets [BucketSize]; - unordered_multiset_type testset(bucket_traits(buckets, BucketSize)); + typename unordered_multiset_type::bucket_type buckets [BucketSize]; + unordered_multiset_type testset(bucket_traits(buckets, BucketSize)); - testset.insert(&values[0] + 2, &values[0] + 5); + testset.insert(&values[0] + 2, &values[0] + 5); - const unordered_multiset_type& const_testset = testset; - { int init_values [] = { 1, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + const unordered_multiset_type& const_testset = testset; - typename unordered_multiset_type::iterator i = testset.begin(); - BOOST_TEST (i->value_ == 1); + if(Incremental){ + { + { int init_values [] = { 4, 5, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } - i = testset.insert (values[0]); - BOOST_TEST (&*i == &values[0]); - - i = testset.iterator_to (values[2]); - BOOST_TEST (&*i == &values[2]); - testset.erase(i); + typename unordered_multiset_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 4); - { int init_values [] = { 1, 3, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } - testset.clear(); - testset.insert(&values[0], &values[0] + values.size()); + i = testset.insert (values[0]); + BOOST_TEST (&*i == &values[0]); + + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); + testset.erase(i); - { int init_values [] = { 1, 2, 2, 3, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + { int init_values [] = { 5, 1, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + testset.clear(); + testset.insert(&values[0], &values[0] + values.size()); - BOOST_TEST (testset.erase(1) == 1); - BOOST_TEST (testset.erase(2) == 2); - BOOST_TEST (testset.erase(3) == 1); - BOOST_TEST (testset.erase(4) == 1); - BOOST_TEST (testset.erase(5) == 1); - BOOST_TEST (testset.empty() == true); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } - //Now with a single bucket - typename unordered_multiset_type::bucket_type single_bucket[1]; - unordered_multiset_type testset2(bucket_traits(single_bucket, 1)); - testset2.insert(&values[0], &values[0] + values.size()); - BOOST_TEST (testset2.erase(5) == 1); - BOOST_TEST (testset2.erase(2) == 2); - BOOST_TEST (testset2.erase(1) == 1); - BOOST_TEST (testset2.erase(4) == 1); - BOOST_TEST (testset2.erase(3) == 1); - BOOST_TEST (testset2.empty() == true); + BOOST_TEST (testset.erase(1) == 1); + BOOST_TEST (testset.erase(2) == 2); + BOOST_TEST (testset.erase(3) == 1); + BOOST_TEST (testset.erase(4) == 1); + BOOST_TEST (testset.erase(5) == 1); + BOOST_TEST (testset.empty() == true); + + //Now with a single bucket + typename unordered_multiset_type::bucket_type single_bucket[1]; + unordered_multiset_type testset2(bucket_traits(single_bucket, 1)); + testset2.insert(&values[0], &values[0] + values.size()); + BOOST_TEST (testset2.erase(5) == 1); + BOOST_TEST (testset2.erase(2) == 2); + BOOST_TEST (testset2.erase(1) == 1); + BOOST_TEST (testset2.erase(4) == 1); + BOOST_TEST (testset2.erase(3) == 1); + BOOST_TEST (testset2.empty() == true); + } + } + else{ + { + { int init_values [] = { 1, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + + typename unordered_multiset_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 1); + + i = testset.insert (values[0]); + BOOST_TEST (&*i == &values[0]); + + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); + testset.erase(i); + + { int init_values [] = { 1, 3, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + testset.clear(); + testset.insert(&values[0], &values[0] + values.size()); + + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + + BOOST_TEST (testset.erase(1) == 1); + BOOST_TEST (testset.erase(2) == 2); + BOOST_TEST (testset.erase(3) == 1); + BOOST_TEST (testset.erase(4) == 1); + BOOST_TEST (testset.erase(5) == 1); + BOOST_TEST (testset.empty() == true); + + //Now with a single bucket + typename unordered_multiset_type::bucket_type single_bucket[1]; + unordered_multiset_type testset2(bucket_traits(single_bucket, 1)); + testset2.insert(&values[0], &values[0] + values.size()); + BOOST_TEST (testset2.erase(5) == 1); + BOOST_TEST (testset2.erase(2) == 2); + BOOST_TEST (testset2.erase(1) == 1); + BOOST_TEST (testset2.erase(4) == 1); + BOOST_TEST (testset2.erase(3) == 1); + BOOST_TEST (testset2.empty() == true); + } } { //Now erase just one per loop @@ -270,11 +330,12 @@ void test_unordered_multiset::test_insert( } } } -} +} //test: insert (seq-version), swap, erase (seq-version), size: -template -void test_unordered_multiset::test_swap(std::vector& values) +template +void test_unordered_multiset:: + test_swap(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -283,17 +344,30 @@ void test_unordered_multiset::test_swap(st , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; typename unordered_multiset_type::bucket_type buckets [BucketSize]; - { - typename unordered_multiset_type::bucket_type buckets2 [BucketSize]; - unordered_multiset_type testset1(&values[0], &values[0] + 2, bucket_traits(buckets, BucketSize)); - unordered_multiset_type testset2(bucket_traits(buckets2, BucketSize)); - testset2.insert (&values[0] + 2, &values[0] + 6); - testset1.swap (testset2); + typename unordered_multiset_type::bucket_type buckets2 [BucketSize]; + unordered_multiset_type testset1(&values[0], &values[0] + 2, bucket_traits(buckets, BucketSize)); + unordered_multiset_type testset2(bucket_traits(buckets2, BucketSize)); + testset2.insert (&values[0] + 2, &values[0] + 6); + testset1.swap (testset2); + + if(Incremental){ + { int init_values [] = { 4, 5, 1, 2 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + { int init_values [] = { 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset2.begin() ); } + testset1.erase (testset1.iterator_to(values[4]), testset1.end()); + BOOST_TEST (testset1.size() == 1); + // BOOST_TEST (&testset1.front() == &values[3]); + BOOST_TEST (&*testset1.begin() == &values[2]); + } + else{ { int init_values [] = { 1, 2, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } @@ -306,9 +380,13 @@ void test_unordered_multiset::test_swap(st } } + + //test: rehash: -template -void test_unordered_multiset::test_rehash(std::vector& values) + +template +void test_unordered_multiset + ::test_rehash(std::vector& values, detail::true_) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -317,6 +395,135 @@ void test_unordered_multiset::test_rehash( , constant_time_size , cache_begin , compare_hash + , incremental + > unordered_multiset_type; + typedef typename unordered_multiset_type::bucket_traits bucket_traits; + //Build a uset + typename unordered_multiset_type::bucket_type buckets1 [BucketSize]; + typename unordered_multiset_type::bucket_type buckets2 [BucketSize*2]; + unordered_multiset_type testset1(&values[0], &values[0] + values.size(), bucket_traits(buckets1, BucketSize)); + //Test current state + BOOST_TEST(testset1.split_count() == BucketSize/2); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash step + BOOST_TEST (testset1.incremental_rehash() == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2+1)); + { int init_values [] = { 5, 1, 2, 2, 3, 4 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Rest of incremental rehashes should lead to the same sequence + for(std::size_t split_bucket = testset1.split_count(); split_bucket != BucketSize; ++split_bucket){ + BOOST_TEST (testset1.incremental_rehash() == true); + BOOST_TEST(testset1.split_count() == (split_bucket+1)); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + //This incremental rehash should fail because we've reached the end of the bucket array + BOOST_TEST (testset1.incremental_rehash() == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + // + //Try incremental hashing specifying a new bucket traits pointing to the same array + // + //This incremental rehash should fail because the new size is not twice the original + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should success because the new size is twice the original + //and split_count is the same as the old bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize*2)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should also success because the new size is half the original + //and split_count is the same as the new bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + // + //Try incremental hashing specifying a new bucket traits pointing to the same array + // + //This incremental rehash should fail because the new size is not twice the original + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets2, BucketSize)) == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should success because the new size is twice the original + //and split_count is the same as the old bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets2, BucketSize*2)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should also success because the new size is half the original + //and split_count is the same as the new bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //Full shrink rehash + testset1.rehash(bucket_traits(buckets1, 4)); + BOOST_TEST (testset1.size() == values.size()); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Full shrink rehash again + testset1.rehash(bucket_traits(buckets1, 2)); + BOOST_TEST (testset1.size() == values.size()); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 2, 2, 4, 3, 5, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Full growing rehash + testset1.rehash(bucket_traits(buckets1, BucketSize)); + BOOST_TEST (testset1.size() == values.size()); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash shrinking + //First incremental rehashes should lead to the same sequence + for(std::size_t split_bucket = testset1.split_count(); split_bucket > 6; --split_bucket){ + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (split_bucket-1)); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + //Incremental rehash step + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2+1)); + { int init_values [] = { 5, 1, 2, 2, 3, 4 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash step 2 + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2)); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //This incremental rehash should fail because we've reached the half of the bucket array + BOOST_TEST(testset1.incremental_rehash(false) == false); + BOOST_TEST(testset1.split_count() == BucketSize/2); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } +} +template +void test_unordered_multiset + ::test_rehash(std::vector& values, detail::false_) +{ + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size + , cache_begin + , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; @@ -325,36 +532,37 @@ void test_unordered_multiset::test_rehash( typename unordered_multiset_type::bucket_type buckets3 [BucketSize*2]; unordered_multiset_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } testset1.rehash(bucket_traits(buckets2, 2)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 4, 2, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } testset1.rehash(bucket_traits(buckets3, BucketSize*2)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash reducing the buckets testset1.rehash(bucket_traits(buckets3, 2)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 4, 2, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash increasing the buckets testset1.rehash(bucket_traits(buckets3, BucketSize*2)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } } //test: find, equal_range (lower_bound, upper_bound): -template -void test_unordered_multiset::test_find(std::vector& values) +template +void test_unordered_multiset:: + test_find(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -363,6 +571,7 @@ void test_unordered_multiset::test_find(st , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; @@ -387,8 +596,8 @@ void test_unordered_multiset::test_find(st } -template -void test_unordered_multiset +template +void test_unordered_multiset ::test_clone(std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -398,6 +607,7 @@ void test_unordered_multiset , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; { @@ -442,7 +652,7 @@ void test_unordered_multiset unordered_multiset_type testset2 (bucket_traits(buckets2, BucketSize*2)); testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); - //Ordering is not guarantee in the cloning so insert data in a set and test + //Ordering is not guaranteed in the cloning so insert data in a set and test std::multiset src(testset1.begin(), testset1.end()); std::multiset @@ -453,7 +663,7 @@ void test_unordered_multiset } } -template +template class test_main_template { public: @@ -471,6 +681,7 @@ class test_main_template >::type , true , false + , Incremental >::test_all(data); test_unordered_multiset < typename detail::get_member_value_traits @@ -482,14 +693,15 @@ class test_main_template >::type , false , false + , Incremental >::test_all(data); return 0; } }; -template -class test_main_template +template +class test_main_template { public: int operator()() @@ -506,6 +718,7 @@ class test_main_template >::type , true , false + , Incremental >::test_all(data); test_unordered_multiset < typename detail::get_member_value_traits @@ -517,6 +730,7 @@ class test_main_template >::type , false , false + , Incremental >::test_all(data); test_unordered_multiset < typename detail::get_base_value_traits @@ -525,6 +739,7 @@ class test_main_template >::type , true , true + , Incremental >::test_all(data); test_unordered_multiset < typename detail::get_member_value_traits @@ -536,6 +751,7 @@ class test_main_template >::type , false , true + , Incremental >::test_all(data); return 0; } @@ -543,10 +759,14 @@ class test_main_template int main( int, char* [] ) { - test_main_template()(); - test_main_template, false>()(); - test_main_template()(); - test_main_template, true>()(); + test_main_template()(); + test_main_template, false, true>()(); + test_main_template()(); + test_main_template, true, true>()(); + test_main_template()(); + test_main_template, false, false>()(); + test_main_template()(); + test_main_template, true, false>()(); return boost::report_errors(); } diff --git a/test/unordered_set_test.cpp b/test/unordered_set_test.cpp index 7702a2e..8aa27da 100644 --- a/test/unordered_set_test.cpp +++ b/test/unordered_set_test.cpp @@ -24,9 +24,9 @@ using namespace boost::intrusive; -static const std::size_t BucketSize = 11; +static const std::size_t BucketSize = 8; -template +template struct test_unordered_set { typedef typename ValueTraits::value_type value_type; @@ -34,14 +34,16 @@ struct test_unordered_set static void test_sort(std::vector& values); static void test_insert(std::vector& values); static void test_swap(std::vector& values); - static void test_rehash(std::vector& values); + static void test_rehash(std::vector& values, detail::true_); + static void test_rehash(std::vector& values, detail::false_); static void test_find(std::vector& values); static void test_impl(); static void test_clone(std::vector& values); }; -template -void test_unordered_set::test_all(std::vector& values) +template +void test_unordered_set:: + test_all(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -50,6 +52,7 @@ void test_unordered_set::test_all(std::vec , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; { @@ -70,15 +73,15 @@ void test_unordered_set::test_all(std::vec test_sort(values); test_insert(values); test_swap(values); - test_rehash(values); + test_rehash(values, detail::bool_()); test_find(values); test_impl(); test_clone(values); } //test case due to an error in tree implementation: -template -void test_unordered_set::test_impl() +template +void test_unordered_set::test_impl() { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -87,6 +90,7 @@ void test_unordered_set::test_impl() , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -107,8 +111,9 @@ void test_unordered_set::test_impl() } //test: constructor, iterator, clear, reverse_iterator, front, back, size: -template -void test_unordered_set::test_sort(std::vector& values) +template +void test_unordered_set:: + test_sort(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -117,23 +122,31 @@ void test_unordered_set::test_sort(std::ve , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; typename unordered_set_type::bucket_type buckets [BucketSize]; unordered_set_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize)); - BOOST_TEST (5 == std::distance(testset1.begin(), testset1.end())); - { int init_values [] = { 1, 2, 3, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + if(Incremental){ + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + else{ + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } testset1.clear(); BOOST_TEST (testset1.empty()); } //test: insert, const_iterator, const_reverse_iterator, erase, iterator_to: -template -void test_unordered_set::test_insert(std::vector& values) +template +void test_unordered_set:: + test_insert(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -142,6 +155,7 @@ void test_unordered_set::test_insert(std:: , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -150,27 +164,47 @@ void test_unordered_set::test_insert(std:: testset.insert(&values[0] + 2, &values[0] + 5); const unordered_set_type& const_testset = testset; - { int init_values [] = { 1, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + if(Incremental) + { + { int init_values [] = { 4, 5, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + typename unordered_set_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 4); - typename unordered_set_type::iterator i = testset.begin(); - BOOST_TEST (i->value_ == 1); + i = testset.insert(values[0]).first; + BOOST_TEST (&*i == &values[0]); - i = testset.insert(values[0]).first; - BOOST_TEST (&*i == &values[0]); + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); - i = testset.iterator_to (values[2]); - BOOST_TEST (&*i == &values[2]); + testset.erase (i); - testset.erase (i); + { int init_values [] = { 5, 1, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + } + else{ + { int init_values [] = { 1, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + typename unordered_set_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 1); - { int init_values [] = { 1, 3, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + i = testset.insert(values[0]).first; + BOOST_TEST (&*i == &values[0]); + + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); + + testset.erase (i); + + { int init_values [] = { 1, 3, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + } } //test: insert (seq-version), swap, erase (seq-version), size: -template -void test_unordered_set::test_swap(std::vector& values) +template +void test_unordered_set:: + test_swap(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -179,6 +213,7 @@ void test_unordered_set::test_swap(std::ve , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -190,20 +225,30 @@ void test_unordered_set::test_swap(std::ve testset2.insert (&values[0] + 2, &values[0] + 6); testset1.swap (testset2); - { int init_values [] = { 1, 2, 4, 5 }; + if(Incremental){ + { int init_values [] = { 4, 5, 1, 2 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + { int init_values [] = { 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset2.begin() ); } + testset1.erase (testset1.iterator_to(values[4]), testset1.end()); + BOOST_TEST (testset1.size() == 1); + BOOST_TEST (&*testset1.begin() == &values[2]); + } + else{ + { int init_values [] = { 1, 2, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } - { int init_values [] = { 2, 3 }; + { int init_values [] = { 2, 3 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset2.begin() ); } - - testset1.erase (testset1.iterator_to(values[5]), testset1.end()); - BOOST_TEST (testset1.size() == 1); - // BOOST_TEST (&testset1.front() == &values[3]); - BOOST_TEST (&*testset1.begin() == &values[3]); + testset1.erase (testset1.iterator_to(values[5]), testset1.end()); + BOOST_TEST (testset1.size() == 1); + BOOST_TEST (&*testset1.begin() == &values[3]); + } } //test: rehash: -template -void test_unordered_set::test_rehash(std::vector& values) +template +void test_unordered_set:: + test_rehash(std::vector& values, detail::true_) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -212,6 +257,137 @@ void test_unordered_set::test_rehash(std:: , constant_time_size , cache_begin , compare_hash + , incremental + > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; + //Build a uset + typename unordered_set_type::bucket_type buckets1 [BucketSize]; + typename unordered_set_type::bucket_type buckets2 [BucketSize*2]; + unordered_set_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); + //Test current state + BOOST_TEST(testset1.split_count() == BucketSize/2); + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash step + BOOST_TEST (testset1.incremental_rehash() == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2+1)); + { int init_values [] = { 5, 1, 2, 3, 4 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Rest of incremental rehashes should lead to the same sequence + for(std::size_t split_bucket = testset1.split_count(); split_bucket != BucketSize; ++split_bucket){ + BOOST_TEST (testset1.incremental_rehash() == true); + BOOST_TEST(testset1.split_count() == (split_bucket+1)); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + //This incremental rehash should fail because we've reached the end of the bucket array + BOOST_TEST(testset1.incremental_rehash() == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + // + //Try incremental hashing specifying a new bucket traits pointing to the same array + // + //This incremental rehash should fail because the new size is not twice the original + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should success because the new size is twice the original + //and split_count is the same as the old bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize*2)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should also success because the new size is half the original + //and split_count is the same as the new bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + // + //Try incremental hashing specifying a new bucket traits pointing to the same array + // + //This incremental rehash should fail because the new size is not twice the original + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets2, BucketSize)) == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should success because the new size is twice the original + //and split_count is the same as the old bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets2, BucketSize*2)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should also success because the new size is half the original + //and split_count is the same as the new bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //Full shrink rehash + testset1.rehash(bucket_traits(buckets1, 4)); + BOOST_TEST (testset1.size() == values.size()-1); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Full shrink rehash again + testset1.rehash(bucket_traits(buckets1, 2)); + BOOST_TEST (testset1.size() == values.size()-1); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 2, 4, 3, 5, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Full growing rehash + testset1.rehash(bucket_traits(buckets1, BucketSize)); + BOOST_TEST (testset1.size() == values.size()-1); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash shrinking + //First incremental rehashes should lead to the same sequence + for(std::size_t split_bucket = testset1.split_count(); split_bucket > 6; --split_bucket){ + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (split_bucket-1)); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + //Incremental rehash step + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2+1)); + { int init_values [] = { 5, 1, 2, 3, 4 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash step 2 + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2)); + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //This incremental rehash should fail because we've reached the half of the bucket array + BOOST_TEST(testset1.incremental_rehash(false) == false); + BOOST_TEST(testset1.split_count() == BucketSize/2); + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } +} + +//test: rehash: +template +void test_unordered_set:: + test_rehash(std::vector& values, detail::false_) +{ + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size + , cache_begin + , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -220,37 +396,38 @@ void test_unordered_set::test_rehash(std:: typename unordered_set_type::bucket_type buckets3 [BucketSize*2]; unordered_set_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 1, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } testset1.rehash(bucket_traits(buckets2, 2)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 4, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } testset1.rehash(bucket_traits(buckets3, BucketSize*2)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 1, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash reducing the buckets testset1.rehash(bucket_traits(buckets3, 2)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 4, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash increasing the buckets testset1.rehash(bucket_traits(buckets3, BucketSize*2)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 1, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } } //test: find, equal_range (lower_bound, upper_bound): -template -void test_unordered_set::test_find(std::vector& values) +template +void test_unordered_set:: + test_find(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -259,6 +436,7 @@ void test_unordered_set::test_find(std::ve , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -281,8 +459,8 @@ void test_unordered_set::test_find(std::ve BOOST_TEST (testset.find (cmp_val) == testset.end()); } -template -void test_unordered_set +template +void test_unordered_set ::test_clone(std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -292,6 +470,7 @@ void test_unordered_set , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; { @@ -319,7 +498,7 @@ void test_unordered_set unordered_set_type testset2 (bucket_traits(buckets2, BucketSize)); testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); - //Ordering is not guarantee in the cloning so insert data in a set and test + //Ordering is not guaranteed in the cloning so insert data in a set and test std::set src(testset1.begin(), testset1.end()); std::set @@ -347,7 +526,7 @@ void test_unordered_set } } -template +template class test_main_template { public: @@ -365,6 +544,7 @@ class test_main_template >::type , true , false + , incremental >::test_all(data); test_unordered_set < typename detail::get_member_value_traits < value_type @@ -375,14 +555,15 @@ class test_main_template >::type , false , false + , incremental >::test_all(data); return 0; } }; -template -class test_main_template +template +class test_main_template { public: int operator()() @@ -399,6 +580,7 @@ class test_main_template >::type , true , false + , incremental >::test_all(data); test_unordered_set < typename detail::get_member_value_traits @@ -410,6 +592,7 @@ class test_main_template >::type , false , false + , incremental >::test_all(data); test_unordered_set < typename detail::get_base_value_traits @@ -418,6 +601,7 @@ class test_main_template >::type , true , true + , incremental >::test_all(data); test_unordered_set < typename detail::get_member_value_traits @@ -429,6 +613,7 @@ class test_main_template >::type , false , true + , incremental >::test_all(data); return 0; } @@ -436,10 +621,14 @@ class test_main_template int main( int, char* [] ) { - test_main_template()(); - test_main_template, false>()(); - test_main_template()(); - test_main_template, true>()(); + test_main_template()(); + test_main_template, false, true>()(); + test_main_template()(); + test_main_template, true, true>()(); + test_main_template()(); + test_main_template, false, false>()(); + test_main_template()(); + test_main_template, true, false>()(); return boost::report_errors(); } #include From a48a5e0f8e6b959568d3b99b3f2d22b94013b7b5 Mon Sep 17 00:00:00 2001 From: "Michael A. Jackson" Date: Sat, 1 Nov 2008 13:15:41 +0000 Subject: [PATCH 10/14] Continuing merge of CMake build system files into trunk with the encouragement of Doug Gregor [SVN r49510] --- CMakeLists.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..73434d8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,22 @@ +#---------------------------------------------------------------------------- +# This file was automatically generated from the original CMakeLists.txt file +# Add a variable to hold the headers for the library +set (lib_headers + intrusive_ptr.hpp + intrusive +) + +# Add a library target to the build system +boost_library_project( + intrusive + # SRCDIRS + # TESTDIRS + HEADERS ${lib_headers} + # DOCDIRS + # DESCRIPTION + MODULARIZED + # AUTHORS + # MAINTAINERS +) + + From 1dc26850af212fa60c40cd6a001678d490260331 Mon Sep 17 00:00:00 2001 From: "Michael A. Jackson" Date: Fri, 7 Nov 2008 17:05:27 +0000 Subject: [PATCH 11/14] Updating dependency information for modularized libraries. [SVN r49628] --- module.cmake | 1 + 1 file changed, 1 insertion(+) create mode 100644 module.cmake diff --git a/module.cmake b/module.cmake new file mode 100644 index 0000000..edc114f --- /dev/null +++ b/module.cmake @@ -0,0 +1 @@ +boost_module(intrusive DEPENDS utility) \ No newline at end of file From 4b272cf3c784e39167f307b88da45746a982357a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 13 Dec 2008 13:49:31 +0000 Subject: [PATCH 12/14] * New treap-based containers: treap, treap_set, treap_multiset. * Corrected compilation bug for Windows-based 64 bit compilers. * Corrected exception-safety bugs in container constructors. * Updated documentation to show rvalue-references funcions instead of emulation functions. [SVN r50259] --- doc/Jamfile.v2 | 5 +- doc/intrusive.qbk | 232 ++++++++++- example/doc_advanced_value_traits.cpp | 2 +- example/doc_advanced_value_traits2.cpp | 2 +- example/doc_assoc_optimized_code.cpp | 2 +- example/doc_auto_unlink.cpp | 2 +- example/doc_avl_set.cpp | 2 +- example/doc_avltree_algorithms.cpp | 4 +- example/doc_bucket_traits.cpp | 2 +- example/doc_clone_from.cpp | 2 +- example/doc_entity.cpp | 2 +- example/doc_erasing_and_disposing.cpp | 2 +- example/doc_external_value_traits.cpp | 2 +- example/doc_how_to_use.cpp | 2 +- example/doc_iterator_from_value.cpp | 2 +- example/doc_list.cpp | 2 +- example/doc_list_algorithms.cpp | 2 +- example/doc_offset_ptr.cpp | 2 +- example/doc_rbtree_algorithms.cpp | 4 +- example/doc_set.cpp | 2 +- example/doc_sg_set.cpp | 2 +- example/doc_slist.cpp | 2 +- example/doc_slist_algorithms.cpp | 2 +- example/doc_splay_algorithms.cpp | 4 +- example/doc_splay_set.cpp | 2 +- example/doc_splaytree_algorithms.cpp | 4 +- example/doc_stateful_value_traits.cpp | 2 +- example/doc_treap_algorithms.cpp | 79 ++++ example/doc_treap_set.cpp | 106 +++++ example/doc_unordered_set.cpp | 2 +- example/doc_value_traits.cpp | 2 +- example/doc_window.cpp | 2 +- perf/perf_list.cpp | 5 +- proj/vc7ide/Intrusive.sln | 16 + .../vc7ide/_intrusivelib/_intrusivelib.vcproj | 18 + proj/vc7ide/to-do.txt | 23 ++ .../treap_multiset/treap_multiset.vcproj | 127 ++++++ proj/vc7ide/treap_set/treap_set.vcproj | 127 ++++++ test/any_test.cpp | 15 +- test/avl_multiset_test.cpp | 44 ++- test/avl_set_test.cpp | 44 ++- test/common_functors.hpp | 2 +- test/custom_bucket_traits_test.cpp | 2 +- test/default_hook_test.cpp | 2 +- test/external_value_traits_test.cpp | 2 +- test/generic_assoc_test.hpp | 27 +- test/generic_multiset_test.hpp | 2 +- test/generic_set_test.hpp | 2 +- test/itestvalue.hpp | 367 ++---------------- test/list_test.cpp | 319 ++------------- test/make_functions_test.cpp | 88 ++++- test/multiset_test.cpp | 44 ++- test/set_test.cpp | 44 ++- test/sg_multiset_test.cpp | 32 +- test/sg_set_test.cpp | 30 +- test/slist_test.cpp | 73 ++-- test/splay_multiset_test.cpp | 42 +- test/splay_set_test.cpp | 40 +- test/stateful_value_traits_test.cpp | 2 +- test/test_container.hpp | 2 +- test/test_macros.hpp | 2 +- test/treap_multiset_test.cpp | 135 +++++++ test/treap_set_test.cpp | 134 +++++++ test/unordered_multiset_test.cpp | 52 ++- test/unordered_set_test.cpp | 52 ++- test/virtual_base_test.cpp | 2 +- 66 files changed, 1580 insertions(+), 824 deletions(-) create mode 100644 example/doc_treap_algorithms.cpp create mode 100644 example/doc_treap_set.cpp create mode 100644 proj/vc7ide/treap_multiset/treap_multiset.vcproj create mode 100644 proj/vc7ide/treap_set/treap_set.vcproj create mode 100644 test/treap_multiset_test.cpp create mode 100644 test/treap_set_test.cpp diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 9cac616..f00fe39 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -38,7 +38,10 @@ doxygen autodoc "sgtree_impl=sgtree" \\ "avl_set_impl=avl_set" \\ "avl_multiset_impl=avl_multiset" \\ - "avltree_impl=avltree"" + "avltree_impl=avltree" \\ + "treap_set_impl=treap_set" \\ + "treap_multiset_impl=treap_multiset" \\ + "treap_impl=treap"" ; xml intrusive : intrusive.qbk ; diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index b80d17e..eb9df46 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -8,7 +8,7 @@ [library Boost.Intrusive [quickbook 1.3] [authors [Krzikalla, Olaf], [Gaztañaga, Ion]] - [copyright 2005 Olaf Krzikalla, 2006-2007 Ion Gaztañaga] + [copyright 2005 Olaf Krzikalla, 2006-2008 Ion Gaztañaga] [id intrusive] [dirname intrusive] [purpose Intrusive containers] @@ -1693,7 +1693,7 @@ has also the size of 3 pointers, two integers and two floating point values [classref boost::intrusive::sgtree sgtree] don't use their own hooks but plain binary search tree hooks. This has many advantages since binary search tree hooks can also be used to insert values in -splay containers. +splay and treap containers. [c++] @@ -1716,8 +1716,7 @@ splay containers. [classref boost::intrusive::bs_set_base_hook bs_set_base_hook] and [classref boost::intrusive::bs_set_member_hook bs_set_member_hook] receive the same options explained in the section -[link intrusive.usage How to use Boost.Intrusive] plus an option to optimize -the size of the node: +[link intrusive.usage How to use Boost.Intrusive]: * [*`tag`] (for base hooks only): This argument serves as a tag, so you can derive from more than one base hook. @@ -1786,22 +1785,180 @@ containers: [endsect] +[section:treap_set_multiset Intrusive treap based associative containers: treap_set, treap_multiset and treap] +The name ['treap] is a mixture of ['tree] and ['heap] indicating that Treaps exhibit the properties of both +binary search trees and heaps. A treap is a binary search tree that orders the nodes +by a key but also by a priority attribute. The nodes are ordered so that the keys form a binary search tree and +the priorities obey the max heap order property. +* If v is a left descendant of u, then key[v] < key[u]; +* If v is a right descendant of u, then key[v] > key[u]; +* If v is a child of u, then priority[v] <= priority[u]; +If priorities are non-random, the tree will usually be unbalanced; this worse theoretical average-case +behavior may be outweighed by better expected-case behavior, as the most important items will be near the root. +This means most important objects will be retrieved faster than less important items and for items keys with equal keys +most important objects will be found first. These properties are important for some applications. +The priority comparison will be provided just like the key comparison, via a funcion object that will be +stored in the intrusive container. This means that the priority can be stored in the value to be introduced +in the treap or computed on flight (via hashing or similar). +[*Boost.Intrusive] offers 3 containers based on treaps: +[classref boost::intrusive::treap_set treap_set], +[classref boost::intrusive::treap_multiset treap_multiset] and +[classref boost::intrusive::treap treap]. The first two are similar to +[classref boost::intrusive::set set] or +[classref boost::intrusive::multiset multiset] and the latter is a generalization +that offers functions both to insert unique and multiple keys. +The memory overhead of these containers with Boost.Intrusive hooks is 3 +pointers. +An empty, [classref boost::intrusive::treap_set treap_set], +[classref boost::intrusive::treap_multiset treap_multiset] or +[classref boost::intrusive::treap treap] +has also the size of 3 pointers and an integer (supposing empty function objects for key and priority +comparison and constant-time size). +[section:treap_set_multiset_hooks Using binary search tree hooks: bs_set_base_hook and bs_set_member_hook] +[classref boost::intrusive::treap_set treap_set], +[classref boost::intrusive::treap_multiset treap_multiset] and +[classref boost::intrusive::treap treap] don't use their +own hooks but plain binary search tree hooks. This has many advantages +since binary search tree hooks can also be used to insert values in +splay containers and scapegoat trees. +[c++] + template + class bs_set_base_hook; +* [classref boost::intrusive::bs_set_base_hook bs_set_base_hook]: + the user class derives publicly from this class to make + it compatible with scapegoat tree based containers. +[c++] + template + class bs_set_member_hook; +* [classref boost::intrusive::set_member_hook set_member_hook]: + the user class contains a public member of this class to make + it compatible with scapegoat tree based containers. +[classref boost::intrusive::bs_set_base_hook bs_set_base_hook] and +[classref boost::intrusive::bs_set_member_hook bs_set_member_hook] receive +the same options explained in the section +[link intrusive.usage How to use Boost.Intrusive]: + +* [*`tag`] (for base hooks only): This argument serves as a tag, + so you can derive from more than one base hook. + Default: `tag`. + +* [*`link_mode`]: The linking policy. + Default: `link_mode`. + +* [*`void_pointer`]: The pointer type to be used + internally in the hook and propagated to the container. + Default: `void_pointer`. + +[endsect] + +[section:treap_set_multiset_containers treap_set, treap_multiset and treap containers] + +[c++] + + template + class treap_set; + + template + class treap_multiset; + + template + class treap; + +These containers receive the same options explained in the section +[link intrusive.usage How to use Boost.Intrusive]: + +* [*`base_hook`] / [*`member_hook`] / + [*`value_traits`]: To specify the hook type or value traits used + to configure the container. (To learn about value traits go to the section + [link intrusive.value_traits Containers with custom ValueTraits].) + +* [*`constant_time_size`]: To activate the constant-time `size()` operation. + Default: `constant_time_size` + +* [*`size_type`]: To specify the type that will be used to store the size + of the container. Default: `size_type` + +And they also can receive additional options: + +* [*`compare`]: Comparison function for the objects to be inserted + in containers. The comparison functor must induce a strict weak ordering. + Default: `compare< std::less >` + +* [*`priority`]: Priority Comparison function for the objects to be inserted + in containers. The comparison functor must induce a strict weak ordering. + Default: `priority< priority_compare >` + +The default `priority_compare` object function will call an unqualified function `priority_order` +passing two constant `T` references as arguments and should return true if the first argument has +higher priority (it will be searched faster), inducing strict weak ordering. +The function will be found using ADL lookup so that +the user just needs to define a `priority_order` function in the same namespace as his class: + +[c++] + + struct MyType + { + friend bool priority_order(const MyType &a, const MyType &b) + {...} + }; + +or + + namespace mytype { + + struct MyType{ ... }; + + bool priority_order(const MyType &a, const MyType &b) + {...} + + } //namespace mytype { + +[endsect] + +[section:treap_set_exceptions Exception safety of treap-based intrusive containers] + +In general, intrusive containers offer strong safety guarantees, but treap containers must deal +with two possibly throwing functors (one for value ordering, another for priority ordering). +Moreover, treap erasure operations require rotations based on the priority order function and +this issue degrades usual `erase(const_iterator)` no-throw guarantee. However, intrusive offers +the strongest possible behaviour in these situations. In summary: + +* If the priority order functor does not throw, treap-based containers, offer exactly the same + guarantees as other tree-based containers. + +* If the priority order functor throws, treap-based containers offer strong guarantee. + +[endsect] + +[section:treap_set_multiset_example Example] + +Now let's see a small example using both hooks and +[classref boost::intrusive::treap_set treap_set]/ +[classref boost::intrusive::treap_multiset treap_multiset] +containers: + +[import ../example/doc_treap_set.cpp] +[doc_treap_set_code] + +[endsect] + +[endsect] [section:advanced_lookups_insertions Advanced lookup and insertion functions for associative containers] @@ -2643,6 +2800,62 @@ For a complete list of functions see [endsect] + +[section:treap_algorithms Intrusive treap algorithms] + +[classref boost::intrusive::treap_algorithms treap_algorithms] have the same +interface as [classref boost::intrusive::rbtree_algorithms rbtree_algorithms]. + +[c++] + + template + struct treap_algorithms; + +[classref boost::intrusive::treap_algorithms treap_algorithms] +is configured with a NodeTraits class, which encapsulates +the information about the node to be manipulated. NodeTraits must support the +following interface: + +[*Typedefs]: + +* `node`: The type of the node that forms the circular treap + +* `node_ptr`: The type of a pointer to a node (usually node*) + +* `const_node_ptr`: The type of a pointer to a const node (usually const node*) + +[*Static functions]: + +* `static node_ptr get_parent(const_node_ptr n);`: + Returns a pointer to the parent node stored in "n". + +* `static void set_parent(node_ptr n, node_ptr p);`: + Sets the pointer to the parent node stored in "n" to "p". + +* `static node_ptr get_left(const_node_ptr n);`: + Returns a pointer to the left node stored in "n". + +* `static void set_left(node_ptr n, node_ptr l);`: + Sets the pointer to the left node stored in "n" to "l". + +* `static node_ptr get_right(const_node_ptr n);`: + Returns a pointer to the right node stored in "n". + +* `static void set_right(node_ptr n, node_ptr r);`: + Sets the pointer to the right node stored in "n" to "r". + +Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms +with our nodes: + +[import ../example/doc_treap_algorithms.cpp] +[doc_treap_algorithms_code] + +For a complete list of functions see +[classref boost::intrusive::treap_algorithms treap_algorithms reference]. + +[endsect] + + [/ / /[section:sgtree_algorithms Intrusive sg tree algorithms] @@ -3488,6 +3701,15 @@ all the objects to be inserted in intrusive containers in containers like `std:: [section:release_notes Release Notes] +[section:release_notes_boost_1_38_00 Boost 1.38 Release] + +* New treap-based containers: treap, treap_set, treap_multiset. +* Corrected compilation bug for Windows-based 64 bit compilers. +* Corrected exception-safety bugs in container constructors. +* Updated documentation to show rvalue-references funcions instead of emulation functions. + +[endsect] + [section:release_notes_boost_1_37_00 Boost 1.37 Release] * Intrusive now takes advantage of compilers with variadic templates. @@ -3577,7 +3799,7 @@ helpful discussions. [endsect] -[xinclude autodoc.xml] +[/xinclude autodoc.xml] [section:license_notices License notices] diff --git a/example/doc_advanced_value_traits.cpp b/example/doc_advanced_value_traits.cpp index f4caafb..dca6585 100644 --- a/example/doc_advanced_value_traits.cpp +++ b/example/doc_advanced_value_traits.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_advanced_value_traits2.cpp b/example/doc_advanced_value_traits2.cpp index 6367af0..ec9214e 100644 --- a/example/doc_advanced_value_traits2.cpp +++ b/example/doc_advanced_value_traits2.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_assoc_optimized_code.cpp b/example/doc_assoc_optimized_code.cpp index 8af780c..7b86a70 100644 --- a/example/doc_assoc_optimized_code.cpp +++ b/example/doc_assoc_optimized_code.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_auto_unlink.cpp b/example/doc_auto_unlink.cpp index 848b973..208fc6f 100644 --- a/example/doc_auto_unlink.cpp +++ b/example/doc_auto_unlink.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_avl_set.cpp b/example/doc_avl_set.cpp index 33a061c..32d339b 100644 --- a/example/doc_avl_set.cpp +++ b/example/doc_avl_set.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_avltree_algorithms.cpp b/example/doc_avltree_algorithms.cpp index 9aa47b2..ee2655c 100644 --- a/example/doc_avltree_algorithms.cpp +++ b/example/doc_avltree_algorithms.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -47,7 +47,7 @@ struct my_avltree_node_traits struct node_ptr_compare { - bool operator()(my_node *a, my_node *b) + bool operator()(const my_node *a, const my_node *b) { return a->int_ < b->int_; } }; diff --git a/example/doc_bucket_traits.cpp b/example/doc_bucket_traits.cpp index c03c125..7663bf4 100644 --- a/example/doc_bucket_traits.cpp +++ b/example/doc_bucket_traits.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_clone_from.cpp b/example/doc_clone_from.cpp index 94c0668..ae3d8c9 100644 --- a/example/doc_clone_from.cpp +++ b/example/doc_clone_from.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_entity.cpp b/example/doc_entity.cpp index 0e2fc54..70b109f 100644 --- a/example/doc_entity.cpp +++ b/example/doc_entity.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_erasing_and_disposing.cpp b/example/doc_erasing_and_disposing.cpp index 51d737f..cf0062d 100644 --- a/example/doc_erasing_and_disposing.cpp +++ b/example/doc_erasing_and_disposing.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_external_value_traits.cpp b/example/doc_external_value_traits.cpp index 80d366e..b53817c 100644 --- a/example/doc_external_value_traits.cpp +++ b/example/doc_external_value_traits.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_how_to_use.cpp b/example/doc_how_to_use.cpp index 8284bd0..2951096 100644 --- a/example/doc_how_to_use.cpp +++ b/example/doc_how_to_use.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_iterator_from_value.cpp b/example/doc_iterator_from_value.cpp index b212a49..875db31 100644 --- a/example/doc_iterator_from_value.cpp +++ b/example/doc_iterator_from_value.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_list.cpp b/example/doc_list.cpp index 7137fcc..a4ffcee 100644 --- a/example/doc_list.cpp +++ b/example/doc_list.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_list_algorithms.cpp b/example/doc_list_algorithms.cpp index 7b4fc89..c5ef4b4 100644 --- a/example/doc_list_algorithms.cpp +++ b/example/doc_list_algorithms.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_offset_ptr.cpp b/example/doc_offset_ptr.cpp index 1d7e87e..9b88708 100644 --- a/example/doc_offset_ptr.cpp +++ b/example/doc_offset_ptr.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_rbtree_algorithms.cpp b/example/doc_rbtree_algorithms.cpp index 6eb25fb..0843365 100644 --- a/example/doc_rbtree_algorithms.cpp +++ b/example/doc_rbtree_algorithms.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -45,7 +45,7 @@ struct my_rbtree_node_traits struct node_ptr_compare { - bool operator()(my_node *a, my_node *b) + bool operator()(const my_node *a, const my_node *b) { return a->int_ < b->int_; } }; diff --git a/example/doc_set.cpp b/example/doc_set.cpp index d9d5d47..c996038 100644 --- a/example/doc_set.cpp +++ b/example/doc_set.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_sg_set.cpp b/example/doc_sg_set.cpp index 2c6eec5..aa33258 100644 --- a/example/doc_sg_set.cpp +++ b/example/doc_sg_set.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_slist.cpp b/example/doc_slist.cpp index f8164bd..42220b9 100644 --- a/example/doc_slist.cpp +++ b/example/doc_slist.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_slist_algorithms.cpp b/example/doc_slist_algorithms.cpp index d89b678..7e7f155 100644 --- a/example/doc_slist_algorithms.cpp +++ b/example/doc_slist_algorithms.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_splay_algorithms.cpp b/example/doc_splay_algorithms.cpp index 80797db..f90a7e2 100644 --- a/example/doc_splay_algorithms.cpp +++ b/example/doc_splay_algorithms.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -41,7 +41,7 @@ struct my_splaytree_node_traits struct node_ptr_compare { - bool operator()(my_node *a, my_node *b) + bool operator()(const my_node *a, const my_node *b) { return a->int_ < b->int_; } }; diff --git a/example/doc_splay_set.cpp b/example/doc_splay_set.cpp index b82f48a..8859165 100644 --- a/example/doc_splay_set.cpp +++ b/example/doc_splay_set.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_splaytree_algorithms.cpp b/example/doc_splaytree_algorithms.cpp index f6c7f6f..aeafaae 100644 --- a/example/doc_splaytree_algorithms.cpp +++ b/example/doc_splaytree_algorithms.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -40,7 +40,7 @@ struct my_splaytree_node_traits struct node_ptr_compare { - bool operator()(my_node *a, my_node *b) + bool operator()(const my_node *a, const my_node *b) { return a->int_ < b->int_; } }; diff --git a/example/doc_stateful_value_traits.cpp b/example/doc_stateful_value_traits.cpp index 96d16f3..4712387 100644 --- a/example/doc_stateful_value_traits.cpp +++ b/example/doc_stateful_value_traits.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_treap_algorithms.cpp b/example/doc_treap_algorithms.cpp new file mode 100644 index 0000000..773aa69 --- /dev/null +++ b/example/doc_treap_algorithms.cpp @@ -0,0 +1,79 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2008 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +//[doc_treap_algorithms_code +#include +#include + +struct my_node +{ + my_node(int i = 0, unsigned int priority = 0) + : prio_(priority), int_(i) + {} + my_node *parent_, *left_, *right_; + int prio_; + //other members + int int_; +}; + +//Define our own treap_node_traits +struct my_treap_node_traits +{ + typedef my_node node; + typedef my_node * node_ptr; + typedef const my_node * const_node_ptr; + + static node_ptr get_parent(const_node_ptr n) { return n->parent_; } + static void set_parent(node_ptr n, node_ptr parent){ n->parent_ = parent; } + static node_ptr get_left(const_node_ptr n) { return n->left_; } + static void set_left(node_ptr n, node_ptr left) { n->left_ = left; } + static node_ptr get_right(const_node_ptr n) { return n->right_; } + static void set_right(node_ptr n, node_ptr right) { n->right_ = right; } +}; + +struct node_ptr_compare +{ bool operator()(const my_node *a, const my_node *b) { return a->int_ < b->int_; } }; + +struct node_ptr_priority +{ bool operator()(const my_node *a, const my_node *b) { return a->prio_ < b->prio_;} }; + +int main() +{ + typedef boost::intrusive::treap_algorithms algo; + my_node header, two(2, 5), three(3, 1); + + //Create an empty treap container: + //"header" will be the header node of the tree + algo::init_header(&header); + + //Now insert node "two" in the tree using the sorting functor + algo::insert_equal_upper_bound(&header, &two, node_ptr_compare(), node_ptr_priority()); + + //Now insert node "three" in the tree using the sorting functor + algo::insert_equal_lower_bound(&header, &three, node_ptr_compare(), node_ptr_priority()); + + //Now take the first node (the left node of the header) + my_node *n = header.left_; + assert(n == &two); + + //Now go to the next node + n = algo::next_node(n); + assert(n == &three); + + //Erase a node just using a pointer to it + algo::unlink(&two, node_ptr_priority()); + + //Erase a node using also the header (faster) + algo::erase(&header, &three, node_ptr_priority()); + return 0; +} + +//] diff --git a/example/doc_treap_set.cpp b/example/doc_treap_set.cpp new file mode 100644 index 0000000..7ae4fec --- /dev/null +++ b/example/doc_treap_set.cpp @@ -0,0 +1,106 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2008 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +//[doc_treap_set_code +#include +#include +#include +#include + +using namespace boost::intrusive; + +class MyClass : public bs_set_base_hook<> //This is a base hook +{ + int int_; + unsigned int prio_; + + public: + //This is a member hook + bs_set_member_hook<> member_hook_; + + MyClass(int i, unsigned int prio) : int_(i), prio_(prio) + {} + + unsigned int get_priority() const + { return this->prio_; } + + //Less and greater operators + friend bool operator< (const MyClass &a, const MyClass &b) + { return a.int_ < b.int_; } + friend bool operator> (const MyClass &a, const MyClass &b) + { return a.int_ > b.int_; } + //Default priority compare + friend bool priority_order (const MyClass &a, const MyClass &b) + { return a.prio_ < b.prio_; } //Lower value means higher priority + //Inverse priority compare + friend bool priority_inverse_order (const MyClass &a, const MyClass &b) + { return a.prio_ > b.prio_; } //Higher value means higher priority +}; + +struct inverse_priority +{ + bool operator()(const MyClass &a, const MyClass &b) const + { return priority_inverse_order(a, b); } +}; + + +//Define an treap_set using the base hook that will store values in reverse order +typedef treap_set< MyClass, compare > > BaseSet; + +//Define an multiset using the member hook that will store +typedef member_hook, &MyClass::member_hook_> MemberOption; +typedef treap_multiset + < MyClass, MemberOption, priority > MemberMultiset; + +int main() +{ + typedef std::vector::iterator VectIt; + + //Create several MyClass objects, each one with a different value + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i, (i % 10))); + + BaseSet baseset; + MemberMultiset membermultiset; + + //Now insert them in the sets + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){ + baseset.insert(*it); + membermultiset.insert(*it); + } + + //Now test treap_sets + { + BaseSet::reverse_iterator rbit(baseset.rbegin()), rbitend(baseset.rend()); + MemberMultiset::iterator mit(membermultiset.begin()), mitend(membermultiset.end()); + VectIt it(values.begin()), itend(values.end()); + + //Test the objects inserted in the base hook treap_set + for(; it != itend; ++it, ++rbit) + if(&*rbit != &*it) return 1; + + //Test the objects inserted in the member hook treap_set + for(it = values.begin(); it != itend; ++it, ++mit) + if(&*mit != &*it) return 1; + + //Test priority order + for(int i = 0; i < 100; ++i){ + if(baseset.top()->get_priority() != static_cast(i/10)) + return 1; + if(membermultiset.top()->get_priority() != 9u - static_cast(i/10)) + return 1; + baseset.erase(baseset.top()); + membermultiset.erase(membermultiset.top()); + } + } + return 0; +} +//] diff --git a/example/doc_unordered_set.cpp b/example/doc_unordered_set.cpp index 531ef10..a007919 100644 --- a/example/doc_unordered_set.cpp +++ b/example/doc_unordered_set.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_value_traits.cpp b/example/doc_value_traits.cpp index e50e23b..f9bb897 100644 --- a/example/doc_value_traits.cpp +++ b/example/doc_value_traits.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/example/doc_window.cpp b/example/doc_window.cpp index 7a0e12d..f00f43b 100644 --- a/example/doc_window.cpp +++ b/example/doc_window.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/perf/perf_list.cpp b/perf/perf_list.cpp index 5bf8012..ef73947 100644 --- a/perf/perf_list.cpp +++ b/perf/perf_list.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -11,6 +11,7 @@ ///////////////////////////////////////////////////////////////////////////// //Includes for tests +#include #include #include #include @@ -545,3 +546,5 @@ int main() do_all_tests(); return 0; } + +#include diff --git a/proj/vc7ide/Intrusive.sln b/proj/vc7ide/Intrusive.sln index 0b105c0..4726fdc 100644 --- a/proj/vc7ide/Intrusive.sln +++ b/proj/vc7ide/Intrusive.sln @@ -83,6 +83,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "any_hook", "any_test\any_te ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "treap_set", "treap_set\treap_set.vcproj", "{1E09E697-4A2F-BC76-7C91-2BA479B29159}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "treap_multiset", "treap_multiset\treap_multiset.vcproj", "{16E09E95-F4A2-C971-BC76-9BA407191C59}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -175,6 +183,14 @@ Global {97B61B24-4C97-9681-50BF-243175A813B6}.Debug.Build.0 = Debug|Win32 {97B61B24-4C97-9681-50BF-243175A813B6}.Release.ActiveCfg = Release|Win32 {97B61B24-4C97-9681-50BF-243175A813B6}.Release.Build.0 = Release|Win32 + {1E09E697-4A2F-BC76-7C91-2BA479B29159}.Debug.ActiveCfg = Debug|Win32 + {1E09E697-4A2F-BC76-7C91-2BA479B29159}.Debug.Build.0 = Debug|Win32 + {1E09E697-4A2F-BC76-7C91-2BA479B29159}.Release.ActiveCfg = Release|Win32 + {1E09E697-4A2F-BC76-7C91-2BA479B29159}.Release.Build.0 = Release|Win32 + {16E09E95-F4A2-C971-BC76-9BA407191C59}.Debug.ActiveCfg = Debug|Win32 + {16E09E95-F4A2-C971-BC76-9BA407191C59}.Debug.Build.0 = Debug|Win32 + {16E09E95-F4A2-C971-BC76-9BA407191C59}.Release.ActiveCfg = Release|Win32 + {16E09E95-F4A2-C971-BC76-9BA407191C59}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj index c5a1d2e..abe74de 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -198,6 +198,15 @@ + + + + + + @@ -219,6 +228,9 @@ + + @@ -397,6 +409,12 @@ + + + + diff --git a/proj/vc7ide/to-do.txt b/proj/vc7ide/to-do.txt index 1874bf6..f62414d 100644 --- a/proj/vc7ide/to-do.txt +++ b/proj/vc7ide/to-do.txt @@ -1,3 +1,26 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2008 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// -> Implement C++0x features (variadic templates & rvalue references) -> Offer bidirectional iterator for hashtables -> Non-array buckets +-> Document incremental<> option better + +-> Revise treap's hooks should be restored if the operation throws +-> Revise treap help to add priority changes (throw, new functions, etc.) +-> Revise make_functions, and any hook tests to add missing containers +-> On exceptions, auto_unlink/safe_link hooks default state should be recovered + (insert_equal, insert_lower_bound, insert_equal_upper_bound) +-> insert_unique_check should also compare priorities. +-> test insert_unique_check with hint in tests +-> revise strong exception safety concepts for treap::erase functions. + What happens with range deletions? +-> Assure stable order for optimize_multikey and inverse order otherwise diff --git a/proj/vc7ide/treap_multiset/treap_multiset.vcproj b/proj/vc7ide/treap_multiset/treap_multiset.vcproj new file mode 100644 index 0000000..b0b1edd --- /dev/null +++ b/proj/vc7ide/treap_multiset/treap_multiset.vcproj @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/treap_set/treap_set.vcproj b/proj/vc7ide/treap_set/treap_set.vcproj new file mode 100644 index 0000000..a6d68a3 --- /dev/null +++ b/proj/vc7ide/treap_set/treap_set.vcproj @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/any_test.cpp b/test/any_test.cpp index 9c24c56..bd2c955 100644 --- a/test/any_test.cpp +++ b/test/any_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include //std::vector @@ -48,8 +49,12 @@ class MyClass : public any_base_hook<> friend std::size_t hash_value(const MyClass &o) { return boost::hash()(o.get()); } + + friend bool priority_order(const MyClass &a, const MyClass &b) + { return a.int_ < b.int_; } }; + void instantiation_test() { typedef member_hook< MyClass, any_member_hook<>, &MyClass::member_hook_> MemberHook; @@ -96,6 +101,14 @@ void instantiation_test() sgtree < MyClass, any_to_bs_set_hook< MemberHook > > sgtree_member; sgtree_member.insert_unique(myclass); } + { + treap < MyClass, any_to_bs_set_hook< BaseHook > > treap_base; + treap_base.insert_unique(myclass); + } + { + treap < MyClass, any_to_bs_set_hook< MemberHook > > treap_member; + treap_member.insert_unique(myclass); + } { splaytree < MyClass, any_to_bs_set_hook< BaseHook > > splaytree_base; splaytree_base.insert_unique(myclass); diff --git a/test/avl_multiset_test.cpp b/test/avl_multiset_test.cpp index dcaf774..bc8c7eb 100644 --- a/test/avl_multiset_test.cpp +++ b/test/avl_multiset_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -17,6 +17,26 @@ #include "smart_ptr.hpp" #include "generic_multiset_test.hpp" +using namespace boost::intrusive; + +struct my_tag; + +template +struct hooks +{ + typedef avl_set_base_hook > base_hook_type; + typedef avl_set_base_hook + + , void_pointer + , tag + , optimize_size > auto_base_hook_type; + typedef avl_set_member_hook + > member_hook_type; + typedef avl_set_member_hook + < link_mode + , void_pointer > auto_member_hook_type; +}; + template< class ValueType , class Option1 = boost::intrusive::none , class Option2 = boost::intrusive::none @@ -39,19 +59,19 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , constant_time_size> value_type; test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::avl_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::avl_set_member_hook_t - , &value_type::avl_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -67,11 +87,11 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , false> value_type; test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::avl_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); @@ -79,8 +99,8 @@ class test_main_template test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::avl_set_member_hook_t - , &value_type::avl_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -88,7 +108,7 @@ class test_main_template test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::avl_set_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type , GetContainer >::test_all(); @@ -96,8 +116,8 @@ class test_main_template test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::avl_set_auto_member_hook_t - , &value_type::avl_set_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type , GetContainer diff --git a/test/avl_set_test.cpp b/test/avl_set_test.cpp index d53b56e..55e415c 100644 --- a/test/avl_set_test.cpp +++ b/test/avl_set_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -16,6 +16,26 @@ #include "smart_ptr.hpp" #include "generic_set_test.hpp" +using namespace boost::intrusive; + +struct my_tag; + +template +struct hooks +{ + typedef avl_set_base_hook > base_hook_type; + typedef avl_set_base_hook + + , void_pointer + , tag + , optimize_size > auto_base_hook_type; + typedef avl_set_member_hook + > member_hook_type; + typedef avl_set_member_hook + < link_mode + , void_pointer > auto_member_hook_type; +}; + template< class ValueType , class Option1 = boost::intrusive::none , class Option2 = boost::intrusive::none @@ -38,19 +58,19 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , constant_time_size> value_type; test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::avl_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::avl_set_member_hook_t - , &value_type::avl_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -66,11 +86,11 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , false> value_type; test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::avl_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); @@ -78,8 +98,8 @@ class test_main_template test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::avl_set_member_hook_t - , &value_type::avl_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -87,7 +107,7 @@ class test_main_template test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::avl_set_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type , GetContainer >::test_all(); @@ -95,8 +115,8 @@ class test_main_template test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::avl_set_auto_member_hook_t - , &value_type::avl_set_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type , GetContainer diff --git a/test/common_functors.hpp b/test/common_functors.hpp index d3bc3fa..db52197 100644 --- a/test/common_functors.hpp +++ b/test/common_functors.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/test/custom_bucket_traits_test.cpp b/test/custom_bucket_traits_test.cpp index 7539b9c..a74eb0b 100644 --- a/test/custom_bucket_traits_test.cpp +++ b/test/custom_bucket_traits_test.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/test/default_hook_test.cpp b/test/default_hook_test.cpp index 90f664d..55c31a2 100644 --- a/test/default_hook_test.cpp +++ b/test/default_hook_test.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/test/external_value_traits_test.cpp b/test/external_value_traits_test.cpp index fa380e2..ec70f13 100644 --- a/test/external_value_traits_test.cpp +++ b/test/external_value_traits_test.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/test/generic_assoc_test.hpp b/test/generic_assoc_test.hpp index 5ee4720..9f39ff7 100644 --- a/test/generic_assoc_test.hpp +++ b/test/generic_assoc_test.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -117,16 +117,27 @@ void test_generic_assoc::test_insert_erase_burst( //Now random insertions std::random_shuffle(values.begin(), values.end()); testset.insert(&values[0], &values[0] + values.size()); - std::sort(values.begin(), values.end()); + std::vector values_ordered(values); + std::sort(values_ordered.begin(), values_ordered.end()); TEST_INTRUSIVE_SEQUENCE_EXPECTED(testset, testset.begin()); - //Random erasure - std::random_shuffle(values.begin(), values.end()); - for(int i = 0; i != MaxValues; ++i){ - it = testset.erase(testset.iterator_to(values[i])); - } + { + typedef typename std::vector::const_iterator cvec_iterator; + //Random erasure + std::vector it_vector; + + for(cvec_iterator it(values.begin()), itend(values.end()) + ; it != itend + ; ++it){ + it_vector.push_back(it); + } + std::random_shuffle(it_vector.begin(), it_vector.end()); + for(int i = 0; i != MaxValues; ++i){ + testset.erase(testset.iterator_to(*it_vector[i])); + } - BOOST_TEST(testset.empty()); + BOOST_TEST(testset.empty()); + } } template class ContainerDefiner> diff --git a/test/generic_multiset_test.hpp b/test/generic_multiset_test.hpp index 0df4e72..21aeb3c 100644 --- a/test/generic_multiset_test.hpp +++ b/test/generic_multiset_test.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/test/generic_set_test.hpp b/test/generic_set_test.hpp index 0498759..5df2489 100644 --- a/test/generic_set_test.hpp +++ b/test/generic_set_test.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/test/itestvalue.hpp b/test/itestvalue.hpp index 4fd6750..a2885db 100644 --- a/test/itestvalue.hpp +++ b/test/itestvalue.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -14,220 +14,25 @@ #define BOOST_INTRUSIVE_DETAIL_ITESTVALUE_HPP #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include "smart_ptr.hpp" namespace boost{ namespace intrusive{ -struct my_tag; - -template -struct set_base_hook_type -{ typedef set_base_hook > type; }; - -template -struct set_auto_base_hook_type -{ typedef set_base_hook, void_pointer, tag, optimize_size > type; }; - -template -struct set_member_hook_type -{ typedef set_member_hook, optimize_size > type; }; - -template -struct set_auto_member_hook_type -{ typedef set_member_hook, void_pointer > type; }; - -template -struct splay_set_base_hook_type -{ typedef splay_set_base_hook > type; }; - -template -struct splay_set_auto_base_hook_type -{ typedef splay_set_base_hook, void_pointer, tag > type; }; - -template -struct splay_set_member_hook_type -{ typedef splay_set_member_hook > type; }; - -template -struct splay_set_auto_member_hook_type -{ typedef splay_set_member_hook, void_pointer > type; }; - -template -struct bs_set_base_hook_type -{ typedef bs_set_base_hook > type; }; - -template -struct bs_set_member_hook_type -{ typedef bs_set_member_hook > type; }; - -template -struct avl_set_base_hook_type -{ typedef avl_set_base_hook > type; }; - -template -struct avl_set_auto_base_hook_type -{ typedef avl_set_base_hook, void_pointer, tag, optimize_size > type; }; - -template -struct avl_set_member_hook_type -{ typedef avl_set_member_hook, optimize_size > type; }; - -template -struct avl_set_auto_member_hook_type -{ typedef avl_set_member_hook, void_pointer > type; }; - -template -struct list_base_hook_type -{ typedef list_base_hook > type; }; - -template -struct list_auto_base_hook_type -{ typedef list_base_hook, void_pointer, tag > type; }; - -template -struct list_member_hook_type -{ typedef list_member_hook > type; }; - -template -struct list_auto_member_hook_type -{ typedef list_member_hook, void_pointer > type; }; - -template -struct slist_base_hook_type -{ typedef slist_base_hook > type; }; - -template -struct slist_auto_base_hook_type -{ typedef slist_base_hook, void_pointer, tag > type; }; - -template -struct slist_member_hook_type -{ typedef slist_member_hook > type; }; - -template -struct slist_auto_member_hook_type -{ typedef slist_member_hook, void_pointer > type; }; - -template -struct uset_base_hook_type -{ typedef unordered_set_base_hook > type; }; - -template -struct uset_auto_base_hook_type +struct testvalue_filler { - typedef unordered_set_base_hook - < link_mode - , void_pointer - , tag - , store_hash - > type; + void *dummy_[3]; }; -template -struct uset_member_hook_type -{ - typedef unordered_set_member_hook - < void_pointer - , optimize_multikey - > type; -}; - -template -struct uset_auto_member_hook_type -{ - typedef unordered_set_member_hook - < link_mode, void_pointer - , store_hash - , optimize_multikey - > type; -}; - -template +template struct testvalue - : set_base_hook_type::type - , set_auto_base_hook_type::type - , splay_set_base_hook_type::type - , splay_set_auto_base_hook_type::type - , bs_set_base_hook_type::type - , avl_set_base_hook_type::type - , avl_set_auto_base_hook_type::type - , list_base_hook_type::type - , list_auto_base_hook_type::type - , slist_base_hook_type::type - , slist_auto_base_hook_type::type - , uset_base_hook_type::type - , uset_auto_base_hook_type::type + : testvalue_filler + , Hooks::base_hook_type + , Hooks::auto_base_hook_type { - typedef typename set_auto_base_hook_type::type set_auto_base_hook_t; - typedef typename set_base_hook_type::type set_base_hook_t; - typedef typename set_auto_member_hook_type::type set_auto_member_hook_t; - typedef typename set_member_hook_type::type set_member_hook_t; - - typedef typename splay_set_auto_base_hook_type::type splay_set_auto_base_hook_t; - typedef typename splay_set_base_hook_type::type splay_set_base_hook_t; - typedef typename splay_set_auto_member_hook_type::type splay_set_auto_member_hook_t; - typedef typename splay_set_member_hook_type::type splay_set_member_hook_t; - - typedef typename bs_set_base_hook_type::type bs_set_base_hook_t; - typedef typename bs_set_member_hook_type::type bs_set_member_hook_t; - - typedef typename avl_set_auto_base_hook_type::type avl_set_auto_base_hook_t; - typedef typename avl_set_base_hook_type::type avl_set_base_hook_t; - typedef typename avl_set_auto_member_hook_type::type avl_set_auto_member_hook_t; - typedef typename avl_set_member_hook_type::type avl_set_member_hook_t; - - typedef typename uset_auto_base_hook_type::type unordered_set_auto_base_hook_t; - typedef typename uset_base_hook_type::type unordered_set_base_hook_t; - typedef typename uset_auto_member_hook_type::type unordered_set_auto_member_hook_t; - typedef typename uset_member_hook_type::type unordered_set_member_hook_t; - - typedef typename list_auto_base_hook_type::type list_auto_base_hook_t; - typedef typename list_base_hook_type::type list_base_hook_t; - typedef typename list_auto_member_hook_type::type list_auto_member_hook_t; - typedef typename list_member_hook_type::type list_member_hook_t; - - typedef typename slist_auto_base_hook_type::type slist_auto_base_hook_t; - typedef typename slist_base_hook_type::type slist_base_hook_t; - typedef typename slist_auto_member_hook_type::type slist_auto_member_hook_t; - typedef typename slist_member_hook_type::type slist_member_hook_t; - - //Set members - set_member_hook_t set_node_; - set_auto_member_hook_t set_auto_node_; - - //SplaySet members - splay_set_member_hook_t splay_set_node_; - splay_set_auto_member_hook_t splay_set_auto_node_; - - //ScapegoatSet members - bs_set_member_hook_t sg_set_node_; - - //AvlSet members - avl_set_member_hook_t avl_set_node_; - avl_set_auto_member_hook_t avl_set_auto_node_; - - //Unordered set members - unordered_set_member_hook_t unordered_set_node_; - unordered_set_auto_member_hook_t unordered_set_auto_node_; - - //List members - list_member_hook_t list_node_; - list_auto_member_hook_t list_auto_node_; - - //Slist members - slist_member_hook_t slist_node_; - slist_auto_member_hook_t slist_auto_node_; - + typename Hooks::member_hook_type node_; + typename Hooks::auto_member_hook_type auto_node_; int value_; static const bool constant_time_size = ConstantTimeSize; @@ -245,130 +50,30 @@ struct testvalue // testvalue is used in std::vector and thus prev and next // have to be handled appropriately when copied: - testvalue & operator= (const testvalue& src) - {/* - set_base_hook_t::operator=(src); - set_auto_base_hook_t::operator=(src); - this->set_node_ = src.set_node_; - this->set_auto_node_ = src.set_auto_node_; - - splay_set_base_hook_t::operator=(src); - splay_set_auto_base_hook_t::operator=(src); - this->splay_set_node_ = src.splay_set_node_; - this->splay_set_auto_node_ = src.splay_set_auto_node_; - - bs_set_base_hook_t::operator=(src); - this->sg_set_node_ = src.sg_set_node_; - - avl_set_base_hook_t::operator=(src); - avl_set_auto_base_hook_t::operator=(src); - this->avl_set_node_ = src.avl_set_node_; - this->avl_set_auto_node_ = src.avl_set_auto_node_; - - unordered_set_base_hook_t::operator=(src); - unordered_set_auto_base_hook_t::operator=(src); - this->unordered_set_node_ = src.unordered_set_node_; - this->unordered_set_auto_node_ = src.unordered_set_auto_node_; - - list_base_hook_t::operator=(src); - list_auto_base_hook_t::operator=(src); - this->list_node_ = src.list_node_; - this->list_auto_node_ = src.list_auto_node_; - - slist_base_hook_t::operator=(src); - slist_auto_base_hook_t::operator=(src); - this->slist_node_ = src.slist_node_; - this->slist_auto_node_ = src.slist_auto_node_; -*/ + { + Hooks::base_hook_type::operator=(src); + Hooks::auto_base_hook_type::operator=(src); + this->node_ = src.node_; + this->auto_node_ = src.auto_node_; value_ = src.value_; return *this; } void swap_nodes(testvalue &other) { - //Set - set_base_hook_t::swap_nodes(other); - set_auto_base_hook_t::swap_nodes(other); - set_node_.swap_nodes(other.set_node_); - set_auto_node_.swap_nodes(other.set_auto_node_); - - //SplaySet - splay_set_base_hook_t::swap_nodes(other); - splay_set_auto_base_hook_t::swap_nodes(other); - splay_set_node_.swap_nodes(other.splay_set_node_); - splay_set_auto_node_.swap_nodes(other.splay_set_auto_node_); - - //ScapeoatSet - bs_set_base_hook_t::swap_nodes(other); - sg_set_node_.swap_nodes(other.sg_set_node_); - - //AvlSet - avl_set_base_hook_t::swap_nodes(other); - avl_set_auto_base_hook_t::swap_nodes(other); - avl_set_node_.swap_nodes(other.avl_set_node_); - avl_set_auto_node_.swap_nodes(other.avl_set_auto_node_); - - //Unordered set - unordered_set_base_hook_t::swap_nodes(other); - unordered_set_auto_base_hook_t::swap_nodes(other); - unordered_set_node_.swap_nodes(other.unordered_set_node_); - unordered_set_auto_node_.swap_nodes(other.unordered_set_auto_node_); - - //List - list_base_hook_t::swap_nodes(other); - list_auto_base_hook_t::swap_nodes(other); - list_node_.swap_nodes(other.list_node_); - list_auto_node_.swap_nodes(other.list_auto_node_); - - //Slist - slist_base_hook_t::swap_nodes(other); - slist_auto_base_hook_t::swap_nodes(other); - slist_node_.swap_nodes(other.slist_node_); - slist_auto_node_.swap_nodes(other.slist_auto_node_); + Hooks::base_hook_type::swap_nodes(other); + Hooks::auto_base_hook_type::swap_nodes(other); + node_.swap_nodes(other.node_); + auto_node_.swap_nodes(other.auto_node_); } bool is_linked() const { - //Set - return set_base_hook_t::is_linked() || - set_auto_base_hook_t::is_linked() || - set_node_.is_linked() || - set_auto_node_.is_linked() || - - //SplaySet - splay_set_base_hook_t::is_linked() || - splay_set_auto_base_hook_t::is_linked() || - splay_set_node_.is_linked() || - splay_set_auto_node_.is_linked() || - - //ScapeoatSet - bs_set_base_hook_t::is_linked() || - sg_set_node_.is_linked() || - - //AvlSet - avl_set_base_hook_t::is_linked() || - avl_set_auto_base_hook_t::is_linked() || - avl_set_node_.is_linked() || - avl_set_auto_node_.is_linked() || - - //Unordered set - unordered_set_base_hook_t::is_linked() || - unordered_set_auto_base_hook_t::is_linked() || - unordered_set_node_.is_linked() || - unordered_set_auto_node_.is_linked() || - - //List - list_base_hook_t::is_linked() || - list_auto_base_hook_t::is_linked() || - list_node_.is_linked() || - list_auto_node_.is_linked() || - - //Slist - slist_base_hook_t::is_linked() || - slist_auto_base_hook_t::is_linked() || - slist_node_.is_linked() || - slist_auto_node_.is_linked(); + return Hooks::base_hook_type::is_linked() || + Hooks::auto_base_hook_type::is_linked() || + node_.is_linked() || + auto_node_.is_linked(); } ~testvalue() @@ -402,24 +107,34 @@ struct testvalue { return other1.value_ != other2; } }; -template -std::size_t hash_value(const testvalue &t) +template +std::size_t hash_value(const testvalue &t) { boost::hash hasher; return hasher(t.value_); } -template +template +bool priority_order(const testvalue &t1, const testvalue &t2) +{ + std::size_t hash1 = hash_value(t1); + boost::hash_combine(hash1,&t1); + std::size_t hash2 = hash_value(t2); + boost::hash_combine(hash2,&t2); + return hash1 < hash2; +} + +template std::ostream& operator<< - (std::ostream& s, const testvalue& t) + (std::ostream& s, const testvalue& t) { return s << t.value_; } struct even_odd { - template + template bool operator() - (const testvalue& v1 - ,const testvalue& v2) const + (const testvalue& v1 + ,const testvalue& v2) const { if ((v1.value_ & 1) == (v2.value_ & 1)) return v1.value_ < v2.value_; @@ -430,9 +145,9 @@ struct even_odd struct is_even { - template + template bool operator() - (const testvalue& v1) const + (const testvalue& v1) const { return (v1.value_ & 1) == 0; } }; diff --git a/test/list_test.cpp b/test/list_test.cpp index 65cfa8b..8e67f8b 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -25,6 +25,19 @@ using namespace boost::intrusive; +class my_tag; + +template +struct hooks +{ + typedef list_base_hook > base_hook_type; + typedef list_base_hook< link_mode + , void_pointer, tag > auto_base_hook_type; + typedef list_member_hook, tag > member_hook_type; + typedef list_member_hook< link_mode + , void_pointer > auto_member_hook_type; +}; + template struct test_list { @@ -400,21 +413,21 @@ class test_main_template public: int operator()() { - typedef testvalue value_type; + typedef testvalue, constant_time_size> value_type; std::vector data (5); for (int i = 0; i < 5; ++i) data[i].value_ = i + 1; test_list < typename detail::get_base_value_traits < value_type - , typename value_type::list_base_hook_t + , typename hooks::base_hook_type >::type >::test_all(data); test_list < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::list_member_hook_t - , &value_type::list_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type >::test_all(data); @@ -428,22 +441,22 @@ class test_main_template public: int operator()() { - typedef testvalue value_type; + typedef testvalue, false> value_type; std::vector data (5); for (int i = 0; i < 5; ++i) data[i].value_ = i + 1; test_list < typename detail::get_base_value_traits < value_type - , typename value_type::list_base_hook_t + , typename hooks::base_hook_type >::type >::test_all(data); test_list < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::list_member_hook_t - , &value_type::list_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type >::test_all(data); @@ -455,15 +468,15 @@ class test_main_template // >::test_all(data); test_list < typename detail::get_base_value_traits < value_type - , typename value_type::list_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type >::test_all(data); test_list < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::list_auto_member_hook_t - , &value_type::list_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type >::test_all(data); @@ -488,285 +501,3 @@ int main( int, char* [] ) return boost::report_errors(); } #include - - - - - - - - - - - - - -/* -#include - - -//////////////////////////////////////////////////// -// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will -// be used to "unpack" into comma-separated values -// in a function call. -//////////////////////////////////////////////////// - -template -struct index_tuple{}; - -template > -struct build_number_seq; - -template -struct build_number_seq > - : build_number_seq > -{}; - -template -struct build_number_seq<0, index_tuple > -{ typedef index_tuple type; }; - -template -struct typelist -{}; - -template -struct invert_typelist; - -template -struct typelist_element; - -template -struct typelist_element > -{ - typedef typename typelist_element >::type type; -}; - -template -struct typelist_element<0, typelist > -{ - typedef Head type; -}; - -template -typelist >::type...> - inverted_typelist(index_tuple, typelist) -{ - return typelist >::type...>(); -} - - -template -struct sizeof_typelist; - -template -struct sizeof_typelist< typelist > -{ - static const std::size_t value = sizeof...(Types); -}; - -//invert_typelist_impl -template -struct invert_typelist_impl; - - -template -struct invert_typelist_impl< Typelist, index_tuple > -{ - static const std::size_t last_idx = sizeof_typelist::value - 1; - typedef typelist - ::type...> type; -}; - -template -struct invert_typelist_impl< Typelist, index_tuple > -{ - typedef Typelist type; -}; - -template -struct invert_typelist_impl< Typelist, index_tuple<> > -{ - typedef Typelist type; -}; - -//invert_typelist -template -struct invert_typelist; - -template -struct invert_typelist< typelist > -{ - typedef typelist typelist_t; - typedef typename build_number_seq::type indexes_t; - typedef typename invert_typelist_impl::type type; -}; - -struct none -{ - template - struct pack : Base - { }; -}; - -//!This option setter specifies the type of -//!a void pointer. This will instruct the hook -//!to use this type of pointer instead of the -//!default one -template -struct void_pointer -{ -/// @cond - template - struct pack : Base - { - typedef VoidPointer void_pointer; - }; -/// @endcond -}; - -//!This option setter specifies the type of -//!the tag of a base hook. A type cannot have two -//!base hooks of the same type, so a tag can be used -//!to differentiate two base hooks with otherwise same type -template -struct tag -{ -/// @cond - template - struct pack : Base - { - typedef Tag tag; - }; -/// @endcond -}; - - -//!This option setter specifies if the hook -//!should be optimized for size instead of for speed. -template -struct optimize_size -{ -/// @cond - template - struct pack : Base - { - static const bool optimize_size = Enabled; - }; -/// @endcond -}; - -//!This option setter specifies if the list container should -//!use a linear implementation instead of a circular one. -template -struct linear -{ -/// @cond - template - struct pack : Base - { - static const bool linear = Enabled; - }; -/// @endcond -}; - -//!This option setter specifies if the list container should -//!use a linear implementation instead of a circular one. -template -struct cache_last -{ -/// @cond - template - struct pack : Base - { - static const bool cache_last = Enabled; - }; -/// @endcond -}; - - - -template -struct do_pack; - -template<> -struct do_pack >; - -template -struct do_pack > -{ - typedef Prev type; -}; - -template -struct do_pack > -{ - typedef typename Prev::template pack type; -}; - -template -struct do_pack > -{ - typedef typename Prev::template pack - >::type> type; -}; - - -template -struct pack_options -{ - typedef typelist typelist_t; - typedef typename invert_typelist::type inverted_typelist; - typedef typename do_pack::type type; -}; - -struct hook_defaults - : public pack_options - < none - , void_pointer - , tag - , optimize_size - , linear - >::type -{}; - - -#include -#include - -struct S -{}; - -int main() -{ - { - typedef typelist typelist_t; - typedef invert_typelist::type inverted_typelist; - std::cout << "original: " << typeid(typelist_t).name() << std::endl; - std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl; - } - { - typedef typelist typelist_t; - typedef invert_typelist::type inverted_typelist; - std::cout << "original: " << typeid(typelist_t).name() << std::endl; - std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl; - } - { - typedef typelist<> typelist_t; - typedef invert_typelist::type inverted_typelist; - std::cout << "original: " << typeid(typelist_t).name() << std::endl; - std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl; - } - { - typedef pack_options::type options_t; - std::cout << "options_t " << typeid(options_t).name() << std::endl; - } - { - typedef pack_options::type options_t; - std::cout << "options_t " << typeid(options_t).name() << std::endl; - } - - hook_defaults h; - return 1; -} -*/ \ No newline at end of file diff --git a/test/make_functions_test.cpp b/test/make_functions_test.cpp index bf40afb..2f8e1aa 100644 --- a/test/make_functions_test.cpp +++ b/test/make_functions_test.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -13,12 +13,22 @@ #include #include #include +#include +#include +#include +#include #include #include "smart_ptr.hpp" #include using namespace boost::intrusive; +struct my_tag; + +typedef make_bs_set_base_hook + < void_pointer >, link_mode + , tag >::type TreapHook; + class MyClass : public make_list_base_hook < void_pointer >, link_mode >::type @@ -28,6 +38,13 @@ class MyClass < void_pointer >, link_mode >::type , public make_unordered_set_base_hook < void_pointer >, link_mode >::type +, public make_avl_set_base_hook + < void_pointer >, link_mode >::type +, public make_splay_set_base_hook + < void_pointer >, link_mode >::type +, public make_bs_set_base_hook + < void_pointer >, link_mode >::type +, public TreapHook { int int_; @@ -44,6 +61,9 @@ class MyClass friend std::size_t hash_value(const MyClass &v) { return boost::hash_value(v.int_); } + + friend bool priority_order(const MyClass &l, const MyClass &r) + { return l.int_ < r.int_; } }; //Define a list that will store MyClass using the public base hook @@ -52,6 +72,12 @@ typedef make_slist::type Slist; typedef make_set::type Set; typedef make_unordered_set::type USet; +typedef make_avl_set::type AvlSet; +typedef make_splay_set::type SplaySet; +typedef make_sg_set::type SgSet; +typedef make_treap_set >::type TreapSet; + int main() { typedef std::vector::iterator VectIt; @@ -68,12 +94,21 @@ int main() Set my_set; USet my_uset(USet::bucket_traits(buckets, 100)); + AvlSet my_avlset; + SplaySet my_splayset; + SgSet my_sgset; + TreapSet my_treapset; + //Now insert them in containers for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){ my_list.push_front(*it); my_slist.push_front(*it); my_set.insert(*it); my_uset.insert(*it); + my_avlset.insert(*it); + my_splayset.insert(*it); + my_sgset.insert(*it); + my_treapset.insert(*it); } //Now test lists @@ -81,14 +116,27 @@ int main() List::const_iterator list_it(my_list.cbegin()); Slist::const_iterator slist_it(my_slist.cbegin()); Set::const_reverse_iterator set_rit(my_set.crbegin()); + + AvlSet::const_reverse_iterator avlset_rit(my_avlset.crbegin()); + SplaySet::const_reverse_iterator splayset_rit(my_splayset.crbegin()); + SgSet::const_reverse_iterator sgset_rit(my_sgset.crbegin()); + TreapSet::const_reverse_iterator treapset_rit(my_treapset.crbegin()); + VectRit vect_it(values.rbegin()), vect_itend(values.rend()); //Test the objects inserted in the base hook list - for(; vect_it != vect_itend; ++vect_it, ++list_it, ++slist_it, ++set_rit){ + for( ; vect_it != vect_itend + ; ++vect_it, ++list_it, ++slist_it, ++set_rit + , ++avlset_rit, ++splayset_rit, ++sgset_rit, ++treapset_rit + ){ if(&*list_it != &*vect_it) return 1; if(&*slist_it != &*vect_it) return 1; if(&*set_rit != &*vect_it) return 1; if(my_uset.find(*set_rit) == my_uset.cend()) return 1; + if(&*avlset_rit != &*vect_it) return 1; + if(&*splayset_rit != &*vect_it) return 1; + if(&*sgset_rit != &*vect_it) return 1; + if(&*treapset_rit != &*vect_it) return 1; } } @@ -117,6 +165,24 @@ int main() return 1; } + if(detail::is_same, link_mode >::type + ,make_avl_set_base_hook<>::type + >::value == false){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_bs_set_base_hook<>::type + >::value == false){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_splay_set_base_hook<>::type + >::value == false){ + return 1; + } + //Check defined types and implicitly defined types are unequal if(detail::is_same, link_mode >::type ,make_list_base_hook<>::type @@ -142,6 +208,24 @@ int main() return 1; } + if(detail::is_same, link_mode >::type + ,make_avl_set_base_hook<>::type + >::value == true){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_splay_set_base_hook<>::type + >::value == true){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_bs_set_base_hook<>::type + >::value == true){ + return 1; + } + return 0; } diff --git a/test/multiset_test.cpp b/test/multiset_test.cpp index 180ee62..6bb0b06 100644 --- a/test/multiset_test.cpp +++ b/test/multiset_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -16,6 +16,26 @@ #include "smart_ptr.hpp" #include "generic_multiset_test.hpp" +using namespace boost::intrusive; + +struct my_tag; + +template +struct hooks +{ + typedef set_base_hook + > base_hook_type; + typedef set_base_hook + + , void_pointer + , tag + , optimize_size > auto_base_hook_type; + typedef set_member_hook, optimize_size > member_hook_type; + typedef set_member_hook + , void_pointer > auto_member_hook_type; +}; + template< class ValueType , class Option1 = boost::intrusive::none , class Option2 = boost::intrusive::none @@ -38,19 +58,19 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , constant_time_size> value_type; test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::set_member_hook_t - , &value_type::set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -66,11 +86,11 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , false> value_type; test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); @@ -78,8 +98,8 @@ class test_main_template test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::set_member_hook_t - , &value_type::set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -87,7 +107,7 @@ class test_main_template test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::set_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type , GetContainer >::test_all(); @@ -95,8 +115,8 @@ class test_main_template test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::set_auto_member_hook_t - , &value_type::set_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type , GetContainer diff --git a/test/set_test.cpp b/test/set_test.cpp index 44a0141..6d28424 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -16,6 +16,26 @@ #include "smart_ptr.hpp" #include "generic_set_test.hpp" +struct my_tag; + +using namespace boost::intrusive; + +template +struct hooks +{ + typedef set_base_hook + > base_hook_type; + typedef set_base_hook + + , void_pointer + , tag + , optimize_size > auto_base_hook_type; + typedef set_member_hook, optimize_size > member_hook_type; + typedef set_member_hook + , void_pointer > auto_member_hook_type; +}; + template< class ValueType , class Option1 = boost::intrusive::none , class Option2 = boost::intrusive::none @@ -38,19 +58,19 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , constant_time_size> value_type; test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::set_member_hook_t - , &value_type::set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -66,11 +86,11 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , false> value_type; test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); @@ -78,8 +98,8 @@ class test_main_template test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::set_member_hook_t - , &value_type::set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -87,7 +107,7 @@ class test_main_template test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::set_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type , GetContainer >::test_all(); @@ -95,8 +115,8 @@ class test_main_template test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::set_auto_member_hook_t - , &value_type::set_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type , GetContainer diff --git a/test/sg_multiset_test.cpp b/test/sg_multiset_test.cpp index e5bff6a..327eaf0 100644 --- a/test/sg_multiset_test.cpp +++ b/test/sg_multiset_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -36,6 +36,22 @@ struct has_rebalance +struct hooks +{ + typedef bs_set_base_hook > base_hook_type; + typedef bs_set_member_hook > member_hook_type; + typedef member_hook_type auto_member_hook_type; + struct auto_base_hook_type + : bs_set_base_hook, tag > + {}; +}; + + template< class ValueType , class Option1 = boost::intrusive::none , class Option2 = boost::intrusive::none @@ -74,34 +90,34 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , true> value_type; test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::bs_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::bs_set_member_hook_t - , &value_type::sg_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer >::test_all(); test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::bs_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainerFixedAlpha >::test_all(); test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::bs_set_member_hook_t - , &value_type::sg_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainerFixedAlpha diff --git a/test/sg_set_test.cpp b/test/sg_set_test.cpp index df424cc..61c19a4 100644 --- a/test/sg_set_test.cpp +++ b/test/sg_set_test.cpp @@ -35,6 +35,22 @@ struct has_rebalance +struct hooks +{ + typedef bs_set_base_hook > base_hook_type; + typedef bs_set_member_hook > member_hook_type; + typedef member_hook_type auto_member_hook_type; + struct auto_base_hook_type + : bs_set_base_hook, tag > + {}; +}; + template< class ValueType , class Option1 = boost::intrusive::none , class Option2 = boost::intrusive::none @@ -73,19 +89,19 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , true> value_type; test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::bs_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::bs_set_member_hook_t - , &value_type::sg_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -93,15 +109,15 @@ class test_main_template test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::bs_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainerFixedAlpha >::test_all(); test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::bs_set_member_hook_t - , &value_type::sg_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainerFixedAlpha diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 7ca0afc..569c1ae 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -24,6 +24,19 @@ using namespace boost::intrusive; +struct my_tag; + +template +struct hooks +{ + typedef slist_base_hook > base_hook_type; + typedef slist_base_hook< link_mode + , void_pointer, tag > auto_base_hook_type; + typedef slist_member_hook, tag > member_hook_type; + typedef slist_member_hook< link_mode + , void_pointer > auto_member_hook_type; +}; + template struct test_slist { @@ -491,14 +504,14 @@ class test_main_template public: int operator()() { - typedef testvalue value_type; + typedef testvalue , constant_time_size> value_type; std::vector data (5); for (int i = 0; i < 5; ++i) data[i].value_ = i + 1; test_slist < typename detail::get_base_value_traits < value_type - , typename value_type::slist_base_hook_t + , typename hooks::base_hook_type >::type , false , false @@ -506,8 +519,8 @@ class test_main_template test_slist < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::slist_member_hook_t - , &value_type::slist_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , false @@ -517,7 +530,7 @@ class test_main_template //Now linear slists test_slist < typename detail::get_base_value_traits < value_type - , typename value_type::slist_base_hook_t + , typename hooks::base_hook_type >::type , true , false @@ -526,8 +539,8 @@ class test_main_template test_slist < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::slist_member_hook_t - , &value_type::slist_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , true @@ -537,7 +550,7 @@ class test_main_template //Now the same but caching the last node test_slist < typename detail::get_base_value_traits < value_type - , typename value_type::slist_base_hook_t + , typename hooks::base_hook_type >::type , false , true @@ -545,8 +558,8 @@ class test_main_template test_slist < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::slist_member_hook_t - , &value_type::slist_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , false @@ -556,7 +569,7 @@ class test_main_template //Now linear slists test_slist < typename detail::get_base_value_traits < value_type - , typename value_type::slist_base_hook_t + , typename hooks::base_hook_type >::type , true , true @@ -565,8 +578,8 @@ class test_main_template test_slist < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::slist_member_hook_t - , &value_type::slist_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , true @@ -582,14 +595,14 @@ class test_main_template public: int operator()() { - typedef testvalue value_type; + typedef testvalue , false> value_type; std::vector data (5); for (int i = 0; i < 5; ++i) data[i].value_ = i + 1; test_slist < typename detail::get_base_value_traits < value_type - , typename value_type::slist_base_hook_t + , typename hooks::base_hook_type >::type , false , false @@ -598,8 +611,8 @@ class test_main_template test_slist < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::slist_member_hook_t - , &value_type::slist_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , false @@ -608,7 +621,7 @@ class test_main_template test_slist < typename detail::get_base_value_traits < value_type - , typename value_type::slist_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type , false , false @@ -617,8 +630,8 @@ class test_main_template test_slist < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::slist_auto_member_hook_t - , &value_type::slist_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type , false @@ -627,7 +640,7 @@ class test_main_template test_slist < typename detail::get_base_value_traits < value_type - , typename value_type::slist_base_hook_t + , typename hooks::base_hook_type >::type , true , false @@ -636,8 +649,8 @@ class test_main_template test_slist < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::slist_member_hook_t - , &value_type::slist_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , true @@ -647,7 +660,7 @@ class test_main_template //Now cache last test_slist < typename detail::get_base_value_traits < value_type - , typename value_type::slist_base_hook_t + , typename hooks::base_hook_type >::type , false , true @@ -656,8 +669,8 @@ class test_main_template test_slist < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::slist_member_hook_t - , &value_type::slist_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , false @@ -666,7 +679,7 @@ class test_main_template test_slist < typename detail::get_base_value_traits < value_type - , typename value_type::slist_base_hook_t + , typename hooks::base_hook_type >::type , true , true @@ -675,8 +688,8 @@ class test_main_template test_slist < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::slist_member_hook_t - , &value_type::slist_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , true diff --git a/test/splay_multiset_test.cpp b/test/splay_multiset_test.cpp index fbccdef..21bd600 100644 --- a/test/splay_multiset_test.cpp +++ b/test/splay_multiset_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -70,6 +70,24 @@ struct has_rebalance +struct hooks +{ + typedef splay_set_base_hook > base_hook_type; + typedef splay_set_base_hook + < link_mode + , void_pointer + , tag > auto_base_hook_type; + typedef splay_set_member_hook > member_hook_type; + typedef splay_set_member_hook + < link_mode + , void_pointer > auto_member_hook_type; +}; + template< class ValueType , class Option1 = boost::intrusive::none , class Option2 = boost::intrusive::none @@ -92,19 +110,19 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , constant_time_size> value_type; test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::splay_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::splay_set_member_hook_t - , &value_type::splay_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -120,11 +138,11 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , false> value_type; test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::splay_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); @@ -132,8 +150,8 @@ class test_main_template test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::splay_set_member_hook_t - , &value_type::splay_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -141,7 +159,7 @@ class test_main_template test::test_generic_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::splay_set_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type , GetContainer >::test_all(); @@ -149,8 +167,8 @@ class test_main_template test::test_generic_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::splay_set_auto_member_hook_t - , &value_type::splay_set_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type , GetContainer diff --git a/test/splay_set_test.cpp b/test/splay_set_test.cpp index 3f61609..299e12b 100644 --- a/test/splay_set_test.cpp +++ b/test/splay_set_test.cpp @@ -67,6 +67,24 @@ struct has_rebalance +struct hooks +{ + typedef splay_set_base_hook > base_hook_type; + typedef splay_set_base_hook + < link_mode + , void_pointer + , tag > auto_base_hook_type; + typedef splay_set_member_hook > member_hook_type; + typedef splay_set_member_hook + < link_mode + , void_pointer > auto_member_hook_type; +}; + template< class ValueType , class Option1 = boost::intrusive::none , class Option2 = boost::intrusive::none @@ -89,19 +107,19 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , constant_time_size> value_type; test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::splay_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::splay_set_member_hook_t - , &value_type::splay_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -117,11 +135,11 @@ class test_main_template int operator()() { using namespace boost::intrusive; - typedef testvalue value_type; + typedef testvalue , false> value_type; test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::splay_set_base_hook_t + , typename hooks::base_hook_type >::type , GetContainer >::test_all(); @@ -129,8 +147,8 @@ class test_main_template test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::splay_set_member_hook_t - , &value_type::splay_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , GetContainer @@ -138,7 +156,7 @@ class test_main_template test::test_generic_set < typename detail::get_base_value_traits < value_type - , typename value_type::splay_set_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type , GetContainer >::test_all(); @@ -146,8 +164,8 @@ class test_main_template test::test_generic_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::splay_set_auto_member_hook_t - , &value_type::splay_set_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type , GetContainer diff --git a/test/stateful_value_traits_test.cpp b/test/stateful_value_traits_test.cpp index aca8cb3..ffba752 100644 --- a/test/stateful_value_traits_test.cpp +++ b/test/stateful_value_traits_test.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/test/test_container.hpp b/test/test_container.hpp index 9ae000a..b3124e9 100644 --- a/test/test_container.hpp +++ b/test/test_container.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/test/test_macros.hpp b/test/test_macros.hpp index 3a76541..0b23322 100644 --- a/test/test_macros.hpp +++ b/test/test_macros.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/test/treap_multiset_test.cpp b/test/treap_multiset_test.cpp new file mode 100644 index 0000000..dbae120 --- /dev/null +++ b/test/treap_multiset_test.cpp @@ -0,0 +1,135 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-2008. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "itestvalue.hpp" +#include "smart_ptr.hpp" +#include "generic_multiset_test.hpp" + +using namespace boost::intrusive; + +struct my_tag; + +template +struct hooks +{ + typedef bs_set_base_hook > base_hook_type; + typedef bs_set_base_hook + < void_pointer + , tag > auto_base_hook_type; + typedef bs_set_member_hook + < void_pointer > member_hook_type; + typedef bs_set_member_hook + < void_pointer > auto_member_hook_type; +}; + +template< class ValueType + , class Option1 = boost::intrusive::none + , class Option2 = boost::intrusive::none + , class Option3 = boost::intrusive::none + > +struct GetContainer +{ + typedef boost::intrusive::treap_multiset + < ValueType + , Option1 + , Option2 + , Option3 + > type; +}; + +template +class test_main_template +{ + public: + int operator()() + { + using namespace boost::intrusive; + typedef testvalue , constant_time_size> value_type; + + test::test_generic_multiset < typename detail::get_base_value_traits + < value_type + , typename hooks::base_hook_type + >::type + , GetContainer + >::test_all(); + test::test_generic_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename hooks::member_hook_type + , &value_type::node_ + > + >::type + , GetContainer + >::test_all(); + return 0; + } +}; + +template +class test_main_template +{ + public: + int operator()() + { + using namespace boost::intrusive; + typedef testvalue , false> value_type; + + test::test_generic_multiset < typename detail::get_base_value_traits + < value_type + , typename hooks::base_hook_type + >::type + , GetContainer + >::test_all(); + + test::test_generic_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename hooks::member_hook_type + , &value_type::node_ + > + >::type + , GetContainer + >::test_all(); + + test::test_generic_multiset < typename detail::get_base_value_traits + < value_type + , typename hooks::auto_base_hook_type + >::type + , GetContainer + >::test_all(); + + test::test_generic_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ + > + >::type + , GetContainer + >::test_all(); + return 0; + } +}; + +int main( int, char* [] ) +{ + test_main_template()(); + test_main_template, false>()(); + test_main_template()(); + test_main_template, true>()(); + return boost::report_errors(); +} + +#include diff --git a/test/treap_set_test.cpp b/test/treap_set_test.cpp new file mode 100644 index 0000000..cbd6471 --- /dev/null +++ b/test/treap_set_test.cpp @@ -0,0 +1,134 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2008. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include +#include "itestvalue.hpp" +#include "smart_ptr.hpp" +#include "generic_set_test.hpp" + +using namespace boost::intrusive; + +struct my_tag; + +template +struct hooks +{ + typedef bs_set_base_hook > base_hook_type; + typedef bs_set_base_hook + < void_pointer + , tag > auto_base_hook_type; + typedef bs_set_member_hook + < void_pointer > member_hook_type; + typedef bs_set_member_hook + < void_pointer > auto_member_hook_type; +}; + +template< class ValueType + , class Option1 = boost::intrusive::none + , class Option2 = boost::intrusive::none + , class Option3 = boost::intrusive::none + > +struct GetContainer +{ + typedef boost::intrusive::treap_set + < ValueType + , Option1 + , Option2 + , Option3 + > type; +}; + +template +class test_main_template +{ + public: + int operator()() + { + using namespace boost::intrusive; + typedef testvalue , constant_time_size> value_type; + + test::test_generic_set < typename detail::get_base_value_traits + < value_type + , typename hooks::base_hook_type + >::type + , GetContainer + >::test_all(); + test::test_generic_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename hooks::member_hook_type + , &value_type::node_ + > + >::type + , GetContainer + >::test_all(); + return 0; + } +}; + +template +class test_main_template +{ + public: + int operator()() + { + using namespace boost::intrusive; + typedef testvalue , false> value_type; + + test::test_generic_set < typename detail::get_base_value_traits + < value_type + , typename hooks::base_hook_type + >::type + , GetContainer + >::test_all(); + + test::test_generic_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename hooks::member_hook_type + , &value_type::node_ + > + >::type + , GetContainer + >::test_all(); + + test::test_generic_set < typename detail::get_base_value_traits + < value_type + , typename hooks::auto_base_hook_type + >::type + , GetContainer + >::test_all(); + + test::test_generic_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ + > + >::type + , GetContainer + >::test_all(); + + return 0; + } +}; + +int main( int, char* [] ) +{ + test_main_template()(); + test_main_template, false>()(); + test_main_template()(); + test_main_template, true>()(); + return boost::report_errors(); +} + +#include diff --git a/test/unordered_multiset_test.cpp b/test/unordered_multiset_test.cpp index 1adab30..868d264 100644 --- a/test/unordered_multiset_test.cpp +++ b/test/unordered_multiset_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -25,6 +25,30 @@ using namespace boost::intrusive; +struct my_tag; + +template +struct hooks +{ + typedef unordered_set_base_hook > base_hook_type; + typedef unordered_set_base_hook + < link_mode + , void_pointer + , tag + , store_hash + > auto_base_hook_type; + + typedef unordered_set_member_hook + < void_pointer + , optimize_multikey + > member_hook_type; + typedef unordered_set_member_hook + < link_mode, void_pointer + , store_hash + , optimize_multikey + > auto_member_hook_type; +}; + static const std::size_t BucketSize = 8; template @@ -669,15 +693,15 @@ class test_main_template public: int operator()() { - typedef testvalue value_type; + typedef testvalue , constant_time_size> value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; - std::vector > data (6); + std::vector , constant_time_size> > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; test_unordered_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::unordered_set_base_hook_t + , typename hooks::base_hook_type >::type , true , false @@ -687,8 +711,8 @@ class test_main_template test_unordered_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::unordered_set_member_hook_t - , &value_type::unordered_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , false @@ -706,15 +730,15 @@ class test_main_template public: int operator()() { - typedef testvalue value_type; + typedef testvalue , false> value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; - std::vector > data (6); + std::vector , false> > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; test_unordered_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::unordered_set_base_hook_t + , typename hooks::base_hook_type >::type , true , false @@ -724,8 +748,8 @@ class test_main_template test_unordered_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::unordered_set_member_hook_t - , &value_type::unordered_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , false @@ -735,7 +759,7 @@ class test_main_template test_unordered_multiset < typename detail::get_base_value_traits < value_type - , typename value_type::unordered_set_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type , true , true @@ -745,8 +769,8 @@ class test_main_template test_unordered_multiset < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::unordered_set_auto_member_hook_t - , &value_type::unordered_set_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type , false diff --git a/test/unordered_set_test.cpp b/test/unordered_set_test.cpp index 8aa27da..b84414b 100644 --- a/test/unordered_set_test.cpp +++ b/test/unordered_set_test.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -24,6 +24,30 @@ using namespace boost::intrusive; +struct my_tag; + +template +struct hooks +{ + typedef unordered_set_base_hook > base_hook_type; + typedef unordered_set_base_hook + < link_mode + , void_pointer + , tag + , store_hash + > auto_base_hook_type; + + typedef unordered_set_member_hook + < void_pointer + , optimize_multikey + > member_hook_type; + typedef unordered_set_member_hook + < link_mode, void_pointer + , store_hash + , optimize_multikey + > auto_member_hook_type; +}; + static const std::size_t BucketSize = 8; template @@ -532,15 +556,15 @@ class test_main_template public: int operator()() { - typedef testvalue value_type; + typedef testvalue , constant_time_size> value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; - std::vector > data (6); + std::vector , constant_time_size> > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; test_unordered_set < typename detail::get_base_value_traits < value_type - , typename value_type::unordered_set_base_hook_t + , typename hooks::base_hook_type >::type , true , false @@ -549,8 +573,8 @@ class test_main_template test_unordered_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::unordered_set_member_hook_t - , &value_type::unordered_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , false @@ -568,15 +592,15 @@ class test_main_template public: int operator()() { - typedef testvalue value_type; + typedef testvalue , false> value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; - std::vector > data (6); + std::vector , false> > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; test_unordered_set < typename detail::get_base_value_traits < value_type - , typename value_type::unordered_set_base_hook_t + , typename hooks::base_hook_type >::type , true , false @@ -586,8 +610,8 @@ class test_main_template test_unordered_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::unordered_set_member_hook_t - , &value_type::unordered_set_node_ + , typename hooks::member_hook_type + , &value_type::node_ > >::type , false @@ -597,7 +621,7 @@ class test_main_template test_unordered_set < typename detail::get_base_value_traits < value_type - , typename value_type::unordered_set_auto_base_hook_t + , typename hooks::auto_base_hook_type >::type , true , true @@ -607,8 +631,8 @@ class test_main_template test_unordered_set < typename detail::get_member_value_traits < value_type , member_hook< value_type - , typename value_type::unordered_set_auto_member_hook_t - , &value_type::unordered_set_auto_node_ + , typename hooks::auto_member_hook_type + , &value_type::auto_node_ > >::type , false diff --git a/test/virtual_base_test.cpp b/test/virtual_base_test.cpp index 14bd885..92a700b 100644 --- a/test/virtual_base_test.cpp +++ b/test/virtual_base_test.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at From 0d754e6863dccc37ac3c1a1bb76a60432d2b814d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 13 Dec 2008 13:55:44 +0000 Subject: [PATCH 13/14] * New treap-based containers: treap, treap_set, treap_multiset. * Corrected compilation bug for Windows-based 64 bit compilers. * Corrected exception-safety bugs in container constructors. * Updated documentation to show rvalue-references funcions instead of emulation functions. [SVN r50260] --- include/boost/intrusive/any_hook.hpp | 4 +- include/boost/intrusive/avl_set.hpp | 63 +- include/boost/intrusive/avl_set_hook.hpp | 2 +- include/boost/intrusive/avltree.hpp | 169 +- include/boost/intrusive/bs_set_hook.hpp | 2 +- .../intrusive/circular_list_algorithms.hpp | 2 +- .../intrusive/circular_slist_algorithms.hpp | 2 +- .../intrusive/derivation_value_traits.hpp | 2 +- include/boost/intrusive/hashtable.hpp | 41 +- include/boost/intrusive/intrusive_fwd.hpp | 47 +- .../intrusive/linear_slist_algorithms.hpp | 2 +- include/boost/intrusive/link_mode.hpp | 2 +- include/boost/intrusive/list.hpp | 17 +- include/boost/intrusive/list_hook.hpp | 2 +- .../boost/intrusive/member_value_traits.hpp | 2 +- include/boost/intrusive/options.hpp | 16 +- include/boost/intrusive/pointer_plus_bits.hpp | 2 +- include/boost/intrusive/priority_compare.hpp | 39 + include/boost/intrusive/rbtree.hpp | 186 +- include/boost/intrusive/rbtree_algorithms.hpp | 2 +- include/boost/intrusive/set.hpp | 59 +- include/boost/intrusive/set_hook.hpp | 2 +- include/boost/intrusive/sg_set.hpp | 59 +- include/boost/intrusive/sgtree.hpp | 160 +- include/boost/intrusive/slist.hpp | 13 +- include/boost/intrusive/slist_hook.hpp | 2 +- include/boost/intrusive/splay_set.hpp | 59 +- include/boost/intrusive/splay_set_hook.hpp | 2 +- include/boost/intrusive/splaytree.hpp | 172 +- include/boost/intrusive/treap.hpp | 1663 ++++++++++++ include/boost/intrusive/treap_algorithms.hpp | 801 ++++++ include/boost/intrusive/treap_set.hpp | 2406 +++++++++++++++++ .../boost/intrusive/trivial_value_traits.hpp | 2 +- include/boost/intrusive/unordered_set.hpp | 18 +- .../boost/intrusive/unordered_set_hook.hpp | 2 +- 35 files changed, 5772 insertions(+), 252 deletions(-) create mode 100644 include/boost/intrusive/priority_compare.hpp create mode 100644 include/boost/intrusive/treap.hpp create mode 100644 include/boost/intrusive/treap_algorithms.hpp create mode 100644 include/boost/intrusive/treap_set.hpp diff --git a/include/boost/intrusive/any_hook.hpp b/include/boost/intrusive/any_hook.hpp index 4690cef..29a5b08 100644 --- a/include/boost/intrusive/any_hook.hpp +++ b/include/boost/intrusive/any_hook.hpp @@ -309,7 +309,7 @@ struct any_to_set_hook {}; //!This option setter specifies that -//!any hook should behave as a set hook +//!any hook should behave as an avl_set hook template struct any_to_avl_set_hook /// @cond @@ -318,7 +318,7 @@ struct any_to_avl_set_hook {}; //!This option setter specifies that any -//!hook should behave as a set hook +//!hook should behave as a bs_set hook template struct any_to_bs_set_hook /// @cond diff --git a/include/boost/intrusive/avl_set.hpp b/include/boost/intrusive/avl_set.hpp index a550232..3998f05 100644 --- a/include/boost/intrusive/avl_set.hpp +++ b/include/boost/intrusive/avl_set.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace boost { @@ -342,7 +343,7 @@ class avl_set_impl //! Requires: value must be an lvalue //! - //! Effects: Tries to inserts value into the avl_set. + //! Effects: Treaps to inserts value into the avl_set. //! //! Returns: If the value //! is not already present inserts it and returns a pair containing the @@ -362,7 +363,7 @@ class avl_set_impl //! Requires: value must be an lvalue //! - //! Effects: Tries to to insert x into the avl_set, using "hint" + //! Effects: Treaps to to insert x into the avl_set, using "hint" //! as a hint to where it will be inserted. //! //! Returns: An iterator that points to the position where the @@ -380,7 +381,7 @@ class avl_set_impl //! Requires: key_value_comp must be a comparison function that induces //! the same strict weak ordering as value_compare. The difference is that - //! key_value_comp compares an aavlitrary key with the contained values. + //! key_value_comp compares an arbitrary key with the contained values. //! //! Effects: Checks if a value can be inserted in the avl_set, using //! a user provided key instead of the value itself. @@ -415,7 +416,7 @@ class avl_set_impl //! Requires: key_value_comp must be a comparison function that induces //! the same strict weak ordering as value_compare. The difference is that - //! key_value_comp compares an aavlitrary key with the contained values. + //! key_value_comp compares an arbitrary key with the contained values. //! //! Effects: Checks if a value can be inserted in the avl_set, using //! a user provided key instead of the value itself, using "hint" @@ -498,7 +499,7 @@ class avl_set_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { return tree_.erase(i); } //! Effects: Erases the range pointed to by b end e. @@ -512,7 +513,7 @@ class avl_set_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { return tree_.erase(b, e); } //! Effects: Erases all the elements with the given value. @@ -540,7 +541,11 @@ class avl_set_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase(key, comp); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -557,9 +562,15 @@ class avl_set_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { return tree_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. @@ -575,7 +586,7 @@ class avl_set_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { return tree_.erase_and_dispose(b, e, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -610,7 +621,11 @@ class avl_set_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase_and_dispose(key, comp, disposer); } //! Effects: Erases all the elements of the container. @@ -1527,7 +1542,7 @@ class avl_multiset_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { return tree_.erase(i); } //! Effects: Erases the range pointed to by b end e. @@ -1541,7 +1556,7 @@ class avl_multiset_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { return tree_.erase(b, e); } //! Effects: Erases all the elements with the given value. @@ -1569,7 +1584,11 @@ class avl_multiset_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase(key, comp); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1586,9 +1605,15 @@ class avl_multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { return tree_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Returns: An iterator to the element after the erased elements. @@ -1604,7 +1629,7 @@ class avl_multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { return tree_.erase_and_dispose(b, e, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1639,7 +1664,11 @@ class avl_multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase_and_dispose(key, comp, disposer); } //! Effects: Erases all the elements of the container. diff --git a/include/boost/intrusive/avl_set_hook.hpp b/include/boost/intrusive/avl_set_hook.hpp index 76fa739..00d2fc8 100644 --- a/include/boost/intrusive/avl_set_hook.hpp +++ b/include/boost/intrusive/avl_set_hook.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/avltree.hpp b/include/boost/intrusive/avltree.hpp index 46038a8..c247e32 100644 --- a/include/boost/intrusive/avltree.hpp +++ b/include/boost/intrusive/avltree.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -77,7 +79,9 @@ template template #endif class avltree_impl + : private detail::clear_on_destructor_base > { + template friend class detail::clear_on_destructor_base; public: typedef typename Config::value_traits value_traits; /// @cond @@ -200,9 +204,11 @@ class avltree_impl //! //! Complexity: Constant. //! - //! Throws: Nothing unless the copy constructor of the value_compare object throws. - avltree_impl( value_compare cmp = value_compare() - , const value_traits &v_traits = value_traits()) + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor of the value_compare object throws. Basic guarantee. + avltree_impl( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) : data_(cmp, v_traits) { node_algorithms::init_header(&priv_header()); @@ -218,10 +224,12 @@ class avltree_impl //! Complexity: Linear in N if [b, e) is already sorted using //! comp and otherwise N * log N, where N is the distance between first and last. //! - //! Throws: Nothing unless the copy constructor of the value_compare object throws. + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare object throws. Basic guarantee. template avltree_impl( bool unique, Iterator b, Iterator e - , value_compare cmp = value_compare() + , const value_compare &cmp = value_compare() , const value_traits &v_traits = value_traits()) : data_(cmp, v_traits) { @@ -237,11 +245,11 @@ class avltree_impl //! are not deleted (i.e. no destructors are called), but the nodes according to //! the value_traits template parameter are reinitialized and thus can be reused. //! - //! Complexity: Linear to elements contained in *this. + //! Complexity: Linear to elements contained in *this. //! //! Throws: Nothing. ~avltree_impl() - { this->clear(); } + {} //! Effects: Returns an iterator pointing to the beginning of the tree. //! @@ -397,7 +405,7 @@ class avltree_impl value_compare value_comp() const { return priv_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -407,7 +415,8 @@ class avltree_impl //! Effects: Returns the number of elements stored in the tree. //! - //! Complexity: Linear to elements contained in *this. + //! Complexity: Linear to elements contained in *this + //! if constant-time size option is disabled. Constant time otherwise. //! //! Throws: Nothing. size_type size() const @@ -419,7 +428,7 @@ class avltree_impl } } - //! Effects: Swaps the contents of two multisets. + //! Effects: Swaps the contents of two avltrees. //! //! Complexity: Constant. //! @@ -445,7 +454,7 @@ class avltree_impl //! Complexity: Average complexity for insert element is at //! most logarithmic. //! - //! Throws: Nothing. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -471,7 +480,7 @@ class avltree_impl //! Complexity: Logarithmic in general, but it is amortized //! constant time if t is inserted immediately before hint. //! - //! Throws: Nothing. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -524,7 +533,7 @@ class avltree_impl std::pair insert_unique(reference value) { insert_commit_data commit_data; - std::pair ret = insert_unique_check(value, commit_data); + std::pair ret = insert_unique_check(value, priv_comp(), commit_data); if(!ret.second) return ret; return std::pair (insert_unique_commit(value, commit_data), true); @@ -547,7 +556,7 @@ class avltree_impl iterator insert_unique(const_iterator hint, reference value) { insert_commit_data commit_data; - std::pair ret = insert_unique_check(hint, value, commit_data); + std::pair ret = insert_unique_check(hint, value, priv_comp(), commit_data); if(!ret.second) return ret.first; return insert_unique_commit(value, commit_data); @@ -580,10 +589,36 @@ class avltree_impl } } - std::pair insert_unique_check - (const_reference value, insert_commit_data &commit_data) - { return insert_unique_check(value, priv_comp(), commit_data); } - + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that + //! part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. template std::pair insert_unique_check (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) @@ -596,10 +631,38 @@ class avltree_impl return std::pair(iterator(ret.first, this), ret.second); } - std::pair insert_unique_check - (const_iterator hint, const_reference value, insert_commit_data &commit_data) - { return insert_unique_check(hint, value, priv_comp(), commit_data); } - + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! constructing that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that key + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This can give a total + //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. template std::pair insert_unique_check (const_iterator hint, const KeyType &key @@ -613,6 +676,23 @@ class avltree_impl return std::pair(iterator(ret.first, this), ret.second); } + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the container between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the avl_set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. iterator insert_unique_commit(reference value, const insert_commit_data &commit_data) { node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); @@ -632,9 +712,9 @@ class avltree_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { - iterator ret(i); + const_iterator ret(i); ++ret; node_ptr to_erase(i.pointed_node()); if(safemode_or_autounlink) @@ -643,7 +723,7 @@ class avltree_impl this->priv_size_traits().decrement(); if(safemode_or_autounlink) node_algorithms::init(to_erase); - return ret; + return ret.unconst(); } //! Effects: Erases the range pointed to by b end e. @@ -655,7 +735,7 @@ class avltree_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { size_type n; return private_erase(b, e, n); } //! Effects: Erases all the elements with the given value. @@ -683,7 +763,11 @@ class avltree_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { std::pair p = this->equal_range(key, comp); size_type n; @@ -703,7 +787,7 @@ class avltree_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { node_ptr to_erase(i.pointed_node()); iterator ret(this->erase(i)); @@ -711,6 +795,12 @@ class avltree_impl return ret; } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. @@ -724,7 +814,7 @@ class avltree_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { size_type n; return private_erase(b, e, n, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -764,7 +854,11 @@ class avltree_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { std::pair p = this->equal_range(key, comp); size_type n; @@ -1212,20 +1306,21 @@ class avltree_impl */ /// @cond + private: template - iterator private_erase(iterator b, iterator e, size_type &n, Disposer disposer) + iterator private_erase(const_iterator b, const_iterator e, size_type &n, Disposer disposer) { for(n = 0; b != e; ++n) this->erase_and_dispose(b++, disposer); - return b; + return b.unconst(); } - iterator private_erase(iterator b, iterator e, size_type &n) + iterator private_erase(const_iterator b, const_iterator e, size_type &n) { for(n = 0; b != e; ++n) this->erase(b++); - return b; + return b.unconst(); } /// @endcond @@ -1446,8 +1541,8 @@ class avltree //Assert if passed value traits are compatible with the type BOOST_STATIC_ASSERT((detail::is_same::value)); - avltree( const value_compare &cmp = value_compare() - , const value_traits &v_traits = value_traits()) + avltree( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) : Base(cmp, v_traits) {} diff --git a/include/boost/intrusive/bs_set_hook.hpp b/include/boost/intrusive/bs_set_hook.hpp index d4726b0..3ab0310 100644 --- a/include/boost/intrusive/bs_set_hook.hpp +++ b/include/boost/intrusive/bs_set_hook.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/circular_list_algorithms.hpp b/include/boost/intrusive/circular_list_algorithms.hpp index d48fffc..aeb0358 100644 --- a/include/boost/intrusive/circular_list_algorithms.hpp +++ b/include/boost/intrusive/circular_list_algorithms.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/circular_slist_algorithms.hpp b/include/boost/intrusive/circular_slist_algorithms.hpp index 5247f57..cb9cb3b 100644 --- a/include/boost/intrusive/circular_slist_algorithms.hpp +++ b/include/boost/intrusive/circular_slist_algorithms.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/derivation_value_traits.hpp b/include/boost/intrusive/derivation_value_traits.hpp index 2036890..58467d5 100644 --- a/include/boost/intrusive/derivation_value_traits.hpp +++ b/include/boost/intrusive/derivation_value_traits.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index c0ef630..0db5f23 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -30,6 +30,7 @@ #include #include #include +#include //Implementation utilities #include #include @@ -572,7 +573,9 @@ template template #endif class hashtable_impl + : private detail::clear_on_destructor_base > { + template friend class detail::clear_on_destructor_base; public: typedef typename Config::value_traits value_traits; @@ -795,7 +798,7 @@ class hashtable_impl //! //! Throws: Nothing. ~hashtable_impl() - { this->clear(); } + {} //! Effects: Returns an iterator pointing to the beginning of the unordered_set. //! @@ -866,7 +869,7 @@ class hashtable_impl key_equal key_eq() const { return this->priv_equal(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: if constant-time size and cache_last options are disabled, //! average constant time (worst case, with empty() == true: O(this->bucket_count()). @@ -1045,6 +1048,18 @@ class hashtable_impl } } + //! Requires: value must be an lvalue + //! + //! Effects: Inserts the value into the unordered_set. + //! + //! Returns: An iterator to the inserted value. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. iterator insert_equal(reference value) { size_type bucket_num; @@ -1055,6 +1070,18 @@ class hashtable_impl return priv_insert_equal_find(value, bucket_num, hash_value, it); } + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Equivalent to this->insert_equal(t) for each element in [b, e). + //! + //! Complexity: Average case O(N), where N is std::distance(b, e). + //! Worst case O(N*this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. template void insert_equal(Iterator b, Iterator e) { @@ -1092,7 +1119,7 @@ class hashtable_impl //! Requires: Dereferencing iterator must yield an lvalue //! of type value_type. //! - //! Effects: Equivalent to this->insert(t) for each element in [b, e). + //! Effects: Equivalent to this->insert_unique(t) for each element in [b, e). //! //! Complexity: Average case O(N), where N is std::distance(b, e). //! Worst case O(N*this->size()). @@ -1275,6 +1302,12 @@ class hashtable_impl priv_erasure_update_cache(); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. diff --git a/include/boost/intrusive/intrusive_fwd.hpp b/include/boost/intrusive/intrusive_fwd.hpp index 38a622f..5b1e451 100644 --- a/include/boost/intrusive/intrusive_fwd.hpp +++ b/include/boost/intrusive/intrusive_fwd.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -311,6 +311,51 @@ template #endif class avl_set_member_hook; + +//treap/treap_set/treap_multiset +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class treap; + +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class treap_set; + +#ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class treap_multiset; + +//Default priority comparison functor +template +struct priority_compare; + //sgtree/sg_set/sg_multiset #ifndef BOOST_INTRUSIVE_VARIADIC_TEMPLATES template diff --git a/include/boost/intrusive/linear_slist_algorithms.hpp b/include/boost/intrusive/linear_slist_algorithms.hpp index a181a51..9d045a5 100644 --- a/include/boost/intrusive/linear_slist_algorithms.hpp +++ b/include/boost/intrusive/linear_slist_algorithms.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/link_mode.hpp b/include/boost/intrusive/link_mode.hpp index 525e150..16b9649 100644 --- a/include/boost/intrusive/link_mode.hpp +++ b/include/boost/intrusive/link_mode.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index c6d94f2..b1f944a 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -72,7 +73,9 @@ template template #endif class list_impl + : private detail::clear_on_destructor_base< list_impl > { + template friend class detail::clear_on_destructor_base; //Public typedefs public: typedef typename Config::value_traits value_traits; @@ -219,11 +222,7 @@ class list_impl //! Complexity: Linear to the number of elements in the list, if //! it's a safe-mode or auto-unlink value . Otherwise constant. ~list_impl() - { - if(safemode_or_autounlink){ - this->clear(); - } - } + {} //! Requires: value must be an lvalue. //! @@ -651,6 +650,12 @@ class list_impl return i.unconst(); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the element range pointed by b and e diff --git a/include/boost/intrusive/list_hook.hpp b/include/boost/intrusive/list_hook.hpp index 86745cf..2deceb0 100644 --- a/include/boost/intrusive/list_hook.hpp +++ b/include/boost/intrusive/list_hook.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/member_value_traits.hpp b/include/boost/intrusive/member_value_traits.hpp index b32f8c4..372334c 100644 --- a/include/boost/intrusive/member_value_traits.hpp +++ b/include/boost/intrusive/member_value_traits.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/options.hpp b/include/boost/intrusive/options.hpp index b937698..8ab0890 100644 --- a/include/boost/intrusive/options.hpp +++ b/include/boost/intrusive/options.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -278,6 +278,20 @@ struct equal /// @endcond }; +//!This option setter specifies the equality +//!functor for the value type +template +struct priority +{ +/// @cond + template + struct pack : Base + { + typedef Priority priority; + }; +/// @endcond +}; + //!This option setter specifies the hash //!functor for the value type template diff --git a/include/boost/intrusive/pointer_plus_bits.hpp b/include/boost/intrusive/pointer_plus_bits.hpp index ec1fe51..b2b51e8 100644 --- a/include/boost/intrusive/pointer_plus_bits.hpp +++ b/include/boost/intrusive/pointer_plus_bits.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/priority_compare.hpp b/include/boost/intrusive/priority_compare.hpp new file mode 100644 index 0000000..19d4265 --- /dev/null +++ b/include/boost/intrusive/priority_compare.hpp @@ -0,0 +1,39 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_PRIORITY_COMPARE_HPP +#define BOOST_INTRUSIVE_PRIORITY_COMPARE_HPP + +#include +#include + +#include + +namespace boost { +namespace intrusive { + +template +struct priority_compare + : public std::binary_function +{ + bool operator()(const T &val, const T &val2) const + { + return priority_order(val, val2); + } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_PRIORITY_COMPARE_HPP diff --git a/include/boost/intrusive/rbtree.hpp b/include/boost/intrusive/rbtree.hpp index 94d1a39..fa7aa4a 100644 --- a/include/boost/intrusive/rbtree.hpp +++ b/include/boost/intrusive/rbtree.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -77,7 +79,9 @@ template template #endif class rbtree_impl + : private detail::clear_on_destructor_base > { + template friend class detail::clear_on_destructor_base; public: typedef typename Config::value_traits value_traits; /// @cond @@ -200,8 +204,10 @@ class rbtree_impl //! //! Complexity: Constant. //! - //! Throws: Nothing unless the copy constructor of the value_compare object throws. - rbtree_impl( value_compare cmp = value_compare() + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructorof the value_compare object throws. Basic guarantee. + rbtree_impl( const value_compare &cmp = value_compare() , const value_traits &v_traits = value_traits()) : data_(cmp, v_traits) { @@ -218,10 +224,12 @@ class rbtree_impl //! Complexity: Linear in N if [b, e) is already sorted using //! comp and otherwise N * log N, where N is the distance between first and last. //! - //! Throws: Nothing unless the copy constructor of the value_compare object throws. + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare object throws. Basic guarantee. template rbtree_impl( bool unique, Iterator b, Iterator e - , value_compare cmp = value_compare() + , const value_compare &cmp = value_compare() , const value_traits &v_traits = value_traits()) : data_(cmp, v_traits) { @@ -241,7 +249,7 @@ class rbtree_impl //! //! Throws: Nothing. ~rbtree_impl() - { this->clear(); } + {} //! Effects: Returns an iterator pointing to the beginning of the tree. //! @@ -397,7 +405,7 @@ class rbtree_impl value_compare value_comp() const { return priv_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -407,7 +415,8 @@ class rbtree_impl //! Effects: Returns the number of elements stored in the tree. //! - //! Complexity: Linear to elements contained in *this. + //! Complexity: Linear to elements contained in *this + //! if constant-time size option is disabled. Constant time otherwise. //! //! Throws: Nothing. size_type size() const @@ -419,7 +428,7 @@ class rbtree_impl } } - //! Effects: Swaps the contents of two multisets. + //! Effects: Swaps the contents of two rbtrees. //! //! Complexity: Constant. //! @@ -445,7 +454,7 @@ class rbtree_impl //! Complexity: Average complexity for insert element is at //! most logarithmic. //! - //! Throws: Nothing. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -471,7 +480,7 @@ class rbtree_impl //! Complexity: Logarithmic in general, but it is amortized //! constant time if t is inserted immediately before hint. //! - //! Throws: Nothing. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -524,7 +533,7 @@ class rbtree_impl std::pair insert_unique(reference value) { insert_commit_data commit_data; - std::pair ret = insert_unique_check(value, commit_data); + std::pair ret = insert_unique_check(value, priv_comp(), commit_data); if(!ret.second) return ret; return std::pair (insert_unique_commit(value, commit_data), true); @@ -547,7 +556,7 @@ class rbtree_impl iterator insert_unique(const_iterator hint, reference value) { insert_commit_data commit_data; - std::pair ret = insert_unique_check(hint, value, commit_data); + std::pair ret = insert_unique_check(hint, value, priv_comp(), commit_data); if(!ret.second) return ret.first; return insert_unique_commit(value, commit_data); @@ -580,10 +589,36 @@ class rbtree_impl } } - std::pair insert_unique_check - (const_reference value, insert_commit_data &commit_data) - { return insert_unique_check(value, priv_comp(), commit_data); } - + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that + //! part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. template std::pair insert_unique_check (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) @@ -596,10 +631,38 @@ class rbtree_impl return std::pair(iterator(ret.first, this), ret.second); } - std::pair insert_unique_check - (const_iterator hint, const_reference value, insert_commit_data &commit_data) - { return insert_unique_check(hint, value, priv_comp(), commit_data); } - + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! constructing that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that key + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This can give a total + //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. template std::pair insert_unique_check (const_iterator hint, const KeyType &key @@ -613,6 +676,23 @@ class rbtree_impl return std::pair(iterator(ret.first, this), ret.second); } + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the container between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the avl_set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. iterator insert_unique_commit(reference value, const insert_commit_data &commit_data) { node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); @@ -632,9 +712,9 @@ class rbtree_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { - iterator ret(i); + const_iterator ret(i); ++ret; node_ptr to_erase(i.pointed_node()); if(safemode_or_autounlink) @@ -643,7 +723,7 @@ class rbtree_impl this->priv_size_traits().decrement(); if(safemode_or_autounlink) node_algorithms::init(to_erase); - return ret; + return ret.unconst(); } //! Effects: Erases the range pointed to by b end e. @@ -655,7 +735,7 @@ class rbtree_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { size_type n; return private_erase(b, e, n); } //! Effects: Erases all the elements with the given value. @@ -683,7 +763,11 @@ class rbtree_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { std::pair p = this->equal_range(key, comp); size_type n; @@ -703,7 +787,7 @@ class rbtree_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { node_ptr to_erase(i.pointed_node()); iterator ret(this->erase(i)); @@ -711,21 +795,11 @@ class rbtree_impl return ret; } - //! Requires: Disposer::operator()(pointer) shouldn't throw. - //! - //! Effects: Erases the range pointed to by b end e. - //! Disposer::operator()(pointer) is called for the removed elements. - //! - //! Complexity: Average complexity for erase range is at most - //! O(log(size() + N)), where N is the number of elements in the range. - //! - //! Throws: Nothing. - //! - //! Note: Invalidates the iterators - //! to the erased elements. + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) - { size_type n; return private_erase(b, e, n, disposer); } + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -749,6 +823,22 @@ class rbtree_impl return n; } + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) + { size_type n; return private_erase(b, e, n, disposer); } + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases all the elements with the given key. @@ -764,7 +854,11 @@ class rbtree_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { std::pair p = this->equal_range(key, comp); size_type n; @@ -1207,18 +1301,18 @@ class rbtree_impl /// @cond private: template - iterator private_erase(iterator b, iterator e, size_type &n, Disposer disposer) + iterator private_erase(const_iterator b, const_iterator e, size_type &n, Disposer disposer) { for(n = 0; b != e; ++n) this->erase_and_dispose(b++, disposer); - return b; + return b.unconst(); } - iterator private_erase(iterator b, iterator e, size_type &n) + iterator private_erase(const_iterator b, const_iterator e, size_type &n) { for(n = 0; b != e; ++n) this->erase(b++); - return b; + return b.unconst(); } /// @endcond diff --git a/include/boost/intrusive/rbtree_algorithms.hpp b/include/boost/intrusive/rbtree_algorithms.hpp index c408193..37140a3 100644 --- a/include/boost/intrusive/rbtree_algorithms.hpp +++ b/include/boost/intrusive/rbtree_algorithms.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/set.hpp b/include/boost/intrusive/set.hpp index d2dff1e..40d7c6b 100644 --- a/include/boost/intrusive/set.hpp +++ b/include/boost/intrusive/set.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -297,7 +298,7 @@ class set_impl value_compare value_comp() const { return tree_.value_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -499,7 +500,7 @@ class set_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { return tree_.erase(i); } //! Effects: Erases the range pointed to by b end e. @@ -513,7 +514,7 @@ class set_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { return tree_.erase(b, e); } //! Effects: Erases all the elements with the given value. @@ -541,7 +542,11 @@ class set_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase(key, comp); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -558,9 +563,15 @@ class set_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { return tree_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. @@ -576,7 +587,7 @@ class set_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { return tree_.erase_and_dispose(b, e, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -611,7 +622,11 @@ class set_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase_and_dispose(key, comp, disposer); } //! Effects: Erases all the elements of the container. @@ -1419,7 +1434,7 @@ class multiset_impl value_compare value_comp() const { return tree_.value_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -1528,7 +1543,7 @@ class multiset_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { return tree_.erase(i); } //! Effects: Erases the range pointed to by b end e. @@ -1542,7 +1557,7 @@ class multiset_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, iterator e) { return tree_.erase(b, e); } //! Effects: Erases all the elements with the given value. @@ -1570,7 +1585,11 @@ class multiset_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase(key, comp); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1587,9 +1606,15 @@ class multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { return tree_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Returns: An iterator to the element after the erased elements. @@ -1605,7 +1630,7 @@ class multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { return tree_.erase_and_dispose(b, e, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1640,7 +1665,11 @@ class multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase_and_dispose(key, comp, disposer); } //! Effects: Erases all the elements of the container. diff --git a/include/boost/intrusive/set_hook.hpp b/include/boost/intrusive/set_hook.hpp index 473dfe3..1420480 100644 --- a/include/boost/intrusive/set_hook.hpp +++ b/include/boost/intrusive/set_hook.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/sg_set.hpp b/include/boost/intrusive/sg_set.hpp index b3570fb..4c519c1 100644 --- a/include/boost/intrusive/sg_set.hpp +++ b/include/boost/intrusive/sg_set.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace boost { @@ -296,7 +297,7 @@ class sg_set_impl value_compare value_comp() const { return tree_.value_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -498,7 +499,7 @@ class sg_set_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { return tree_.erase(i); } //! Effects: Erases the range pointed to by b end e. @@ -512,7 +513,7 @@ class sg_set_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { return tree_.erase(b, e); } //! Effects: Erases all the elements with the given value. @@ -540,7 +541,11 @@ class sg_set_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase(key, comp); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -557,9 +562,15 @@ class sg_set_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { return tree_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. @@ -575,7 +586,7 @@ class sg_set_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { return tree_.erase_and_dispose(b, e, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -610,7 +621,11 @@ class sg_set_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase_and_dispose(key, comp, disposer); } //! Effects: Erases all the elements of the container. @@ -1458,7 +1473,7 @@ class sg_multiset_impl value_compare value_comp() const { return tree_.value_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -1567,7 +1582,7 @@ class sg_multiset_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { return tree_.erase(i); } //! Effects: Erases the range pointed to by b end e. @@ -1581,7 +1596,7 @@ class sg_multiset_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { return tree_.erase(b, e); } //! Effects: Erases all the elements with the given value. @@ -1609,7 +1624,11 @@ class sg_multiset_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase(key, comp); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1626,9 +1645,15 @@ class sg_multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { return tree_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Returns: An iterator to the element after the erased elements. @@ -1644,7 +1669,7 @@ class sg_multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { return tree_.erase_and_dispose(b, e, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1679,7 +1704,11 @@ class sg_multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase_and_dispose(key, comp, disposer); } //! Effects: Erases all the elements of the container. diff --git a/include/boost/intrusive/sgtree.hpp b/include/boost/intrusive/sgtree.hpp index 63022a4..0d19919 100644 --- a/include/boost/intrusive/sgtree.hpp +++ b/include/boost/intrusive/sgtree.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -204,7 +206,9 @@ template template #endif class sgtree_impl + : private detail::clear_on_destructor_base > { + template friend class detail::clear_on_destructor_base; public: typedef typename Config::value_traits value_traits; /// @cond @@ -354,8 +358,10 @@ class sgtree_impl //! //! Complexity: Constant. //! - //! Throws: Nothing unless the copy constructor of the value_compare object throws. - sgtree_impl( value_compare cmp = value_compare() + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructorof the value_compare object throws. Basic guarantee. + sgtree_impl( const value_compare &cmp = value_compare() , const value_traits &v_traits = value_traits()) : data_(cmp, v_traits) { @@ -372,10 +378,12 @@ class sgtree_impl //! Complexity: Linear in N if [b, e) is already sorted using //! comp and otherwise N * log N, where N is the distance between first and last. //! - //! Throws: Nothing unless the copy constructor of the value_compare object throws. + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare object throws. Basic guarantee. template sgtree_impl( bool unique, Iterator b, Iterator e - , value_compare cmp = value_compare() + , const value_compare &cmp = value_compare() , const value_traits &v_traits = value_traits()) : data_(cmp, v_traits) { @@ -395,7 +403,7 @@ class sgtree_impl //! //! Throws: Nothing. ~sgtree_impl() - { this->clear(); } + {} //! Effects: Returns an iterator pointing to the beginning of the tree. //! @@ -551,7 +559,7 @@ class sgtree_impl value_compare value_comp() const { return priv_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -561,7 +569,8 @@ class sgtree_impl //! Effects: Returns the number of elements stored in the tree. //! - //! Complexity: Linear to elements contained in *this. + //! Complexity: Linear to elements contained in *this + //! if constant-time size option is disabled. Constant time otherwise. //! //! Throws: Nothing. size_type size() const @@ -573,7 +582,7 @@ class sgtree_impl } } - //! Effects: Swaps the contents of two multisets. + //! Effects: Swaps the contents of two sgtrees. //! //! Complexity: Constant. //! @@ -601,7 +610,7 @@ class sgtree_impl //! Complexity: Average complexity for insert element is at //! most logarithmic. //! - //! Throws: Nothing. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -688,7 +697,7 @@ class sgtree_impl std::pair insert_unique(reference value) { insert_commit_data commit_data; - std::pair ret = insert_unique_check(value, commit_data); + std::pair ret = insert_unique_check(value, priv_comp(), commit_data); if(!ret.second) return ret; return std::pair (insert_unique_commit(value, commit_data), true); @@ -711,7 +720,7 @@ class sgtree_impl iterator insert_unique(const_iterator hint, reference value) { insert_commit_data commit_data; - std::pair ret = insert_unique_check(hint, value, commit_data); + std::pair ret = insert_unique_check(hint, value, priv_comp(), commit_data); if(!ret.second) return ret.first; return insert_unique_commit(value, commit_data); @@ -744,10 +753,36 @@ class sgtree_impl } } - std::pair insert_unique_check - (const_reference value, insert_commit_data &commit_data) - { return insert_unique_check(value, priv_comp(), commit_data); } - + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that + //! part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. template std::pair insert_unique_check (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) @@ -760,10 +795,38 @@ class sgtree_impl return std::pair(iterator(ret.first, this), ret.second); } - std::pair insert_unique_check - (const_iterator hint, const_reference value, insert_commit_data &commit_data) - { return insert_unique_check(hint, value, priv_comp(), commit_data); } - + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! constructing that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that key + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This can give a total + //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. template std::pair insert_unique_check (const_iterator hint, const KeyType &key @@ -777,6 +840,23 @@ class sgtree_impl return std::pair(iterator(ret.first, this), ret.second); } + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the container between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the avl_set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. iterator insert_unique_commit(reference value, const insert_commit_data &commit_data) { node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); @@ -799,9 +879,9 @@ class sgtree_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { - iterator ret(i); + const_iterator ret(i); ++ret; node_ptr to_erase(i.pointed_node()); if(safemode_or_autounlink) @@ -814,7 +894,7 @@ class sgtree_impl this->priv_size_traits().decrement(); if(safemode_or_autounlink) node_algorithms::init(to_erase); - return ret; + return ret.unconst(); } //! Effects: Erases the range pointed to by b end e. @@ -826,7 +906,7 @@ class sgtree_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { size_type n; return private_erase(b, e, n); } //! Effects: Erases all the elements with the given value. @@ -854,7 +934,11 @@ class sgtree_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { std::pair p = this->equal_range(key, comp); size_type n; @@ -874,7 +958,7 @@ class sgtree_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { node_ptr to_erase(i.pointed_node()); iterator ret(this->erase(i)); @@ -882,6 +966,12 @@ class sgtree_impl return ret; } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. @@ -895,7 +985,7 @@ class sgtree_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { size_type n; return private_erase(b, e, n, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -935,7 +1025,11 @@ class sgtree_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { std::pair p = this->equal_range(key, comp); size_type n; @@ -1437,18 +1531,18 @@ class sgtree_impl /// @cond private: template - iterator private_erase(iterator b, iterator e, size_type &n, Disposer disposer) + iterator private_erase(const_iterator b, const_iterator e, size_type &n, Disposer disposer) { for(n = 0; b != e; ++n) this->erase_and_dispose(b++, disposer); - return b; + return b.unconst(); } - iterator private_erase(iterator b, iterator e, size_type &n) + iterator private_erase(const_iterator b, const_iterator e, size_type &n) { for(n = 0; b != e; ++n) this->erase(b++); - return b; + return b.unconst(); } /// @endcond diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index 0577d71..a08752e 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -102,7 +103,9 @@ template template #endif class slist_impl + : private detail::clear_on_destructor_base > { + template friend class detail::clear_on_destructor_base; //Public typedefs public: typedef typename Config::value_traits value_traits; @@ -295,7 +298,7 @@ class slist_impl //! Complexity: Linear to the number of elements in the list, if //! it's a safe-mode or auto-unlink value. Otherwise constant. ~slist_impl() - { this->clear(); } + {} //! Effects: Erases all the elements of the container. //! @@ -978,6 +981,12 @@ class slist_impl iterator erase_and_dispose(const_iterator i, Disposer disposer) { return this->erase_after_and_dispose(this->previous(i), disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: first and last must be valid iterator to elements in *this. //! Disposer::operator()(pointer) shouldn't throw. //! diff --git a/include/boost/intrusive/slist_hook.hpp b/include/boost/intrusive/slist_hook.hpp index 8164d62..7779b98 100644 --- a/include/boost/intrusive/slist_hook.hpp +++ b/include/boost/intrusive/slist_hook.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/splay_set.hpp b/include/boost/intrusive/splay_set.hpp index f86ae8b..79bdbc1 100644 --- a/include/boost/intrusive/splay_set.hpp +++ b/include/boost/intrusive/splay_set.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace boost { @@ -296,7 +297,7 @@ class splay_set_impl value_compare value_comp() const { return tree_.value_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -497,7 +498,7 @@ class splay_set_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { return tree_.erase(i); } //! Effects: Erases the range pointed to by b end e. @@ -511,7 +512,7 @@ class splay_set_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { return tree_.erase(b, e); } //! Effects: Erases all the elements with the given value. @@ -539,7 +540,11 @@ class splay_set_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase(key, comp); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -556,9 +561,15 @@ class splay_set_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { return tree_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. @@ -574,7 +585,7 @@ class splay_set_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { return tree_.erase_and_dispose(b, e, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -609,7 +620,11 @@ class splay_set_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond +) { return tree_.erase_and_dispose(key, comp, disposer); } //! Effects: Erases all the elements of the container. @@ -1494,7 +1509,7 @@ class splay_multiset_impl value_compare value_comp() const { return tree_.value_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -1602,7 +1617,7 @@ class splay_multiset_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { return tree_.erase(i); } //! Effects: Erases the range pointed to by b end e. @@ -1616,7 +1631,7 @@ class splay_multiset_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { return tree_.erase(b, e); } //! Effects: Erases all the elements with the given value. @@ -1644,7 +1659,11 @@ class splay_multiset_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase(key, comp); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1661,9 +1680,15 @@ class splay_multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { return tree_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Returns: An iterator to the element after the erased elements. @@ -1679,7 +1704,7 @@ class splay_multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { return tree_.erase_and_dispose(b, e, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1714,7 +1739,11 @@ class splay_multiset_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { return tree_.erase_and_dispose(key, comp, disposer); } //! Effects: Erases all the elements of the container. diff --git a/include/boost/intrusive/splay_set_hook.hpp b/include/boost/intrusive/splay_set_hook.hpp index 17f18bc..472fde3 100644 --- a/include/boost/intrusive/splay_set_hook.hpp +++ b/include/boost/intrusive/splay_set_hook.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/splaytree.hpp b/include/boost/intrusive/splaytree.hpp index 94a0985..971f846 100644 --- a/include/boost/intrusive/splaytree.hpp +++ b/include/boost/intrusive/splaytree.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -76,7 +78,9 @@ template template #endif class splaytree_impl + : private detail::clear_on_destructor_base > { + template friend class detail::clear_on_destructor_base; public: typedef typename Config::value_traits value_traits; /// @cond @@ -199,9 +203,11 @@ class splaytree_impl //! //! Complexity: Constant. //! - //! Throws: Nothing unless the copy constructor of the value_compare object throws. - splaytree_impl( value_compare cmp = value_compare() - , const value_traits &v_traits = value_traits()) + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructorof the value_compare object throws. Basic guarantee. + splaytree_impl( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) : data_(cmp, v_traits) { node_algorithms::init_header(&priv_header()); @@ -217,11 +223,13 @@ class splaytree_impl //! Complexity: Linear in N if [b, e) is already sorted using //! comp and otherwise amortized N * log N, where N is the distance between first and last. //! - //! Throws: Nothing unless the copy constructor of the value_compare object throws. + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare object throws. Basic guarantee. template - splaytree_impl( bool unique, Iterator b, Iterator e - , value_compare cmp = value_compare() - , const value_traits &v_traits = value_traits()) + splaytree_impl ( bool unique, Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) : data_(cmp, v_traits) { node_algorithms::init_header(&priv_header()); @@ -241,7 +249,7 @@ class splaytree_impl //! //! Throws: Nothing. ~splaytree_impl() - { this->clear(); } + {} //! Effects: Returns an iterator pointing to the beginning of the tree. //! @@ -397,7 +405,7 @@ class splaytree_impl value_compare value_comp() const { return priv_comp(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: Constant. //! @@ -407,7 +415,8 @@ class splaytree_impl //! Effects: Returns the number of elements stored in the tree. //! - //! Complexity: Linear to elements contained in *this. + //! Complexity: Linear to elements contained in *this + //! if constant-time size option is disabled. Constant time otherwise. //! //! Throws: Nothing. size_type size() const @@ -420,7 +429,7 @@ class splaytree_impl } } - //! Effects: Swaps the contents of two multisets. + //! Effects: Swaps the contents of two splaytrees. //! //! Complexity: Constant. //! @@ -446,7 +455,7 @@ class splaytree_impl //! Complexity: Average complexity for insert element is amortized //! logarithmic. //! - //! Throws: Nothing. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -472,7 +481,7 @@ class splaytree_impl //! Complexity: Amortized logarithmic in general, but it is amortized //! constant time if t is inserted immediately before hint. //! - //! Throws: Nothing. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -526,7 +535,7 @@ class splaytree_impl std::pair insert_unique(reference value) { insert_commit_data commit_data; - std::pair ret = insert_unique_check(value, commit_data); + std::pair ret = insert_unique_check(value, priv_comp(), commit_data); if(!ret.second) return ret; return std::pair (insert_unique_commit(value, commit_data), true); @@ -549,7 +558,7 @@ class splaytree_impl iterator insert_unique(const_iterator hint, reference value) { insert_commit_data commit_data; - std::pair ret = insert_unique_check(hint, value, commit_data); + std::pair ret = insert_unique_check(hint, value, priv_comp(), commit_data); if(!ret.second) return ret.first; return insert_unique_commit(value, commit_data); @@ -575,10 +584,36 @@ class splaytree_impl this->insert_unique(*b); } - std::pair insert_unique_check - (const_reference value, insert_commit_data &commit_data) - { return insert_unique_check(value, priv_comp(), commit_data); } - + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that + //! part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. template std::pair insert_unique_check (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) @@ -591,10 +626,38 @@ class splaytree_impl return std::pair(iterator(ret.first, this), ret.second); } - std::pair insert_unique_check - (const_iterator hint, const_reference value, insert_commit_data &commit_data) - { return insert_unique_check(hint, value, priv_comp(), commit_data); } - + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! constructing that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that key + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This can give a total + //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. template std::pair insert_unique_check (const_iterator hint, const KeyType &key @@ -608,6 +671,23 @@ class splaytree_impl return std::pair(iterator(ret.first, this), ret.second); } + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the container between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the avl_set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. iterator insert_unique_commit(reference value, const insert_commit_data &commit_data) { node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); @@ -627,9 +707,9 @@ class splaytree_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator i) + iterator erase(const_iterator i) { - iterator ret(i); + const_iterator ret(i); ++ret; node_ptr to_erase(i.pointed_node()); if(safemode_or_autounlink) @@ -638,7 +718,7 @@ class splaytree_impl this->priv_size_traits().decrement(); if(safemode_or_autounlink) node_algorithms::init(to_erase); - return ret; + return ret.unconst(); } //! Effects: Erases the range pointed to by b end e. @@ -650,7 +730,7 @@ class splaytree_impl //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. - iterator erase(iterator b, iterator e) + iterator erase(const_iterator b, const_iterator e) { size_type n; return private_erase(b, e, n); } //! Effects: Erases all the elements with the given value. @@ -678,7 +758,11 @@ class splaytree_impl //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - size_type erase(const KeyType& key, KeyValueCompare comp) + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { std::pair p = this->equal_range(key, comp); size_type n; @@ -698,7 +782,7 @@ class splaytree_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator i, Disposer disposer) + iterator erase_and_dispose(const_iterator i, Disposer disposer) { node_ptr to_erase(i.pointed_node()); iterator ret(this->erase(i)); @@ -706,6 +790,12 @@ class splaytree_impl return ret; } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. @@ -719,7 +809,7 @@ class splaytree_impl //! Note: Invalidates the iterators //! to the erased elements. template - iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) { size_type n; return private_erase(b, e, n, disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -759,7 +849,11 @@ class splaytree_impl //! Note: Invalidates the iterators //! to the erased elements. template - size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) { std::pair p = this->equal_range(key, comp); size_type n; @@ -1293,18 +1387,18 @@ class splaytree_impl /// @cond private: template - iterator private_erase(iterator b, iterator e, size_type &n, Disposer disposer) + iterator private_erase(const_iterator b, const_iterator e, size_type &n, Disposer disposer) { for(n = 0; b != e; ++n) this->erase_and_dispose(b++, disposer); - return b; + return b.unconst(); } - iterator private_erase(iterator b, iterator e, size_type &n) + iterator private_erase(const_iterator b, const_iterator e, size_type &n) { for(n = 0; b != e; ++n) this->erase(b++); - return b; + return b.unconst(); } /// @endcond @@ -1529,14 +1623,14 @@ class splaytree BOOST_STATIC_ASSERT((detail::is_same::value)); splaytree( const value_compare &cmp = value_compare() - , const value_traits &v_traits = value_traits()) + , const value_traits &v_traits = value_traits()) : Base(cmp, v_traits) {} template splaytree( bool unique, Iterator b, Iterator e - , const value_compare &cmp = value_compare() - , const value_traits &v_traits = value_traits()) + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) : Base(unique, b, e, cmp, v_traits) {} diff --git a/include/boost/intrusive/treap.hpp b/include/boost/intrusive/treap.hpp new file mode 100644 index 0000000..7298db3 --- /dev/null +++ b/include/boost/intrusive/treap.hpp @@ -0,0 +1,1663 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTRUSIVE_TRIE_HPP +#define BOOST_INTRUSIVE_TRIE_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +/// @cond + +template +struct treap_setopt +{ + typedef ValueTraits value_traits; + typedef Compare compare; + typedef PrioCompare priority_compare; + typedef SizeType size_type; + static const bool constant_time_size = ConstantTimeSize; +}; + +template +struct treap_set_defaults + : pack_options + < none + , base_hook + , constant_time_size + , size_type + , compare > + , priority > + >::type +{}; + +/// @endcond + +//! The class template treap is an intrusive treap container that +//! is used to construct intrusive set and multiset containers. The no-throw +//! guarantee holds only, if the value_compare object and priority_compare object +//! don't throw. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<>, +//! \c compare<> and \c priority_compare<> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +class treap_impl + : private detail::clear_on_destructor_base > +{ + template friend class detail::clear_on_destructor_base; + public: + typedef typename Config::value_traits value_traits; + /// @cond + static const bool external_value_traits = + detail::external_value_traits_is_true::value; + typedef typename detail::eval_if_c + < external_value_traits + , detail::eval_value_traits + , detail::identity + >::type real_value_traits; + /// @endcond + typedef typename real_value_traits::pointer pointer; + typedef typename real_value_traits::const_pointer const_pointer; + typedef typename std::iterator_traits::value_type value_type; + typedef value_type key_type; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename Config::size_type size_type; + typedef typename Config::compare value_compare; + typedef typename Config::priority_compare priority_compare; + typedef value_compare key_compare; + typedef tree_iterator iterator; + typedef tree_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef typename real_value_traits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef treap_algorithms node_algorithms; + + static const bool constant_time_size = Config::constant_time_size; + static const bool stateful_value_traits = detail::store_cont_ptr_on_it::value; + + /// @cond + private: + typedef detail::size_holder size_traits; + + //noncopyable + treap_impl (const treap_impl&); + treap_impl operator =(const treap_impl&); + + enum { safemode_or_autounlink = + (int)real_value_traits::link_mode == (int)auto_unlink || + (int)real_value_traits::link_mode == (int)safe_link }; + + //Constant-time size is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(constant_time_size && ((int)real_value_traits::link_mode == (int)auto_unlink))); + + struct header_plus_size : public size_traits + { node header_; }; + + struct node_plus_pred_t : public detail::ebo_functor_holder + { + node_plus_pred_t(const value_compare &comp, const priority_compare &p_comp) + : detail::ebo_functor_holder(comp) + , header_plus_priority_size_(p_comp) + {} + struct header_plus_priority_size + : public detail::ebo_functor_holder + { + header_plus_priority_size(const priority_compare &p_comp) + : detail::ebo_functor_holder(p_comp) + {} + header_plus_size header_plus_size_; + } header_plus_priority_size_; + }; + + struct data_t : public treap_impl::value_traits + { + typedef typename treap_impl::value_traits value_traits; + data_t(const value_compare & comp, const priority_compare &pcomp, const value_traits &val_traits) + : value_traits(val_traits), node_plus_pred_(comp, pcomp) + {} + node_plus_pred_t node_plus_pred_; + } data_; + + const value_compare &priv_comp() const + { return data_.node_plus_pred_.get(); } + + value_compare &priv_comp() + { return data_.node_plus_pred_.get(); } + + const priority_compare &priv_pcomp() const + { return data_.node_plus_pred_.header_plus_priority_size_.get(); } + + priority_compare &priv_pcomp() + { return data_.node_plus_pred_.header_plus_priority_size_.get(); } + + const node &priv_header() const + { return data_.node_plus_pred_.header_plus_priority_size_.header_plus_size_.header_; } + + node &priv_header() + { return data_.node_plus_pred_.header_plus_priority_size_.header_plus_size_.header_; } + + static node_ptr uncast(const_node_ptr ptr) + { + return node_ptr(const_cast(detail::get_pointer(ptr))); + } + + size_traits &priv_size_traits() + { return data_.node_plus_pred_.header_plus_priority_size_.header_plus_size_; } + + const size_traits &priv_size_traits() const + { return data_.node_plus_pred_.header_plus_priority_size_.header_plus_size_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_.get_value_traits(*this); } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_; } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_.get_value_traits(*this); } + + /// @endcond + + public: + + const real_value_traits &get_real_value_traits() const + { return this->get_real_value_traits(detail::bool_()); } + + real_value_traits &get_real_value_traits() + { return this->get_real_value_traits(detail::bool_()); } + + typedef typename node_algorithms::insert_commit_data insert_commit_data; + + //! Effects: Constructs an empty tree. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor of the value_compare/priority_compare objects throw. Basic guarantee. + treap_impl( const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : data_(cmp, pcmp, v_traits) + { + node_algorithms::init_header(&priv_header()); + this->priv_size_traits().set_size(size_type(0)); + } + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! cmp must be a comparison function that induces a strict weak ordering. + //! + //! Effects: Constructs an empty tree and inserts elements from + //! [b, e). + //! + //! Complexity: Linear in N if [b, e) is already sorted using + //! comp and otherwise N * log N, where N is the distance between first and last. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare/priority_compare objects + //! throw. Basic guarantee. + template + treap_impl( bool unique, Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : data_(cmp, pcmp, v_traits) + { + node_algorithms::init_header(&priv_header()); + this->priv_size_traits().set_size(size_type(0)); + if(unique) + this->insert_unique(b, e); + else + this->insert_equal(b, e); + } + + //! Effects: Detaches all elements from this. The objects in the set + //! are not deleted (i.e. no destructors are called), but the nodes according to + //! the value_traits template parameter are reinitialized and thus can be reused. + //! + //! Complexity: Linear to elements contained in *this + //! if constant-time size option is disabled. Constant time otherwise. + //! + //! Throws: Nothing. + ~treap_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return iterator (node_traits::get_left(node_ptr(&priv_header())), this); } + + //! Effects: Returns a const_iterator pointing to the beginning of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return this->cbegin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return const_iterator (node_traits::get_left(const_node_ptr(&priv_header())), this); } + + //! Effects: Returns an iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return iterator (node_ptr(&priv_header()), this); } + + //! Effects: Returns a const_iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a const_iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return const_iterator (uncast(const_node_ptr(&priv_header())), this); } + + + //! Effects: Returns an iterator pointing to the highest priority object of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator top() + { return this->empty() ? this->end() : iterator (node_traits::get_parent(node_ptr(&priv_header())), this); } + + //! Effects: Returns a const_iterator pointing to the highest priority object of the tree.. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator top() const + { return this->ctop(); } + + //! Effects: Returns a const_iterator pointing to the highest priority object of the tree.. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator ctop() const + { return this->empty() ? this->cend() : const_iterator (node_traits::get_parent(const_node_ptr(&priv_header())), this); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return reverse_iterator(this->end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(this->end()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return reverse_iterator(this->begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rend() const + { return const_reverse_iterator(this->begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return const_reverse_iterator(this->begin()); } + + //! Effects: Returns a reverse_iterator pointing to the highest priority object of the + //! reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rtop() + { return reverse_iterator(this->top()); } + + //! Effects: Returns a const_reverse_iterator pointing to the highest priority objec + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rtop() const + { return const_reverse_iterator(this->top()); } + + //! Effects: Returns a const_reverse_iterator pointing to the highest priority object + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crtop() const + { return const_reverse_iterator(this->top()); } + + //! Precondition: end_iterator must be a valid end iterator + //! of treap. + //! + //! Effects: Returns a const reference to the treap associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static treap_impl &container_from_end_iterator(iterator end_iterator) + { return priv_container_from_end_iterator(end_iterator); } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of treap. + //! + //! Effects: Returns a const reference to the treap associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const treap_impl &container_from_end_iterator(const_iterator end_iterator) + { return priv_container_from_end_iterator(end_iterator); } + + //! Precondition: it must be a valid iterator + //! of treap. + //! + //! Effects: Returns a const reference to the tree associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static treap_impl &container_from_iterator(iterator it) + { return priv_container_from_iterator(it); } + + //! Precondition: it must be a valid end const_iterator + //! of treap. + //! + //! Effects: Returns a const reference to the tree associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static const treap_impl &container_from_iterator(const_iterator it) + { return priv_container_from_iterator(it); } + + //! Effects: Returns the value_compare object used by the tree. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return this->priv_comp(); } + + //! Effects: Returns the priority_compare object used by the tree. + //! + //! Complexity: Constant. + //! + //! Throws: If priority_compare copy-constructor throws. + priority_compare priority_comp() const + { return this->priv_pcomp(); } + + //! Effects: Returns true if the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return node_algorithms::unique(const_node_ptr(&priv_header())); } + + //! Effects: Returns the number of elements stored in the tree. + //! + //! Complexity: Linear to elements contained in *this + //! if constant-time size option is disabled. Constant time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { + if(constant_time_size) + return this->priv_size_traits().get_size(); + else{ + return (size_type)node_algorithms::size(const_node_ptr(&priv_header())); + } + } + + //! Effects: Swaps the contents of two treaps. + //! + //! Complexity: Constant. + //! + //! Throws: If the comparison functor's swap call throws. + void swap(treap_impl& other) + { + //This can throw + using std::swap; + swap(priv_comp(), priv_comp()); + swap(priv_pcomp(), priv_pcomp()); + //These can't throw + node_algorithms::swap_tree(node_ptr(&priv_header()), node_ptr(&other.priv_header())); + if(constant_time_size){ + size_type backup = this->priv_size_traits().get_size(); + this->priv_size_traits().set_size(other.priv_size_traits().get_size()); + other.priv_size_traits().set_size(backup); + } + } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the tree before the upper bound. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If the internal value_compare or priority_compare funcstions throw. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_equal(reference value) + { + detail::key_nodeptr_comp + key_node_comp(priv_comp(), this); + detail::key_nodeptr_comp + key_node_pcomp(priv_pcomp(), this); + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + this->priv_size_traits().increment(); + return iterator(node_algorithms::insert_equal_upper_bound + (node_ptr(&priv_header()), to_insert, key_node_comp, key_node_pcomp), this); + } + + //! Requires: value must be an lvalue, and "hint" must be + //! a valid iterator. + //! + //! Effects: Inserts x into the tree, using "hint" as a hint to + //! where it will be inserted. If "hint" is the upper_bound + //! the insertion takes constant time (two comparisons in the worst case) + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the internal value_compare or priority_compare funcstions throw. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_equal(const_iterator hint, reference value) + { + detail::key_nodeptr_comp + key_node_comp(priv_comp(), this); + detail::key_nodeptr_comp + key_node_pcomp(priv_pcomp(), this); + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + this->priv_size_traits().increment(); + return iterator(node_algorithms::insert_equal + (node_ptr(&priv_header()), hint.pointed_node(), to_insert, key_node_comp, key_node_pcomp), this); + } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Inserts a each element of a range into the tree + //! before the upper bound of the key of each element. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: If the internal value_compare or priority_compare funcstions throw. + //! Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert_equal(Iterator b, Iterator e) + { + iterator end(this->end()); + for (; b != e; ++b) + this->insert_equal(end, *b); + } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the tree if the value + //! is not already present. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If the internal value_compare or priority_compare funcstions throw. + //! Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + std::pair insert_unique(reference value) + { + insert_commit_data commit_data; + std::pair ret = insert_unique_check(value, priv_comp(), priv_pcomp(), commit_data); + if(!ret.second) + return ret; + return std::pair (insert_unique_commit(value, commit_data), true); + } + + //! Requires: value must be an lvalue, and "hint" must be + //! a valid iterator + //! + //! Effects: Tries to insert x into the tree, using "hint" as a hint + //! to where it will be inserted. + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time (two comparisons in the worst case) + //! if t is inserted immediately before hint. + //! + //! Throws: If the internal value_compare or priority_compare funcstions throw. + //! Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_unique(const_iterator hint, reference value) + { + insert_commit_data commit_data; + std::pair ret = insert_unique_check(hint, value, priv_comp(), priv_pcomp(), commit_data); + if(!ret.second) + return ret.first; + return insert_unique_commit(value, commit_data); + } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Tries to insert each element of a range into the tree. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: If the internal value_compare or priority_compare funcstions throw. + //! Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert_unique(Iterator b, Iterator e) + { + if(this->empty()){ + iterator end(this->end()); + for (; b != e; ++b) + this->insert_unique(end, *b); + } + else{ + for (; b != e; ++b) + this->insert_unique(*b); + } + } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that + //! part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. + template + std::pair insert_unique_check + ( const KeyType &key, KeyValueCompare key_value_comp + , KeyValuePrioCompare key_value_pcomp, insert_commit_data &commit_data) + { + detail::key_nodeptr_comp + comp(key_value_comp, this); + detail::key_nodeptr_comp + pcomp(key_value_pcomp, this); + std::pair ret = + (node_algorithms::insert_unique_check + (node_ptr(&priv_header()), key, comp, pcomp, commit_data)); + return std::pair(iterator(ret.first, this), ret.second); + } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! constructing that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that key + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This can give a total + //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. + template + std::pair insert_unique_check + ( const_iterator hint, const KeyType &key + , KeyValueCompare key_value_comp + , KeyValuePrioCompare key_value_pcomp + , insert_commit_data &commit_data) + { + detail::key_nodeptr_comp + comp(key_value_comp, this); + detail::key_nodeptr_comp + pcomp(key_value_pcomp, this); + std::pair ret = + (node_algorithms::insert_unique_check + (node_ptr(&priv_header()), hint.pointed_node(), key, comp, pcomp, commit_data)); + return std::pair(iterator(ret.first, this), ret.second); + } + + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the container between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the avl_set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + iterator insert_unique_commit(reference value, const insert_commit_data &commit_data) + { + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + this->priv_size_traits().increment(); + node_algorithms::insert_unique_commit(node_ptr(&priv_header()), to_insert, commit_data); + return iterator(to_insert, this); + } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: if the internal priority_compare function throws. Strong guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator i) + { + const_iterator ret(i); + ++ret; + node_ptr to_erase(i.pointed_node()); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(!node_algorithms::unique(to_erase)); + detail::key_nodeptr_comp + key_node_pcomp(priv_pcomp(), this); + node_algorithms::erase(&priv_header(), to_erase,key_node_pcomp); + this->priv_size_traits().decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + return ret.unconst(); + } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: if the internal priority_compare function throws. Strong guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator b, const_iterator e) + { size_type n; return private_erase(b, e, n); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: if the internal priority_compare function throws. Strong guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return this->erase(value, priv_comp()); } + + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: if the internal priority_compare function throws. Strong guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { + std::pair p = this->equal_range(key, comp); + size_type n; + private_erase(p.first, p.second, n); + return n; + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by pos. + //! Disposer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: if the internal priority_compare function throws. Strong guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator i, Disposer disposer) + { + node_ptr to_erase(i.pointed_node()); + iterator ret(this->erase(i)); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + return ret; + } + + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: if the internal priority_compare function throws. Strong guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) + { size_type n; return private_erase(b, e, n, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: if the priority_compare function throws then weak guarantee and heap invariants are broken. + //! The safest thing would be to clear or destroy the container. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_dispose(const_reference value, Disposer disposer) + { + std::pair p = this->equal_range(value); + size_type n; + private_erase(p.first, p.second, n, disposer); + return n; + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: if the priority_compare function throws then weak guarantee and heap invariants are broken. + //! The safest thing would be to clear or destroy the container. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { + std::pair p = this->equal_range(key, comp); + size_type n; + private_erase(p.first, p.second, n, disposer); + return n; + } + + //! Effects: Erases all of the elements. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { + if(safemode_or_autounlink){ + this->clear_and_dispose(detail::null_disposer()); + } + else{ + node_algorithms::init_header(&priv_header()); + this->priv_size_traits().set_size(0); + } + } + + //! Effects: Erases all of the elements calling disposer(p) for + //! each node to be erased. + //! Complexity: Average complexity for is at most O(log(size() + N)), + //! where N is the number of elements in the container. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. Calls N times to disposer functor. + template + void clear_and_dispose(Disposer disposer) + { + node_algorithms::clear_and_dispose(node_ptr(&priv_header()) + , detail::node_disposer(disposer, this)); + node_algorithms::init_header(&priv_header()); + this->priv_size_traits().set_size(0); + } + + //! Effects: Returns the number of contained elements with the given value + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given value. + //! + //! Throws: Nothing. + size_type count(const_reference value) const + { return this->count(value, priv_comp()); } + + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: Nothing. + template + size_type count(const KeyType &key, KeyValueCompare comp) const + { + std::pair ret = this->equal_range(key, comp); + return std::distance(ret.first, ret.second); + } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + iterator lower_bound(const_reference value) + { return this->lower_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + const_iterator lower_bound(const_reference value) const + { return this->lower_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + iterator lower_bound(const KeyType &key, KeyValueCompare comp) + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return iterator(node_algorithms::lower_bound + (const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! Effects: Returns a const iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + const_iterator lower_bound(const KeyType &key, KeyValueCompare comp) const + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return const_iterator(node_algorithms::lower_bound + (const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + iterator upper_bound(const_reference value) + { return this->upper_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k according to comp or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + iterator upper_bound(const KeyType &key, KeyValueCompare comp) + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return iterator(node_algorithms::upper_bound + (const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + const_iterator upper_bound(const_reference value) const + { return this->upper_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k according to comp or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + const_iterator upper_bound(const KeyType &key, KeyValueCompare comp) const + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return const_iterator(node_algorithms::upper_bound + (const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! Effects: Finds an iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + iterator find(const_reference value) + { return this->find(value, priv_comp()); } + + //! Effects: Finds an iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + iterator find(const KeyType &key, KeyValueCompare comp) + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return iterator + (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! Effects: Finds a const_iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + const_iterator find(const_reference value) const + { return this->find(value, priv_comp()); } + + //! Effects: Finds a const_iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + const_iterator find(const KeyType &key, KeyValueCompare comp) const + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return const_iterator + (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + std::pair equal_range(const_reference value) + { return this->equal_range(value, priv_comp()); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + std::pair equal_range(const KeyType &key, KeyValueCompare comp) + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + std::pair ret + (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp)); + return std::pair(iterator(ret.first, this), iterator(ret.second, this)); + } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + std::pair + equal_range(const_reference value) const + { return this->equal_range(value, priv_comp()); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + std::pair + equal_range(const KeyType &key, KeyValueCompare comp) const + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + std::pair ret + (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp)); + return std::pair(const_iterator(ret.first, this), const_iterator(ret.second, this)); + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. Copies the predicate from the source container. + //! + //! If cloner throws, all cloned elements are unlinked and disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. + template + void clone_from(const treap_impl &src, Cloner cloner, Disposer disposer) + { + this->clear_and_dispose(disposer); + if(!src.empty()){ + detail::exception_disposer + rollback(*this, disposer); + node_algorithms::clone + (const_node_ptr(&src.priv_header()) + ,node_ptr(&this->priv_header()) + ,detail::node_cloner(cloner, this) + ,detail::node_disposer(disposer, this)); + this->priv_size_traits().set_size(src.priv_size_traits().get_size()); + this->priv_comp() = src.priv_comp(); + rollback.release(); + } + } + + //! Effects: Unlinks the leftmost node from the tree. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + pointer unlink_leftmost_without_rebalance() + { + node_ptr to_be_disposed(node_algorithms::unlink_leftmost_without_rebalance + (node_ptr(&priv_header()))); + if(!to_be_disposed) + return 0; + this->priv_size_traits().decrement(); + if(safemode_or_autounlink)//If this is commented does not work with normal_link + node_algorithms::init(to_be_disposed); + return get_real_value_traits().to_value_ptr(to_be_disposed); + } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! with_this is not equivalent to *replace_this according to the + //! ordering and priority rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + void replace_node(iterator replace_this, reference with_this) + { + node_algorithms::replace_node( get_real_value_traits().to_node_ptr(*replace_this) + , node_ptr(&priv_header()) + , get_real_value_traits().to_node_ptr(with_this)); + } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { + BOOST_STATIC_ASSERT((!stateful_value_traits)); + return iterator (value_traits::to_node_ptr(value), 0); + } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { + BOOST_STATIC_ASSERT((!stateful_value_traits)); + return const_iterator (value_traits::to_node_ptr(const_cast (value)), 0); + } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return iterator (value_traits::to_node_ptr(value), this); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return const_iterator (value_traits::to_node_ptr(const_cast (value)), this); } + + //! Requires: value shall not be in a tree. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function puts the hook in the well-known default state + //! used by auto_unlink and safe hooks. + static void init_node(reference value) + { node_algorithms::init(value_traits::to_node_ptr(value)); } + + /// @cond + private: + template + iterator private_erase(const_iterator b, const_iterator e, size_type &n, Disposer disposer) + { + for(n = 0; b != e; ++n) + this->erase_and_dispose(b++, disposer); + return b.unconst(); + } + + iterator private_erase(const_iterator b, const_iterator e, size_type &n) + { + for(n = 0; b != e; ++n) + this->erase(b++); + return b.unconst(); + } + /// @endcond + + private: + static treap_impl &priv_container_from_end_iterator(const const_iterator &end_iterator) + { + header_plus_size *r = detail::parent_from_member + ( detail::get_pointer(end_iterator.pointed_node()), &header_plus_size::header_); + typename node_plus_pred_t::header_plus_priority_size *n = + detail::parent_from_member + < typename node_plus_pred_t::header_plus_priority_size + , header_plus_size> + (r, &node_plus_pred_t::header_plus_priority_size::header_plus_size_); + node_plus_pred_t *pn = detail::parent_from_member + < node_plus_pred_t + , typename node_plus_pred_t::header_plus_priority_size> + (n, &node_plus_pred_t::header_plus_priority_size_); + data_t *d = detail::parent_from_member(pn, &data_t::node_plus_pred_); + treap_impl *tr = detail::parent_from_member(d, &treap_impl::data_); + return *tr; + } + + static treap_impl &priv_container_from_iterator(const const_iterator &it) + { return priv_container_from_end_iterator(it.end_iterator_from_it()); } +}; + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator< +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_impl &x, const treap_impl &y) +#else +(const treap_impl &x, const treap_impl &y) +#endif +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +bool operator== +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_impl &x, const treap_impl &y) +#else +(const treap_impl &x, const treap_impl &y) +#endif +{ + typedef treap_impl tree_type; + typedef typename tree_type::const_iterator const_iterator; + + if(tree_type::constant_time_size && x.size() != y.size()){ + return false; + } + const_iterator end1 = x.end(); + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + if(tree_type::constant_time_size){ + while (i1 != end1 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1; + } + else{ + const_iterator end2 = y.end(); + while (i1 != end1 && i2 != end2 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1 && i2 == end2; + } +} + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator!= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_impl &x, const treap_impl &y) +#else +(const treap_impl &x, const treap_impl &y) +#endif +{ return !(x == y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_impl &x, const treap_impl &y) +#else +(const treap_impl &x, const treap_impl &y) +#endif +{ return y < x; } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator<= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_impl &x, const treap_impl &y) +#else +(const treap_impl &x, const treap_impl &y) +#endif +{ return !(y < x); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator>= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_impl &x, const treap_impl &y) +#else +(const treap_impl &x, const treap_impl &y) +#endif +{ return !(x < y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline void swap +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(treap_impl &x, treap_impl &y) +#else +(treap_impl &x, treap_impl &y) +#endif +{ x.swap(y); } + +/// @cond +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_treap_opt +{ + typedef typename pack_options + < treap_set_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; + typedef typename detail::get_value_traits + ::type value_traits; + + typedef treap_setopt + < value_traits + , typename packed_options::compare + , typename packed_options::priority + , typename packed_options::size_type + , packed_options::constant_time_size + > type; +}; +/// @endcond + +//! Helper metafunction to define a \c treap that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_trie +{ + /// @cond + typedef treap_impl + < typename make_treap_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class treap + : public make_trie::type +{ + typedef typename make_trie + ::type Base; + + public: + typedef typename Base::value_compare value_compare; + typedef typename Base::priority_compare priority_compare; + typedef typename Base::value_traits value_traits; + typedef typename Base::real_value_traits real_value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + + treap( const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, pcmp, v_traits) + {} + + template + treap( bool unique, Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : Base(unique, b, e, cmp, pcmp, v_traits) + {} + + static treap &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const treap &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static treap &container_from_it(iterator it) + { return static_cast(Base::container_from_iterator(it)); } + + static const treap &container_from_it(const_iterator it) + { return static_cast(Base::container_from_iterator(it)); } +}; + +#endif + + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_TRIE_HPP diff --git a/include/boost/intrusive/treap_algorithms.hpp b/include/boost/intrusive/treap_algorithms.hpp new file mode 100644 index 0000000..bdceac2 --- /dev/null +++ b/include/boost/intrusive/treap_algorithms.hpp @@ -0,0 +1,801 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2008. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_TRIE_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_TRIE_ALGORITHMS_HPP + +#include + +#include +#include + +#include +#include +#include +#include + + +namespace boost { +namespace intrusive { + +//! treap_algorithms provides basic algorithms to manipulate +//! nodes forming a treap. +//! +//! (1) the header node is maintained with links not only to the root +//! but also to the leftmost node of the tree, to enable constant time +//! begin(), and to the rightmost node of the tree, to enable linear time +//! performance when used with the generic set algorithms (set_union, +//! etc.); +//! +//! (2) when a node being deleted has two children its successor node is +//! relinked into its place, rather than copied, so that the only +//! pointers invalidated are those referring to the deleted node. +//! +//! treap_algorithms is configured with a NodeTraits class, which encapsulates the +//! information about the node to be manipulated. NodeTraits must support the +//! following interface: +//! +//! Typedefs: +//! +//! node: The type of the node that forms the circular list +//! +//! node_ptr: A pointer to a node +//! +//! const_node_ptr: A pointer to a const node +//! +//! Static functions: +//! +//! static node_ptr get_parent(const_node_ptr n); +//! +//! static void set_parent(node_ptr n, node_ptr parent); +//! +//! static node_ptr get_left(const_node_ptr n); +//! +//! static void set_left(node_ptr n, node_ptr left); +//! +//! static node_ptr get_right(const_node_ptr n); +//! +//! static void set_right(node_ptr n, node_ptr right); +template +class treap_algorithms +{ + public: + typedef NodeTraits node_traits; + typedef typename NodeTraits::node node; + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + + /// @cond + private: + + class remove_on_destroy + { + remove_on_destroy(const remove_on_destroy&); + remove_on_destroy& operator=(const remove_on_destroy&); + public: + remove_on_destroy(node_ptr header, node_ptr z) + : header_(header), z_(z), remove_it_(true) + {} + ~remove_on_destroy() + { + if(remove_it_){ + tree_algorithms::erase(header_, z_); + } + } + + void release() + { remove_it_ = false; } + + const node_ptr header_; + const node_ptr z_; + bool remove_it_; + }; + + class rerotate_on_destroy + { + rerotate_on_destroy(const remove_on_destroy&); + rerotate_on_destroy& operator=(const rerotate_on_destroy&); + + public: + rerotate_on_destroy(node_ptr header, node_ptr p, std::size_t &n) + : header_(header), p_(p), n_(n), remove_it_(true) + {} + + ~rerotate_on_destroy() + { + if(remove_it_){ + rotate_up_n(header_, p_, n_); + } + } + + void release() + { remove_it_ = false; } + + const node_ptr header_; + const node_ptr p_; + std::size_t &n_; + bool remove_it_; + }; + + static void rotate_up_n(const node_ptr header, const node_ptr p, std::size_t n) + { + for( node_ptr p_parent = NodeTraits::get_parent(p) + ; n-- + ; p_parent = NodeTraits::get_parent(p)){ + //Check if left child + if(p == NodeTraits::get_left(p_parent)){ + tree_algorithms::rotate_right(p_parent, header); + } + else{ //Right child + tree_algorithms::rotate_left(p_parent, header); + } + } + } + + typedef detail::tree_algorithms tree_algorithms; + + static node_ptr uncast(const_node_ptr ptr) + { + return node_ptr(const_cast(::boost::intrusive::detail::get_pointer(ptr))); + } + /// @endcond + + public: + static node_ptr begin_node(const_node_ptr header) + { return tree_algorithms::begin_node(header); } + + static node_ptr end_node(const_node_ptr header) + { return tree_algorithms::end_node(header); } + + //! This type is the information that will be + //! filled by insert_unique_check + struct insert_commit_data + /// @cond + : public tree_algorithms::insert_commit_data + /// @endcond + { + /// @cond + std::size_t rotations; + /// @endcond + }; + + //! Requires: header1 and header2 must be the header nodes + //! of two trees. + //! + //! Effects: Swaps two trees. After the function header1 will contain + //! links to the second tree and header2 will have links to the first tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static void swap_tree(node_ptr header1, node_ptr header2) + { return tree_algorithms::swap_tree(header1, header2); } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees. + //! + //! Effects: Swaps two nodes. After the function node1 will be inserted + //! in the position node2 before the function. node2 will be inserted in the + //! position node1 had before the function. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! node1 and node2 are not equivalent according to the ordering rules. + //! + //!Experimental function + static void swap_nodes(node_ptr node1, node_ptr node2) + { + if(node1 == node2) + return; + + node_ptr header1(tree_algorithms::get_header(node1)), header2(tree_algorithms::get_header(node2)); + swap_nodes(node1, header1, node2, header2); + } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees with header header1 and header2. + //! + //! Effects: Swaps two nodes. After the function node1 will be inserted + //! in the position node2 before the function. node2 will be inserted in the + //! position node1 had before the function. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! node1 and node2 are not equivalent according to the ordering rules. + //! + //!Experimental function + static void swap_nodes(node_ptr node1, node_ptr header1, node_ptr node2, node_ptr header2) + { tree_algorithms::swap_nodes(node1, header1, node2, header2); } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! new_node is not equivalent to node_to_be_replaced according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing and comparison is needed. + //! + //!Experimental function + static void replace_node(node_ptr node_to_be_replaced, node_ptr new_node) + { + if(node_to_be_replaced == new_node) + return; + replace_node(node_to_be_replaced, tree_algorithms::get_header(node_to_be_replaced), new_node); + } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! with header "header" and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! new_node is not equivalent to node_to_be_replaced according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + //! + //!Experimental function + static void replace_node(node_ptr node_to_be_replaced, node_ptr header, node_ptr new_node) + { tree_algorithms::replace_node(node_to_be_replaced, header, new_node); } + + //! Requires: node is a tree node but not the header. + //! + //! Effects: Unlinks the node and rebalances the tree. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + template + static void unlink(node_ptr node, NodePriorityCompare prio) + { + node_ptr x = NodeTraits::get_parent(node); + if(x){ + while(!is_header(x)) + x = NodeTraits::get_parent(x); + erase(x, node, prio); + } + } + + //! Requires: header is the header of a tree. + //! + //! Effects: Unlinks the leftmost node from the tree, and + //! updates the header link to the new leftmost node. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + static node_ptr unlink_leftmost_without_rebalance(node_ptr header) + { return tree_algorithms::unlink_leftmost_without_rebalance(header); } + + //! Requires: node is a node of the tree or an node initialized + //! by init(...). + //! + //! Effects: Returns true if the node is initialized by init(). + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + static bool unique(const_node_ptr node) + { return tree_algorithms::unique(node); } + + //! Requires: node is a node of the tree but it's not the header. + //! + //! Effects: Returns the number of nodes of the subtree. + //! + //! Complexity: Linear time. + //! + //! Throws: Nothing. + static std::size_t count(const_node_ptr node) + { return tree_algorithms::count(node); } + + //! Requires: header is the header node of the tree. + //! + //! Effects: Returns the number of nodes above the header. + //! + //! Complexity: Linear time. + //! + //! Throws: Nothing. + static std::size_t size(const_node_ptr header) + { return tree_algorithms::size(header); } + + //! Requires: p is a node from the tree except the header. + //! + //! Effects: Returns the next node of the tree. + //! + //! Complexity: Average constant time. + //! + //! Throws: Nothing. + static node_ptr next_node(node_ptr p) + { return tree_algorithms::next_node(p); } + + //! Requires: p is a node from the tree except the leftmost node. + //! + //! Effects: Returns the previous node of the tree. + //! + //! Complexity: Average constant time. + //! + //! Throws: Nothing. + static node_ptr prev_node(node_ptr p) + { return tree_algorithms::prev_node(p); } + + //! Requires: node must not be part of any tree. + //! + //! Effects: After the function unique(node) == true. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Nodes: If node is inserted in a tree, this function corrupts the tree. + static void init(node_ptr node) + { tree_algorithms::init(node); } + + //! Requires: node must not be part of any tree. + //! + //! Effects: Initializes the header to represent an empty tree. + //! unique(header) == true. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Nodes: If node is inserted in a tree, this function corrupts the tree. + static void init_header(node_ptr header) + { + tree_algorithms::init_header(header); + } + + //! Requires: header must be the header of a tree, z a node + //! of that tree and z != header. + //! + //! Effects: Erases node "z" from the tree with header "header". + //! + //! Complexity: Amortized constant time. + //! + //! Throws: Nothing. + template + static node_ptr erase(node_ptr header, node_ptr z, NodePriorityCompare pcomp) + { + rebalance_for_erasure(header, z, pcomp); + tree_algorithms::erase(header, z); +// assert(check_invariant(header, pcomp)); + return z; + } + + //! Requires: "cloner" must be a function + //! object taking a node_ptr and returning a new cloned node of it. "disposer" must + //! take a node_ptr and shouldn't throw. + //! + //! Effects: First empties target tree calling + //! void disposer::operator()(node_ptr) for every node of the tree + //! except the header. + //! + //! Then, duplicates the entire tree pointed by "source_header" cloning each + //! source node with node_ptr Cloner::operator()(node_ptr) to obtain + //! the nodes of the target tree. If "cloner" throws, the cloned target nodes + //! are disposed using void disposer(node_ptr). + //! + //! Complexity: Linear to the number of element of the source tree plus the. + //! number of elements of tree target tree when calling this function. + //! + //! Throws: If cloner functor throws. If this happens target nodes are disposed. + template + static void clone + (const_node_ptr source_header, node_ptr target_header, Cloner cloner, Disposer disposer) + { + tree_algorithms::clone(source_header, target_header, cloner, disposer); + } + + //! Requires: "disposer" must be an object function + //! taking a node_ptr parameter and shouldn't throw. + //! + //! Effects: Empties the target tree calling + //! void disposer::operator()(node_ptr) for every node of the tree + //! except the header. + //! + //! Complexity: Linear to the number of element of the source tree plus the. + //! number of elements of tree target tree when calling this function. + //! + //! Throws: If cloner functor throws. If this happens target nodes are disposed. + template + static void clear_and_dispose(node_ptr header, Disposer disposer) + { tree_algorithms::clear_and_dispose(header, disposer); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the first element that is + //! not less than "key" according to "comp" or "header" if that element does + //! not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr lower_bound + (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp) + { return tree_algorithms::lower_bound(header, key, comp); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the first element that is greater + //! than "key" according to "comp" or "header" if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr upper_bound + (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp) + { return tree_algorithms::upper_bound(header, key, comp); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the element that is equivalent to + //! "key" according to "comp" or "header" if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr find + (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp) + { return tree_algorithms::find(header, key, comp); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an a pair of node_ptr delimiting a range containing + //! all elements that are equivalent to "key" according to "comp" or an + //! empty range that indicates the position where those elements would be + //! if they there are no equivalent elements. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static std::pair equal_range + (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp) + { return tree_algorithms::equal_range(header, key, comp); } + + //! Requires: "h" must be the header node of a tree. + //! NodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares two node_ptrs. + //! + //! Effects: Inserts new_node into the tree before the upper bound + //! according to "comp". + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr insert_equal_upper_bound + (node_ptr h, node_ptr new_node, NodePtrCompare comp, PriorityNodeCompare pcomp) + { + insert_commit_data commit_data; + tree_algorithms::insert_equal_upper_bound_check(h, new_node, comp, commit_data); + rebalance_after_insertion_check(h, commit_data.node, new_node, pcomp, commit_data.rotations); + tree_algorithms::insert_unique_commit(h, new_node, commit_data); + rebalance_after_insertion_commit(h, new_node, commit_data.rotations); + return new_node; + } + + //! Requires: "h" must be the header node of a tree. + //! NodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares two node_ptrs. + //! + //! Effects: Inserts new_node into the tree before the lower bound + //! according to "comp". + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr insert_equal_lower_bound + (node_ptr h, node_ptr new_node, NodePtrCompare comp, NodePriorityCompare pcomp) + { + insert_commit_data commit_data; + tree_algorithms::insert_equal_lower_bound_check(h, new_node, comp, commit_data); + rebalance_after_insertion_check(h, commit_data.node, new_node, pcomp, commit_data.rotations); + tree_algorithms::insert_unique_commit(h, new_node, commit_data); + rebalance_after_insertion_commit(h, new_node, commit_data.rotations); + return new_node; + } + + //! Requires: "header" must be the header node of a tree. + //! NodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares two node_ptrs. "hint" is node from + //! the "header"'s tree. + //! + //! Effects: Inserts new_node into the tree, using "hint" as a hint to + //! where it will be inserted. If "hint" is the upper_bound + //! the insertion takes constant time (two comparisons in the worst case). + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time if new_node is inserted immediately before "hint". + //! + //! Throws: If "comp" throws. + template + static node_ptr insert_equal + (node_ptr h, node_ptr hint, node_ptr new_node, NodePtrCompare comp, NodePriorityCompare pcomp) + { + insert_commit_data commit_data; + tree_algorithms::insert_equal_check(h, hint, new_node, comp, commit_data); + rebalance_after_insertion_check(h, commit_data.node, new_node, pcomp, commit_data.rotations); + tree_algorithms::insert_unique_commit(h, new_node, commit_data); + rebalance_after_insertion_commit(h, new_node, commit_data.rotations); + return new_node; + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares KeyType with a node_ptr. + //! + //! Effects: Checks if there is an equivalent node to "key" in the + //! tree according to "comp" and obtains the needed information to realize + //! a constant-time node insertion if there is no equivalent node. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing a node_ptr to the already present node + //! and false. If there is not equivalent key can be inserted returns true + //! in the returned pair's boolean and fills "commit_data" that is meant to + //! be used with the "insert_commit" function to achieve a constant-time + //! insertion function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Notes: This function is used to improve performance when constructing + //! a node is expensive and the user does not want to have two equivalent nodes + //! in the tree: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the node and this function offers the possibility to use that part + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the node and use + //! "insert_commit" to insert the node in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_unique_commit" only + //! if no more objects are inserted or erased from the set. + template + static std::pair insert_unique_check + (const_node_ptr header, const KeyType &key + ,KeyNodePtrCompare comp, KeyNodePtrPrioCompare pcomp + ,insert_commit_data &commit_data) + { + std::pair ret = + tree_algorithms::insert_unique_check(header, key, comp, commit_data); + if(ret.second) + rebalance_after_insertion_check(header, commit_data.node, key, pcomp, commit_data.rotations); + return ret; + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares KeyType with a node_ptr. + //! "hint" is node from the "header"'s tree. + //! + //! Effects: Checks if there is an equivalent node to "key" in the + //! tree according to "comp" using "hint" as a hint to where it should be + //! inserted and obtains the needed information to realize + //! a constant-time node insertion if there is no equivalent node. + //! If "hint" is the upper_bound the function has constant time + //! complexity (two comparisons in the worst case). + //! + //! Returns: If there is an equivalent value + //! returns a pair containing a node_ptr to the already present node + //! and false. If there is not equivalent key can be inserted returns true + //! in the returned pair's boolean and fills "commit_data" that is meant to + //! be used with the "insert_commit" function to achieve a constant-time + //! insertion function. + //! + //! Complexity: Average complexity is at most logarithmic, but it is + //! amortized constant time if new_node should be inserted immediately before "hint". + //! + //! Throws: If "comp" throws. + //! + //! Notes: This function is used to improve performance when constructing + //! a node is expensive and the user does not want to have two equivalent nodes + //! in the tree: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the node and this function offers the possibility to use that part + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the node and use + //! "insert_commit" to insert the node in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_unique_commit" only + //! if no more objects are inserted or erased from the set. + template + static std::pair insert_unique_check + (const_node_ptr header, node_ptr hint, const KeyType &key + ,KeyNodePtrCompare comp, KeyNodePtrPrioCompare pcomp, insert_commit_data &commit_data) + { + std::pair ret = + tree_algorithms::insert_unique_check(header, hint, key, comp, commit_data); + if(ret.second) + rebalance_after_insertion_check(header, commit_data.node, key, pcomp, commit_data.rotations); + return ret; + } + + //! Requires: "header" must be the header node of a tree. + //! "commit_data" must have been obtained from a previous call to + //! "insert_unique_check". No objects should have been inserted or erased + //! from the set between the "insert_unique_check" that filled "commit_data" + //! and the call to "insert_commit". + //! + //! + //! Effects: Inserts new_node in the set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_unique_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + static void insert_unique_commit + (node_ptr header, node_ptr new_node, const insert_commit_data &commit_data) + { + tree_algorithms::insert_unique_commit(header, new_node, commit_data); + rebalance_after_insertion_commit(header, new_node, commit_data.rotations); + } + + //! Requires: "n" must be a node inserted in a tree. + //! + //! Effects: Returns a pointer to the header node of the tree. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + static node_ptr get_header(node_ptr n) + { return tree_algorithms::get_header(n); } + + /// @cond + private: + + //! Requires: p is a node of a tree. + //! + //! Effects: Returns true if p is the header of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static bool is_header(const_node_ptr p) + { + return tree_algorithms::is_header(p); + } + + template + static void rebalance_for_erasure(node_ptr header, node_ptr z, NodePriorityCompare pcomp) + { + std::size_t n = 0; + rerotate_on_destroy rb(header, z, n); + + node_ptr z_left = NodeTraits::get_left(z); + node_ptr z_right = NodeTraits::get_right(z); + while(z_left || z_right){ + if(!z_right || (z_left && pcomp(z_left, z_right))){ + tree_algorithms::rotate_right(z, header); + } + else{ + tree_algorithms::rotate_left(z, header); + } + ++n; + z_left = NodeTraits::get_left(z); + z_right = NodeTraits::get_right(z); + } + rb.release(); + } + + template + static void rebalance_after_insertion_check + ( const_node_ptr header, const_node_ptr upnode, const Key &k + , KeyNodePriorityCompare pcomp, std::size_t &num_rotations) + { + //First check rotations since pcomp can throw + num_rotations = 0; + std::size_t n = 0; + while(upnode != header && pcomp(k, upnode)){ + ++n; + upnode = NodeTraits::get_parent(upnode); + } + num_rotations = n; + } + + static void rebalance_after_insertion_commit(node_ptr header, node_ptr p, std::size_t n) + { + // Now to n rotations + for( node_ptr p_parent = NodeTraits::get_parent(p) + ; n-- + ; p_parent = NodeTraits::get_parent(p)){ + //Check if left child + if(p == NodeTraits::get_left(p_parent)){ + tree_algorithms::rotate_right(p_parent, header); + } + else{ //Right child + tree_algorithms::rotate_left(p_parent, header); + } + } + } + + template + static bool check_invariant(const_node_ptr header, NodePriorityCompare pcomp) + { + node_ptr beg = begin_node(header); + node_ptr end = end_node(header); + + while(beg != end){ + node_ptr p = NodeTraits::get_parent(beg); + if(p != header){ + if(pcomp(beg, p)) + return false; + } + beg = next_node(beg); + } + return true; + } + + /// @endcond +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_TRIE_ALGORITHMS_HPP diff --git a/include/boost/intrusive/treap_set.hpp b/include/boost/intrusive/treap_set.hpp new file mode 100644 index 0000000..9322a6b --- /dev/null +++ b/include/boost/intrusive/treap_set.hpp @@ -0,0 +1,2406 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2008 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTRUSIVE_TRIE_SET_HPP +#define BOOST_INTRUSIVE_TRIE_SET_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template treap_set is an intrusive container, that mimics most of +//! the interface of std::set as described in the C++ standard. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<>, +//! \c compare<> and \c priority_compare<> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +class treap_set_impl +{ + /// @cond + typedef treap_impl tree_type; + //! This class is + //! non-copyable + treap_set_impl (const treap_set_impl&); + + //! This class is + //! non-assignable + treap_set_impl &operator =(const treap_set_impl&); + + typedef tree_type implementation_defined; + /// @endcond + + public: + typedef typename implementation_defined::value_type value_type; + typedef typename implementation_defined::value_traits value_traits; + typedef typename implementation_defined::pointer pointer; + typedef typename implementation_defined::const_pointer const_pointer; + typedef typename implementation_defined::reference reference; + typedef typename implementation_defined::const_reference const_reference; + typedef typename implementation_defined::difference_type difference_type; + typedef typename implementation_defined::size_type size_type; + typedef typename implementation_defined::value_compare value_compare; + typedef typename implementation_defined::priority_compare priority_compare; + typedef typename implementation_defined::key_compare key_compare; + typedef typename implementation_defined::iterator iterator; + typedef typename implementation_defined::const_iterator const_iterator; + typedef typename implementation_defined::reverse_iterator reverse_iterator; + typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator; + typedef typename implementation_defined::insert_commit_data insert_commit_data; + typedef typename implementation_defined::node_traits node_traits; + typedef typename implementation_defined::node node; + typedef typename implementation_defined::node_ptr node_ptr; + typedef typename implementation_defined::const_node_ptr const_node_ptr; + typedef typename implementation_defined::node_algorithms node_algorithms; + + /// @cond + private: + tree_type tree_; + /// @endcond + + public: + //! Effects: Constructs an empty treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor of the value_compare object throws. + treap_set_impl( const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : tree_(cmp, pcmp, v_traits) + {} + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! cmp must be a comparison function that induces a strict weak ordering. + //! + //! Effects: Constructs an empty treap_set and inserts elements from + //! [b, e). + //! + //! Complexity: Linear in N if [b, e) is already sorted using + //! comp and otherwise N * log N, where N is std::distance(last, first). + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare object throws. + template + treap_set_impl( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : tree_(true, b, e, cmp, pcmp, v_traits) + {} + + //! Effects: Detaches all elements from this. The objects in the treap_set + //! are not deleted (i.e. no destructors are called). + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + ~treap_set_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns an iterator pointing to the highest priority object of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator top() + { return tree_.top(); } + + //! Effects: Returns a const_iterator pointing to the highest priority object of the tree.. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator top() const + { return this->ctop(); } + + //! Effects: Returns a const_iterator pointing to the highest priority object of the tree.. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator ctop() const + { return tree_.ctop(); } + + //! Effects: Returns a const_iterator pointing to the end of the treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rbegin() const + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crbegin() const + { return tree_.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rend() const + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Effects: Returns a reverse_iterator pointing to the highest priority object of the + //! reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rtop() + { return tree_.rtop(); } + + //! Effects: Returns a const_reverse_iterator pointing to the highest priority objec + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rtop() const + { return tree_.crtop(); } + + //! Effects: Returns a const_reverse_iterator pointing to the highest priority object + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crtop() const + { return tree_.crtop(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of treap_set. + //! + //! Effects: Returns a const reference to the treap_set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static treap_set_impl &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &treap_set_impl::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of treap_set. + //! + //! Effects: Returns a const reference to the treap_set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const treap_set_impl &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &treap_set_impl::tree_); + } + + //! Precondition: it must be a valid iterator of set. + //! + //! Effects: Returns a reference to the set associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static treap_set_impl &container_from_iterator(iterator it) + { + return *detail::parent_from_member + ( &tree_type::container_from_iterator(it) + , &treap_set_impl::tree_); + } + + //! Precondition: it must be a valid const_iterator of set. + //! + //! Effects: Returns a const reference to the set associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static const treap_set_impl &container_from_iterator(const_iterator it) + { + return *detail::parent_from_member + ( &tree_type::container_from_iterator(it) + , &treap_set_impl::tree_); + } + + //! Effects: Returns the key_compare object used by the treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: If key_compare copy-constructor throws. + key_compare key_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns the value_compare object used by the treap_set. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns true if the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return tree_.empty(); } + + //! Effects: Returns the number of elements stored in the treap_set. + //! + //! Complexity: Linear to elements contained in *this if, + //! constant-time size option is enabled. Constant-time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { return tree_.size(); } + + //! Effects: Swaps the contents of two sets. + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison functor + //! found using ADL throws. Strong guarantee. + void swap(treap_set_impl& other) + { tree_.swap(other.tree_); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. Copies the predicate from the source container. + //! + //! If cloner throws, all cloned elements are unlinked and disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. + template + void clone_from(const treap_set_impl &src, Cloner cloner, Disposer disposer) + { tree_.clone_from(src.tree_, cloner, disposer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Tries to inserts value into the treap_set. + //! + //! Returns: If the value + //! is not already present inserts it and returns a pair containing the + //! iterator to the new value and true. If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + std::pair insert(reference value) + { return tree_.insert_unique(value); } + + //! Requires: value must be an lvalue + //! + //! Effects: Tries to to insert x into the treap_set, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: An iterator that points to the position where the + //! new element was inserted into the treap_set. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(const_iterator hint, reference value) + { return tree_.insert_unique(hint, value); } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an ascapegoatitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the treap_set, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that + //! part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the treap_set. + template + std::pair insert_check + (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { return tree_.insert_unique_check(key, key_value_comp, commit_data); } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an ascapegoatitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the treap_set, using + //! a user provided key instead of the value itself, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! constructing that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that key + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This can give a total + //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the treap_set. + template + std::pair insert_check + (const_iterator hint, const KeyType &key + ,KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { return tree_.insert_unique_check(hint, key, key_value_comp, commit_data); } + + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the treap_set between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the treap_set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + iterator insert_commit(reference value, const insert_commit_data &commit_data) + { return tree_.insert_unique_commit(value, commit_data); } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Inserts a range into the treap_set. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert(Iterator b, Iterator e) + { tree_.insert_unique(b, e); } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity is constant time. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator i) + { return tree_.erase(i); } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator b, const_iterator e) + { return tree_.erase(b, e); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size()) + this->count(value)). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return tree_.erase(value); } + + //! Effects: Erases all the elements that compare equal with + //! the given key and the given comparison functor. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If the comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { return tree_.erase(key, comp); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by pos. + //! Disposer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator i, Disposer disposer) + { return tree_.erase_and_dispose(i, disposer); } + + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) + { return tree_.erase_and_dispose(b, e, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Throws: If the internal value_compare ordering function throws. + //! + //! Complexity: O(log(size() + this->count(value)). Basic guarantee. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_dispose(const_reference value, Disposer disposer) + { return tree_.erase_and_dispose(value, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { return tree_.erase_and_dispose(key, comp, disposer); } + + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { return tree_.clear(); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + void clear_and_dispose(Disposer disposer) + { return tree_.clear_and_dispose(disposer); } + + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If the internal value_compare ordering function throws. + size_type count(const_reference value) const + { return tree_.find(value) != end(); } + + //! Effects: Returns the number of contained elements with the same key + //! compared with the given comparison functor. + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If comp ordering function throws. + template + size_type count(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp) != end(); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator lower_bound(const_reference value) + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator lower_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns a const iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator lower_bound(const_reference value) const + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator lower_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator upper_bound(const_reference value) + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator upper_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.upper_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator upper_bound(const_reference value) const + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator upper_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.upper_bound(key, comp); } + + //! Effects: Finds an iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator find(const_reference value) + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator find(const KeyType& key, KeyValueCompare comp) + { return tree_.find(key, comp); } + + //! Effects: Finds a const_iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator find(const_reference value) const + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a const_iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator find(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + std::pair equal_range(const_reference value) + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair equal_range(const KeyType& key, KeyValueCompare comp) + { return tree_.equal_range(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + std::pair + equal_range(const_reference value) const + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair + equal_range(const KeyType& key, KeyValueCompare comp) const + { return tree_.equal_range(key, comp); } + + //! Requires: value must be an lvalue and shall be in a treap_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the treap_set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a treap_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! treap_set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a treap_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the treap_set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return tree_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a treap_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! treap_set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return tree_.iterator_to(value); } + + //! Requires: value shall not be in a treap_set/treap_multiset. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function puts the hook in the well-known default state + //! used by auto_unlink and safe hooks. + static void init_node(reference value) + { tree_type::init_node(value); } + + //! Effects: Unlinks the leftmost node from the tree. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + pointer unlink_leftmost_without_rebalance() + { return tree_.unlink_leftmost_without_rebalance(); } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! with_this is not equivalent to *replace_this according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + void replace_node(iterator replace_this, reference with_this) + { tree_.replace_node(replace_this, with_this); } + + //! Effects: Rebalances the tree. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear. + void rebalance() + { tree_.rebalance(); } + + //! Requires: old_root is a node of a tree. + //! + //! Effects: Rebalances the subtree rooted at old_root. + //! + //! Returns: The new root of the subtree. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements in the subtree. + iterator rebalance_subtree(iterator root) + { return tree_.rebalance_subtree(root); } + + //! Returns: The balance factor (alpha) used in this tree + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + float balance_factor() const + { return tree_.balance_factor(); } + + //! Requires: new_alpha must be a value between 0.5 and 1.0 + //! + //! Effects: Establishes a new balance factor (alpha) and rebalances + //! the tree if the new balance factor is stricter (less) than the old factor. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements in the subtree. + void balance_factor(float new_alpha) + { tree_.balance_factor(new_alpha); } + + /// @cond + friend bool operator==(const treap_set_impl &x, const treap_set_impl &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const treap_set_impl &x, const treap_set_impl &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator!= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_set_impl &x, const treap_set_impl &y) +#else +(const treap_set_impl &x, const treap_set_impl &y) +#endif +{ return !(x == y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_set_impl &x, const treap_set_impl &y) +#else +(const treap_set_impl &x, const treap_set_impl &y) +#endif +{ return y < x; } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator<= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_set_impl &x, const treap_set_impl &y) +#else +(const treap_set_impl &x, const treap_set_impl &y) +#endif +{ return !(y < x); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator>= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_set_impl &x, const treap_set_impl &y) +#else +(const treap_set_impl &x, const treap_set_impl &y) +#endif +{ return !(x < y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline void swap +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(treap_set_impl &x, treap_set_impl &y) +#else +(treap_set_impl &x, treap_set_impl &y) +#endif +{ x.swap(y); } + +//! Helper metafunction to define a \c treap_set that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_treap_set +{ + /// @cond + typedef treap_set_impl + < typename make_treap_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class treap_set + : public make_treap_set::type +{ + typedef typename make_treap_set + ::type Base; + + public: + typedef typename Base::value_compare value_compare; + typedef typename Base::priority_compare priority_compare; + typedef typename Base::value_traits value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + + treap_set( const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, pcmp, v_traits) + {} + + template + treap_set( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : Base(b, e, cmp, pcmp, v_traits) + {} + + static treap_set &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const treap_set &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static treap_set &container_from_iterator(iterator it) + { return static_cast(Base::container_from_iterator(it)); } + + static const treap_set &container_from_iterator(const_iterator it) + { return static_cast(Base::container_from_iterator(it)); } +}; + +#endif + +//! The class template treap_multiset is an intrusive container, that mimics most of +//! the interface of std::treap_multiset as described in the C++ standard. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<>, +//! \c compare<> and \c priority_compare<> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +class treap_multiset_impl +{ + /// @cond + typedef treap_impl tree_type; + + //Non-copyable and non-assignable + treap_multiset_impl (const treap_multiset_impl&); + treap_multiset_impl &operator =(const treap_multiset_impl&); + typedef tree_type implementation_defined; + /// @endcond + + public: + typedef typename implementation_defined::value_type value_type; + typedef typename implementation_defined::value_traits value_traits; + typedef typename implementation_defined::pointer pointer; + typedef typename implementation_defined::const_pointer const_pointer; + typedef typename implementation_defined::reference reference; + typedef typename implementation_defined::const_reference const_reference; + typedef typename implementation_defined::difference_type difference_type; + typedef typename implementation_defined::size_type size_type; + typedef typename implementation_defined::value_compare value_compare; + typedef typename implementation_defined::priority_compare priority_compare; + typedef typename implementation_defined::key_compare key_compare; + typedef typename implementation_defined::iterator iterator; + typedef typename implementation_defined::const_iterator const_iterator; + typedef typename implementation_defined::reverse_iterator reverse_iterator; + typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator; + typedef typename implementation_defined::insert_commit_data insert_commit_data; + typedef typename implementation_defined::node_traits node_traits; + typedef typename implementation_defined::node node; + typedef typename implementation_defined::node_ptr node_ptr; + typedef typename implementation_defined::const_node_ptr const_node_ptr; + typedef typename implementation_defined::node_algorithms node_algorithms; + + /// @cond + private: + tree_type tree_; + /// @endcond + + public: + //! Effects: Constructs an empty treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor of the value_compare/priority_compare objects throw. + treap_multiset_impl( const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : tree_(cmp, pcmp, v_traits) + {} + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! cmp must be a comparison function that induces a strict weak ordering. + //! + //! Effects: Constructs an empty treap_multiset and inserts elements from + //! [b, e). + //! + //! Complexity: Linear in N if [b, e) is already sorted using + //! comp and otherwise N * log N, where N is the distance between first and last + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare/priority_compare objects throw. + template + treap_multiset_impl( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : tree_(false, b, e, cmp, pcmp, v_traits) + {} + + //! Effects: Detaches all elements from this. The objects in the treap_multiset + //! are not deleted (i.e. no destructors are called). + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + ~treap_multiset_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns an iterator pointing to the highest priority object of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator top() + { return tree_.top(); } + + //! Effects: Returns a const_iterator pointing to the highest priority object of the tree.. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator top() const + { return this->ctop(); } + + //! Effects: Returns a const_iterator pointing to the highest priority object of the tree.. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator ctop() const + { return tree_.ctop(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rbegin() const + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crbegin() const + { return tree_.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rend() const + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Effects: Returns a reverse_iterator pointing to the highest priority object of the + //! reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rtop() + { return tree_.rtop(); } + + //! Effects: Returns a const_reverse_iterator pointing to the highest priority objec + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rtop() const + { return tree_.crtop(); } + + //! Effects: Returns a const_reverse_iterator pointing to the highest priority object + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crtop() const + { return tree_.crtop(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of treap_multiset. + //! + //! Effects: Returns a const reference to the treap_multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static treap_multiset_impl &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &treap_multiset_impl::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of treap_multiset. + //! + //! Effects: Returns a const reference to the treap_multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const treap_multiset_impl &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &treap_multiset_impl::tree_); + } + + //! Precondition: it must be a valid iterator of multiset. + //! + //! Effects: Returns a const reference to the multiset associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static treap_multiset_impl &container_from_iterator(iterator it) + { + return *detail::parent_from_member + ( &tree_type::container_from_iterator(it) + , &treap_multiset_impl::tree_); + } + + //! Precondition: it must be a valid const_iterator of multiset. + //! + //! Effects: Returns a const reference to the multiset associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const treap_multiset_impl &container_from_iterator(const_iterator it) + { + return *detail::parent_from_member + ( &tree_type::container_from_iterator(it) + , &treap_multiset_impl::tree_); + } + + //! Effects: Returns the key_compare object used by the treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If key_compare copy-constructor throws. + key_compare key_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns the value_compare object used by the treap_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns true if the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return tree_.empty(); } + + //! Effects: Returns the number of elements stored in the treap_multiset. + //! + //! Complexity: Linear to elements contained in *this if, + //! constant-time size option is enabled. Constant-time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { return tree_.size(); } + + //! Effects: Swaps the contents of two treap_multisets. + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison functor + //! found using ADL throws. Strong guarantee. + void swap(treap_multiset_impl& other) + { tree_.swap(other.tree_); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. Copies the predicate from the source container. + //! + //! If cloner throws, all cloned elements are unlinked and disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. + template + void clone_from(const treap_multiset_impl &src, Cloner cloner, Disposer disposer) + { tree_.clone_from(src.tree_, cloner, disposer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the treap_multiset. + //! + //! Returns: An iterator that points to the position where the new + //! element was inserted. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(reference value) + { return tree_.insert_equal(value); } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts x into the treap_multiset, using pos as a hint to + //! where it will be inserted. + //! + //! Returns: An iterator that points to the position where the new + //! element was inserted. + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(const_iterator hint, reference value) + { return tree_.insert_equal(hint, value); } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Inserts a range into the treap_multiset. + //! + //! Returns: An iterator that points to the position where the new + //! element was inserted. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert(Iterator b, Iterator e) + { tree_.insert_equal(b, e); } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity is constant time. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator i) + { return tree_.erase(i); } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator b, const_iterator e) + { return tree_.erase(b, e); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(value)). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return tree_.erase(value); } + + //! Effects: Erases all the elements that compare equal with + //! the given key and the given comparison functor. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { return tree_.erase(key, comp); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Effects: Erases the element pointed to by pos. + //! Disposer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator i, Disposer disposer) + { return tree_.erase_and_dispose(i, disposer); } + + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Effects: Erases the range pointed to by b end e. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) + { return tree_.erase_and_dispose(b, e, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(value)). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_dispose(const_reference value, Disposer disposer) + { return tree_.erase_and_dispose(value, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { return tree_.erase_and_dispose(key, comp, disposer); } + + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { return tree_.clear(); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + void clear_and_dispose(Disposer disposer) + { return tree_.clear_and_dispose(disposer); } + + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If the internal value_compare ordering function throws. + size_type count(const_reference value) const + { return tree_.count(value); } + + //! Effects: Returns the number of contained elements with the same key + //! compared with the given comparison functor. + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If comp ordering function throws. + template + size_type count(const KeyType& key, KeyValueCompare comp) const + { return tree_.count(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator lower_bound(const_reference value) + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator lower_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns a const iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator lower_bound(const_reference value) const + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator lower_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator upper_bound(const_reference value) + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator upper_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.upper_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator upper_bound(const_reference value) const + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator upper_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.upper_bound(key, comp); } + + //! Effects: Finds an iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator find(const_reference value) + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator find(const KeyType& key, KeyValueCompare comp) + { return tree_.find(key, comp); } + + //! Effects: Finds a const_iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator find(const_reference value) const + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a const_iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator find(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + std::pair equal_range(const_reference value) + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair equal_range(const KeyType& key, KeyValueCompare comp) + { return tree_.equal_range(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + std::pair + equal_range(const_reference value) const + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair + equal_range(const KeyType& key, KeyValueCompare comp) const + { return tree_.equal_range(key, comp); } + + //! Requires: value must be an lvalue and shall be in a treap_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the treap_multiset + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a treap_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! treap_multiset that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a treap_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the treap_multiset + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return tree_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a treap_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! treap_multiset that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return tree_.iterator_to(value); } + + //! Requires: value shall not be in a treap_multiset/treap_multiset. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function puts the hook in the well-known default state + //! used by auto_unlink and safe hooks. + static void init_node(reference value) + { tree_type::init_node(value); } + + //! Effects: Unlinks the leftmost node from the tree. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + pointer unlink_leftmost_without_rebalance() + { return tree_.unlink_leftmost_without_rebalance(); } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! with_this is not equivalent to *replace_this according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + void replace_node(iterator replace_this, reference with_this) + { tree_.replace_node(replace_this, with_this); } + + //! Effects: Rebalances the tree. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear. + void rebalance() + { tree_.rebalance(); } + + //! Requires: old_root is a node of a tree. + //! + //! Effects: Rebalances the subtree rooted at old_root. + //! + //! Returns: The new root of the subtree. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements in the subtree. + iterator rebalance_subtree(iterator root) + { return tree_.rebalance_subtree(root); } + + //! Returns: The balance factor (alpha) used in this tree + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + float balance_factor() const + { return tree_.balance_factor(); } + + //! Requires: new_alpha must be a value between 0.5 and 1.0 + //! + //! Effects: Establishes a new balance factor (alpha) and rebalances + //! the tree if the new balance factor is stricter (less) than the old factor. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements in the subtree. + void balance_factor(float new_alpha) + { tree_.balance_factor(new_alpha); } + + /// @cond + friend bool operator==(const treap_multiset_impl &x, const treap_multiset_impl &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const treap_multiset_impl &x, const treap_multiset_impl &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator!= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_multiset_impl &x, const treap_multiset_impl &y) +#else +(const treap_multiset_impl &x, const treap_multiset_impl &y) +#endif +{ return !(x == y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_multiset_impl &x, const treap_multiset_impl &y) +#else +(const treap_multiset_impl &x, const treap_multiset_impl &y) +#endif +{ return y < x; } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator<= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_multiset_impl &x, const treap_multiset_impl &y) +#else +(const treap_multiset_impl &x, const treap_multiset_impl &y) +#endif +{ return !(y < x); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator>= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const treap_multiset_impl &x, const treap_multiset_impl &y) +#else +(const treap_multiset_impl &x, const treap_multiset_impl &y) +#endif +{ return !(x < y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline void swap +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(treap_multiset_impl &x, treap_multiset_impl &y) +#else +(treap_multiset_impl &x, treap_multiset_impl &y) +#endif +{ x.swap(y); } + +//! Helper metafunction to define a \c treap_multiset that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_treap_multiset +{ + /// @cond + typedef treap_multiset_impl + < typename make_treap_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class treap_multiset + : public make_treap_multiset::type +{ + typedef typename make_treap_multiset + ::type Base; + + public: + typedef typename Base::value_compare value_compare; + typedef typename Base::priority_compare priority_compare; + typedef typename Base::value_traits value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + + treap_multiset( const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, pcmp, v_traits) + {} + + template + treap_multiset( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const priority_compare &pcmp = priority_compare() + , const value_traits &v_traits = value_traits()) + : Base(b, e, cmp, pcmp, v_traits) + {} + + static treap_multiset &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const treap_multiset &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static treap_multiset &container_from_iterator(iterator it) + { return static_cast(Base::container_from_iterator(it)); } + + static const treap_multiset &container_from_iterator(const_iterator it) + { return static_cast(Base::container_from_iterator(it)); } +}; + +#endif + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_TRIE_SET_HPP diff --git a/include/boost/intrusive/trivial_value_traits.hpp b/include/boost/intrusive/trivial_value_traits.hpp index 3d8797e..dcf996d 100644 --- a/include/boost/intrusive/trivial_value_traits.hpp +++ b/include/boost/intrusive/trivial_value_traits.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/unordered_set.hpp b/include/boost/intrusive/unordered_set.hpp index 8f1f9d1..cdca860 100644 --- a/include/boost/intrusive/unordered_set.hpp +++ b/include/boost/intrusive/unordered_set.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -235,7 +235,7 @@ class unordered_set_impl key_equal key_eq() const { return table_.key_eq(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: if constant-time size and cache_last options are disabled, //! average constant time (worst case, with empty() == true: O(this->bucket_count()). @@ -463,6 +463,12 @@ class unordered_set_impl iterator erase_and_dispose(const_iterator i, Disposer disposer) { return table_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. @@ -1288,7 +1294,7 @@ class unordered_multiset_impl key_equal key_eq() const { return table_.key_eq(); } - //! Effects: Returns true is the container is empty. + //! Effects: Returns true if the container is empty. //! //! Complexity: if constant-time size and cache_last options are disabled, //! average constant time (worst case, with empty() == true: O(this->bucket_count()). @@ -1453,6 +1459,12 @@ class unordered_multiset_impl void erase_and_dispose(const_iterator i, Disposer disposer) { table_.erase_and_dispose(i, disposer); } + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: Erases the range pointed to by b end e. diff --git a/include/boost/intrusive/unordered_set_hook.hpp b/include/boost/intrusive/unordered_set_hook.hpp index 0d5d4e8..adb3a8d 100644 --- a/include/boost/intrusive/unordered_set_hook.hpp +++ b/include/boost/intrusive/unordered_set_hook.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at From 119fb288ff69bd0c90bda4bd092a98443f6330fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 13 Dec 2008 13:56:15 +0000 Subject: [PATCH 14/14] * New treap-based containers: treap, treap_set, treap_multiset. * Corrected compilation bug for Windows-based 64 bit compilers. * Corrected exception-safety bugs in container constructors. * Updated documentation to show rvalue-references funcions instead of emulation functions. [SVN r50261] --- include/boost/intrusive/detail/assert.hpp | 2 +- .../detail/clear_on_destructor_base.hpp | 36 ++++ .../boost/intrusive/detail/config_begin.hpp | 4 +- include/boost/intrusive/detail/config_end.hpp | 2 +- .../intrusive/detail/ebo_functor_holder.hpp | 2 +- .../boost/intrusive/detail/generic_hook.hpp | 2 +- .../boost/intrusive/detail/hashtable_node.hpp | 2 +- include/boost/intrusive/detail/list_node.hpp | 2 +- include/boost/intrusive/detail/mpl.hpp | 4 +- .../intrusive/detail/parent_from_member.hpp | 2 +- .../boost/intrusive/detail/rbtree_node.hpp | 2 +- include/boost/intrusive/detail/slist_node.hpp | 2 +- .../intrusive/detail/transform_iterator.hpp | 2 +- .../intrusive/detail/tree_algorithms.hpp | 162 +++++++++--------- include/boost/intrusive/detail/tree_node.hpp | 3 + include/boost/intrusive/detail/utilities.hpp | 13 +- 16 files changed, 146 insertions(+), 96 deletions(-) create mode 100644 include/boost/intrusive/detail/clear_on_destructor_base.hpp diff --git a/include/boost/intrusive/detail/assert.hpp b/include/boost/intrusive/detail/assert.hpp index e742b7e..0fe98f8 100644 --- a/include/boost/intrusive/detail/assert.hpp +++ b/include/boost/intrusive/detail/assert.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/clear_on_destructor_base.hpp b/include/boost/intrusive/detail/clear_on_destructor_base.hpp new file mode 100644 index 0000000..838dd67 --- /dev/null +++ b/include/boost/intrusive/detail/clear_on_destructor_base.hpp @@ -0,0 +1,36 @@ +//////} // /////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_DETAIL_CLEAR_ON_DESTRUCTOR_HPP +#define BOOST_INTRUSIVE_DETAIL_CLEAR_ON_DESTRUCTOR_HPP + +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +class clear_on_destructor_base +{ + protected: + ~clear_on_destructor_base() + { + static_cast(this)->clear(); + } +}; + +} // namespace detail { +} // namespace intrusive { +} // namespace boost { + +#include + +#endif //#ifndef BOOST_INTRUSIVE_DETAIL_CLEAR_ON_DESTRUCTOR_HPP diff --git a/include/boost/intrusive/detail/config_begin.hpp b/include/boost/intrusive/detail/config_begin.hpp index 411b8ae..1c390be 100644 --- a/include/boost/intrusive/detail/config_begin.hpp +++ b/include/boost/intrusive/detail/config_begin.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -44,6 +44,8 @@ #pragma warning (disable : 4267) //conversion from 'X' to 'Y', possible loss of data #pragma warning (disable : 4127) //conditional expression is constant #pragma warning (disable : 4706) //assignment within conditional expression + #pragma warning (disable : 4541) //'typeid' used on polymorphic type 'boost::exception' with /GR- + #pragma warning (disable : 4512) //'typeid' used on polymorphic type 'boost::exception' with /GR- #endif //#define BOOST_INTRUSIVE_USE_ITERATOR_FACADE diff --git a/include/boost/intrusive/detail/config_end.hpp b/include/boost/intrusive/detail/config_end.hpp index 703d038..f04b2e9 100644 --- a/include/boost/intrusive/detail/config_end.hpp +++ b/include/boost/intrusive/detail/config_end.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/ebo_functor_holder.hpp b/include/boost/intrusive/detail/ebo_functor_holder.hpp index 369d2ca..43cc975 100644 --- a/include/boost/intrusive/detail/ebo_functor_holder.hpp +++ b/include/boost/intrusive/detail/ebo_functor_holder.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Joaquin M Lopez Munoz 2006-2007 +// (C) Copyright Joaquin M Lopez Munoz 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/generic_hook.hpp b/include/boost/intrusive/detail/generic_hook.hpp index 837f928..1b4736b 100644 --- a/include/boost/intrusive/detail/generic_hook.hpp +++ b/include/boost/intrusive/detail/generic_hook.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/hashtable_node.hpp b/include/boost/intrusive/detail/hashtable_node.hpp index 44a5f5a..fbb150d 100644 --- a/include/boost/intrusive/detail/hashtable_node.hpp +++ b/include/boost/intrusive/detail/hashtable_node.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/list_node.hpp b/include/boost/intrusive/detail/list_node.hpp index a0bc8ba..effd36a 100644 --- a/include/boost/intrusive/detail/list_node.hpp +++ b/include/boost/intrusive/detail/list_node.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/mpl.hpp b/include/boost/intrusive/detail/mpl.hpp index 27e7f37..15954b9 100644 --- a/include/boost/intrusive/detail/mpl.hpp +++ b/include/boost/intrusive/detail/mpl.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -129,7 +129,7 @@ struct identity #define BOOST_INTRUSIVE_TT_DECL #endif -#if defined(_MSC_EXTENSIONS) && !defined(__BORLAND__) +#if defined(_MSC_EXTENSIONS) && !defined(__BORLAND__) && !defined(_WIN64) #define BOOST_INTRUSIVE_TT_TEST_MSC_FUNC_SIGS #endif diff --git a/include/boost/intrusive/detail/parent_from_member.hpp b/include/boost/intrusive/detail/parent_from_member.hpp index d5fc96a..c99ac6c 100644 --- a/include/boost/intrusive/detail/parent_from_member.hpp +++ b/include/boost/intrusive/detail/parent_from_member.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/rbtree_node.hpp b/include/boost/intrusive/detail/rbtree_node.hpp index 5345209..6d6dd84 100644 --- a/include/boost/intrusive/detail/rbtree_node.hpp +++ b/include/boost/intrusive/detail/rbtree_node.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/slist_node.hpp b/include/boost/intrusive/detail/slist_node.hpp index c0636e1..4101092 100644 --- a/include/boost/intrusive/detail/slist_node.hpp +++ b/include/boost/intrusive/detail/slist_node.hpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // // (C) Copyright Olaf Krzikalla 2004-2006. -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/transform_iterator.hpp b/include/boost/intrusive/detail/transform_iterator.hpp index f5fe05c..a4afd77 100644 --- a/include/boost/intrusive/detail/transform_iterator.hpp +++ b/include/boost/intrusive/detail/transform_iterator.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007 +// (C) Copyright Ion Gaztanaga 2007-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/intrusive/detail/tree_algorithms.hpp b/include/boost/intrusive/detail/tree_algorithms.hpp index 0aa06f7..1fe196b 100644 --- a/include/boost/intrusive/detail/tree_algorithms.hpp +++ b/include/boost/intrusive/detail/tree_algorithms.hpp @@ -721,22 +721,6 @@ class tree_algorithms static bool is_header(const_node_ptr p) { -/* - node_ptr p_parent = NodeTraits::get_parent(p); - if(!p_parent) - return true; - if(!NodeTraits::get_parent(p_parent) != p) - return false; - if(NodeTraits::get_left(p) != 0){ - if(NodeTraits::get_parent(NodeTraits::get_left(p)) != p){ - is_header = true; - } - if(NodeTraits::get_parent(p) == NodeTraits::get_left(p)){ - is_header = true; - } - } -*/ - bool is_header = false; if(NodeTraits::get_parent(p) == p){ is_header = true; @@ -1015,42 +999,71 @@ class tree_algorithms } } - //! Requires: "header" must be the header node of a tree. - //! NodePtrCompare is a function object that induces a strict weak - //! ordering compatible with the strict weak ordering used to create the - //! the tree. NodePtrCompare compares two node_ptrs. "hint" is node from - //! the "header"'s tree. - //! - //! Effects: Inserts new_node into the tree, using "hint" as a hint to - //! where it will be inserted. If "hint" is the upper_bound - //! the insertion takes constant time (two comparisons in the worst case). - //! - //! Complexity: Logarithmic in general, but it is amortized - //! constant time if new_node is inserted immediately before "hint". - //! - //! Throws: If "comp" throws. template - static node_ptr insert_equal - (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0) + static void insert_equal_check + ( node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp + , insert_commit_data &commit_data, std::size_t *pdepth = 0) { if(hint == header || !comp(hint, new_node)){ node_ptr prev(hint); if(hint == NodeTraits::get_left(header) || !comp(new_node, (prev = prev_node(hint)))){ bool link_left = unique(header) || !NodeTraits::get_left(hint); - link(header, new_node, link_left ? hint : prev, link_left); - if(pdepth) *pdepth = depth(new_node) + 1; - return new_node; + commit_data.link_left = link_left; + commit_data.node = link_left ? hint : prev; + if(pdepth){ + *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1; + } } else{ - return insert_equal_upper_bound(header, new_node, comp, pdepth); + insert_equal_upper_bound_check(header, new_node, comp, commit_data, pdepth); } } else{ - return insert_equal_lower_bound(header, new_node, comp, pdepth); + insert_equal_lower_bound_check(header, new_node, comp, commit_data, pdepth); } } + template + static void insert_equal_upper_bound_check + (node_ptr h, node_ptr new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0) + { insert_equal_check_impl(true, h, new_node, comp, commit_data, pdepth); } + + template + static void insert_equal_lower_bound_check + (node_ptr h, node_ptr new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0) + { insert_equal_check_impl(false, h, new_node, comp, commit_data, pdepth); } + + template + static node_ptr insert_equal + (node_ptr h, node_ptr hint, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0) + { + insert_commit_data commit_data; + insert_equal_check(h, hint, new_node, comp, commit_data, pdepth); + link(h, new_node, commit_data.node, commit_data.link_left); + return new_node; + } + + template + static node_ptr insert_equal_upper_bound + (node_ptr h, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0) + { + insert_commit_data commit_data; + insert_equal_upper_bound_check(h, new_node, comp, commit_data, pdepth); + link(h, new_node, commit_data.node, commit_data.link_left); + return new_node; + } + + template + static node_ptr insert_equal_lower_bound + (node_ptr h, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0) + { + insert_commit_data commit_data; + insert_equal_lower_bound_check(h, new_node, comp, commit_data, pdepth); + link(h, new_node, commit_data.node, commit_data.link_left); + return new_node; + } + //! Requires: p can't be a header node. //! //! Effects: Calculates the depth of a node: the depth of a @@ -1071,48 +1084,6 @@ class tree_algorithms return depth; } - template - static node_ptr insert_equal_upper_bound - (node_ptr h, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0) - { - std::size_t depth = 0; - node_ptr y(h); - node_ptr x(NodeTraits::get_parent(y)); - - while(x){ - ++depth; - y = x; - x = comp(new_node, x) ? - NodeTraits::get_left(x) : NodeTraits::get_right(x); - } - - bool link_left = (y == h) || comp(new_node, y); - link(h, new_node, y, link_left); - if(pdepth) *pdepth = depth; - return new_node; - } - - template - static node_ptr insert_equal_lower_bound - (node_ptr h, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0) - { - std::size_t depth = 0; - node_ptr y(h); - node_ptr x(NodeTraits::get_parent(y)); - - while(x){ - ++depth; - y = x; - x = !comp(x, new_node) ? - NodeTraits::get_left(x) : NodeTraits::get_right(x); - } - - bool link_left = (y == h) || !comp(y, new_node); - link(h, new_node, y, link_left); - if(pdepth) *pdepth = depth; - return new_node; - } - //! Requires: "cloner" must be a function //! object taking a node_ptr and returning a new cloned node of it. "disposer" must //! take a node_ptr and shouldn't throw. @@ -1557,6 +1528,39 @@ class tree_algorithms } private: + template + static void insert_equal_check_impl + (bool upper, node_ptr h, node_ptr new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0) + { + std::size_t depth = 0; + node_ptr y(h); + node_ptr x(NodeTraits::get_parent(y)); + bool link_left; + + if(upper){ + while(x){ + ++depth; + y = x; + x = comp(new_node, x) ? + NodeTraits::get_left(x) : NodeTraits::get_right(x); + } + link_left = (y == h) || comp(new_node, y); + } + else{ + while(x){ + ++depth; + y = x; + x = !comp(x, new_node) ? + NodeTraits::get_left(x) : NodeTraits::get_right(x); + } + link_left = (y == h) || !comp(y, new_node); + } + + commit_data.link_left = link_left; + commit_data.node = y; + if(pdepth) *pdepth = depth; + } + static void erase_impl(node_ptr header, node_ptr z, data_for_rebalance &info) { node_ptr y(z); diff --git a/include/boost/intrusive/detail/tree_node.hpp b/include/boost/intrusive/detail/tree_node.hpp index a375cba..be3c976 100644 --- a/include/boost/intrusive/detail/tree_node.hpp +++ b/include/boost/intrusive/detail/tree_node.hpp @@ -173,6 +173,9 @@ class tree_iterator return tree_iterator(node_algorithms::get_header(this->pointed_node()), this->get_container()); } + tree_iterator unconst() const + { return tree_iterator(this->pointed_node(), this->get_container()); } + private: struct members : public detail::select_constptr diff --git a/include/boost/intrusive/detail/utilities.hpp b/include/boost/intrusive/detail/utilities.hpp index 7a92449..ad81dc2 100644 --- a/include/boost/intrusive/detail/utilities.hpp +++ b/include/boost/intrusive/detail/utilities.hpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -211,20 +211,25 @@ struct key_nodeptr_comp { typedef typename Container::real_value_traits real_value_traits; typedef typename real_value_traits::node_ptr node_ptr; + typedef typename real_value_traits::const_node_ptr const_node_ptr; typedef detail::ebo_functor_holder base_t; key_nodeptr_comp(KeyValueCompare kcomp, const Container *cont) : base_t(kcomp), cont_(cont) {} template - bool operator()(node_ptr node, const KeyType &key) const + bool operator()( const_node_ptr node, const KeyType &key + , typename enable_if_c + ::value>::type * = 0) const { return base_t::get()(*cont_->get_real_value_traits().to_value_ptr(node), key); } template - bool operator()(const KeyType &key, node_ptr node) const + bool operator()(const KeyType &key, const_node_ptr node + , typename enable_if_c + ::value>::type * = 0) const { return base_t::get()(key, *cont_->get_real_value_traits().to_value_ptr(node)); } - bool operator()(node_ptr node1, node_ptr node2) const + bool operator()(const_node_ptr node1, const_node_ptr node2) const { return base_t::get() ( *cont_->get_real_value_traits().to_value_ptr(node1)