diff --git a/include/boost/intrusive/avl_set.hpp b/include/boost/intrusive/avl_set.hpp index 74e8967..8ff22a4 100644 --- a/include/boost/intrusive/avl_set.hpp +++ b/include/boost/intrusive/avl_set.hpp @@ -113,8 +113,8 @@ class avl_set_impl //! Effects: Detaches all elements from this. The objects in the avl_set //! are not deleted (i.e. no destructors are called). //! - //! Complexity: O(log(size()) + size()) if it's a safe-mode or auto-unlink - //! value. Otherwise constant. + //! 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. ~avl_set_impl() @@ -1178,8 +1178,8 @@ class avl_multiset_impl //! Effects: Detaches all elements from this. The objects in the avl_multiset //! are not deleted (i.e. no destructors are called). //! - //! Complexity: O(log(size()) + size()) if it's a safe-mode or - //! auto-unlink value. Otherwise constant. + //! 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. ~avl_multiset_impl() diff --git a/include/boost/intrusive/avl_set_hook.hpp b/include/boost/intrusive/avl_set_hook.hpp index 390c577..93a9a85 100644 --- a/include/boost/intrusive/avl_set_hook.hpp +++ b/include/boost/intrusive/avl_set_hook.hpp @@ -57,18 +57,25 @@ struct make_avl_set_base_hook }; //! Derive a class from avl_set_base_hook in order to store objects in -//! in an set/multiset. avl_set_base_hook holds the data necessary to maintain -//! the set/multiset and provides an appropriate value_traits class for set/multiset. +//! in an avl_set/avl_multiset. avl_set_base_hook holds the data necessary to maintain +//! the avl_set/avl_multiset and provides an appropriate value_traits class for avl_set/avl_multiset. //! -//! The first integer template argument defines a tag to identify the node. +//! The hook admits the following options: \c tag<>, \c void_pointer<>, +//! \c link_mode<> and \c optimize_size<>. +//! +//! \c tag<> defines a tag to identify the node. //! The same tag value can be used in different classes, but if a class is -//! derived from more than one avl_set_base_hook, then each avl_set_base_hook needs its +//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its //! unique tag. //! -//! The second boolean template parameter will specify the linking mode of the 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. //! -//! The third argument is the pointer type that will be used internally in the hook -//! and the set/multiset configured from this hook. +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c optimize_size<> will tell the hook to optimize the hook for size instead +//! of speed. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else @@ -107,7 +114,7 @@ class avl_set_base_hook //! Effects: If link_mode is \c normal_link, the destructor does //! nothing (ie. no code is generated). If link_mode is \c safe_link and the - //! object is stored in an set an assertion is raised. If link_mode is + //! object is stored in a set an assertion is raised. If link_mode is //! \c auto_unlink and \c is_linked() is true, the node is unlinked. //! //! Throws: Nothing. @@ -169,13 +176,20 @@ struct make_avl_set_member_hook }; //! Put a public data member avl_set_member_hook in order to store objects of this class in -//! an set/multiset. avl_set_member_hook holds the data necessary for maintaining the -//! set/multiset and provides an appropriate value_traits class for set/multiset. +//! an avl_set/avl_multiset. avl_set_member_hook holds the data necessary for maintaining the +//! avl_set/avl_multiset and provides an appropriate value_traits class for avl_set/avl_multiset. //! -//! The first boolean template parameter will specify the linking mode of the hook. +//! The hook admits the following options: \c void_pointer<>, +//! \c link_mode<> and \c optimize_size<>. //! -//! The second argument is the pointer type that will be used internally in the hook -//! and the set/multiset configured from this 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. +//! +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c optimize_size<> will tell the hook to optimize the hook for size instead +//! of speed. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else @@ -214,7 +228,7 @@ class avl_set_member_hook //! Effects: If link_mode is \c normal_link, the destructor does //! nothing (ie. no code is generated). If link_mode is \c safe_link and the - //! object is stored in an set an assertion is raised. If link_mode is + //! object is stored in a set an assertion is raised. If link_mode is //! \c auto_unlink and \c is_linked() is true, the node is unlinked. //! //! Throws: Nothing. diff --git a/include/boost/intrusive/avltree.hpp b/include/boost/intrusive/avltree.hpp index e5af13b..86a2957 100644 --- a/include/boost/intrusive/avltree.hpp +++ b/include/boost/intrusive/avltree.hpp @@ -413,10 +413,7 @@ class avltree_impl if(constant_time_size) return this->priv_size_traits().get_size(); else{ - const_iterator beg(this->cbegin()), end(this->cend()); - size_type i = 0; - for(;beg != end; ++beg) ++i; - return i; + return (size_type)node_algorithms::size(const_node_ptr(&priv_header())); } } diff --git a/include/boost/intrusive/avltree_algorithms.hpp b/include/boost/intrusive/avltree_algorithms.hpp index 3783ef8..94d046f 100644 --- a/include/boost/intrusive/avltree_algorithms.hpp +++ b/include/boost/intrusive/avltree_algorithms.hpp @@ -282,6 +282,16 @@ class avltree_algorithms 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. diff --git a/include/boost/intrusive/bs_set_hook.hpp b/include/boost/intrusive/bs_set_hook.hpp new file mode 100644 index 0000000..bf55042 --- /dev/null +++ b/include/boost/intrusive/bs_set_hook.hpp @@ -0,0 +1,288 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// 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_BS_SET_HOOK_HPP +#define BOOST_INTRUSIVE_BS_SET_HOOK_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +/// @cond +template +struct get_bs_set_node_algo +{ + typedef detail::tree_algorithms > type; +}; +/// @endcond + +//! 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 +template +#else +template +#endif +struct make_bs_set_base_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, O1, O2, O3>::type packed_options; + + //Scapegoat trees can't be auto unlink trees + BOOST_STATIC_ASSERT(((int)packed_options::link_mode != (int)auto_unlink)); + + typedef detail::generic_hook + < get_bs_set_node_algo + , typename packed_options::tag + , packed_options::link_mode + , detail::BsSetBaseHook + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +//! Derive a class from bs_set_base_hook in order to store objects in +//! in a bs_set/bs_multiset. bs_set_base_hook holds the data necessary to maintain +//! the bs_set/bs_multiset and provides an appropriate value_traits class for bs_set/bs_multiset. +//! +//! The hook admits the following options: \c tag<>, \c void_pointer<>, +//! \c link_mode<>. +//! +//! \c tag<> defines a tag to identify the node. +//! The same tag value can be used in different classes, but if a class is +//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its +//! unique tag. +//! +//! \c void_pointer<> is the pointer type that will be used internally in the hook +//! and the the container configured to use this 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 +template +#else +template +#endif +class bs_set_base_hook + : public make_bs_set_base_hook::type +{ + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + bs_set_base_hook(); + + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + bs_set_base_hook(const bs_set_base_hook& ); + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + bs_set_base_hook& operator=(const bs_set_base_hook& ); + + //! Effects: If link_mode is \c normal_link, the destructor does + //! nothing (ie. no code is generated). If link_mode is \c safe_link and the + //! object is stored in a set an assertion is raised. If link_mode is + //! \c auto_unlink and \c is_linked() is true, the node is unlinked. + //! + //! Throws: Nothing. + ~bs_set_base_hook(); + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(bs_set_base_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether \c set::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. + //! + //! Throws: Nothing. + void unlink(); + #endif +}; + +//! 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 +template +#else +template +#endif +struct make_bs_set_member_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, O1, O2, O3>::type packed_options; + + //Scapegoat trees can't be auto unlink trees + BOOST_STATIC_ASSERT(((int)packed_options::link_mode != (int)auto_unlink)); + + typedef detail::generic_hook + < get_bs_set_node_algo + , member_tag + , packed_options::link_mode + , detail::NoBaseHook + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +//! Put a public data member bs_set_member_hook in order to store objects of this class in +//! a bs_set/bs_multiset. bs_set_member_hook holds the data necessary for maintaining the +//! bs_set/bs_multiset and provides an appropriate value_traits class for bs_set/bs_multiset. +//! +//! The hook admits the following options: \c void_pointer<>, \c link_mode<>. +//! +//! \c void_pointer<> is the pointer type that will be used internally in the hook +//! and the the container configured to use this 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 +template +#else +template +#endif +class bs_set_member_hook + : public make_bs_set_member_hook::type +{ + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + bs_set_member_hook(); + + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + bs_set_member_hook(const bs_set_member_hook& ); + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + bs_set_member_hook& operator=(const bs_set_member_hook& ); + + //! Effects: If link_mode is \c normal_link, the destructor does + //! nothing (ie. no code is generated). If link_mode is \c safe_link and the + //! object is stored in a set an assertion is raised. If link_mode is + //! \c auto_unlink and \c is_linked() is true, the node is unlinked. + //! + //! Throws: Nothing. + ~bs_set_member_hook(); + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(bs_set_member_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether \c set::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. + //! + //! Throws: Nothing. + void unlink(); + #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 + +#include + +#endif //BOOST_INTRUSIVE_BS_SET_HOOK_HPP diff --git a/include/boost/intrusive/detail/config_begin.hpp b/include/boost/intrusive/detail/config_begin.hpp index f30069d..411b8ae 100644 --- a/include/boost/intrusive/detail/config_begin.hpp +++ b/include/boost/intrusive/detail/config_begin.hpp @@ -42,6 +42,8 @@ #pragma warning (disable : 4522) #pragma warning (disable : 4146) #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 #endif //#define BOOST_INTRUSIVE_USE_ITERATOR_FACADE diff --git a/include/boost/intrusive/detail/generic_hook.hpp b/include/boost/intrusive/detail/generic_hook.hpp index f6e156d..87dafe2 100644 --- a/include/boost/intrusive/detail/generic_hook.hpp +++ b/include/boost/intrusive/detail/generic_hook.hpp @@ -34,6 +34,7 @@ enum , UsetBaseHook , SplaySetBaseHook , AvlSetBaseHook +, BsSetBaseHook }; struct no_default_definer{}; @@ -65,6 +66,10 @@ template struct default_definer { typedef Hook default_avl_set_hook; }; +template +struct default_definer +{ typedef Hook default_bs_set_hook; }; + template struct make_default_definer { diff --git a/include/boost/intrusive/detail/tree_algorithms.hpp b/include/boost/intrusive/detail/tree_algorithms.hpp index 471aa5a..1a6c045 100644 --- a/include/boost/intrusive/detail/tree_algorithms.hpp +++ b/include/boost/intrusive/detail/tree_algorithms.hpp @@ -118,7 +118,7 @@ class tree_algorithms struct nop_erase_fixup { - void operator()(node_ptr to_erase, node_ptr successor){} + void operator()(node_ptr, node_ptr){} }; /// @cond @@ -598,14 +598,49 @@ class tree_algorithms //! Complexity: Linear time. //! //! Throws: Nothing. - static std::size_t count(const_node_ptr node) + static std::size_t count(const_node_ptr subtree) { - std::size_t result = 1; - if(NodeTraits::get_left(node)) - result += count(NodeTraits::get_left(node)); - if(NodeTraits::get_right(node)) - result += count(NodeTraits::get_right(node)); - return result; + if(!subtree) return 0; + std::size_t count = 0; + node_ptr p = minimum(uncast(subtree)); + bool continue_looping = true; + while(continue_looping){ + ++count; + node_ptr p_right(NodeTraits::get_right(p)); + if(p_right){ + p = minimum(p_right); + } + else { + for(;;){ + node_ptr q; + if (p == subtree){ + continue_looping = false; + break; + } + q = p; + p = NodeTraits::get_parent(p); + if (NodeTraits::get_left(p) == q) + break; + } + } + } + return count; + } + + //! 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 size(const_node_ptr header) + { + node_ptr beg(begin_node(header)); + node_ptr end(end_node(header)); + std::size_t i = 0; + for(;beg != end; beg = next_node(beg)) ++i; + return i; } //! Requires: header1 and header2 must be the header nodes @@ -659,6 +694,22 @@ 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; @@ -875,8 +926,9 @@ class tree_algorithms template static std::pair insert_unique_check (const_node_ptr header, const KeyType &key - ,KeyNodePtrCompare comp, insert_commit_data &commit_data) + ,KeyNodePtrCompare comp, insert_commit_data &commit_data, std::size_t *pdepth = 0) { + std::size_t depth = 0; node_ptr h(uncast(header)); node_ptr y(h); node_ptr x(NodeTraits::get_parent(y)); @@ -886,11 +938,14 @@ class tree_algorithms //store it in the left or right node bool left_child = true; while(x){ + ++depth; y = x; x = (left_child = comp(key, x)) ? NodeTraits::get_left(x) : (prev = y, NodeTraits::get_right(x)); } + if(pdepth) *pdepth = depth; + //Since we've found the upper bound there is no other value with the same key if: // - There is no previous node // - The previous node is less than the key @@ -909,7 +964,7 @@ class tree_algorithms template static std::pair insert_unique_check (const_node_ptr header, node_ptr hint, const KeyType &key - ,KeyNodePtrCompare comp, insert_commit_data &commit_data) + ,KeyNodePtrCompare comp, insert_commit_data &commit_data, std::size_t *pdepth = 0) { //hint must be bigger than the key if(hint == header || comp(key, hint)){ @@ -918,15 +973,18 @@ class tree_algorithms if(prev == NodeTraits::get_left(header) || comp((prev = prev_node(hint)), key)){ commit_data.link_left = unique(header) || !NodeTraits::get_left(hint); commit_data.node = commit_data.link_left ? hint : prev; + if(pdepth){ + *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1; + } return std::pair(node_ptr(), true); } else{ - return insert_unique_check(header, key, comp, commit_data); + return insert_unique_check(header, key, comp, commit_data, pdepth); } } //The hint was wrong, use hintless insert else{ - return insert_unique_check(header, key, comp, commit_data); + return insert_unique_check(header, key, comp, commit_data, pdepth); } } @@ -946,7 +1004,7 @@ class tree_algorithms //! Throws: If "comp" throws. template static node_ptr insert_equal - (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp) + (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp, std::size_t *pdepth = 0) { if(hint == header || !comp(hint, new_node)){ node_ptr prev(hint); @@ -954,25 +1012,48 @@ class tree_algorithms !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; } else{ - return insert_equal_upper_bound(header, new_node, comp); + return insert_equal_upper_bound(header, new_node, comp, pdepth); } } else{ - return insert_equal_lower_bound(header, new_node, comp); + return insert_equal_lower_bound(header, new_node, comp, pdepth); } } + //! Requires: p can't be a header node. + //! + //! Effects: Calculates the depth of a node: the depth of a + //! node is the length (number of edges) of the path from the root + //! to that node. (The root node is at depth 0.) + //! + //! Complexity: Logarithmic to the number of nodes in the tree. + //! + //! Throws: Nothing. + static std::size_t depth(const_node_ptr p) + { + std::size_t depth = 0; + node_ptr p_parent; + while(p != NodeTraits::get_parent(p_parent = NodeTraits::get_parent(p))){ + ++depth; + p = p_parent; + } + return depth; + } + template static node_ptr insert_equal_upper_bound - (node_ptr h, node_ptr new_node, NodePtrCompare comp) + (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); @@ -980,17 +1061,20 @@ class tree_algorithms 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) + (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); @@ -998,6 +1082,7 @@ class tree_algorithms bool link_left = (y == h) || !comp(y, new_node); link(h, new_node, y, link_left); + if(pdepth) *pdepth = depth; return new_node; } @@ -1240,7 +1325,6 @@ class tree_algorithms NodeTraits::set_left(z, 0); } - // delete node | complexity : constant | exception : nothrow static void erase(node_ptr header, node_ptr z) { data_for_rebalance ignored; @@ -1273,6 +1357,160 @@ class tree_algorithms } } + static void tree_to_vine(node_ptr header) + { subtree_to_vine(NodeTraits::get_parent(header)); } + + static void vine_to_tree(node_ptr header, std::size_t count) + { vine_to_subtree(NodeTraits::get_parent(header), count); } + + static void rebalance(node_ptr header) + { + //Taken from: + //"Tree rebalancing in optimal time and space" + //Quentin F. Stout and Bette L. Warren + std::size_t len; + 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; + node_ptr new_root = subtree_to_vine(old_root, &len); + return vine_to_subtree(new_root, len); + } + + static node_ptr subtree_to_vine(node_ptr old_root, std::size_t *plen = 0) + { + std::size_t len; + len = 0; + if(!old_root) return 0; + + //To avoid irregularities in the algorithm (old_root can be a + //left or right child or even the root of the tree) just put the + //root as the right child of its parent. Before doing this backup + //information to restore the original relationship after + //the algorithm is applied. + node_ptr super_root = NodeTraits::get_parent(old_root); + assert(super_root); + + //Get info + node_ptr super_root_right_backup = NodeTraits::get_right(super_root); + bool super_root_is_header = is_header(super_root); + bool old_root_is_right = is_right_child(old_root); + + node_ptr x(old_root); + node_ptr new_root(x); + node_ptr save; + bool moved_to_right = false; + for( ; x; x = save){ + save = NodeTraits::get_left(x); + if(save){ + // Right rotation + node_ptr save_right = NodeTraits::get_right(save); + node_ptr x_parent = NodeTraits::get_parent(x); + NodeTraits::set_parent(save, x_parent); + NodeTraits::set_right (x_parent, save); + NodeTraits::set_parent(x, save); + NodeTraits::set_right (save, x); + NodeTraits::set_left(x, save_right); + if(save_right) + NodeTraits::set_parent(save_right, x); + if(!moved_to_right) + new_root = save; + } + else{ + moved_to_right = true; + save = NodeTraits::get_right(x); + ++len; + } + } + + if(super_root_is_header){ + NodeTraits::set_right(super_root, super_root_right_backup); + NodeTraits::set_parent(super_root, new_root); + } + else if(old_root_is_right){ + NodeTraits::set_right(super_root, new_root); + } + else{ + NodeTraits::set_right(super_root, super_root_right_backup); + NodeTraits::set_left(super_root, new_root); + } + if(plen) *plen = len; + return new_root; + } + + static node_ptr vine_to_subtree(node_ptr old_root, std::size_t count) + { + std::size_t leaf_nodes = count + 1 - ((size_t) 1 << floor_log2 (count + 1)); + std::size_t vine_nodes = count - leaf_nodes; + + node_ptr new_root = compress_subtree(old_root, leaf_nodes); + while(vine_nodes > 1){ + vine_nodes /= 2; + new_root = compress_subtree(new_root, vine_nodes); + } + return new_root; + } + + static node_ptr compress_subtree(node_ptr old_root, std::size_t count) + { + if(!old_root) return old_root; + + //To avoid irregularities in the algorithm (old_root can be + //left or right child or even the root of the tree) just put the + //root as the right child of its parent. First obtain + //information to restore the original relationship after + //the algorithm is applied. + node_ptr super_root = NodeTraits::get_parent(old_root); + assert(super_root); + + //Get info + node_ptr super_root_right_backup = NodeTraits::get_right(super_root); + bool super_root_is_header = is_header(super_root); + bool old_root_is_right = is_right_child(old_root); + + //Put old_root as right child + NodeTraits::set_right(super_root, old_root); + + //Start the compression algorithm + node_ptr even_parent = super_root; + node_ptr new_root = old_root; + + while(count--){ + node_ptr even = NodeTraits::get_right(even_parent); + node_ptr odd = NodeTraits::get_right(even); + + if(new_root == old_root) + new_root = odd; + + node_ptr even_right = NodeTraits::get_left(odd); + NodeTraits::set_right(even, even_right); + if (even_right) + NodeTraits::set_parent(even_right, even); + + NodeTraits::set_right(even_parent, odd); + NodeTraits::set_parent(odd, even_parent); + NodeTraits::set_left(odd, even); + NodeTraits::set_parent(even, odd); + even_parent = odd; + } + + if(super_root_is_header){ + NodeTraits::set_parent(super_root, new_root); + NodeTraits::set_right(super_root, super_root_right_backup); + } + else if(old_root_is_right){ + NodeTraits::set_right(super_root, new_root); + } + else{ + NodeTraits::set_left(super_root, new_root); + NodeTraits::set_right(super_root, super_root_right_backup); + } + return new_root; + } + private: static void erase_impl(node_ptr header, node_ptr z, data_for_rebalance &info) { diff --git a/include/boost/intrusive/detail/utilities.hpp b/include/boost/intrusive/detail/utilities.hpp index a07d3b2..6529a97 100644 --- a/include/boost/intrusive/detail/utilities.hpp +++ b/include/boost/intrusive/detail/utilities.hpp @@ -19,7 +19,10 @@ #include #include #include +#include +#include #include +#include #include namespace boost { @@ -472,6 +475,75 @@ struct member_hook_traits } }; +//This function uses binary search to discover the +//highest set bit of the integer +inline std::size_t floor_log2 (std::size_t x) +{ + const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT; + const bool Size_t_Bits_Power_2= !(Bits & (Bits-1)); + BOOST_STATIC_ASSERT(Size_t_Bits_Power_2); + + std::size_t n = x; + std::size_t log2 = 0; + + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ + std::size_t tmp = n >> shift; + if (tmp) + log2 += shift, n = tmp; + } + + return log2; +} + +inline float fast_log2 (float val) +{ + boost::uint32_t * const exp_ptr = reinterpret_cast (&val); + boost::uint32_t x = *exp_ptr; + const int log_2 = (int)(((x >> 23) & 255) - 128); + x &= ~(255 << 23); + x += 127 << 23; + *exp_ptr = x; + + val = ((-1.0f/3) * val + 2) * val - 2.0f/3; + + return (val + log_2); +} + +inline std::size_t ceil_log2 (std::size_t x) +{ + return ((x & (x-1))!= 0) + floor_log2(x); +} + +template +struct sqrt2_pow_max; + +template<> +struct sqrt2_pow_max<32> +{ + static const std::size_t value = 0xb504f334; + static const std::size_t pow = 31; +}; + +#ifdef BOOST_NO_INT64_T + +template<> +struct sqrt2_pow_max<64> +{ + static const std::size_t value = 0xb504f333f9de6484; + static const std::size_t pow = 63; +}; + +#endif + +// Returns floor(pow(sqrt(2), x * 2 + 1)). +// Defined for X from 0 up to the number of bits in size_t minus 1. +inline std::size_t sqrt2_pow_2xplus1 (std::size_t x) +{ + const std::size_t value = sqrt2_pow_max::value; + const std::size_t pow = sqrt2_pow_max::pow; + return (value >> (pow - x)) + 1; +} + } //namespace detail } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index 1eeb2ff..e21f883 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -42,6 +42,23 @@ namespace intrusive { namespace detail{ +template +struct store_hash_bool +{ + template + struct two_or_three {one _[2 + Add];}; + template static one test(...); + template static two_or_three + test (detail::bool_* = 0); + static const std::size_t value = sizeof(test(0)); +}; + +template +struct store_hash_is_true +{ + static const bool value = store_hash_bool::value > sizeof(one)*2; +}; + template struct bucket_plus_size : public detail::size_holder @@ -320,9 +337,11 @@ class hashtable_impl 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; /// @cond private: + typedef detail::bool_ store_hash_t; typedef detail::size_holder size_traits; typedef detail::data_t base_type; typedef detail::transform_iterator @@ -737,14 +756,15 @@ class hashtable_impl iterator insert_equal(reference value) { - size_type bucket_num, hash_func; + size_type bucket_num, hash_value; siterator it = this->priv_find - (value, this->priv_hasher(), this->priv_equal(), bucket_num, hash_func); + (value, this->priv_hasher(), this->priv_equal(), bucket_num, hash_value); bucket_type &b = this->priv_buckets()[bucket_num]; if(it == invalid_local_it(this->get_real_bucket_traits())){ it = b.before_begin(); } node_ptr n = node_ptr(&from_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)); this->priv_size_traits().increment(); @@ -881,6 +901,7 @@ class hashtable_impl bucket_type &b = this->priv_buckets()[bucket_num]; this->priv_size_traits().increment(); node_ptr n = node_ptr(&from_value_to_node(value)); + this->priv_store_hash(n, commit_data.hash, store_hash_t()); if(safemode_or_autounlink) BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n)); return iterator( b.insert_after(b.before_begin(), *n), this); @@ -1262,8 +1283,8 @@ class hashtable_impl const_iterator find (const KeyType &key, KeyHasher hash_func, KeyValueEqual equal_func) const { - size_type bucket_n, hash; - siterator sit = this->priv_find(key, hash_func, equal_func, bucket_n, hash); + size_type bucket_n, hash_value; + siterator sit = this->priv_find(key, hash_func, equal_func, bucket_n, hash_value); return const_iterator(sit, this); } @@ -1636,10 +1657,9 @@ class hashtable_impl siterator i(old_bucket.begin()); for(;i != end; ++i){ const value_type &v = *this->get_real_value_traits().to_value_ptr(i.pointed_node()); - const std::size_t hash_value = this->priv_hasher()(v); + const std::size_t hash_value = this->priv_hash_when_rehashing(v, store_hash_t()); const size_type new_n = (power_2_buckets) - ? ( hash_value & (new_buckets_len-1)) - : ( hash_value % new_buckets_len); + ? (hash_value & (new_buckets_len-1)) : (hash_value % new_buckets_len); //If this is a buffer expansion don't move if it's not necessary if(same_buffer && new_n == n){ ++before_i; @@ -1723,6 +1743,19 @@ class hashtable_impl /// @cond private: + + std::size_t priv_hash_when_rehashing(const value_type &v, detail::true_) + { return node_traits::get_hash(this->get_real_value_traits().to_node_ptr(v)); } + + std::size_t priv_hash_when_rehashing(const value_type &v, detail::false_) + { return priv_hasher()(v); } + + void priv_store_hash(node_ptr p, std::size_t h, detail::true_) + { return node_traits::set_hash(p, h); } + + void priv_store_hash(node_ptr, std::size_t, detail::false_) + {} + static siterator invalid_local_it(const real_bucket_traits &b) { return b.bucket_begin()->end(); } diff --git a/include/boost/intrusive/intrusive_fwd.hpp b/include/boost/intrusive/intrusive_fwd.hpp index 49c6526..67d50a7 100644 --- a/include/boost/intrusive/intrusive_fwd.hpp +++ b/include/boost/intrusive/intrusive_fwd.hpp @@ -239,6 +239,48 @@ template > class avl_set_member_hook; +//sgtree/sg_set/sg_multiset +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +class sgtree; + +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +class sg_set; + +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +class sg_multiset; + +template + < class O1 = none + , class O2 = none + , class O3 = none + > +class bs_set_base_hook; + +template + < class O1 = none + , class O2 = none + , class O3 = none + > +class bs_set_member_hook; + //hash/unordered //rbtree/set/multiset template @@ -281,6 +323,7 @@ template < class O1 = none , class O2 = none , class O3 = none + , class O4 = none > class unordered_set_base_hook; @@ -288,6 +331,7 @@ template < class O1 = none , class O2 = none , class O3 = none + , class O4 = none > class unordered_set_member_hook; diff --git a/include/boost/intrusive/options.hpp b/include/boost/intrusive/options.hpp index 8a1a67a..3ced4ea 100644 --- a/include/boost/intrusive/options.hpp +++ b/include/boost/intrusive/options.hpp @@ -183,6 +183,30 @@ struct compare /// @endcond }; +//!This option setter for scapegoat containers specifies if +//!the intrusive scapegoat container should use a non-variable +//!alpha value that does not need floating-point operations. +//! +//!If activated, the fixed alpha value is 1/sqrt(2). This +//!option also saves some space in the container since +//!the alpha value and some additional data does not need +//!to be stored in the container. +//! +//!If the user only needs an alpha value near 1/sqrt(2), this +//!option also improves performance since avoids logarithm +//!and division operations when rebalancing the tree. +template +struct floating_point +{ +/// @cond + template + struct pack : Base + { + static const bool floating_point = Enabled; + }; +/// @endcond +}; + //!This option setter specifies the equality //!functor for the value type template @@ -341,6 +365,23 @@ struct bucket_traits /// @endcond }; +//!This option setter specifies if the unordered hook +//!should offer room to store the hash value. +//!Storing the hash in the hook will speed up rehashing +//!processes in applications where rehashing is frequent, +//!rehashing might throw or the value is heavy to hash. +template +struct store_hash +{ +/// @cond + template + struct pack : Base + { + static const bool store_hash = Enabled; + }; +/// @endcond +}; + //!This option setter specifies if the bucket array will be always power of two. //!This allows using masks instead of the default modulo operation to determine //!the bucket number from the hash value, leading to better performance. @@ -386,7 +427,7 @@ template , class O7 = none , class O8 = none , class O9 = none - , class Option10 = none + , class Option10 = none > struct pack_options { @@ -433,6 +474,7 @@ struct hook_defaults , link_mode , tag , optimize_size + , store_hash >::type {}; diff --git a/include/boost/intrusive/rbtree.hpp b/include/boost/intrusive/rbtree.hpp index fd2019b..1682a35 100644 --- a/include/boost/intrusive/rbtree.hpp +++ b/include/boost/intrusive/rbtree.hpp @@ -413,10 +413,7 @@ class rbtree_impl if(constant_time_size) return this->priv_size_traits().get_size(); else{ - const_iterator beg(this->cbegin()), end(this->cend()); - size_type i = 0; - for(;beg != end; ++beg) ++i; - return i; + return (size_type)node_algorithms::size(const_node_ptr(&priv_header())); } } diff --git a/include/boost/intrusive/rbtree_algorithms.hpp b/include/boost/intrusive/rbtree_algorithms.hpp index 76b4486..c5fae2a 100644 --- a/include/boost/intrusive/rbtree_algorithms.hpp +++ b/include/boost/intrusive/rbtree_algorithms.hpp @@ -334,6 +334,16 @@ class rbtree_algorithms 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. diff --git a/include/boost/intrusive/set.hpp b/include/boost/intrusive/set.hpp index a622cf9..03c52ab 100644 --- a/include/boost/intrusive/set.hpp +++ b/include/boost/intrusive/set.hpp @@ -114,8 +114,8 @@ class set_impl //! Effects: Detaches all elements from this. The objects in the set //! are not deleted (i.e. no destructors are called). //! - //! Complexity: O(log(size()) + size()) if it's a safe-mode or auto-unlink - //! value. Otherwise constant. + //! 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. ~set_impl() @@ -1179,8 +1179,8 @@ class multiset_impl //! Effects: Detaches all elements from this. The objects in the set //! are not deleted (i.e. no destructors are called). //! - //! Complexity: O(log(size()) + size()) if it's a safe-mode or - //! auto-unlink value. Otherwise constant. + //! 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. ~multiset_impl() diff --git a/include/boost/intrusive/set_hook.hpp b/include/boost/intrusive/set_hook.hpp index aea5398..f439866 100644 --- a/include/boost/intrusive/set_hook.hpp +++ b/include/boost/intrusive/set_hook.hpp @@ -58,18 +58,25 @@ struct make_set_base_hook }; //! Derive a class from set_base_hook in order to store objects in -//! in an set/multiset. set_base_hook holds the data necessary to maintain +//! in a set/multiset. set_base_hook holds the data necessary to maintain //! the set/multiset and provides an appropriate value_traits class for set/multiset. //! -//! The first integer template argument defines a tag to identify the node. +//! The hook admits the following options: \c tag<>, \c void_pointer<>, +//! \c link_mode<> and \c optimize_size<>. +//! +//! \c tag<> defines a tag to identify the node. //! The same tag value can be used in different classes, but if a class is -//! derived from more than one set_base_hook, then each set_base_hook needs its +//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its //! unique tag. //! -//! The second boolean template parameter will specify the linking mode of the 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. //! -//! The third argument is the pointer type that will be used internally in the hook -//! and the set/multiset configured from this hook. +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c optimize_size<> will tell the hook to optimize the hook for size instead +//! of speed. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else @@ -108,7 +115,7 @@ class set_base_hook //! Effects: If link_mode is \c normal_link, the destructor does //! nothing (ie. no code is generated). If link_mode is \c safe_link and the - //! object is stored in an set an assertion is raised. If link_mode is + //! object is stored in a set an assertion is raised. If link_mode is //! \c auto_unlink and \c is_linked() is true, the node is unlinked. //! //! Throws: Nothing. @@ -170,13 +177,20 @@ struct make_set_member_hook }; //! Put a public data member set_member_hook in order to store objects of this class in -//! an set/multiset. set_member_hook holds the data necessary for maintaining the +//! a set/multiset. set_member_hook holds the data necessary for maintaining the //! set/multiset and provides an appropriate value_traits class for set/multiset. //! -//! The first boolean template parameter will specify the linking mode of the hook. +//! The hook admits the following options: \c void_pointer<>, +//! \c link_mode<> and \c optimize_size<>. //! -//! The second argument is the pointer type that will be used internally in the hook -//! and the set/multiset configured from this 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. +//! +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c optimize_size<> will tell the hook to optimize the hook for size instead +//! of speed. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else @@ -215,7 +229,7 @@ class set_member_hook //! Effects: If link_mode is \c normal_link, the destructor does //! nothing (ie. no code is generated). If link_mode is \c safe_link and the - //! object is stored in an set an assertion is raised. If link_mode is + //! object is stored in a set an assertion is raised. If link_mode is //! \c auto_unlink and \c is_linked() is true, the node is unlinked. //! //! Throws: Nothing. diff --git a/include/boost/intrusive/sg_set.hpp b/include/boost/intrusive/sg_set.hpp new file mode 100644 index 0000000..2ef7799 --- /dev/null +++ b/include/boost/intrusive/sg_set.hpp @@ -0,0 +1,2147 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// 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_SG_SET_HPP +#define BOOST_INTRUSIVE_SG_SET_HPP + +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template sg_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<> and +//! \c compare<>. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class sg_set_impl +{ + /// @cond + typedef sgtree_impl tree_type; + //! This class is + //! non-copyable + sg_set_impl (const sg_set_impl&); + + //! This class is + //! non-assignable + sg_set_impl &operator =(const sg_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::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 sg_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. + sg_set_impl( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(cmp, 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 sg_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 + sg_set_impl( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(true, b, e, cmp, v_traits) + {} + + //! Effects: Detaches all elements from this. The objects in the sg_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. + ~sg_set_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed sg_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 sg_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 sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed sg_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 sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of sg_set. + //! + //! Effects: Returns a const reference to the sg_set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static sg_set_impl &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &sg_set_impl::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of sg_set. + //! + //! Effects: Returns a const reference to the sg_set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const sg_set_impl &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &sg_set_impl::tree_); + } + + //! Effects: Returns the key_compare object used by the sg_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 sg_set. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns true is the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return tree_.empty(); } + + //! Effects: Returns the number of elements stored in the sg_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(sg_set_impl& other) + { tree_.swap(other.tree_); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! 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. + //! + //! 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. + template + void clone_from(const sg_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 sg_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 sg_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 sg_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 sg_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 sg_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 sg_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 sg_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 sg_set between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the sg_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 sg_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(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(iterator b, 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) + { 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(iterator i, Disposer disposer) + { return tree_.erase_and_dispose(i, disposer); } + + //! 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(iterator b, 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) + { 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 sg_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the sg_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 sg_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! sg_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 sg_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the sg_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 sg_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! sg_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 sg_set/sg_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 sg_set_impl &x, const sg_set_impl &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const sg_set_impl &x, const sg_set_impl &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef 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 +template +#else +template +#endif +inline bool operator> +#ifdef 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 +template +#else +template +#endif +inline bool operator<= +#ifdef 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 +template +#else +template +#endif +inline bool operator>= +#ifdef 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 +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(sg_set_impl &x, sg_set_impl &y) +#else +(sg_set_impl &x, sg_set_impl &y) +#endif +{ x.swap(y); } + +//! 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 +template +#else +template +#endif +struct make_sg_set +{ + /// @cond + typedef sg_set_impl + < typename make_sgtree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class sg_set + : public make_sg_set::type +{ + typedef typename make_sg_set + ::type Base; + + public: + typedef typename Base::value_compare value_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)); + + sg_set( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + sg_set( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(b, e, cmp, v_traits) + {} + + static sg_set &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const sg_set &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + +//! The class template sg_multiset is an intrusive container, that mimics most of +//! the interface of std::sg_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<> and +//! \c compare<>. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class sg_multiset_impl +{ + /// @cond + typedef sgtree_impl tree_type; + + //Non-copyable and non-assignable + sg_multiset_impl (const sg_multiset_impl&); + sg_multiset_impl &operator =(const sg_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::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 sg_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/operator() of the value_compare object throws. + sg_multiset_impl( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(cmp, 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 sg_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 object throws. + template + sg_multiset_impl( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(false, b, e, cmp, v_traits) + {} + + //! Effects: Detaches all elements from this. The objects in the sg_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. + ~sg_multiset_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed sg_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 sg_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 sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed sg_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 sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of sg_multiset. + //! + //! Effects: Returns a const reference to the sg_multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static sg_multiset_impl &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &sg_multiset_impl::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of sg_multiset. + //! + //! Effects: Returns a const reference to the sg_multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const sg_multiset_impl &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &sg_multiset_impl::tree_); + } + + //! Effects: Returns the key_compare object used by the sg_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 sg_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns true is the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return tree_.empty(); } + + //! Effects: Returns the number of elements stored in the sg_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 sg_multisets. + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison functor + //! found using ADL throws. Strong guarantee. + void swap(sg_multiset_impl& other) + { tree_.swap(other.tree_); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! 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. + //! + //! 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. + template + void clone_from(const sg_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 sg_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 sg_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 sg_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(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(iterator b, 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) + { 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(iterator i, Disposer disposer) + { return tree_.erase_and_dispose(i, disposer); } + + //! 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(iterator b, 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) + { 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 sg_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the sg_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 sg_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! sg_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 sg_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the sg_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 sg_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! sg_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 sg_multiset/sg_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 sg_multiset_impl &x, const sg_multiset_impl &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const sg_multiset_impl &x, const sg_multiset_impl &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef 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 +template +#else +template +#endif +inline bool operator> +#ifdef 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 +template +#else +template +#endif +inline bool operator<= +#ifdef 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 +template +#else +template +#endif +inline bool operator>= +#ifdef 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 +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(sg_multiset_impl &x, sg_multiset_impl &y) +#else +(sg_multiset_impl &x, sg_multiset_impl &y) +#endif +{ x.swap(y); } + +//! 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 +template +#else +template +#endif +struct make_sg_multiset +{ + /// @cond + typedef sg_multiset_impl + < typename make_sgtree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class sg_multiset + : public make_sg_multiset::type +{ + typedef typename make_sg_multiset + ::type Base; + + public: + typedef typename Base::value_compare value_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)); + + sg_multiset( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + sg_multiset( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(b, e, cmp, v_traits) + {} + + static sg_multiset &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const sg_multiset &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SG_SET_HPP diff --git a/include/boost/intrusive/sgtree.hpp b/include/boost/intrusive/sgtree.hpp new file mode 100644 index 0000000..d62851f --- /dev/null +++ b/include/boost/intrusive/sgtree.hpp @@ -0,0 +1,1648 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// 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. +// +///////////////////////////////////////////////////////////////////////////// +// +// The option that yields to non-floating point 1/sqrt(2) alpha is taken +// from the scapegoat tree implementation of the PSPP library. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_SGTREE_HPP +#define BOOST_INTRUSIVE_SGTREE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +/// @cond + +namespace detail{ + +//! Returns floor(log(n)/log(sqrt(2))) -> floor(2*log2(n)) +//! Undefined if N is 0. +//! +//! This function does not use float point operations. +inline std::size_t calculate_h_sqrt2 (std::size_t n) +{ + std::size_t f_log2 = detail::floor_log2(n); + return (2*f_log2) + (n >= detail::sqrt2_pow_2xplus1 (f_log2)); +} + +struct h_alpha_sqrt2_t +{ + h_alpha_sqrt2_t(void){} + std::size_t operator()(std::size_t n) const + { return calculate_h_sqrt2(n); } +}; + +struct alpha_0_75_by_max_size_t +{ + alpha_0_75_by_max_size_t(void){} + std::size_t operator()(std::size_t max_tree_size) const + { + const std::size_t max_tree_size_limit = ((~std::size_t(0))/std::size_t(3)); + return max_tree_size > max_tree_size_limit ? max_tree_size/4*3 : max_tree_size*3/4; + } +}; + +struct h_alpha_t +{ + h_alpha_t(float inv_minus_logalpha) + : inv_minus_logalpha_(inv_minus_logalpha) + {} + + std::size_t operator()(std::size_t n) const + { + //Returns floor(log1/alpha(n)) -> + // floor(log(n)/log(1/alpha)) -> + // floor(log(n)/(-log(alpha))) + //return static_cast(std::log(float(n))*inv_minus_logalpha_); + return static_cast(detail::fast_log2(float(n))*inv_minus_logalpha_); + } + + private: + //Since the function will be repeatedly called + //precalculate constant data to avoid repeated + //calls to log and division. + //This will store 1/(-std::log(alpha_)) + float inv_minus_logalpha_; +}; + +struct alpha_by_max_size_t +{ + alpha_by_max_size_t(float alpha) + : alpha_(alpha) + {} + + float operator()(std::size_t max_tree_size) const + { return float(max_tree_size)*alpha_; } + + private: + float alpha_; + float inv_minus_logalpha_; +}; + +template +struct alpha_holder +{ + typedef boost::intrusive::detail::h_alpha_t h_alpha_t; + typedef boost::intrusive::detail::alpha_by_max_size_t multiply_by_alpha_t; + + alpha_holder() + { set_alpha(0.7f); } + + float get_alpha() const + { return alpha_; } + + void set_alpha(float alpha) + { + alpha_ = alpha; + inv_minus_logalpha_ = 1/(-detail::fast_log2(alpha)); + } + + h_alpha_t get_h_alpha_t() const + { return h_alpha_t(inv_minus_logalpha_); } + + multiply_by_alpha_t get_multiply_by_alpha_t() const + { return multiply_by_alpha_t(alpha_); } + + private: + float alpha_; + float inv_minus_logalpha_; +}; + +template<> +struct alpha_holder +{ + //This specialization uses alpha = 1/sqrt(2) + //without using floating point operations + //Downside: alpha CAN't be changed. + typedef boost::intrusive::detail::h_alpha_sqrt2_t h_alpha_t; + typedef boost::intrusive::detail::alpha_0_75_by_max_size_t multiply_by_alpha_t; + + float get_alpha() const + { return 0.70710677f; } + + void set_alpha(float) + { //alpha CAN't be changed. + assert(0); + } + + h_alpha_t get_h_alpha_t() const + { return h_alpha_t(); } + + multiply_by_alpha_t get_multiply_by_alpha_t() const + { return multiply_by_alpha_t(); } +}; + +} //namespace detail{ + +template +struct sg_setopt +{ + typedef ValueTraits value_traits; + typedef Compare compare; + typedef SizeType size_type; + static const bool floating_point = FloatingPoint; +}; + +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 + > + , floating_point + , size_type + , compare > + >::type +{}; + +/// @endcond + +//! The class template sgtree is an intrusive scapegoat tree container, that +//! is used to construct intrusive sg_set and sg_multiset containers. +//! The no-throw guarantee holds only, if the value_compare object +//! doesn'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 floating_point<>, \c size_type<> and +//! \c compare<>. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class sgtree_impl +{ + 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 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 sgtree_algorithms node_algorithms; + + static const bool floating_point = Config::floating_point; + static const bool constant_time_size = true; + static const bool stateful_value_traits = detail::store_cont_ptr_on_it::value; + + /// @cond + private: + typedef detail::size_holder size_traits; + typedef detail::alpha_holder alpha_traits; + typedef typename alpha_traits::h_alpha_t h_alpha_t; + typedef typename alpha_traits::multiply_by_alpha_t multiply_by_alpha_t; + + //noncopyable + sgtree_impl (const sgtree_impl&); + sgtree_impl operator =(const sgtree_impl&); + + enum { safemode_or_autounlink = + (int)real_value_traits::link_mode == (int)auto_unlink || + (int)real_value_traits::link_mode == (int)safe_link }; + + BOOST_STATIC_ASSERT(((int)real_value_traits::link_mode != (int)auto_unlink)); + + //BOOST_STATIC_ASSERT(( + // (int)real_value_traits::link_mode != (int)auto_unlink || + // !floating_point + // )); + + struct header_plus_alpha : public alpha_traits + { node header_; }; + + struct node_plus_pred_t : public detail::ebo_functor_holder + { + node_plus_pred_t(const value_compare &comp) + : detail::ebo_functor_holder(comp) + {} + header_plus_alpha header_plus_alpha_; + size_traits size_traits_; + }; + + struct data_t : public sgtree_impl::value_traits + { + typedef typename sgtree_impl::value_traits value_traits; + data_t(const value_compare & comp, const value_traits &val_traits) + : value_traits(val_traits), node_plus_pred_(comp) + , max_tree_size_(0) + {} + node_plus_pred_t node_plus_pred_; + size_type max_tree_size_; + } data_; + + float priv_alpha() const + { return this->priv_alpha_traits().get_alpha(); } + + void priv_alpha(float alpha) + { return this->priv_alpha_traits().set_alpha(alpha); } + + const value_compare &priv_comp() const + { return data_.node_plus_pred_.get(); } + + value_compare &priv_comp() + { return data_.node_plus_pred_.get(); } + + const node &priv_header() const + { return data_.node_plus_pred_.header_plus_alpha_.header_; } + + node &priv_header() + { return data_.node_plus_pred_.header_plus_alpha_.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_.size_traits_; } + + const size_traits &priv_size_traits() const + { return data_.node_plus_pred_.size_traits_; } + + alpha_traits &priv_alpha_traits() + { return data_.node_plus_pred_.header_plus_alpha_; } + + const alpha_traits &priv_alpha_traits() const + { return data_.node_plus_pred_.header_plus_alpha_; } + + 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); } + + h_alpha_t get_h_alpha_func() const + { return priv_alpha_traits().get_h_alpha_t(); } + + multiply_by_alpha_t get_alpha_by_max_size_func() const + { return priv_alpha_traits().get_multiply_by_alpha_t(); } + + /// @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: Nothing unless the copy constructor of the value_compare object throws. + sgtree_impl( value_compare cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : data_(cmp, 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: Nothing unless the copy constructor of the value_compare object throws. + template + sgtree_impl( bool unique, Iterator b, Iterator e + , value_compare cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : data_(cmp, 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. + //! + //! Throws: Nothing. + ~sgtree_impl() + { this->clear(); } + + //! 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 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 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 a reverse_iterator pointing to the beginning of the + //! reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return reverse_iterator(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(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(end()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return reverse_iterator(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(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(begin()); } + + //! Precondition: end_iterator must be a valid end iterator + //! of sgtree. + //! + //! Effects: Returns a const reference to the sgtree associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static sgtree_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 sgtree. + //! + //! Effects: Returns a const reference to the sgtree associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const sgtree_impl &container_from_end_iterator(const_iterator end_iterator) + { return priv_container_from_end_iterator(end_iterator); } + + //! 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 priv_comp(); } + + //! Effects: Returns true is 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. + //! + //! 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 multisets. + //! + //! Complexity: Constant. + //! + //! Throws: If the comparison functor's swap call throws. + void swap(sgtree_impl& other) + { + //This can throw + using std::swap; + swap(priv_comp(), priv_comp()); + swap(priv_alpha_traits(), priv_alpha_traits()); + swap(data_.max_tree_size_, other.data_.max_tree_size_); + //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: Nothing. + //! + //! 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); + 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(); + std::size_t max_tree_size = (std::size_t)data_.max_tree_size_; + node_ptr p = node_algorithms::insert_equal_upper_bound + (node_ptr(&priv_header()), to_insert, key_node_comp + , (size_type)this->size(), this->get_h_alpha_func(), max_tree_size); + data_.max_tree_size_ = (size_type)max_tree_size; + return iterator(p, 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: Nothing. + //! + //! 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); + 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(); + std::size_t max_tree_size = (std::size_t)data_.max_tree_size_; + node_ptr p = node_algorithms::insert_equal + (node_ptr(&priv_header()), hint.pointed_node(), to_insert, key_node_comp + , (std::size_t)this->size(), this->get_h_alpha_func(), max_tree_size); + data_.max_tree_size_ = (size_type)max_tree_size; + return iterator(p, 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: Nothing. + //! + //! 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: Nothing. + //! + //! 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, 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: Nothing. + //! + //! 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, 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: Nothing. + //! + //! 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); + } + } + + std::pair insert_unique_check + (const_reference value, insert_commit_data &commit_data) + { return insert_unique_check(value, priv_comp(), commit_data); } + + template + std::pair insert_unique_check + (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { + detail::key_nodeptr_comp + comp(key_value_comp, this); + std::pair ret = + (node_algorithms::insert_unique_check + (node_ptr(&priv_header()), key, comp, commit_data)); + 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); } + + template + std::pair insert_unique_check + (const_iterator hint, const KeyType &key + ,KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { + detail::key_nodeptr_comp + comp(key_value_comp, this); + std::pair ret = + (node_algorithms::insert_unique_check + (node_ptr(&priv_header()), hint.pointed_node(), key, comp, commit_data)); + return std::pair(iterator(ret.first, this), ret.second); + } + + 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(); + std::size_t max_tree_size = (std::size_t)data_.max_tree_size_; + node_algorithms::insert_unique_commit + ( node_ptr(&priv_header()), to_insert, commit_data + , (std::size_t)this->size(), this->get_h_alpha_func(), max_tree_size); + data_.max_tree_size_ = (size_type)max_tree_size; + return iterator(to_insert, this); + } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(iterator i) + { + 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)); + std::size_t max_tree_size = data_.max_tree_size_; + node_algorithms::erase + ( &priv_header(), to_erase, (std::size_t)this->size() + , max_tree_size, this->get_alpha_by_max_size_func()); + data_.max_tree_size_ = (size_type)max_tree_size; + this->priv_size_traits().decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + return ret; + } + + //! 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: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(iterator b, 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: Nothing. + //! + //! 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: Nothing. + //! + //! 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) + { + 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: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(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; + } + + //! 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(iterator b, 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: 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) + { + 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: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + { + 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. + //! + //! 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. + //! + //! 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. + template + void clone_from(const sgtree_impl &src, Cloner cloner, Disposer disposer) + { + this->clear_and_dispose(disposer); + if(!src.empty()){ + 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()); + } + } + + //! 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 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)); } + + //! Effects: Rebalances the tree. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear. + void rebalance() + { node_algorithms::rebalance(node_ptr(&priv_header())); } + + //! 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 iterator(node_algorithms::rebalance_subtree(root.pointed_node()), this); } + + //! Returns: The balance factor (alpha) used in this tree + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + float balance_factor() const + { return this->priv_alpha(); } + + //! 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) + { + BOOST_INTRUSIVE_INVARIANT_ASSERT((new_alpha > 0.5f && new_alpha < 1.0f)); + if(new_alpha < 0.5f && new_alpha >= 1.0f) return; + + //The alpha factor CAN't be changed if the fixed, floating operation-less + //1/sqrt(2) alpha factor option is activated + BOOST_STATIC_ASSERT((floating_point)); + float old_alpha = this->priv_alpha(); + this->priv_alpha(new_alpha); + + if(new_alpha < old_alpha){ + data_.max_tree_size_ = this->size(); + this->rebalance(); + } + } +/* + //! Effects: removes x from a tree of the appropriate type. It has no effect, + //! if x is not in such a tree. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This static function is only usable with the "safe mode" + //! hook and non-constant time size lists. Otherwise, the user must use + //! the non-static "erase(reference )" member. If the user calls + //! this function with a non "safe mode" or constant time size list + //! a compilation error will be issued. + template + static void remove_node(T& value) + { + //This function is only usable for safe mode hooks and non-constant + //time lists. + //BOOST_STATIC_ASSERT((!(safemode_or_autounlink && constant_time_size))); + BOOST_STATIC_ASSERT((!constant_time_size)); + BOOST_STATIC_ASSERT((boost::is_convertible::value)); + node_ptr to_remove(value_traits::to_node_ptr(value)); + node_algorithms::unlink_and_rebalance(to_remove); + if(safemode_or_autounlink) + node_algorithms::init(to_remove); + } +*/ + + /// @cond + private: + template + iterator private_erase(iterator b, iterator e, size_type &n, Disposer disposer) + { + for(n = 0; b != e; ++n) + this->erase_and_dispose(b++, disposer); + return b; + } + + iterator private_erase(iterator b, iterator e, size_type &n) + { + for(n = 0; b != e; ++n) + this->erase(b++); + return b; + } + /// @endcond + + private: + static sgtree_impl &priv_container_from_end_iterator(const const_iterator &end_iterator) + { + header_plus_alpha *r = detail::parent_from_member + ( detail::get_pointer(end_iterator.pointed_node()), &header_plus_alpha::header_); + node_plus_pred_t *n = detail::parent_from_member + (r, &node_plus_pred_t::header_plus_alpha_); + data_t *d = detail::parent_from_member(n, &data_t::node_plus_pred_); + sgtree_impl *scapegoat = detail::parent_from_member(d, &sgtree_impl::data_); + return *scapegoat; + } +}; + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator< +#ifdef 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 +template +#else +template +#endif +bool operator== +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const sgtree_impl &x, const sgtree_impl &y) +#else +(const sgtree_impl &x, const sgtree_impl &y) +#endif +{ + typedef sgtree_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; + } +} + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef 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 +template +#else +template +#endif +inline bool operator> +#ifdef 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 +template +#else +template +#endif +inline bool operator<= +#ifdef 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 +template +#else +template +#endif +inline bool operator>= +#ifdef 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 +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(sgtree_impl &x, sgtree_impl &y) +#else +(sgtree_impl &x, sgtree_impl &y) +#endif +{ x.swap(y); } + +/// @cond +template +struct make_sgtree_opt +{ + typedef typename pack_options + < sg_set_defaults, O1, O2, O3, O4>::type packed_options; + typedef typename detail::get_value_traits + ::type value_traits; + + typedef sg_setopt + < value_traits + , typename packed_options::compare + , typename packed_options::size_type + , packed_options::floating_point + > type; +}; +/// @endcond + +//! 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 +template +#else +template +#endif +struct make_sgtree +{ + /// @cond + typedef sgtree_impl + < typename make_sgtree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class sgtree + : public make_sgtree::type +{ + typedef typename make_sgtree + ::type Base; + + public: + typedef typename Base::value_compare value_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)); + + sgtree( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + sgtree( bool unique, Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(unique, b, e, cmp, v_traits) + {} + + static sgtree &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const sgtree &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SGTREE_HPP diff --git a/include/boost/intrusive/sgtree_algorithms.hpp b/include/boost/intrusive/sgtree_algorithms.hpp new file mode 100644 index 0000000..4f2a9c7 --- /dev/null +++ b/include/boost/intrusive/sgtree_algorithms.hpp @@ -0,0 +1,704 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007. +// +// 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. +// +///////////////////////////////////////////////////////////////////////////// +// +// Scapegoat tree algorithms are taken from the paper titled: +// "Scapegoat Trees" by Igal Galperin Ronald L. Rivest. +// +///////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTRUSIVE_SGTREE_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_SGTREE_ALGORITHMS_HPP + +#include + +#include +#include +#include +#include +#include +#include + + +namespace boost { +namespace intrusive { + +//! sgtree_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 sgtree_algorithms +{ + public: + typedef NodeTraits node_traits; + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + + /// @cond + private: + + typedef typename NodeTraits::node node; + 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 + : tree_algorithms::insert_commit_data + { + std::size_t depth; + }; + + //! 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. + static void unlink(node_ptr node) + { + node_ptr x = NodeTraits::get_parent(node); + if(x){ + while(!is_header(x)) + x = NodeTraits::get_parent(x); + tree_algorithms::erase(x, node); + } + } + + //! 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, std::size_t tree_size, std::size_t &max_tree_size, AlphaByMaxSize alpha_by_maxsize) + { + //typename tree_algorithms::data_for_rebalance info; + tree_algorithms::erase(header, z); + --tree_size; + if (tree_size > 0 && + tree_size < alpha_by_maxsize(max_tree_size)){ + tree_algorithms::rebalance(header); + max_tree_size = tree_size; + } + 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 + ,std::size_t tree_size, H_Alpha h_alpha, std::size_t &max_tree_size) + { + std::size_t depth; + tree_algorithms::insert_equal_upper_bound(h, new_node, comp, &depth); + rebalance_after_insertion(new_node, depth, tree_size+1, h_alpha, max_tree_size); + 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 + ,std::size_t tree_size, H_Alpha h_alpha, std::size_t &max_tree_size) + { + std::size_t depth; + tree_algorithms::insert_equal_lower_bound(h, new_node, comp, &depth); + rebalance_after_insertion(new_node, depth, tree_size+1, h_alpha, max_tree_size); + 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 header, node_ptr hint, node_ptr new_node, NodePtrCompare comp + ,std::size_t tree_size, H_Alpha h_alpha, std::size_t &max_tree_size) + { + std::size_t depth; + tree_algorithms::insert_equal(header, hint, new_node, comp, &depth); + rebalance_after_insertion(new_node, depth, tree_size+1, h_alpha, max_tree_size); + 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, insert_commit_data &commit_data) + { + std::size_t depth; + std::pair ret = + tree_algorithms::insert_unique_check(header, key, comp, commit_data, &depth); + commit_data.depth = depth; + 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, insert_commit_data &commit_data) + { + std::size_t depth; + std::pair ret = + tree_algorithms::insert_unique_check + (header, hint, key, comp, commit_data, &depth); + commit_data.depth = depth; + 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. + template + static void insert_unique_commit + (node_ptr header, node_ptr new_value, const insert_commit_data &commit_data + ,std::size_t tree_size, H_Alpha h_alpha, std::size_t &max_tree_size) + { + tree_algorithms::insert_unique_commit(header, new_value, commit_data); + rebalance_after_insertion(new_value, commit_data.depth, tree_size+1, h_alpha, max_tree_size); + } + + //! Requires: header must be the header of a tree. + //! + //! Effects: Rebalances the tree. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear. + static void rebalance(node_ptr header) + { tree_algorithms::rebalance(header); } + + //! 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. + static node_ptr rebalance_subtree(node_ptr old_root) + { return tree_algorithms::rebalance_subtree(old_root); } + + /// @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_after_insertion + ( node_ptr x, std::size_t depth + , std::size_t tree_size, H_Alpha h_alpha, std::size_t &max_tree_size) + { + if(tree_size > max_tree_size) + max_tree_size = tree_size; + + if(tree_size != 1 && depth > h_alpha(tree_size)){ + //Find the first non height-balanced node + //as described in the section 4.2 of the paper. + //This method is the alternative method described + //in the paper. Authors claim that this method + //may tend to yield more balanced trees on the average + //than the weight balanced method. + node_ptr s = x; + std::size_t size = 1; + + for(std::size_t i = 1; true; ++i){ + bool rebalance = false; + if(i == depth){ + assert(tree_size == count(s)); + rebalance = true; + } + else if(i > h_alpha(size)){ + node_ptr s_parent = NodeTraits::get_parent(s); + node_ptr s_parent_left = NodeTraits::get_left(s_parent); + size += 1 + tree_algorithms::count + ( s_parent_left == s ? NodeTraits::get_right(s_parent) : s_parent_left ); + s = s_parent; + rebalance = true; + } + if(rebalance){ + rebalance_subtree(s); + break; + } + } + } + } + + /// @endcond +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SGTREE_ALGORITHMS_HPP diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index dbfb503..dadd25b 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -565,7 +565,7 @@ class slist_impl if(node_traits::get_next(first) == root) return; bool end_found = false; - node_ptr new_last; + node_ptr new_last(0); //Now find the new last node according to the shift count. //If we find the root node before finding the new last node diff --git a/include/boost/intrusive/slist_hook.hpp b/include/boost/intrusive/slist_hook.hpp index a08f071..547ca6f 100644 --- a/include/boost/intrusive/slist_hook.hpp +++ b/include/boost/intrusive/slist_hook.hpp @@ -60,15 +60,19 @@ struct make_slist_base_hook //! in an list. slist_base_hook holds the data necessary to maintain the //! list and provides an appropriate value_traits class for list. //! -//! The first integer template argument defines a tag to identify the node. +//! The hook admits the following options: \c tag<>, \c void_pointer<> and +//! \c link_mode<>. +//! +//! \c tag<> defines a tag to identify the node. //! The same tag value can be used in different classes, but if a class is -//! derived from more than one slist_base_hook, then each slist_base_hook needs its +//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its //! unique tag. //! -//! The second boolean template parameter will specify the linking mode of the hook. +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). //! -//! The third argument is the pointer type that will be used internally in the hook -//! and the list configured from this 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 template #else @@ -171,10 +175,14 @@ struct make_slist_member_hook //! an list. slist_member_hook holds the data necessary for maintaining the list and //! provides an appropriate value_traits class for list. //! -//! The first boolean template parameter will specify the linking mode of the hook. +//! The hook admits the following options: \c void_pointer<> and +//! \c link_mode<>. +//! +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). //! -//! The second argument is the pointer type that will be used internally in the hook -//! and the list configured from this 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 template #else diff --git a/include/boost/intrusive/splay_set.hpp b/include/boost/intrusive/splay_set.hpp index fb803c3..82aa409 100644 --- a/include/boost/intrusive/splay_set.hpp +++ b/include/boost/intrusive/splay_set.hpp @@ -98,7 +98,7 @@ class splay_set_impl //! [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). + //! comp and otherwise amortized 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) @@ -113,8 +113,8 @@ class splay_set_impl //! Effects: Detaches all elements from this. The objects in the splay_set //! are not deleted (i.e. no destructors are called). //! - //! Complexity: O(log(size()) + size()) if it's a safe-mode or auto-unlink - //! value. Otherwise constant. + //! 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. ~splay_set_impl() @@ -321,8 +321,7 @@ class splay_set_impl //! returns a pair containing an iterator to the already present value //! and false. //! - //! Complexity: Average complexity for insert element is at - //! most logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! @@ -339,7 +338,7 @@ class splay_set_impl //! Returns: An iterator that points to the position where the //! new element was inserted into the splay_set. //! - //! Complexity: Logarithmic in general, but it's amortized + //! Complexity: Amortized 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. @@ -362,7 +361,7 @@ class splay_set_impl //! pair boolean and fills "commit_data" that is meant to be used with //! the "insert_commit" function. //! - //! Complexity: Average complexity is at most logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If the key_value_comp ordering function throws. Strong guarantee. //! @@ -398,7 +397,7 @@ class splay_set_impl //! 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 + //! Complexity: Amortized 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. @@ -447,7 +446,7 @@ class splay_set_impl //! //! Effects: Inserts a range into the splay_set. //! - //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! Complexity: Insert range is amortized 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(). //! @@ -474,7 +473,7 @@ class splay_set_impl //! Effects: Erases the range pointed to by b end e. //! - //! Complexity: Average complexity for erase range is at most + //! Complexity: Average complexity for erase range is amortized //! O(log(size() + N)), where N is the number of elements in the range. //! //! Returns: An iterator to the element after the erased elements. @@ -490,7 +489,7 @@ class splay_set_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size()) + this->count(value)). + //! Complexity: Amortized O(log(size()) + this->count(value)). //! //! Throws: If the internal value_compare ordering function throws. Basic guarantee. //! @@ -504,7 +503,7 @@ class splay_set_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + this->count(key, comp)). + //! Complexity: Amortized O(log(size() + this->count(key, comp)). //! //! Throws: If the comp ordering function throws. Basic guarantee. //! @@ -556,7 +555,7 @@ class splay_set_impl //! //! Throws: If the internal value_compare ordering function throws. //! - //! Complexity: O(log(size() + this->count(value)). Basic guarantee. + //! Complexity: Amortized O(log(size() + this->count(value)). Basic guarantee. //! //! Throws: Nothing. //! @@ -574,7 +573,7 @@ class splay_set_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + this->count(key, comp)). + //! Complexity: Amortized O(log(size() + this->count(key, comp)). //! //! Throws: If comp ordering function throws. Basic guarantee. //! @@ -613,7 +612,7 @@ class splay_set_impl //! Effects: Returns the number of contained elements with the given key //! - //! Complexity: Logarithmic to the number of elements contained plus lineal + //! Complexity: Amortized 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. @@ -623,7 +622,7 @@ class splay_set_impl //! 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 + //! Complexity: Amortized logarithmic to the number of elements contained plus lineal //! to number of objects with the given key. //! //! Throws: If comp ordering function throws. @@ -654,7 +653,7 @@ class splay_set_impl //! 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. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. iterator lower_bound(const_reference value) @@ -668,7 +667,7 @@ class splay_set_impl //! key according to the comparison functor is not less than k or //! end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If comp ordering function throws. //! @@ -710,7 +709,7 @@ class splay_set_impl //! Effects: Returns an iterator to the first element whose //! key is greater than k or end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. iterator upper_bound(const_reference value) @@ -724,7 +723,7 @@ class splay_set_impl //! key according to the comparison functor is greater than key or //! end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If comp ordering function throws. //! @@ -766,7 +765,7 @@ class splay_set_impl //! Effects: Finds an iterator to the first element whose value is //! "value" or end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. iterator find(const_reference value) @@ -780,7 +779,7 @@ class splay_set_impl //! "key" according to the comparison functor or end() if that element //! does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If comp ordering function throws. //! @@ -823,7 +822,7 @@ class splay_set_impl //! an empty range that indicates the position where those elements would be //! if they there is no elements with key k. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. std::pair equal_range(const_reference value) @@ -838,7 +837,7 @@ class splay_set_impl //! that indicates the position where those elements would be //! if they there is no elements with key k. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If comp ordering function throws. //! @@ -984,7 +983,7 @@ class splay_set_impl //! Effects: Rearranges the splay set so that the element pointed by i //! is placed as the root of the tree, improving future searches of this value. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. void splay_up(iterator i) @@ -995,7 +994,7 @@ class splay_set_impl //! tree. If the element is not present returns the last node compared with the key. //! If the tree is empty, end() is returned. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Returns: An iterator to the new root of the tree, end() if the tree is empty. //! @@ -1008,7 +1007,7 @@ class splay_set_impl //! with a key equivalent to value the element is placed as the root of the //! tree. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Returns: An iterator to the new root of the tree, end() if the tree is empty. //! @@ -1016,6 +1015,26 @@ class splay_set_impl iterator splay_down(const value_type &value) { return tree_.splay_down(value); } + //! 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); } + /// @cond friend bool operator==(const splay_set_impl &x, const splay_set_impl &y) { return x.tree_ == y.tree_; } @@ -1220,7 +1239,7 @@ class splay_multiset_impl //! [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. + //! comp and otherwise amortized 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) @@ -1235,8 +1254,8 @@ class splay_multiset_impl //! Effects: Detaches all elements from this. The objects in the set //! are not deleted (i.e. no destructors are called). //! - //! Complexity: O(log(size()) + size()) if it's a safe-mode or - //! auto-unlink value. Otherwise constant. + //! 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. ~splay_multiset_impl() @@ -1440,8 +1459,7 @@ class splay_multiset_impl //! Returns: An iterator that points to the position where the new //! element was inserted. //! - //! Complexity: Average complexity for insert element is at - //! most logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! @@ -1458,7 +1476,7 @@ class splay_multiset_impl //! Returns: An iterator that points to the position where the new //! element was inserted. //! - //! Complexity: Logarithmic in general, but it is amortized + //! Complexity: Amortized 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. @@ -1476,7 +1494,7 @@ class splay_multiset_impl //! 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 + //! Complexity: Insert range is amortized 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(). //! @@ -1505,7 +1523,7 @@ class splay_multiset_impl //! //! Returns: An iterator to the element after the erased elements. //! - //! Complexity: Average complexity for erase range is at most + //! Complexity: Average complexity for erase range is amortized //! O(log(size() + N)), where N is the number of elements in the range. //! //! Throws: Nothing. @@ -1519,7 +1537,7 @@ class splay_multiset_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + this->count(value)). + //! Complexity: Amortized O(log(size() + this->count(value)). //! //! Throws: If the internal value_compare ordering function throws. Basic guarantee. //! @@ -1533,7 +1551,7 @@ class splay_multiset_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + this->count(key, comp)). + //! Complexity: Amortized O(log(size() + this->count(key, comp)). //! //! Throws: If comp ordering function throws. Basic guarantee. //! @@ -1567,7 +1585,7 @@ class splay_multiset_impl //! 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 + //! Complexity: Average complexity for erase range is amortized //! O(log(size() + N)), where N is the number of elements in the range. //! //! Throws: Nothing. @@ -1585,7 +1603,7 @@ class splay_multiset_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + this->count(value)). + //! Complexity: Amortized O(log(size() + this->count(value)). //! //! Throws: If the internal value_compare ordering function throws. Basic guarantee. //! @@ -1603,7 +1621,7 @@ class splay_multiset_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + this->count(key, comp)). + //! Complexity: Amortized O(log(size() + this->count(key, comp)). //! //! Throws: If comp ordering function throws. Basic guarantee. //! @@ -1642,7 +1660,7 @@ class splay_multiset_impl //! Effects: Returns the number of contained elements with the given key //! - //! Complexity: Logarithmic to the number of elements contained plus lineal + //! Complexity: Amortized 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. @@ -1652,7 +1670,7 @@ class splay_multiset_impl //! 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 + //! Complexity: Amortized logarithmic to the number of elements contained plus lineal //! to number of objects with the given key. //! //! Throws: If comp ordering function throws. @@ -1683,7 +1701,7 @@ class splay_multiset_impl //! 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. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. iterator lower_bound(const_reference value) @@ -1697,7 +1715,7 @@ class splay_multiset_impl //! key according to the comparison functor is not less than k or //! end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If comp ordering function throws. //! @@ -1739,7 +1757,7 @@ class splay_multiset_impl //! Effects: Returns an iterator to the first element whose //! key is greater than k or end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. iterator upper_bound(const_reference value) @@ -1753,7 +1771,7 @@ class splay_multiset_impl //! key according to the comparison functor is greater than key or //! end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If comp ordering function throws. //! @@ -1795,7 +1813,7 @@ class splay_multiset_impl //! Effects: Finds an iterator to the first element whose value is //! "value" or end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. iterator find(const_reference value) @@ -1809,7 +1827,7 @@ class splay_multiset_impl //! "key" according to the comparison functor or end() if that element //! does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If comp ordering function throws. //! @@ -1852,7 +1870,7 @@ class splay_multiset_impl //! an empty range that indicates the position where those elements would be //! if they there is no elements with key k. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If the internal value_compare ordering function throws. std::pair equal_range(const_reference value) @@ -1867,7 +1885,7 @@ class splay_multiset_impl //! that indicates the position where those elements would be //! if they there is no elements with key k. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: If comp ordering function throws. //! @@ -2013,7 +2031,7 @@ class splay_multiset_impl //! Effects: Rearranges the splay set so that the element pointed by i //! is placed as the root of the tree, improving future searches of this value. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. void splay_up(iterator i) @@ -2024,7 +2042,7 @@ class splay_multiset_impl //! tree. If the element is not present returns the last node compared with the key. //! If the tree is empty, end() is returned. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Returns: An iterator to the new root of the tree, end() if the tree is empty. //! @@ -2037,7 +2055,7 @@ class splay_multiset_impl //! with a key equivalent to value the element is placed as the root of the //! tree. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Returns: An iterator to the new root of the tree, end() if the tree is empty. //! @@ -2045,6 +2063,26 @@ class splay_multiset_impl iterator splay_down(const value_type &value) { return tree_.splay_down(value); } + //! 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); } + /// @cond friend bool operator==(const splay_multiset_impl &x, const splay_multiset_impl &y) { return x.tree_ == y.tree_; } diff --git a/include/boost/intrusive/splay_set_hook.hpp b/include/boost/intrusive/splay_set_hook.hpp index 69c5306..ddd7031 100644 --- a/include/boost/intrusive/splay_set_hook.hpp +++ b/include/boost/intrusive/splay_set_hook.hpp @@ -56,18 +56,22 @@ struct make_splay_set_base_hook }; //! Derive a class from splay_set_base_hook in order to store objects in -//! in an set/multiset. splay_set_base_hook holds the data necessary to maintain -//! the set/multiset and provides an appropriate value_traits class for set/multiset. +//! in a splay_set/splay_multiset. splay_set_base_hook holds the data necessary to maintain +//! the splay_set/splay_multiset and provides an appropriate value_traits class for splay_set/splay_multiset. //! -//! The first integer template argument defines a tag to identify the node. +//! The hook admits the following options: \c tag<>, \c void_pointer<>, +//! \c link_mode<> and \c optimize_size<>. +//! +//! \c tag<> defines a tag to identify the node. //! The same tag value can be used in different classes, but if a class is -//! derived from more than one splay_set_base_hook, then each splay_set_base_hook needs its +//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its //! unique tag. //! -//! The second boolean template parameter will specify the linking mode of the 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. //! -//! The third argument is the pointer type that will be used internally in the hook -//! and the set/multiset configured from this 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 template #else @@ -106,7 +110,7 @@ class splay_set_base_hook //! Effects: If link_mode is \c normal_link, the destructor does //! nothing (ie. no code is generated). If link_mode is \c safe_link and the - //! object is stored in an set an assertion is raised. If link_mode is + //! object is stored in a set an assertion is raised. If link_mode is //! \c auto_unlink and \c is_linked() is true, the node is unlinked. //! //! Throws: Nothing. @@ -166,14 +170,19 @@ struct make_splay_set_member_hook typedef implementation_defined type; }; -//! Put a public data member splay_set_member_hook in order to store objects of this class in -//! an set/multiset. splay_set_member_hook holds the data necessary for maintaining the -//! set/multiset and provides an appropriate value_traits class for set/multiset. +//! Put a public data member splay_set_member_hook in order to store objects of this +//! class in a splay_set/splay_multiset. splay_set_member_hook holds the data +//! necessary for maintaining the splay_set/splay_multiset and provides an appropriate +//! value_traits class for splay_set/splay_multiset. //! -//! The first boolean template parameter will specify the linking mode of the hook. +//! The hook admits the following options: \c void_pointer<>, +//! \c link_mode<> and \c optimize_size<>. //! -//! The second argument is the pointer type that will be used internally in the hook -//! and the set/multiset configured from this 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. +//! +//! \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 template #else @@ -212,7 +221,7 @@ class splay_set_member_hook //! Effects: If link_mode is \c normal_link, the destructor does //! nothing (ie. no code is generated). If link_mode is \c safe_link and the - //! object is stored in an set an assertion is raised. If link_mode is + //! object is stored in a set an assertion is raised. If link_mode is //! \c auto_unlink and \c is_linked() is true, the node is unlinked. //! //! Throws: Nothing. diff --git a/include/boost/intrusive/splaytree.hpp b/include/boost/intrusive/splaytree.hpp index 8b6fe15..d733f50 100644 --- a/include/boost/intrusive/splaytree.hpp +++ b/include/boost/intrusive/splaytree.hpp @@ -217,7 +217,7 @@ class splaytree_impl //! Effects: Constructs an empty tree. //! - //! Complexity: Constant. + //! Complexity: Constant. //! //! Throws: Nothing unless the copy constructor of the value_compare object throws. splaytree_impl( value_compare cmp = value_compare() @@ -235,7 +235,7 @@ class splaytree_impl //! [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. + //! 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. template @@ -256,7 +256,8 @@ class splaytree_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 the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. //! //! Throws: Nothing. ~splaytree_impl() @@ -413,10 +414,7 @@ class splaytree_impl return this->priv_size_traits().get_size(); } else{ - const_iterator beg(this->cbegin()), end(this->cend()); - size_type i = 0; - for(;beg != end; ++beg) ++i; - return i; + return (size_type)node_algorithms::size(const_node_ptr(&priv_header())); } } @@ -443,8 +441,8 @@ class splaytree_impl //! //! Effects: Inserts value into the tree before the lower bound. //! - //! Complexity: Average complexity for insert element is at - //! most logarithmic. + //! Complexity: Average complexity for insert element is amortized + //! logarithmic. //! //! Throws: Nothing. //! @@ -469,7 +467,7 @@ class splaytree_impl //! 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 + //! Complexity: Amortized logarithmic in general, but it is amortized //! constant time if t is inserted immediately before hint. //! //! Throws: Nothing. @@ -494,7 +492,7 @@ class splaytree_impl //! 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 + //! Complexity: Insert range is in general amortized 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(). //! @@ -517,8 +515,7 @@ class splaytree_impl //! Effects: Inserts value into the tree if the value //! is not already present. //! - //! Complexity: Average complexity for insert element is at - //! most logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. //! @@ -539,7 +536,7 @@ class splaytree_impl //! 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 + //! Complexity: Amortized logarithmic in general, but it is amortized //! constant time (two comparisons in the worst case) //! if t is inserted immediately before hint. //! @@ -561,7 +558,7 @@ class splaytree_impl //! //! 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 + //! Complexity: Insert range is in general amortized 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(). //! @@ -644,7 +641,7 @@ class splaytree_impl //! Effects: Erases the range pointed to by b end e. //! - //! Complexity: Average complexity for erase range is at most + //! Complexity: Average complexity for erase range is amortized //! O(log(size() + N)), where N is the number of elements in the range. //! //! Throws: Nothing. @@ -658,7 +655,7 @@ class splaytree_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + N). + //! Complexity: Amortized O(log(size() + N). //! //! Throws: Nothing. //! @@ -672,7 +669,7 @@ class splaytree_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + N). + //! Complexity: Amortized O(log(size() + N). //! //! Throws: Nothing. //! @@ -712,7 +709,7 @@ class splaytree_impl //! 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 + //! Complexity: Average complexity for erase range is amortized //! O(log(size() + N)), where N is the number of elements in the range. //! //! Throws: Nothing. @@ -730,7 +727,7 @@ class splaytree_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + N). + //! Complexity: Amortized O(log(size() + N). //! //! Throws: Nothing. //! @@ -753,7 +750,7 @@ class splaytree_impl //! //! Returns: The number of erased elements. //! - //! Complexity: O(log(size() + N). + //! Complexity: Amortized O(log(size() + N). //! //! Throws: Nothing. //! @@ -790,7 +787,7 @@ class splaytree_impl //! 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)), + //! Complexity: Amortized O(log(size() + N)), //! where N is the number of elements in the container. //! //! Throws: Nothing. @@ -808,7 +805,7 @@ class splaytree_impl //! Effects: Returns the number of contained elements with the given value //! - //! Complexity: Logarithmic to the number of elements contained plus lineal + //! Complexity: Amortized logarithmic to the number of elements contained plus lineal //! to number of objects with the given value. //! //! Throws: Nothing. @@ -817,7 +814,7 @@ class splaytree_impl //! Effects: Returns the number of contained elements with the given key //! - //! Complexity: Logarithmic to the number of elements contained plus lineal + //! Complexity: Amortized logarithmic to the number of elements contained plus lineal //! to number of objects with the given key. //! //! Throws: Nothing. @@ -830,7 +827,7 @@ class splaytree_impl //! Effects: Returns the number of contained elements with the given value //! - //! Complexity: Logarithmic to the number of elements contained plus lineal + //! Complexity: Amortized logarithmic to the number of elements contained plus lineal //! to number of objects with the given value. //! //! Throws: Nothing. @@ -839,7 +836,7 @@ class splaytree_impl //! Effects: Returns the number of contained elements with the given key //! - //! Complexity: Logarithmic to the number of elements contained plus lineal + //! Complexity: Amortized logarithmic to the number of elements contained plus lineal //! to number of objects with the given key. //! //! Throws: Nothing. @@ -853,7 +850,7 @@ class splaytree_impl //! 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. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. iterator lower_bound(const_reference value) @@ -901,7 +898,7 @@ class splaytree_impl //! Effects: Returns an iterator to the first element whose //! key is greater than k or end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. iterator upper_bound(const_reference value) @@ -911,7 +908,7 @@ class splaytree_impl //! key is greater than k according to comp or end() if that element //! does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. template @@ -951,7 +948,7 @@ class splaytree_impl //! Effects: Finds an iterator to the first element whose key is //! k or end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. iterator find(const_reference value) @@ -960,7 +957,7 @@ class splaytree_impl //! Effects: Finds an iterator to the first element whose key is //! k or end() if that element does not exist. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. template @@ -1000,7 +997,7 @@ class splaytree_impl //! an empty range that indicates the position where those elements would be //! if they there is no elements with key k. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. std::pair equal_range(const_reference value) @@ -1010,7 +1007,7 @@ class splaytree_impl //! an empty range that indicates the position where those elements would be //! if they there is no elements with key k. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. template @@ -1106,7 +1103,7 @@ class splaytree_impl //! Effects: Rearranges the splay set so that the element pointed by i //! is placed as the root of the tree, improving future searches of this value. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Throws: Nothing. void splay_up(iterator i) @@ -1117,7 +1114,7 @@ class splaytree_impl //! tree. If the element is not present returns the last node compared with the key. //! If the tree is empty, end() is returned. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Returns: An iterator to the new root of the tree, end() if the tree is empty. //! @@ -1135,7 +1132,7 @@ class splaytree_impl //! with a key equivalent to value the element is placed as the root of the //! tree. //! - //! Complexity: Logarithmic. + //! Complexity: Amortized logarithmic. //! //! Returns: An iterator to the new root of the tree, end() if the tree is empty. //! @@ -1238,6 +1235,26 @@ class splaytree_impl static void init_node(reference value) { node_algorithms::init(value_traits::to_node_ptr(value)); } + //! Effects: Rebalances the tree. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear. + void rebalance() + { node_algorithms::rebalance(node_ptr(&priv_header())); } + + //! 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 iterator(node_algorithms::rebalance_subtree(root.pointed_node()), this); } + /* //! Effects: removes x from a tree of the appropriate type. It has no effect, //! if x is not in such a tree. diff --git a/include/boost/intrusive/splaytree_algorithms.hpp b/include/boost/intrusive/splaytree_algorithms.hpp index 92a11ec..2fbcb92 100644 --- a/include/boost/intrusive/splaytree_algorithms.hpp +++ b/include/boost/intrusive/splaytree_algorithms.hpp @@ -291,6 +291,16 @@ class splaytree_algorithms 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: header1 and header2 must be the header nodes //! of two trees. //! @@ -361,20 +371,18 @@ class splaytree_algorithms template static std::pair insert_unique_check (node_ptr header, const KeyType &key - ,KeyNodePtrCompare comp, insert_commit_data &commit_data, bool splay = true) + ,KeyNodePtrCompare comp, insert_commit_data &commit_data) { - if(splay) - splay_down(header, key, comp); + splay_down(header, key, comp); return tree_algorithms::insert_unique_check(header, key, comp, commit_data); } template static std::pair insert_unique_check (node_ptr header, node_ptr hint, const KeyType &key - ,KeyNodePtrCompare comp, insert_commit_data &commit_data, bool splay = true) + ,KeyNodePtrCompare comp, insert_commit_data &commit_data) { - if(splay) - splay_down(header, key, comp); + splay_down(header, key, comp); return tree_algorithms::insert_unique_check(header, hint, key, comp, commit_data); } @@ -494,28 +502,25 @@ class splaytree_algorithms //! Throws: If "comp" throws. template static node_ptr insert_equal - (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp, bool splay = true) + (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp) { - if(splay) - splay_down(header, new_node, comp); + splay_down(header, new_node, comp); return tree_algorithms::insert_equal(header, hint, new_node, comp); } template static node_ptr insert_equal_upper_bound - (node_ptr header, node_ptr new_node, NodePtrCompare comp, bool splay = true) + (node_ptr header, node_ptr new_node, NodePtrCompare comp) { - if(splay) - splay_down(header, new_node, comp); + splay_down(header, new_node, comp); return tree_algorithms::insert_equal_upper_bound(header, new_node, comp); } template static node_ptr insert_equal_lower_bound - (node_ptr header, node_ptr new_node, NodePtrCompare comp, bool splay = true) + (node_ptr header, node_ptr new_node, NodePtrCompare comp) { - if(splay) - splay_down(header, new_node, comp); + splay_down(header, new_node, comp); return tree_algorithms::insert_equal_lower_bound(header, new_node, comp); } @@ -629,7 +634,7 @@ class splaytree_algorithms // top-down splay | complexity : logarithmic | exception : strong, note A template - static node_ptr splay_down(node_ptr header, const KeyType &key, KeyNodePtrCompare comp, bool splay = true) + static node_ptr splay_down(node_ptr header, const KeyType &key, KeyNodePtrCompare comp) { if(!NodeTraits::get_parent(header)) return header; @@ -728,6 +733,28 @@ class splaytree_algorithms return t; } + //! Requires: header must be the header of a tree. + //! + //! Effects: Rebalances the tree. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear. + static void rebalance(node_ptr header) + { tree_algorithms::rebalance(header); } + + //! 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. + static node_ptr rebalance_subtree(node_ptr old_root) + { return tree_algorithms::rebalance_subtree(old_root); } + private: /// @cond diff --git a/include/boost/intrusive/unordered_set_hook.hpp b/include/boost/intrusive/unordered_set_hook.hpp index 9096911..ffac564 100644 --- a/include/boost/intrusive/unordered_set_hook.hpp +++ b/include/boost/intrusive/unordered_set_hook.hpp @@ -25,10 +25,52 @@ namespace boost { namespace intrusive { /// @cond + template +struct slist_node_plus_hash +{ + typedef typename boost::pointer_to_other + ::type node_ptr; + node_ptr next_; + std::size_t hash_; +}; + +// slist_node_traits can be used with circular_slist_algorithms and supplies +// a slist_node holding the pointers needed for a singly-linked list +// it is used by slist_base_hook and slist_member_hook +template +struct slist_node_traits_plus_hash +{ + typedef slist_node_plus_hash node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + + static const bool store_hash = true; + + static node_ptr get_next(const_node_ptr n) + { return n->next_; } + + static void set_next(node_ptr n, node_ptr next) + { n->next_ = next; } + + static std::size_t get_hash(const_node_ptr n) + { return n->hash_; } + + static void set_hash(node_ptr n, std::size_t h) + { n->hash_ = h; } +}; + +template struct get_uset_node_algo { - typedef circular_slist_algorithms > type; + typedef typename detail::if_c + < StoreHash + , slist_node_traits_plus_hash + , slist_node_traits + >::type node_traits_type; + typedef circular_slist_algorithms type; }; /// @endcond @@ -37,16 +79,18 @@ struct get_uset_node_algo #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else -template +template #endif struct make_unordered_set_base_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + < hook_defaults, O1, O2, O3, O4>::type packed_options; typedef detail::generic_hook - < get_slist_node_algo + < get_uset_node_algo , typename packed_options::tag , packed_options::link_mode , detail::UsetBaseHook @@ -59,22 +103,29 @@ struct make_unordered_set_base_hook //! in an unordered_set/unordered_multi_set. unordered_set_base_hook holds the data necessary to maintain //! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set. //! -//! The first integer template argument defines a tag to identify the node. +//! The hook admits the following options: \c tag<>, \c void_pointer<>, +//! \c link_mode<> and \c store_hash<>. +//! +//! \c tag<> defines a tag to identify the node. //! The same tag value can be used in different classes, but if a class is -//! derived from more than one unordered_set_base_hook, then each unordered_set_base_hook needs its +//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its //! unique tag. //! -//! The second boolean template parameter will specify the linking mode of the 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. //! -//! The third argument is the pointer type that will be used internally in the hook -//! and the unordered_set/unordered_multi_set configured from this hook. +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c store_hash<> will tell the hook to store the hash of the value +//! to speed up rehashings. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else -template +template #endif class unordered_set_base_hook - : public make_unordered_set_base_hook::type + : public make_unordered_set_base_hook::type { #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED //! Effects: If link_mode is \c auto_unlink or \c safe_link @@ -149,16 +200,18 @@ class unordered_set_base_hook #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else -template +template #endif struct make_unordered_set_member_hook { /// @cond typedef typename pack_options - < hook_defaults, O1, O2, O3>::type packed_options; + < hook_defaults, O1, O2, O3, O4>::type packed_options; typedef detail::generic_hook - < get_uset_node_algo + < get_uset_node_algo< typename packed_options::void_pointer + , packed_options::store_hash + > , member_tag , packed_options::link_mode , detail::NoBaseHook @@ -171,17 +224,24 @@ struct make_unordered_set_member_hook //! an unordered_set/unordered_multi_set. unordered_set_member_hook holds the data necessary for maintaining the //! unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set. //! -//! The first boolean template parameter will specify the linking mode of the hook. +//! The hook admits the following options: \c void_pointer<>, +//! \c link_mode<> and \c store_hash<>. //! -//! The second argument is the pointer type that will be used internally in the hook -//! and the unordered_set/unordered_multi_set configured from this 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. +//! +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c store_hash<> will tell the hook to store the hash of the value +//! to speed up rehashings. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else -template +template #endif class unordered_set_member_hook - : public make_unordered_set_member_hook::type + : public make_unordered_set_member_hook::type { #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED //! Effects: If link_mode is \c auto_unlink or \c safe_link