blob: 32c8c5d3a620f98f1e8a27dcf2ac3087edf50f15 [file] [log] [blame]
/* Copyright 2003-2008 Joaquin M Lopez Munoz.
* 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/multi_index for library home page.
*
* The internal implementation of red-black trees is based on that of SGI STL
* stl_tree.h file:
*
* Copyright (c) 1996,1997
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_NODE_HPP
#define BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_NODE_HPP
#if defined(_MSC_VER)&&(_MSC_VER>=1200)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <cstddef>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/multi_index/detail/prevent_eti.hpp>
#if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES)
#include <boost/mpl/and.hpp>
#include <boost/mpl/if.hpp>
#include <boost/multi_index/detail/uintptr_type.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/is_same.hpp>
#endif
namespace boost{
namespace multi_index{
namespace detail{
/* definition of red-black nodes for ordered_index */
enum ordered_index_color{red=false,black=true};
enum ordered_index_side{to_left=false,to_right=true};
template<typename Allocator>
struct ordered_index_node_impl; /* fwd decl. */
template<typename Allocator>
struct ordered_index_node_std_base
{
typedef typename prevent_eti<
Allocator,
typename boost::detail::allocator::rebind_to<
Allocator,
ordered_index_node_impl<Allocator>
>::type
>::type::pointer pointer;
typedef typename prevent_eti<
Allocator,
typename boost::detail::allocator::rebind_to<
Allocator,
ordered_index_node_impl<Allocator>
>::type
>::type::const_pointer const_pointer;
typedef ordered_index_color& color_ref;
typedef pointer& parent_ref;
ordered_index_color& color(){return color_;}
ordered_index_color color()const{return color_;}
pointer& parent(){return parent_;}
pointer parent()const{return parent_;}
pointer& left(){return left_;}
pointer left()const{return left_;}
pointer& right(){return right_;}
pointer right()const{return right_;}
private:
ordered_index_color color_;
pointer parent_;
pointer left_;
pointer right_;
};
#if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES)
/* If ordered_index_node_impl has even alignment, we can use the least
* significant bit of one of the ordered_index_node_impl pointers to
* store color information. This typically reduces the size of
* ordered_index_node_impl by 25%.
*/
#if defined(BOOST_MSVC)
/* This code casts pointers to an integer type that has been computed
* to be large enough to hold the pointer, however the metaprogramming
* logic is not always spotted by the VC++ code analyser that issues a
* long list of warnings.
*/
#pragma warning(push)
#pragma warning(disable:4312 4311)
#endif
template<typename Allocator>
struct ordered_index_node_compressed_base
{
typedef ordered_index_node_impl<Allocator>* pointer;
typedef const ordered_index_node_impl<Allocator>* const_pointer;
struct color_ref
{
color_ref(uintptr_type* r_):r(r_){}
operator ordered_index_color()const
{
return ordered_index_color(*r&uintptr_type(1));
}
color_ref& operator=(ordered_index_color c)
{
*r&=~uintptr_type(1);
*r|=uintptr_type(c);
return *this;
}
color_ref& operator=(const color_ref& x)
{
return operator=(x.operator ordered_index_color());
}
private:
uintptr_type* r;
};
struct parent_ref
{
parent_ref(uintptr_type* r_):r(r_){}
operator pointer()const
{
return (pointer)(void*)(*r&~uintptr_type(1));
}
parent_ref& operator=(pointer p)
{
*r=((uintptr_type)(void*)p)|(*r&uintptr_type(1));
return *this;
}
parent_ref& operator=(const parent_ref& x)
{
return operator=(x.operator pointer());
}
pointer operator->()const
{
return operator pointer();
}
private:
uintptr_type* r;
};
color_ref color(){return color_ref(&parentcolor_);}
ordered_index_color color()const
{
return ordered_index_color(parentcolor_&std::size_t(1ul));
}
parent_ref parent(){return parent_ref(&parentcolor_);}
pointer parent()const
{
return (pointer)(void*)(parentcolor_&~uintptr_type(1));
}
pointer& left(){return left_;}
pointer left()const{return left_;}
pointer& right(){return right_;}
pointer right()const{return right_;}
private:
uintptr_type parentcolor_;
pointer left_;
pointer right_;
};
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#endif
template<typename Allocator>
struct ordered_index_node_impl_base:
#if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES)
mpl::if_c<
!(has_uintptr_type::value)||
(alignment_of<ordered_index_node_compressed_base<Allocator> >::value%2)||
!(is_same<
typename prevent_eti<
Allocator,
typename boost::detail::allocator::rebind_to<
Allocator,
ordered_index_node_impl<Allocator>
>::type
>::type::pointer,
ordered_index_node_impl<Allocator>*>::value),
ordered_index_node_std_base<Allocator>,
ordered_index_node_compressed_base<Allocator>
>::type
#else
ordered_index_node_std_base<Allocator>
#endif
{};
template<typename Allocator>
struct ordered_index_node_impl:ordered_index_node_impl_base<Allocator>
{
private:
typedef ordered_index_node_impl_base<Allocator> super;
public:
typedef typename super::color_ref color_ref;
typedef typename super::parent_ref parent_ref;
typedef typename super::pointer pointer;
typedef typename super::const_pointer const_pointer;
/* interoperability with bidir_node_iterator */
static void increment(pointer& x)
{
if(x->right()!=pointer(0)){
x=x->right();
while(x->left()!=pointer(0))x=x->left();
}
else{
pointer y=x->parent();
while(x==y->right()){
x=y;
y=y->parent();
}
if(x->right()!=y)x=y;
}
}
static void decrement(pointer& x)
{
if(x->color()==red&&x->parent()->parent()==x){
x=x->right();
}
else if(x->left()!=pointer(0)){
pointer y=x->left();
while(y->right()!=pointer(0))y=y->right();
x=y;
}else{
pointer y=x->parent();
while(x==y->left()){
x=y;
y=y->parent();
}
x=y;
}
}
/* algorithmic stuff */
static void rotate_left(pointer x,parent_ref root)
{
pointer y=x->right();
x->right()=y->left();
if(y->left()!=pointer(0))y->left()->parent()=x;
y->parent()=x->parent();
if(x==root) root=y;
else if(x==x->parent()->left())x->parent()->left()=y;
else x->parent()->right()=y;
y->left()=x;
x->parent()=y;
}
static pointer minimum(pointer x)
{
while(x->left()!=pointer(0))x=x->left();
return x;
}
static pointer maximum(pointer x)
{
while(x->right()!=pointer(0))x=x->right();
return x;
}
static void rotate_right(pointer x,parent_ref root)
{
pointer y=x->left();
x->left()=y->right();
if(y->right()!=pointer(0))y->right()->parent()=x;
y->parent()=x->parent();
if(x==root) root=y;
else if(x==x->parent()->right())x->parent()->right()=y;
else x->parent()->left()=y;
y->right()=x;
x->parent()=y;
}
static void rebalance(pointer x,parent_ref root)
{
x->color()=red;
while(x!=root&&x->parent()->color()==red){
if(x->parent()==x->parent()->parent()->left()){
pointer y=x->parent()->parent()->right();
if(y!=pointer(0)&&y->color()==red){
x->parent()->color()=black;
y->color()=black;
x->parent()->parent()->color()=red;
x=x->parent()->parent();
}
else{
if(x==x->parent()->right()){
x=x->parent();
rotate_left(x,root);
}
x->parent()->color()=black;
x->parent()->parent()->color()=red;
rotate_right(x->parent()->parent(),root);
}
}
else{
pointer y=x->parent()->parent()->left();
if(y!=pointer(0)&&y->color()==red){
x->parent()->color()=black;
y->color()=black;
x->parent()->parent()->color()=red;
x=x->parent()->parent();
}
else{
if(x==x->parent()->left()){
x=x->parent();
rotate_right(x,root);
}
x->parent()->color()=black;
x->parent()->parent()->color()=red;
rotate_left(x->parent()->parent(),root);
}
}
}
root->color()=black;
}
static void link(
pointer x,ordered_index_side side,pointer position,pointer header)
{
if(side==to_left){
position->left()=x; /* also makes leftmost=x when parent==header */
if(position==header){
header->parent()=x;
header->right()=x;
}
else if(position==header->left()){
header->left()=x; /* maintain leftmost pointing to min node */
}
}
else{
position->right()=x;
if(position==header->right()){
header->right()=x; /* maintain rightmost pointing to max node */
}
}
x->parent()=position;
x->left()=pointer(0);
x->right()=pointer(0);
ordered_index_node_impl::rebalance(x,header->parent());
}
static pointer rebalance_for_erase(
pointer z,parent_ref root,pointer& leftmost,pointer& rightmost)
{
pointer y=z;
pointer x=pointer(0);
pointer x_parent=pointer(0);
if(y->left()==pointer(0)){ /* z has at most one non-null child. y==z. */
x=y->right(); /* x might be null */
}
else{
if(y->right()==pointer(0)){ /* z has exactly one non-null child. y==z. */
x=y->left(); /* x is not null */
}
else{ /* z has two non-null children. Set y to */
y=y->right(); /* z's successor. x might be null. */
while(y->left()!=pointer(0))y=y->left();
x=y->right();
}
}
if(y!=z){
z->left()->parent()=y; /* relink y in place of z. y is z's successor */
y->left()=z->left();
if(y!=z->right()){
x_parent=y->parent();
if(x!=pointer(0))x->parent()=y->parent();
y->parent()->left()=x; /* y must be a child of left */
y->right()=z->right();
z->right()->parent()=y;
}
else{
x_parent=y;
}
if(root==z) root=y;
else if(z->parent()->left()==z)z->parent()->left()=y;
else z->parent()->right()=y;
y->parent()=z->parent();
ordered_index_color c=y->color();
y->color()=z->color();
z->color()=c;
y=z; /* y now points to node to be actually deleted */
}
else{ /* y==z */
x_parent=y->parent();
if(x!=pointer(0))x->parent()=y->parent();
if(root==z){
root=x;
}
else{
if(z->parent()->left()==z)z->parent()->left()=x;
else z->parent()->right()=x;
}
if(leftmost==z){
if(z->right()==pointer(0)){ /* z->left() must be null also */
leftmost=z->parent();
}
else{
leftmost=minimum(x); /* makes leftmost==header if z==root */
}
}
if(rightmost==z){
if(z->left()==pointer(0)){ /* z->right() must be null also */
rightmost=z->parent();
}
else{ /* x==z->left() */
rightmost=maximum(x); /* makes rightmost==header if z==root */
}
}
}
if(y->color()!=red){
while(x!=root&&(x==pointer(0)|| x->color()==black)){
if(x==x_parent->left()){
pointer w=x_parent->right();
if(w->color()==red){
w->color()=black;
x_parent->color()=red;
rotate_left(x_parent,root);
w=x_parent->right();
}
if((w->left()==pointer(0)||w->left()->color()==black) &&
(w->right()==pointer(0)||w->right()->color()==black)){
w->color()=red;
x=x_parent;
x_parent=x_parent->parent();
}
else{
if(w->right()==pointer(0 )
|| w->right()->color()==black){
if(w->left()!=pointer(0)) w->left()->color()=black;
w->color()=red;
rotate_right(w,root);
w=x_parent->right();
}
w->color()=x_parent->color();
x_parent->color()=black;
if(w->right()!=pointer(0))w->right()->color()=black;
rotate_left(x_parent,root);
break;
}
}
else{ /* same as above,with right <-> left */
pointer w=x_parent->left();
if(w->color()==red){
w->color()=black;
x_parent->color()=red;
rotate_right(x_parent,root);
w=x_parent->left();
}
if((w->right()==pointer(0)||w->right()->color()==black) &&
(w->left()==pointer(0)||w->left()->color()==black)){
w->color()=red;
x=x_parent;
x_parent=x_parent->parent();
}
else{
if(w->left()==pointer(0)||w->left()->color()==black){
if(w->right()!=pointer(0))w->right()->color()=black;
w->color()=red;
rotate_left(w,root);
w=x_parent->left();
}
w->color()=x_parent->color();
x_parent->color()=black;
if(w->left()!=pointer(0))w->left()->color()=black;
rotate_right(x_parent,root);
break;
}
}
}
if(x!=pointer(0))x->color()=black;
}
return y;
}
static void restore(pointer x,pointer position,pointer header)
{
if(position->left()==pointer(0)||position->left()==header){
link(x,to_left,position,header);
}
else{
decrement(position);
link(x,to_right,position,header);
}
}
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
/* invariant stuff */
static std::size_t black_count(pointer node,pointer root)
{
if(node==pointer(0))return 0;
std::size_t sum=0;
for(;;){
if(node->color()==black)++sum;
if(node==root)break;
node=node->parent();
}
return sum;
}
#endif
};
template<typename Super>
struct ordered_index_node_trampoline:
prevent_eti<
Super,
ordered_index_node_impl<
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
>
>::type
{
typedef typename prevent_eti<
Super,
ordered_index_node_impl<
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
>
>::type impl_type;
};
template<typename Super>
struct ordered_index_node:Super,ordered_index_node_trampoline<Super>
{
private:
typedef ordered_index_node_trampoline<Super> trampoline;
public:
typedef typename trampoline::impl_type impl_type;
typedef typename trampoline::color_ref impl_color_ref;
typedef typename trampoline::parent_ref impl_parent_ref;
typedef typename trampoline::pointer impl_pointer;
typedef typename trampoline::const_pointer const_impl_pointer;
impl_color_ref color(){return trampoline::color();}
ordered_index_color color()const{return trampoline::color();}
impl_parent_ref parent(){return trampoline::parent();}
impl_pointer parent()const{return trampoline::parent();}
impl_pointer& left(){return trampoline::left();}
impl_pointer left()const{return trampoline::left();}
impl_pointer& right(){return trampoline::right();}
impl_pointer right()const{return trampoline::right();}
impl_pointer impl()
{
return static_cast<impl_pointer>(
static_cast<impl_type*>(static_cast<trampoline*>(this)));
}
const_impl_pointer impl()const
{
return static_cast<const_impl_pointer>(
static_cast<const impl_type*>(static_cast<const trampoline*>(this)));
}
static ordered_index_node* from_impl(impl_pointer x)
{
return static_cast<ordered_index_node*>(
static_cast<trampoline*>(&*x));
}
static const ordered_index_node* from_impl(const_impl_pointer x)
{
return static_cast<const ordered_index_node*>(
static_cast<const trampoline*>(&*x));
}
/* interoperability with bidir_node_iterator */
static void increment(ordered_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::increment(xi);
x=from_impl(xi);
}
static void decrement(ordered_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::decrement(xi);
x=from_impl(xi);
}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif