/* 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 |