Chris@16: ///////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@101: // (C) Copyright Ion Gaztanaga 2006-2014. Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. Chris@16: // (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // See http://www.boost.org/libs/intrusive for documentation. Chris@16: // Chris@16: ///////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #ifndef BOOST_INTRUSIVE_TREAP_ALGORITHMS_HPP Chris@16: #define BOOST_INTRUSIVE_TREAP_ALGORITHMS_HPP Chris@16: Chris@16: #include Chris@101: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: Chris@101: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@101: # pragma once Chris@101: #endif Chris@16: Chris@16: namespace boost { Chris@16: namespace intrusive { Chris@16: Chris@101: #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@101: Chris@101: namespace detail Chris@101: { Chris@101: Chris@101: template Chris@101: struct treap_node_extra_checker Chris@101: : public ExtraChecker Chris@101: { Chris@101: typedef ExtraChecker base_checker_t; Chris@101: typedef ValueTraits value_traits; Chris@101: typedef typename value_traits::node_traits node_traits; Chris@101: typedef typename node_traits::const_node_ptr const_node_ptr; Chris@101: Chris@101: typedef typename base_checker_t::return_type return_type; Chris@101: Chris@101: treap_node_extra_checker(const NodePtrPrioCompare& prio_comp, ExtraChecker extra_checker) Chris@101: : base_checker_t(extra_checker), prio_comp_(prio_comp) Chris@101: {} Chris@101: Chris@101: void operator () (const const_node_ptr& p, Chris@101: const return_type& check_return_left, const return_type& check_return_right, Chris@101: return_type& check_return) Chris@101: { Chris@101: if (node_traits::get_left(p)) Chris@101: BOOST_INTRUSIVE_INVARIANT_ASSERT(!prio_comp_(node_traits::get_left(p), p)); Chris@101: if (node_traits::get_right(p)) Chris@101: BOOST_INTRUSIVE_INVARIANT_ASSERT(!prio_comp_(node_traits::get_right(p), p)); Chris@101: base_checker_t::operator()(p, check_return_left, check_return_right, check_return); Chris@101: } Chris@101: Chris@101: const NodePtrPrioCompare prio_comp_; Chris@101: }; Chris@101: Chris@101: } // namespace detail Chris@101: Chris@101: #endif //#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@101: Chris@16: //! treap_algorithms provides basic algorithms to manipulate Chris@16: //! nodes forming a treap. Chris@16: //! Chris@16: //! (1) the header node is maintained with links not only to the root Chris@16: //! but also to the leftmost node of the tree, to enable constant time Chris@16: //! begin(), and to the rightmost node of the tree, to enable linear time Chris@16: //! performance when used with the generic set algorithms (set_union, Chris@16: //! etc.); Chris@16: //! Chris@16: //! (2) when a node being deleted has two children its successor node is Chris@16: //! relinked into its place, rather than copied, so that the only Chris@16: //! pointers invalidated are those referring to the deleted node. Chris@16: //! Chris@16: //! treap_algorithms is configured with a NodeTraits class, which encapsulates the Chris@16: //! information about the node to be manipulated. NodeTraits must support the Chris@16: //! following interface: Chris@16: //! Chris@16: //! Typedefs: Chris@16: //! Chris@16: //! node: The type of the node that forms the treap Chris@16: //! Chris@16: //! node_ptr: A pointer to a node Chris@16: //! Chris@16: //! const_node_ptr: A pointer to a const node Chris@16: //! Chris@16: //! Static functions: Chris@16: //! Chris@16: //! static node_ptr get_parent(const_node_ptr n); Chris@16: //! Chris@16: //! static void set_parent(node_ptr n, node_ptr parent); Chris@16: //! Chris@16: //! static node_ptr get_left(const_node_ptr n); Chris@16: //! Chris@16: //! static void set_left(node_ptr n, node_ptr left); Chris@16: //! Chris@16: //! static node_ptr get_right(const_node_ptr n); Chris@16: //! Chris@16: //! static void set_right(node_ptr n, node_ptr right); Chris@16: template Chris@16: class treap_algorithms Chris@16: #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@16: : public bstree_algorithms Chris@16: #endif Chris@16: { Chris@16: public: Chris@16: typedef NodeTraits node_traits; Chris@16: typedef typename NodeTraits::node node; Chris@16: typedef typename NodeTraits::node_ptr node_ptr; Chris@16: typedef typename NodeTraits::const_node_ptr const_node_ptr; Chris@16: Chris@16: /// @cond Chris@16: private: Chris@16: Chris@16: typedef bstree_algorithms bstree_algo; Chris@16: Chris@16: class rerotate_on_destroy Chris@16: { Chris@16: rerotate_on_destroy& operator=(const rerotate_on_destroy&); Chris@16: Chris@16: public: Chris@16: rerotate_on_destroy(const node_ptr & header, const node_ptr & p, std::size_t &n) Chris@16: : header_(header), p_(p), n_(n), remove_it_(true) Chris@16: {} Chris@16: Chris@16: ~rerotate_on_destroy() Chris@16: { Chris@16: if(remove_it_){ Chris@16: rotate_up_n(header_, p_, n_); Chris@16: } Chris@16: } Chris@16: Chris@16: void release() Chris@16: { remove_it_ = false; } Chris@16: Chris@16: const node_ptr header_; Chris@16: const node_ptr p_; Chris@16: std::size_t &n_; Chris@16: bool remove_it_; Chris@16: }; Chris@16: Chris@16: static void rotate_up_n(const node_ptr header, const node_ptr p, std::size_t n) Chris@16: { Chris@101: node_ptr p_parent(NodeTraits::get_parent(p)); Chris@101: node_ptr p_grandparent(NodeTraits::get_parent(p_parent)); Chris@101: while(n--){ Chris@101: if(p == NodeTraits::get_left(p_parent)){ //p is left child Chris@101: bstree_algo::rotate_right(p_parent, p, p_grandparent, header); Chris@16: } Chris@101: else{ //p is right child Chris@101: bstree_algo::rotate_left(p_parent, p, p_grandparent, header); Chris@16: } Chris@101: p_parent = p_grandparent; Chris@101: p_grandparent = NodeTraits::get_parent(p_parent); Chris@16: } Chris@16: } Chris@16: Chris@16: /// @endcond Chris@16: Chris@16: public: Chris@16: //! This type is the information that will be Chris@16: //! filled by insert_unique_check Chris@16: struct insert_commit_data Chris@16: /// @cond Chris@16: : public bstree_algo::insert_commit_data Chris@16: /// @endcond Chris@16: { Chris@16: /// @cond Chris@16: std::size_t rotations; Chris@16: /// @endcond Chris@16: }; Chris@16: Chris@16: #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::get_header(const const_node_ptr&) Chris@16: static node_ptr get_header(const const_node_ptr & n); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::begin_node Chris@16: static node_ptr begin_node(const const_node_ptr & header); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::end_node Chris@16: static node_ptr end_node(const const_node_ptr & header); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::swap_tree Chris@16: static void swap_tree(const node_ptr & header1, const node_ptr & header2); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(const node_ptr&,const node_ptr&) Chris@16: static void swap_nodes(const node_ptr & node1, const node_ptr & node2); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(const node_ptr&,const node_ptr&,const node_ptr&,const node_ptr&) Chris@16: static void swap_nodes(const node_ptr & node1, const node_ptr & header1, const node_ptr & node2, const node_ptr & header2); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::replace_node(const node_ptr&,const node_ptr&) Chris@16: static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & new_node); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::replace_node(const node_ptr&,const node_ptr&,const node_ptr&) Chris@16: static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & header, const node_ptr & new_node); Chris@16: #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::unlink(const node_ptr&) Chris@16: template Chris@16: static void unlink(const node_ptr & node, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: node_ptr x = NodeTraits::get_parent(node); Chris@16: if(x){ Chris@16: while(!bstree_algo::is_header(x)) Chris@16: x = NodeTraits::get_parent(x); Chris@16: erase(x, node, pcomp); Chris@16: } Chris@16: } Chris@16: Chris@16: #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::unlink_leftmost_without_rebalance Chris@16: static node_ptr unlink_leftmost_without_rebalance(const node_ptr & header); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::unique(const const_node_ptr&) Chris@16: static bool unique(const const_node_ptr & node); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::size(const const_node_ptr&) Chris@16: static std::size_t size(const const_node_ptr & header); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::next_node(const node_ptr&) Chris@16: static node_ptr next_node(const node_ptr & node); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::prev_node(const node_ptr&) Chris@16: static node_ptr prev_node(const node_ptr & node); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::init(const node_ptr&) Chris@16: static void init(const node_ptr & node); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::init_header(const node_ptr&) Chris@16: static void init_header(const node_ptr & header); Chris@16: #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::erase(const node_ptr&,const node_ptr&) Chris@16: template Chris@16: static node_ptr erase(const node_ptr & header, const node_ptr & z, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: rebalance_for_erasure(header, z, pcomp); Chris@16: bstree_algo::erase(header, z); Chris@16: return z; Chris@16: } Chris@16: Chris@16: #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::clone(const const_node_ptr&,const node_ptr&,Cloner,Disposer) Chris@16: template Chris@16: static void clone Chris@16: (const const_node_ptr & source_header, const node_ptr & target_header, Cloner cloner, Disposer disposer); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::clear_and_dispose(const node_ptr&,Disposer) Chris@16: template Chris@16: static void clear_and_dispose(const node_ptr & header, Disposer disposer); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::lower_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare) Chris@16: template Chris@16: static node_ptr lower_bound Chris@16: (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::upper_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare) Chris@16: template Chris@16: static node_ptr upper_bound Chris@16: (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::find(const const_node_ptr&, const KeyType&,KeyNodePtrCompare) Chris@16: template Chris@16: static node_ptr find Chris@16: (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::equal_range(const const_node_ptr&,const KeyType&,KeyNodePtrCompare) Chris@16: template Chris@16: static std::pair equal_range Chris@16: (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::bounded_range(const const_node_ptr&,const KeyType&,const KeyType&,KeyNodePtrCompare,bool,bool) Chris@16: template Chris@16: static std::pair bounded_range Chris@16: (const const_node_ptr & header, const KeyType &lower_key, const KeyType &upper_key, KeyNodePtrCompare comp Chris@16: , bool left_closed, bool right_closed); Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::count(const const_node_ptr&,const KeyType&,KeyNodePtrCompare) Chris@16: template Chris@16: static std::size_t count(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp); Chris@101: Chris@16: #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@16: Chris@16: //! Requires: "h" must be the header node of a tree. Chris@16: //! NodePtrCompare is a function object that induces a strict weak Chris@16: //! ordering compatible with the strict weak ordering used to create the Chris@16: //! the tree. NodePtrCompare compares two node_ptrs. Chris@16: //! NodePtrPriorityCompare is a priority function object that induces a strict weak Chris@16: //! ordering compatible with the one used to create the Chris@16: //! the tree. NodePtrPriorityCompare compares two node_ptrs. Chris@16: //! Chris@16: //! Effects: Inserts new_node into the tree before the upper bound Chris@16: //! according to "comp" and rotates the tree according to "pcomp". Chris@16: //! Chris@16: //! Complexity: Average complexity for insert element is at Chris@16: //! most logarithmic. Chris@16: //! Chris@16: //! Throws: If "comp" throw or "pcomp" throw. Chris@16: template Chris@16: static node_ptr insert_equal_upper_bound Chris@16: (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: insert_commit_data commit_data; Chris@16: bstree_algo::insert_equal_upper_bound_check(h, new_node, comp, commit_data); Chris@16: rebalance_check_and_commit(h, new_node, pcomp, commit_data); Chris@16: return new_node; Chris@16: } Chris@16: Chris@16: //! Requires: "h" must be the header node of a tree. Chris@16: //! NodePtrCompare is a function object that induces a strict weak Chris@16: //! ordering compatible with the strict weak ordering used to create the Chris@16: //! the tree. NodePtrCompare compares two node_ptrs. Chris@16: //! NodePtrPriorityCompare is a priority function object that induces a strict weak Chris@16: //! ordering compatible with the one used to create the Chris@16: //! the tree. NodePtrPriorityCompare compares two node_ptrs. Chris@16: //! Chris@16: //! Effects: Inserts new_node into the tree before the upper bound Chris@16: //! according to "comp" and rotates the tree according to "pcomp". Chris@16: //! Chris@16: //! Complexity: Average complexity for insert element is at Chris@16: //! most logarithmic. Chris@16: //! Chris@16: //! Throws: If "comp" throws. Chris@16: template Chris@16: static node_ptr insert_equal_lower_bound Chris@16: (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: insert_commit_data commit_data; Chris@16: bstree_algo::insert_equal_lower_bound_check(h, new_node, comp, commit_data); Chris@16: rebalance_check_and_commit(h, new_node, pcomp, commit_data); Chris@16: return new_node; Chris@16: } Chris@16: Chris@16: //! Requires: "header" must be the header node of a tree. Chris@16: //! NodePtrCompare is a function object that induces a strict weak Chris@16: //! ordering compatible with the strict weak ordering used to create the Chris@16: //! the tree. NodePtrCompare compares two node_ptrs. "hint" is node from Chris@16: //! the "header"'s tree. Chris@16: //! NodePtrPriorityCompare is a priority function object that induces a strict weak Chris@16: //! ordering compatible with the one used to create the Chris@16: //! the tree. NodePtrPriorityCompare compares two node_ptrs. Chris@16: //! Chris@16: //! Effects: Inserts new_node into the tree, using "hint" as a hint to Chris@16: //! where it will be inserted. If "hint" is the upper_bound Chris@16: //! the insertion takes constant time (two comparisons in the worst case). Chris@16: //! Rotates the tree according to "pcomp". Chris@16: //! Chris@16: //! Complexity: Logarithmic in general, but it is amortized Chris@16: //! constant time if new_node is inserted immediately before "hint". Chris@16: //! Chris@16: //! Throws: If "comp" throw or "pcomp" throw. Chris@16: template Chris@16: static node_ptr insert_equal Chris@16: (const node_ptr & h, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: insert_commit_data commit_data; Chris@16: bstree_algo::insert_equal_check(h, hint, new_node, comp, commit_data); Chris@16: rebalance_check_and_commit(h, new_node, pcomp, commit_data); Chris@16: return new_node; Chris@16: } Chris@16: Chris@16: //! Requires: "header" must be the header node of a tree. Chris@16: //! "pos" must be a valid node of the tree (including header end) node. Chris@16: //! "pos" must be a node pointing to the successor to "new_node" Chris@16: //! once inserted according to the order of already inserted nodes. This function does not Chris@16: //! check "pos" and this precondition must be guaranteed by the caller. Chris@16: //! NodePtrPriorityCompare is a priority function object that induces a strict weak Chris@16: //! ordering compatible with the one used to create the Chris@16: //! the tree. NodePtrPriorityCompare compares two node_ptrs. Chris@16: //! Chris@16: //! Effects: Inserts new_node into the tree before "pos" Chris@16: //! and rotates the tree according to "pcomp". Chris@16: //! Chris@16: //! Complexity: Constant-time. Chris@16: //! Chris@16: //! Throws: If "pcomp" throws, strong guarantee. Chris@16: //! Chris@16: //! Note: If "pos" is not the successor of the newly inserted "new_node" Chris@16: //! tree invariants might be broken. Chris@16: template Chris@16: static node_ptr insert_before Chris@16: (const node_ptr & header, const node_ptr & pos, const node_ptr & new_node, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: insert_commit_data commit_data; Chris@16: bstree_algo::insert_before_check(header, pos, commit_data); Chris@16: rebalance_check_and_commit(header, new_node, pcomp, commit_data); Chris@16: return new_node; Chris@16: } Chris@16: Chris@16: //! Requires: "header" must be the header node of a tree. Chris@16: //! "new_node" must be, according to the used ordering no less than the Chris@16: //! greatest inserted key. Chris@16: //! NodePtrPriorityCompare is a priority function object that induces a strict weak Chris@16: //! ordering compatible with the one used to create the Chris@16: //! the tree. NodePtrPriorityCompare compares two node_ptrs. Chris@16: //! Chris@16: //! Effects: Inserts x into the tree in the last position Chris@16: //! and rotates the tree according to "pcomp". Chris@16: //! Chris@16: //! Complexity: Constant-time. Chris@16: //! Chris@16: //! Throws: If "pcomp" throws, strong guarantee. Chris@16: //! Chris@16: //! Note: If "new_node" is less than the greatest inserted key Chris@16: //! tree invariants are broken. This function is slightly faster than Chris@16: //! using "insert_before". Chris@16: template Chris@16: static void push_back(const node_ptr & header, const node_ptr & new_node, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: insert_commit_data commit_data; Chris@16: bstree_algo::push_back_check(header, commit_data); Chris@16: rebalance_check_and_commit(header, new_node, pcomp, commit_data); Chris@16: } Chris@16: Chris@16: //! Requires: "header" must be the header node of a tree. Chris@16: //! "new_node" must be, according to the used ordering, no greater than the Chris@16: //! lowest inserted key. Chris@16: //! NodePtrPriorityCompare is a priority function object that induces a strict weak Chris@16: //! ordering compatible with the one used to create the Chris@16: //! the tree. NodePtrPriorityCompare compares two node_ptrs. Chris@16: //! Chris@16: //! Effects: Inserts x into the tree in the first position Chris@16: //! and rotates the tree according to "pcomp". Chris@16: //! Chris@16: //! Complexity: Constant-time. Chris@16: //! Chris@16: //! Throws: If "pcomp" throws, strong guarantee. Chris@16: //! Chris@16: //! Note: If "new_node" is greater than the lowest inserted key Chris@16: //! tree invariants are broken. This function is slightly faster than Chris@16: //! using "insert_before". Chris@16: template Chris@16: static void push_front(const node_ptr & header, const node_ptr & new_node, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: insert_commit_data commit_data; Chris@16: bstree_algo::push_front_check(header, commit_data); Chris@16: rebalance_check_and_commit(header, new_node, pcomp, commit_data); Chris@16: } Chris@16: Chris@16: //! Requires: "header" must be the header node of a tree. Chris@16: //! KeyNodePtrCompare is a function object that induces a strict weak Chris@16: //! ordering compatible with the strict weak ordering used to create the Chris@16: //! the tree. NodePtrCompare compares KeyType with a node_ptr. Chris@16: //! Chris@16: //! Effects: Checks if there is an equivalent node to "key" in the Chris@16: //! tree according to "comp" and obtains the needed information to realize Chris@16: //! a constant-time node insertion if there is no equivalent node. Chris@16: //! Chris@16: //! Returns: If there is an equivalent value Chris@16: //! returns a pair containing a node_ptr to the already present node Chris@16: //! and false. If there is not equivalent key can be inserted returns true Chris@16: //! in the returned pair's boolean and fills "commit_data" that is meant to Chris@16: //! be used with the "insert_commit" function to achieve a constant-time Chris@16: //! insertion function. Chris@16: //! Chris@16: //! Complexity: Average complexity is at most logarithmic. Chris@16: //! Chris@16: //! Throws: If "comp" throws. Chris@16: //! Chris@16: //! Notes: This function is used to improve performance when constructing Chris@16: //! a node is expensive and the user does not want to have two equivalent nodes Chris@16: //! in the tree: if there is an equivalent value Chris@16: //! the constructed object must be discarded. Many times, the part of the Chris@16: //! node that is used to impose the order is much cheaper to construct Chris@16: //! than the node and this function offers the possibility to use that part Chris@16: //! to check if the insertion will be successful. Chris@16: //! Chris@16: //! If the check is successful, the user can construct the node and use Chris@16: //! "insert_commit" to insert the node in constant-time. This gives a total Chris@16: //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). Chris@16: //! Chris@16: //! "commit_data" remains valid for a subsequent "insert_unique_commit" only Chris@16: //! if no more objects are inserted or erased from the set. Chris@16: template Chris@16: static std::pair insert_unique_check Chris@16: (const const_node_ptr & header, const KeyType &key Chris@16: ,KeyNodePtrCompare comp, KeyNodePtrPrioCompare pcomp Chris@16: ,insert_commit_data &commit_data) Chris@16: { Chris@16: std::pair ret = Chris@16: bstree_algo::insert_unique_check(header, key, comp, commit_data); Chris@16: if(ret.second) Chris@16: rebalance_after_insertion_check(header, commit_data.node, key, pcomp, commit_data.rotations); Chris@16: return ret; Chris@16: } Chris@16: Chris@16: //! Requires: "header" must be the header node of a tree. Chris@16: //! KeyNodePtrCompare is a function object that induces a strict weak Chris@16: //! ordering compatible with the strict weak ordering used to create the Chris@16: //! the tree. NodePtrCompare compares KeyType with a node_ptr. Chris@16: //! "hint" is node from the "header"'s tree. Chris@16: //! Chris@16: //! Effects: Checks if there is an equivalent node to "key" in the Chris@16: //! tree according to "comp" using "hint" as a hint to where it should be Chris@16: //! inserted and obtains the needed information to realize Chris@16: //! a constant-time node insertion if there is no equivalent node. Chris@16: //! If "hint" is the upper_bound the function has constant time Chris@16: //! complexity (two comparisons in the worst case). Chris@16: //! Chris@16: //! Returns: If there is an equivalent value Chris@16: //! returns a pair containing a node_ptr to the already present node Chris@16: //! and false. If there is not equivalent key can be inserted returns true Chris@16: //! in the returned pair's boolean and fills "commit_data" that is meant to Chris@16: //! be used with the "insert_commit" function to achieve a constant-time Chris@16: //! insertion function. Chris@16: //! Chris@16: //! Complexity: Average complexity is at most logarithmic, but it is Chris@16: //! amortized constant time if new_node should be inserted immediately before "hint". Chris@16: //! Chris@16: //! Throws: If "comp" throws. Chris@16: //! Chris@16: //! Notes: This function is used to improve performance when constructing Chris@16: //! a node is expensive and the user does not want to have two equivalent nodes Chris@16: //! in the tree: if there is an equivalent value Chris@16: //! the constructed object must be discarded. Many times, the part of the Chris@16: //! node that is used to impose the order is much cheaper to construct Chris@16: //! than the node and this function offers the possibility to use that part Chris@16: //! to check if the insertion will be successful. Chris@16: //! Chris@16: //! If the check is successful, the user can construct the node and use Chris@16: //! "insert_commit" to insert the node in constant-time. This gives a total Chris@16: //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). Chris@16: //! Chris@16: //! "commit_data" remains valid for a subsequent "insert_unique_commit" only Chris@16: //! if no more objects are inserted or erased from the set. Chris@16: template Chris@16: static std::pair insert_unique_check Chris@16: (const const_node_ptr & header, const node_ptr & hint, const KeyType &key Chris@16: ,KeyNodePtrCompare comp, KeyNodePtrPrioCompare pcomp, insert_commit_data &commit_data) Chris@16: { Chris@16: std::pair ret = Chris@16: bstree_algo::insert_unique_check(header, hint, key, comp, commit_data); Chris@16: if(ret.second) Chris@16: rebalance_after_insertion_check(header, commit_data.node, key, pcomp, commit_data.rotations); Chris@16: return ret; Chris@16: } Chris@16: Chris@16: //! Requires: "header" must be the header node of a tree. Chris@16: //! "commit_data" must have been obtained from a previous call to Chris@16: //! "insert_unique_check". No objects should have been inserted or erased Chris@16: //! from the set between the "insert_unique_check" that filled "commit_data" Chris@16: //! and the call to "insert_commit". Chris@16: //! Chris@16: //! Chris@16: //! Effects: Inserts new_node in the set using the information obtained Chris@16: //! from the "commit_data" that a previous "insert_check" filled. Chris@16: //! Chris@16: //! Complexity: Constant time. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Notes: This function has only sense if a "insert_unique_check" has been Chris@16: //! previously executed to fill "commit_data". No value should be inserted or Chris@16: //! erased between the "insert_check" and "insert_commit" calls. Chris@16: static void insert_unique_commit Chris@16: (const node_ptr & header, const node_ptr & new_node, const insert_commit_data &commit_data) Chris@16: { Chris@16: bstree_algo::insert_unique_commit(header, new_node, commit_data); Chris@101: rotate_up_n(header, new_node, commit_data.rotations); Chris@16: } Chris@16: Chris@16: #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@16: Chris@16: //! @copydoc ::boost::intrusive::bstree_algorithms::is_header Chris@16: static bool is_header(const const_node_ptr & p); Chris@16: #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED Chris@16: Chris@16: /// @cond Chris@16: private: Chris@16: Chris@16: template Chris@16: static void rebalance_for_erasure(const node_ptr & header, const node_ptr & z, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: std::size_t n = 0; Chris@16: rerotate_on_destroy rb(header, z, n); Chris@16: Chris@16: node_ptr z_left = NodeTraits::get_left(z); Chris@16: node_ptr z_right = NodeTraits::get_right(z); Chris@16: while(z_left || z_right){ Chris@101: const node_ptr z_parent(NodeTraits::get_parent(z)); Chris@16: if(!z_right || (z_left && pcomp(z_left, z_right))){ Chris@101: bstree_algo::rotate_right(z, z_left, z_parent, header); Chris@16: } Chris@16: else{ Chris@101: bstree_algo::rotate_left(z, z_right, z_parent, header); Chris@16: } Chris@16: ++n; Chris@16: z_left = NodeTraits::get_left(z); Chris@16: z_right = NodeTraits::get_right(z); Chris@16: } Chris@16: rb.release(); Chris@16: } Chris@16: Chris@16: template Chris@16: static void rebalance_check_and_commit Chris@16: (const node_ptr & h, const node_ptr & new_node, NodePtrPriorityCompare pcomp, insert_commit_data &commit_data) Chris@16: { Chris@16: rebalance_after_insertion_check(h, commit_data.node, new_node, pcomp, commit_data.rotations); Chris@16: //No-throw Chris@16: bstree_algo::insert_unique_commit(h, new_node, commit_data); Chris@101: rotate_up_n(h, new_node, commit_data.rotations); Chris@16: } Chris@16: Chris@16: template Chris@16: static void rebalance_after_insertion_check Chris@16: (const const_node_ptr &header, const const_node_ptr & up, const Key &k Chris@16: , KeyNodePriorityCompare pcomp, std::size_t &num_rotations) Chris@16: { Chris@16: const_node_ptr upnode(up); Chris@16: //First check rotations since pcomp can throw Chris@16: num_rotations = 0; Chris@16: std::size_t n = 0; Chris@16: while(upnode != header && pcomp(k, upnode)){ Chris@16: ++n; Chris@16: upnode = NodeTraits::get_parent(upnode); Chris@16: } Chris@16: num_rotations = n; Chris@16: } Chris@16: Chris@16: template Chris@16: static bool check_invariant(const const_node_ptr & header, NodePtrPriorityCompare pcomp) Chris@16: { Chris@16: node_ptr beg = begin_node(header); Chris@16: node_ptr end = end_node(header); Chris@16: Chris@16: while(beg != end){ Chris@16: node_ptr p = NodeTraits::get_parent(beg); Chris@16: if(p != header){ Chris@16: if(pcomp(beg, p)) Chris@16: return false; Chris@16: } Chris@16: beg = next_node(beg); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: /// @endcond Chris@16: }; Chris@16: Chris@16: /// @cond Chris@16: Chris@16: template Chris@16: struct get_algo Chris@16: { Chris@16: typedef treap_algorithms type; Chris@16: }; Chris@16: Chris@101: template Chris@101: struct get_node_checker Chris@101: { Chris@101: typedef detail::bstree_node_checker type; Chris@101: }; Chris@101: Chris@16: /// @endcond Chris@16: Chris@16: } //namespace intrusive Chris@16: } //namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif //BOOST_INTRUSIVE_TREAP_ALGORITHMS_HPP