ext-boost/boost/intrusive/rbtree_algorithms.hpp
2014-12-28 01:22:08 -02:00

574 lines
24 KiB
C++

/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Olaf Krzikalla 2004-2006.
// (C) Copyright Ion Gaztanaga 2006-2014.
//
// 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 tree destruction algorithm is based on Julienne Walker and The EC Team code:
//
// This code is in the public domain. Anyone may use it or change it in any way that
// they see fit. The author assumes no responsibility for damages incurred through
// use of the original code or any variations thereof.
//
// It is requested, but not required, that due credit is given to the original author
// and anyone who has modified the code through a header comment, such as this one.
#ifndef BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP
#define BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP
#if defined(_MSC_VER)
# pragma once
#endif
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <cstddef>
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/algo_type.hpp>
#include <boost/intrusive/bstree_algorithms.hpp>
#include <boost/intrusive/detail/ebo_functor_holder.hpp>
namespace boost {
namespace intrusive {
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class NodeTraits, class F>
struct rbtree_node_cloner
: private detail::ebo_functor_holder<F>
{
typedef typename NodeTraits::node_ptr node_ptr;
typedef detail::ebo_functor_holder<F> base_t;
rbtree_node_cloner(F f)
: base_t(f)
{}
node_ptr operator()(const node_ptr & p)
{
node_ptr n = base_t::get()(p);
NodeTraits::set_color(n, NodeTraits::get_color(p));
return n;
}
};
namespace detail {
template<class ValueTraits, class NodePtrCompare, class ExtraChecker>
struct rbtree_node_checker
: public bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker>
{
typedef bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> base_checker_t;
typedef ValueTraits value_traits;
typedef typename value_traits::node_traits node_traits;
typedef typename node_traits::const_node_ptr const_node_ptr;
typedef typename base_checker_t::return_type return_type;
rbtree_node_checker(const NodePtrCompare& comp, ExtraChecker extra_checker)
: base_checker_t(comp, extra_checker)
{}
void operator () (const const_node_ptr& p,
const return_type& check_return_left, const return_type& check_return_right,
return_type& check_return)
{
if (node_traits::get_color(p) == node_traits::red())
{
if (node_traits::get_left(p))
BOOST_INTRUSIVE_INVARIANT_ASSERT(node_traits::get_color(node_traits::get_left(p)) == node_traits::black());
if (node_traits::get_right(p))
BOOST_INTRUSIVE_INVARIANT_ASSERT(node_traits::get_color(node_traits::get_right(p)) == node_traits::black());
}
base_checker_t::operator()(p, check_return_left, check_return_right, check_return);
}
};
} // namespace detail
#endif //#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! rbtree_algorithms provides basic algorithms to manipulate
//! nodes forming a red-black tree. The insertion and deletion algorithms are
//! based on those in Cormen, Leiserson, and Rivest, Introduction to Algorithms
//! (MIT Press, 1990), except that
//!
//! (1) the header node is maintained with links not only to the root
//! but also to the leftmost node of the tree, to enable constant time
//! begin(), and to the rightmost node of the tree, to enable linear time
//! performance when used with the generic set algorithms (set_union,
//! etc.);
//!
//! (2) when a node being deleted has two children its successor node is
//! relinked into its place, rather than copied, so that the only
//! pointers invalidated are those referring to the deleted node.
//!
//! rbtree_algorithms is configured with a NodeTraits class, which encapsulates the
//! information about the node to be manipulated. NodeTraits must support the
//! following interface:
//!
//! <b>Typedefs</b>:
//!
//! <tt>node</tt>: The type of the node that forms the binary search tree
//!
//! <tt>node_ptr</tt>: A pointer to a node
//!
//! <tt>const_node_ptr</tt>: A pointer to a const node
//!
//! <tt>color</tt>: The type that can store the color of a node
//!
//! <b>Static functions</b>:
//!
//! <tt>static node_ptr get_parent(const_node_ptr n);</tt>
//!
//! <tt>static void set_parent(node_ptr n, node_ptr parent);</tt>
//!
//! <tt>static node_ptr get_left(const_node_ptr n);</tt>
//!
//! <tt>static void set_left(node_ptr n, node_ptr left);</tt>
//!
//! <tt>static node_ptr get_right(const_node_ptr n);</tt>
//!
//! <tt>static void set_right(node_ptr n, node_ptr right);</tt>
//!
//! <tt>static color get_color(const_node_ptr n);</tt>
//!
//! <tt>static void set_color(node_ptr n, color c);</tt>
//!
//! <tt>static color black();</tt>
//!
//! <tt>static color red();</tt>
template<class NodeTraits>
class rbtree_algorithms
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
: public bstree_algorithms<NodeTraits>
#endif
{
public:
typedef NodeTraits node_traits;
typedef typename NodeTraits::node node;
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
typedef typename NodeTraits::color color;
/// @cond
private:
typedef bstree_algorithms<NodeTraits> bstree_algo;
/// @endcond
public:
//! This type is the information that will be
//! filled by insert_unique_check
typedef typename bstree_algo::insert_commit_data insert_commit_data;
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::get_header(const const_node_ptr&)
static node_ptr get_header(const const_node_ptr & n);
//! @copydoc ::boost::intrusive::bstree_algorithms::begin_node
static node_ptr begin_node(const const_node_ptr & header);
//! @copydoc ::boost::intrusive::bstree_algorithms::end_node
static node_ptr end_node(const const_node_ptr & header);
//! @copydoc ::boost::intrusive::bstree_algorithms::swap_tree
static void swap_tree(const node_ptr & header1, const node_ptr & header2);
#endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(const node_ptr&,const node_ptr&)
static void swap_nodes(const node_ptr & node1, const node_ptr & node2)
{
if(node1 == node2)
return;
node_ptr header1(bstree_algo::get_header(node1)), header2(bstree_algo::get_header(node2));
swap_nodes(node1, header1, node2, header2);
}
//! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(const node_ptr&,const node_ptr&,const node_ptr&,const node_ptr&)
static void swap_nodes(const node_ptr & node1, const node_ptr & header1, const node_ptr & node2, const node_ptr & header2)
{
if(node1 == node2) return;
bstree_algo::swap_nodes(node1, header1, node2, header2);
//Swap color
color c = NodeTraits::get_color(node1);
NodeTraits::set_color(node1, NodeTraits::get_color(node2));
NodeTraits::set_color(node2, c);
}
//! @copydoc ::boost::intrusive::bstree_algorithms::replace_node(const node_ptr&,const node_ptr&)
static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & new_node)
{
if(node_to_be_replaced == new_node)
return;
replace_node(node_to_be_replaced, bstree_algo::get_header(node_to_be_replaced), new_node);
}
//! @copydoc ::boost::intrusive::bstree_algorithms::replace_node(const node_ptr&,const node_ptr&,const node_ptr&)
static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & header, const node_ptr & new_node)
{
bstree_algo::replace_node(node_to_be_replaced, header, new_node);
NodeTraits::set_color(new_node, NodeTraits::get_color(node_to_be_replaced));
}
//! @copydoc ::boost::intrusive::bstree_algorithms::unlink(const node_ptr&)
static void unlink(const node_ptr& node)
{
node_ptr x = NodeTraits::get_parent(node);
if(x){
while(!is_header(x))
x = NodeTraits::get_parent(x);
erase(x, node);
}
}
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::unlink_leftmost_without_rebalance
static node_ptr unlink_leftmost_without_rebalance(const node_ptr & header);
//! @copydoc ::boost::intrusive::bstree_algorithms::unique(const const_node_ptr&)
static bool unique(const const_node_ptr & node);
//! @copydoc ::boost::intrusive::bstree_algorithms::size(const const_node_ptr&)
static std::size_t size(const const_node_ptr & header);
//! @copydoc ::boost::intrusive::bstree_algorithms::next_node(const node_ptr&)
static node_ptr next_node(const node_ptr & node);
//! @copydoc ::boost::intrusive::bstree_algorithms::prev_node(const node_ptr&)
static node_ptr prev_node(const node_ptr & node);
//! @copydoc ::boost::intrusive::bstree_algorithms::init(const node_ptr&)
static void init(const node_ptr & node);
#endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::init_header(const node_ptr&)
static void init_header(const node_ptr & header)
{
bstree_algo::init_header(header);
NodeTraits::set_color(header, NodeTraits::red());
}
//! @copydoc ::boost::intrusive::bstree_algorithms::erase(const node_ptr&,const node_ptr&)
static node_ptr erase(const node_ptr & header, const node_ptr & z)
{
typename bstree_algo::data_for_rebalance info;
bstree_algo::erase(header, z, info);
color new_z_color;
if(info.y != z){
new_z_color = NodeTraits::get_color(info.y);
NodeTraits::set_color(info.y, NodeTraits::get_color(z));
}
else{
new_z_color = NodeTraits::get_color(z);
}
//Rebalance rbtree if needed
if(new_z_color != NodeTraits::red()){
rebalance_after_erasure(header, info.x, info.x_parent);
}
return z;
}
//! @copydoc ::boost::intrusive::bstree_algorithms::clone(const const_node_ptr&,const node_ptr&,Cloner,Disposer)
template <class Cloner, class Disposer>
static void clone
(const const_node_ptr & source_header, const node_ptr & target_header, Cloner cloner, Disposer disposer)
{
rbtree_node_cloner<NodeTraits, Cloner> new_cloner(cloner);
bstree_algo::clone(source_header, target_header, new_cloner, disposer);
}
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::clear_and_dispose(const node_ptr&,Disposer)
template<class Disposer>
static void clear_and_dispose(const node_ptr & header, Disposer disposer);
//! @copydoc ::boost::intrusive::bstree_algorithms::lower_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static node_ptr lower_bound
(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
//! @copydoc ::boost::intrusive::bstree_algorithms::upper_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static node_ptr upper_bound
(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
//! @copydoc ::boost::intrusive::bstree_algorithms::find(const const_node_ptr&, const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static node_ptr find
(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
//! @copydoc ::boost::intrusive::bstree_algorithms::equal_range(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static std::pair<node_ptr, node_ptr> equal_range
(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
//! @copydoc ::boost::intrusive::bstree_algorithms::bounded_range(const const_node_ptr&,const KeyType&,const KeyType&,KeyNodePtrCompare,bool,bool)
template<class KeyType, class KeyNodePtrCompare>
static std::pair<node_ptr, node_ptr> bounded_range
(const const_node_ptr & header, const KeyType &lower_key, const KeyType &upper_key, KeyNodePtrCompare comp
, bool left_closed, bool right_closed);
//! @copydoc ::boost::intrusive::bstree_algorithms::count(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static std::size_t count(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
#endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal_upper_bound(const node_ptr&,const node_ptr&,NodePtrCompare)
template<class NodePtrCompare>
static node_ptr insert_equal_upper_bound
(const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp)
{
bstree_algo::insert_equal_upper_bound(h, new_node, comp);
rebalance_after_insertion(h, new_node);
return new_node;
}
//! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal_lower_bound(const node_ptr&,const node_ptr&,NodePtrCompare)
template<class NodePtrCompare>
static node_ptr insert_equal_lower_bound
(const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp)
{
bstree_algo::insert_equal_lower_bound(h, new_node, comp);
rebalance_after_insertion(h, new_node);
return new_node;
}
//! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal(const node_ptr&,const node_ptr&,const node_ptr&,NodePtrCompare)
template<class NodePtrCompare>
static node_ptr insert_equal
(const node_ptr & header, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp)
{
bstree_algo::insert_equal(header, hint, new_node, comp);
rebalance_after_insertion(header, new_node);
return new_node;
}
//! @copydoc ::boost::intrusive::bstree_algorithms::insert_before(const node_ptr&,const node_ptr&,const node_ptr&)
static node_ptr insert_before
(const node_ptr & header, const node_ptr & pos, const node_ptr & new_node)
{
bstree_algo::insert_before(header, pos, new_node);
rebalance_after_insertion(header, new_node);
return new_node;
}
//! @copydoc ::boost::intrusive::bstree_algorithms::push_back(const node_ptr&,const node_ptr&)
static void push_back(const node_ptr & header, const node_ptr & new_node)
{
bstree_algo::push_back(header, new_node);
rebalance_after_insertion(header, new_node);
}
//! @copydoc ::boost::intrusive::bstree_algorithms::push_front(const node_ptr&,const node_ptr&)
static void push_front(const node_ptr & header, const node_ptr & new_node)
{
bstree_algo::push_front(header, new_node);
rebalance_after_insertion(header, new_node);
}
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_check(const const_node_ptr&,const KeyType&,KeyNodePtrCompare,insert_commit_data&)
template<class KeyType, class KeyNodePtrCompare>
static std::pair<node_ptr, bool> insert_unique_check
(const const_node_ptr & header, const KeyType &key
,KeyNodePtrCompare comp, insert_commit_data &commit_data);
//! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_check(const const_node_ptr&,const node_ptr&,const KeyType&,KeyNodePtrCompare,insert_commit_data&)
template<class KeyType, class KeyNodePtrCompare>
static std::pair<node_ptr, bool> insert_unique_check
(const const_node_ptr & header, const node_ptr &hint, const KeyType &key
,KeyNodePtrCompare comp, insert_commit_data &commit_data);
#endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_commit(const node_ptr&,const node_ptr&,const insert_commit_data&)
static void insert_unique_commit
(const node_ptr & header, const node_ptr & new_value, const insert_commit_data &commit_data)
{
bstree_algo::insert_unique_commit(header, new_value, commit_data);
rebalance_after_insertion(header, new_value);
}
//! @copydoc ::boost::intrusive::bstree_algorithms::is_header
static bool is_header(const const_node_ptr & p)
{
return NodeTraits::get_color(p) == NodeTraits::red() &&
bstree_algo::is_header(p);
}
/// @cond
private:
static void rebalance_after_erasure(const node_ptr & header, node_ptr x, node_ptr x_parent)
{
while(1){
if(x_parent == header || (x && NodeTraits::get_color(x) != NodeTraits::black())){
break;
}
//Don't cache x_is_leftchild or similar because x can be null and
//equal to both x_parent_left and x_parent_right
const node_ptr x_parent_left(NodeTraits::get_left(x_parent));
if(x == x_parent_left){ //x is left child
node_ptr w = NodeTraits::get_right(x_parent);
BOOST_INTRUSIVE_INVARIANT_ASSERT(w);
if(NodeTraits::get_color(w) == NodeTraits::red()){
NodeTraits::set_color(w, NodeTraits::black());
NodeTraits::set_color(x_parent, NodeTraits::red());
bstree_algo::rotate_left(x_parent, w, NodeTraits::get_parent(x_parent), header);
w = NodeTraits::get_right(x_parent);
}
node_ptr const w_left (NodeTraits::get_left(w));
node_ptr const w_right(NodeTraits::get_right(w));
if((!w_left || NodeTraits::get_color(w_left) == NodeTraits::black()) &&
(!w_right || NodeTraits::get_color(w_right) == NodeTraits::black())){
NodeTraits::set_color(w, NodeTraits::red());
x = x_parent;
x_parent = NodeTraits::get_parent(x_parent);
}
else {
if(!w_right || NodeTraits::get_color(w_right) == NodeTraits::black()){
NodeTraits::set_color(w_left, NodeTraits::black());
NodeTraits::set_color(w, NodeTraits::red());
bstree_algo::rotate_right(w, w_left, NodeTraits::get_parent(w), header);
w = NodeTraits::get_right(x_parent);
}
NodeTraits::set_color(w, NodeTraits::get_color(x_parent));
NodeTraits::set_color(x_parent, NodeTraits::black());
const node_ptr new_wright(NodeTraits::get_right(w));
if(new_wright)
NodeTraits::set_color(new_wright, NodeTraits::black());
bstree_algo::rotate_left(x_parent, NodeTraits::get_right(x_parent), NodeTraits::get_parent(x_parent), header);
break;
}
}
else {
// same as above, with right_ <-> left_.
node_ptr w = x_parent_left;
if(NodeTraits::get_color(w) == NodeTraits::red()){
NodeTraits::set_color(w, NodeTraits::black());
NodeTraits::set_color(x_parent, NodeTraits::red());
bstree_algo::rotate_right(x_parent, w, NodeTraits::get_parent(x_parent), header);
w = NodeTraits::get_left(x_parent);
}
node_ptr const w_left (NodeTraits::get_left(w));
node_ptr const w_right(NodeTraits::get_right(w));
if((!w_right || NodeTraits::get_color(w_right) == NodeTraits::black()) &&
(!w_left || NodeTraits::get_color(w_left) == NodeTraits::black())){
NodeTraits::set_color(w, NodeTraits::red());
x = x_parent;
x_parent = NodeTraits::get_parent(x_parent);
}
else {
if(!w_left || NodeTraits::get_color(w_left) == NodeTraits::black()){
NodeTraits::set_color(w_right, NodeTraits::black());
NodeTraits::set_color(w, NodeTraits::red());
bstree_algo::rotate_left(w, w_right, NodeTraits::get_parent(w), header);
w = NodeTraits::get_left(x_parent);
}
NodeTraits::set_color(w, NodeTraits::get_color(x_parent));
NodeTraits::set_color(x_parent, NodeTraits::black());
const node_ptr new_wleft(NodeTraits::get_left(w));
if(new_wleft)
NodeTraits::set_color(new_wleft, NodeTraits::black());
bstree_algo::rotate_right(x_parent, NodeTraits::get_left(x_parent), NodeTraits::get_parent(x_parent), header);
break;
}
}
}
if(x)
NodeTraits::set_color(x, NodeTraits::black());
}
static void rebalance_after_insertion(const node_ptr & header, node_ptr p)
{
NodeTraits::set_color(p, NodeTraits::red());
while(1){
node_ptr p_parent(NodeTraits::get_parent(p));
const node_ptr p_grandparent(NodeTraits::get_parent(p_parent));
if(p_parent == header || NodeTraits::get_color(p_parent) == NodeTraits::black() || p_grandparent == header){
break;
}
NodeTraits::set_color(p_grandparent, NodeTraits::red());
node_ptr const p_grandparent_left (NodeTraits::get_left (p_grandparent));
bool const p_parent_is_left_child = p_parent == p_grandparent_left;
node_ptr const x(p_parent_is_left_child ? NodeTraits::get_right(p_grandparent) : p_grandparent_left);
if(x && NodeTraits::get_color(x) == NodeTraits::red()){
NodeTraits::set_color(x, NodeTraits::black());
NodeTraits::set_color(p_parent, NodeTraits::black());
p = p_grandparent;
}
else{ //Final step
const bool p_is_left_child(NodeTraits::get_left(p_parent) == p);
if(p_parent_is_left_child){ //p_parent is left child
if(!p_is_left_child){ //p is right child
bstree_algo::rotate_left_no_parent_fix(p_parent, p);
//No need to link p and p_grandparent:
// [NodeTraits::set_parent(p, p_grandparent) + NodeTraits::set_left(p_grandparent, p)]
//as p_grandparent is not the header, another rotation is coming and p_parent
//will be the left child of p_grandparent
p_parent = p;
}
bstree_algo::rotate_right(p_grandparent, p_parent, NodeTraits::get_parent(p_grandparent), header);
}
else{ //p_parent is right child
if(p_is_left_child){ //p is left child
bstree_algo::rotate_right_no_parent_fix(p_parent, p);
//No need to link p and p_grandparent:
// [NodeTraits::set_parent(p, p_grandparent) + NodeTraits::set_right(p_grandparent, p)]
//as p_grandparent is not the header, another rotation is coming and p_parent
//will be the right child of p_grandparent
p_parent = p;
}
bstree_algo::rotate_left(p_grandparent, p_parent, NodeTraits::get_parent(p_grandparent), header);
}
NodeTraits::set_color(p_parent, NodeTraits::black());
break;
}
}
NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black());
}
/// @endcond
};
/// @cond
template<class NodeTraits>
struct get_algo<RbTreeAlgorithms, NodeTraits>
{
typedef rbtree_algorithms<NodeTraits> type;
};
template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
struct get_node_checker<RbTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
{
typedef detail::rbtree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
};
/// @endcond
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP