This repository has been archived on 2024-12-16. You can view files and clone it, but cannot push or open issues or pull requests.
CodeBlocksPortable/WATCOM/h/_rbtree.h

2140 lines
70 KiB
C++

///////////////////////////////////////////////////////////////////////////
// FILE: _rbtree (std::_OW::RedBlackTree definition)
//
// =========================================================================
//
// Open Watcom Project
//
// Copyright (c) 2004-2010 The Open Watcom Contributors. All Rights Reserved.
//
// This file is automatically generated. Do not edit directly.
//
// =========================================================================
//
// Description: This header is an OpenWatcom red black tree container
// implementation. Although it not part of the 14882 C++ standard
// library it is written with a similar interface. It is used by
// the OpenWatcom implementation of the C++ standard library
// (map, set, multimap, multiset)
///////////////////////////////////////////////////////////////////////////
#ifndef __RBTREE_H_INCLUDED
#define __RBTREE_H_INCLUDED
#ifndef _ENABLE_AUTODEPEND
#pragma read_only_file;
#endif
#ifndef __cplusplus
#error This header file requires C++
#endif
#ifndef _UTILITY_INCLUDED
#include <utility>
#endif
#ifndef _ITERATOR_INCLUDED
#include <iterator>
#endif
#ifndef _FUNCTIONAL_INCLUDED
#include <function>
#endif
#ifndef _MEMORY_INCLUDED
#include <memory>
#endif
namespace std {
namespace _ow {
/* ==================================================================
* value wrappers
* Two classes/functors for set and map that allow single keys and
* pairs to be used so memory is not wasted. Provides a common
* interface for getting the key value so the same tree code can be used.
*/
template< class Key >
struct TreeKeyWrapper{
typedef Key const value_type;
Key const& operator()( value_type const & v ) const
{ return( v ); }
};
template< class Key, class Type >
struct TreePairWrapper{
typedef pair< Key const, Type > value_type;
Key const& operator()( value_type const & v ) const
{ return( v.first ); }
};
/* ==================================================================
* Red-Black Tree container interface
* To do:
* * find out what supposed to do with allocator alloc/construct exceptions
* * rebind and copy allocator
* * finish off all functions so has 14882 style interface
* * check const is used where ever it can/needed
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
class RedBlackTree{
public:
typedef ValueWrapper::value_type value_type;
typedef Key key_type;
typedef unsigned int size_type;
protected:
struct Node{
enum Chroma { red = 0, black = 1 };
value_type value;
Node* left;
Node* right;
private:
Node* parent;
#if 0
// simple implementation
Chroma colour;
public:
void setParent( Node* const p ) { parent = p; }
Node* getParent() { return( parent ); }
void setRed() { colour = red; }
void setBlack() { colour = black; }
Chroma getColour() { return( colour ); }
void setColour( Chroma c ) { colour = c; }
bool isRed() { return( colour == red ); }
bool isBlack() { return( colour == black ); }
#else
// colour hidden in parent
public:
void setParent( Node* const p )
{ // debug assert parent really has lsb clear ?
parent = (Node*)( (long)p | ((long)parent & 1) );
}
Node* getParent()
{ return( (Node*)( (long)parent & -2 ) ); }
void setRed()
{ parent = (Node*)( (long)parent & -2 ) ; }
void setBlack()
{ parent = (Node*)( (long)parent | 1 ) ; }
Chroma getColour()
{ return( (Chroma)( (long)parent & 1 ) ); }
void setColour( Chroma c )
{
parent = (Node*)( (long)parent & -2 );
parent = (Node*)( (long)parent | c );
}
bool isRed()
{ return( !( (long)parent & 1 ) ); }
bool isBlack()
{ return( (bool)( (long)parent & 1 ) ); }
#endif
Node( const value_type& v, Node* const p = 0, Chroma c = red )
: value( v ), left( 0 ), right( 0 )
{
setParent(p);
setColour(c);
}
};
// !!! moved up here until compiler bug fixed !!!
Allocator::rebind< Node >::other mem;
public:
class iterator;
//ctors and dtor
explicit RedBlackTree( Compare c, Allocator a )
: mRoot(0), mFirst(0), mLast(0), mSize(0), mError(0), cmp(c), mem(a)
{ }
template< class InputIterator >
RedBlackTree(
InputIterator f,
InputIterator l,
Compare const &c,
Allocator const &a )
: mRoot(0), mFirst(0), mLast(0), mSize(0), mError(0), cmp(c), mem(a)
{
// presume init data sorted, hint ignored when tree empty
iterator hint;
for( ; f != l ; ++f ) hint = insert( hint, *f ).first;
}
RedBlackTree( RedBlackTree const & );
RedBlackTree& operator=( RedBlackTree const & );
~RedBlackTree();
Allocator get_allocator() const
{ Allocator a( mem ); return( a ); }
/* ------------------------------------------------------------------
* iterators
*/
class iterator_base :
public std::iterator< std::bidirectional_iterator_tag, value_type> {
friend class RedBlackTree;
typedef RedBlackTree<Key, Compare, Allocator, ValueWrapper> rbt_type;
public:
bool operator==( iterator_base i )
{ return( self==i.self ); }
bool operator!=( iterator_base i )
{ return( self!=i.self ); }
iterator_base& operator++()
{
self = rbt->walkRight( self );
return *this;
}
iterator_base& operator--()
{
self ? self = rbt->walkLeft( self ) : self = rbt->mLast;
return *this;
}
protected:
iterator_base( iterator_base const & i ) : self( i.self ), rbt( i.rbt )
{ }
iterator_base() : self( 0 ), rbt( 0 )
{ }
iterator_base( rbt_type const * rb, Node* n ) : self(n), rbt(rb)
{ }
Node* getNodePtr()
{ return( self ); }
Node* self;
rbt_type const *rbt;
};
class iterator : public iterator_base{
public:
iterator() : iterator_base() { }
iterator( iterator_base const & i ) : iterator_base( i ) { }
iterator( rbt_type const * rb, Node* n )
: iterator_base( rb, n )
{ }
RedBlackTree::value_type& operator*()
{ return( self->value ); }
RedBlackTree::value_type* operator->()
{ return &(self->value); }
iterator& operator++()
{ return( (iterator&)iterator_base::operator++( ) ); }
iterator operator++( int )
{ iterator i = *this; operator++(); return i; }
iterator& operator--()
{ return( (iterator&)iterator_base::operator--( ) ); }
iterator operator--( int )
{ iterator i = *this; operator--(); return i; }
};
class const_iterator : public iterator_base{
public:
const_iterator( iterator_base const & i ) : iterator_base( i ) { }
const_iterator() : iterator_base() { }
const_iterator( rbt_type const* rb, Node* n )
: iterator_base( rb, n )
{ }
RedBlackTree::value_type const& operator*()
{ return self->value; }
RedBlackTree::value_type const* operator->()
{ return &(self->value); }
const_iterator& operator++()
{ return( (const_iterator&)iterator_base::operator++()); }
const_iterator operator++( int )
{ const_iterator i = *this; operator++(); return i; }
const_iterator& operator--()
{ return( (const_iterator&)iterator_base::operator--()); }
const_iterator operator--( int )
{ const_iterator i = *this; operator--(); return i; }
};
friend class iterator_base;
friend class iterator;
friend class const_iterator;
/*
* end of iterators
* ------------------------------------------------------------------ */
iterator end()
{ return iterator( this, (Node*) 0 ); }
iterator begin()
{ return iterator( this, mFirst ); }
const_iterator end() const
{ return const_iterator( this, (Node*)0 ); }
const_iterator begin() const
{ return const_iterator( this, mFirst ); }
//pair< iterator, bool > insert( value_type const & );
// TODO: Move to out-of-line when compiler supports syntax.
template< class InputIterator >
void RedBlackTree< Key, Compare, Allocator, ValueWrapper>::insert(
InputIterator first_it, InputIterator last_it )
{
// presume data sorted; use last insert point as hint
iterator hint;
if( first_it != last_it ) hint = insert( *first_it ).first;
for( ++first_it ; first_it != last_it ; ++first_it )
hint = insert( hint, *first_it ).first;
}
void erase( iterator );
size_type erase( key_type const & );
//void erase(iterator first, iterator last);
void clear();
iterator find( key_type const & );
bool empty() const { return( mSize == 0 ); }
size_type size() const { return( mSize ); }
size_type max_size() const;
iterator upper_bound( key_type const & );
const_iterator upper_bound( key_type const & x) const;
iterator lower_bound( key_type const & );
const_iterator lower_bound( key_type const & x) const;
std::pair< iterator, iterator >
equal_range( key_type const & x )
{ return( make_pair( lower_bound(x), upper_bound(x) ) ); }
std::pair< const_iterator, const_iterator >
equal_range( key_type const & x ) const
{ return( make_pair( lower_bound(x), upper_bound(x) ) ); }
bool _Sane();
int mError;
protected:
void doubleBlackTransform( Node* parent, bool lefty );
void insBalTransform( Node* inserted );
// std::pair< iterator, bool > unbalancedInsert( value_type const & );
int blackHeight( iterator );
int height( iterator );
Node* walkRight( Node* ) const;
Node* walkLeft( Node* ) const;
int mSize;
Node* mRoot;
Node* mFirst;
Node* mLast;
Compare cmp;
ValueWrapper keyGetter;
std::pair< RedBlackTree::iterator, bool >
unbalancedInsert( value_type const & v );
public:
std::pair< RedBlackTree::iterator, bool >
insert( value_type const & v );
std::pair< RedBlackTree::iterator, bool >
insert( iterator hint, value_type const & v );
}; //class RedBlackTree
/* ==================================================================
* Red-Black Tree Functions
*/
/* ------------------------------------------------------------------
* Copy Ctor
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::RedBlackTree(
RedBlackTree< Key, Compare, Allocator, ValueWrapper > const & that )
: mem(that.mem)
{
//copy comparator ?
//other bits?
mSize = that.mSize;
//copy nodes
//special case node
if( !that.mRoot ) {
// no root, therefore first and last don't exist either
mFirst = 0;
mLast = 0;
mRoot = 0;
return;
}
mRoot = mem.allocate( 1 );
try {
mem.construct( mRoot,
Node( that.mRoot->value, 0, that.mRoot->getColour() ) );
} catch( ... ) {
mem.deallocate( mRoot, 1 );
mRoot = 0;
throw;
}
Node* n;
Node* o;
o = that.mRoot;
n = mRoot;
for( ;; ) {
//check to see if reached first/last and fix up
if( o == that.mFirst ) {
mFirst = n;
}
if( o == that.mLast ) {
mLast = n;
}
//logic for tree traverse and copy
if( o->left && !n->left ) {
//copy left node if we can/haven't already
o = o->left;
try {
n->left = mem.allocate( 1 );
try {
mem.construct( n->left,
Node( o->value, n, o->getColour() ) );
} catch( ... ) {
mem.deallocate( n->left, 1 );
throw;
}
} catch( ... ) {
n->left = 0;
clear();
throw;
}
n = n->left;
} else if( o->right && !n->right ) {
//or copy right node if we can/haven't already
o = o->right;
try {
n->right = mem.allocate( 1 );
try {
mem.construct( n->right,
Node( o->value, n, o->getColour() ) );
} catch( ... ) {
mem.deallocate( n->right, 1 );
throw;
}
} catch( ... ) {
n->right = 0;
clear();
throw;
}
n = n->right;
} else if( o->getParent() ) {
//no children nodes left to copy, move back up
o = o->getParent();
n = n->getParent();
} else {
//no children nodes left to copy and we are root therefore
//finished
return;
}
} //end for( ;; )
}
/* ------------------------------------------------------------------
* operator=
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >&
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::operator=(
RedBlackTree< Key, Compare, Allocator, ValueWrapper > const & that )
{
clear();
new ( this ) RedBlackTree( that ); //call copy ctor to do the copy
return( *this );
}
/* ------------------------------------------------------------------
* Dtor
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::~RedBlackTree()
{
clear();
}
/* ------------------------------------------------------------------
* clear()
*
* erase all elements. Should be quicker than iterating through each one as we
* don't have to walk and rebalance
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
void RedBlackTree< Key, Compare, Allocator, ValueWrapper >::clear( )
{
//note copy constructor clean up assumes clear() need any members set
//correctly except mRoot
Node* n = mRoot;
while( n ) {
if( n->left ) n = n->left;
else if( n->right ) n = n->right;
else {
//delete it when all children gone
if( !n->getParent() ) {
//if no parent then root, therefore finished
mem.destroy( n );
mem.deallocate( n, 1 );
mSize = 0;
mRoot = 0;
mFirst = 0;
mLast = 0;
return;
}
if( n == n->getParent()->left ) n->getParent()->left = 0;
else n->getParent()->right = 0;
Node* delme = n;
n = n->getParent();
mem.destroy( delme );
mem.deallocate( delme, 1 );
}
}
}
/* ------------------------------------------------------------------
* Find( )
* Climb the tree until we get to the key :)
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::iterator
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::find(Key const& findMe)
{
Node* n=mRoot;
Node* notLT=0;
while( n ) {
if( cmp(findMe, keyGetter(n->value) ) ) n = n->left;
else {
notLT=n;
n=n->right;
}
}
// the last node the key is not less than (if any) may be equal, in which
// case it was found
if( notLT && !(cmp(keyGetter(notLT->value), findMe) ) ) // !(a<b) & !(b<a) then a==b
return iterator(this, notLT);
else
return end();
}
/* ------------------------------------------------------------------
* lower_bound( key_type )
*
* find first[lowest/most left] node that !(node.key < k) [equivalent to
* node.key >= k]
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::iterator
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::lower_bound(
key_type const & findMe )
{
Node* n = mRoot;
Node* nodeNotLTkey = 0;
while( n ) {
if( cmp( keyGetter(n->value), findMe ) ) n = n->right;
else {
nodeNotLTkey = n;
n = n->left;
}
}
// if there are no nodes >= findMe then nodeNotLTkey will still be 0 thus
// the end() iterator will be created as expected
return( iterator(this, nodeNotLTkey) );
}
/* ------------------------------------------------------------------
* lower_bound( key_type ) const
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::const_iterator
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::lower_bound(
key_type const & k ) const
{
return( const_cast<RedBlackTree*>(this)->lower_bound( k ) );
}
/* ------------------------------------------------------------------
* upper_bound( key_type )
* find first[lowest/most left] node that node.key > k
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::iterator
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::upper_bound(
key_type const & findMe )
{
Node* n = mRoot;
Node* nodeGTkey = 0;
while( n ) {
if( cmp( findMe, keyGetter(n->value) ) ) {
nodeGTkey = n;
n = n->left;
} else {
n = n->right;
}
}
// if there are no node > findMe then nodeNotGTkey will still be 0 thus
// the end() iterator will be created as expected
return( iterator(this, nodeGTkey) );
}
/* ------------------------------------------------------------------
* upper_bound( key_type ) const
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::const_iterator
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::upper_bound(
key_type const & k ) const
{
return( const_cast<RedBlackTree*>(this)->upper_bound( k ) );
}
/* ------------------------------------------------------------------
* walkRight( Node* )
*
* iterate to next greater node
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::Node*
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::walkRight(
Node* n ) const
{
if( n->right) {
n = n->right;
while( n->left ) n = n->left;
} else {
while( n->getParent() && (n == n->getParent()->right) ) {
n = n->getParent();
}
n = n->getParent();
}
return n;
}
/* ------------------------------------------------------------------
* walkLeft( Node* )
* iterate to next node with lower key
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::Node*
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::walkLeft(
Node* n ) const
{
if( n->left ) {
n = n->left;
while( n->right ) n = n->right;
} else {
while( n->getParent() && (n == n->getParent()->left) ) {
n = n->getParent();
}
n = n->getParent();
}
return n;
}
/* ------------------------------------------------------------------
* blackHeight( iterator )
* calculate black height of node
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
int RedBlackTree< Key, Compare, Allocator, ValueWrapper >::blackHeight(
iterator i)
{
Node* n = i.getNodePtr();
int c = 0;
while(n) {
if( n->isBlack() ) c++;
n = n->getParent();
}
return c;
}
/* ------------------------------------------------------------------
* height( iterator )
* calculate height of node
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
int RedBlackTree< Key, Compare, Allocator, ValueWrapper >::height( iterator i )
{
Node* n = i.getNodePtr();
int c = 0;
while(n) {
c++;
n = n->getParent();
}
return c;
}
/* ------------------------------------------------------------------
* insBalTransform
*
* Ref: Chris Okasaki paper (2005?) proposing simple transform for insert
* ballance and Lyn Turbak CS231 handout #21 (2001)
*
* if uncle is red we just do a colour change, if uncle is black we do a
* transform in summary 4 cases transform to this:
*
* y(b)
* / \
* x(r) z(r)
* / \ / \
* a(b) b(b) c(b) d(b)
*
* case 1: case 2: case 3: case 4:
* (insert x) (insert y) (insert z) (insert y)
* z z x x
* / \ / \ / \ / \
* y d x d a y a z
* / \ / \ / \ / \
* x c a y b z y d
* / \ / \ / \ / \
* a b b c c d b c
*/
template<class Key, class Compare, class Allocator, class ValueWrapper>
void RedBlackTree<Key, Compare, Allocator, ValueWrapper>::insBalTransform(
Node* inserted)
{
// at this point inserted->colour == red;
for( ;; ) {
/* terminating case
* 1. we have moved up the tree and are now the root
* 2. our parent is the root (therefore must be black)
* 3. our parent is black (no red-red problem any more)
*/
if( inserted->getParent() == 0 ||
inserted->getParent()->getParent() == 0 ||
inserted->getParent()->isBlack() )
return;
/* so at this point parent must also be red, and grandparent must be
* black therefore our sibling must be black (our children are black
* by definition) leaving two main cases : our uncle can black or red
*/
Node* parent = inserted->getParent();
Node* grandparent = inserted->getParent()->getParent();
Node* uncle;
//find uncle
if( parent == grandparent->left ) uncle = grandparent->right;
else uncle = grandparent->left;
if( uncle && (uncle->isRed()) ) { // main case a: red uncle
// now we propergate grandparents blackness between parent and
// uncle (without need to rotate)
grandparent->setRed();
parent->setBlack();
uncle->setBlack();
mRoot->setBlack(); // just in case grandparent was root
inserted = grandparent; // prepare to propergate red-red up tree
// the execusion flow now jumps back to the for loop instead of
// recursive insBalTransform( inserted );
} else { // main case b: black uncle
Node *x,*y,*z,*b,*c;
// case 1
if( (inserted == parent->left) && (parent == grandparent->left) ) {
x = inserted;
y = parent;
z = grandparent;
b = x->right;
c = y->right;
}
//case 2
else if( (inserted == parent->right) && (parent == grandparent->left) ){
x = parent;
y = inserted;
z = grandparent;
b = y->left;
c = y->right;
}
//case 3
else if( (inserted == parent->right) && (parent == grandparent->right) ){
x = grandparent;
y = parent;
z = inserted;
b = y->left;
c = z->left;
}
//case4
else if( (inserted == parent->left) && (parent == grandparent->right) ){
x = grandparent;
y = inserted;
z = parent;
b = y->left;
c = y->right;
}
//recolour - can use this order becase all leafs a,b,c,d must be
//black (uncle is black) this will stop red-red violation from
//propergating
y->setBlack();
x->setRed();
z->setRed();
//transform to balanced structure
if( grandparent == mRoot ) {
mRoot = y;
y->setParent( 0 );
} else {
if (grandparent->getParent()->left == grandparent){
grandparent->getParent()->left = y;
} else { //grandparent is righty
grandparent->getParent()->right = y;
}
y->setParent( grandparent->getParent() );
}
y->left = x;
y->right = z;
x->setParent( y );
z->setParent( y );
x->right = b;
z->left = c;
if( b ) b->setParent( x );
if( c ) c->setParent( z );
// a and d are always already linked to the right parent in this
// case we have fixed the red-red violation so finish
return;
} //end main case uncle black
} //end for( ever )
}
/* ------------------------------------------------------------------
* _Sane( )
*
* test the implementation for errors and test the container hasn't been
* corrupt return true if everything is ok
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
bool RedBlackTree< Key, Compare, Allocator, ValueWrapper >::_Sane()
{
if( !mRoot ) {
//no element in tree
if( mSize != 0 ) {
mError = 10;
return false;
} else {
//nothing else in tree to check
return true;
}
}
iterator it = begin();
Node* n = it.getNodePtr();
Node* highN = n;
Node* lowN = n;
Key const * lowkey = &keyGetter(n->value);
Key const * highkey = &keyGetter(n->value);
int count = 0;
int maxheight = height(it);
int bheight = -1;
if( n->left ) { //begining element cant have a left node
mError = 20;
return false;
}
if( mRoot->isRed() ) {
mError = 25;
return false; //root should always be black
}
do {
if( ++count > size() ){
mError = 30; // we could have got trapped in
return false; // a loop, cant be more iterations
} // than size
Node* n_old = n;
n = it.getNodePtr();
if( (it != begin()) && (n_old == n) ) {
mError = 40; //circular links:
return false; //iterating didn't advance
}
if( n->isRed() &&
n->getParent() &&
n->getParent()->isRed() ) {
mError = 50;
return false; //red-red error
}
if( n->getParent() &&
(n->getParent()->left != n) &&
(n->getParent()->right != n) ) {
mError = 60;
return false; //links broken
}
if( !n->getParent() && (mRoot != n) ) {
mError = 70;
return false; //links broken
}
if( (n->left == n) || (n->right == n) ) {
mError = 80;
return false; //simple circular loop detection
//? not sure this works as iterating will get stuck before
//detection ?
}
if( !n->getParent() && n!=mRoot) {
mError = 90;
return false; //no parent but not root
}
//keep track of the lowest key we come across
if( cmp( keyGetter(n->value), *lowkey) ) {
lowkey = &keyGetter(n->value);
lowN = n;
}
//keep track of the highest key we come across
if( cmp(*highkey, keyGetter(n->value)) ) {
highkey = &keyGetter(n->value);
highN = n;
}
if( !n->left || !n->right ) { //null child is a leaf
int bh = blackHeight(it);
if( bheight == -1 ) bheight = bh;
else if(bheight != bh) {
mError = 100;
return false; //black height to leaves not same
}
}
int h = height(it); //keep track of deepest node depth
if( h > maxheight ) maxheight = h;
} while( ++it != end() );
if( count != size() ) {
mError = 110;
return false;
}
if( n->right ) { // end element cant have a right node
mError = 120;
return false;
}
if( (highN != (--end()).getNodePtr()) ||
(lowN != begin().getNodePtr()) ) {
mError = 130;
return false;
}
return true;
}
/* ------------------------------------------------------------------
* Erase( key )
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::size_type
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::erase( const Key& k )
{
iterator it = find(k);
if(it == end()) return 0;
else{
erase(it);
return 1;
}
}
/* ------------------------------------------------------------------
* Erase( iterator )
* Maybe to do: this isn't the most easy to understand, is there a nicer
* way of writing it?
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
void RedBlackTree< Key, Compare, Allocator, ValueWrapper >::erase(
iterator it )
{
Node* delme = it.getNodePtr();
Node* child; //(re)moved endnode child
Node* parent; // parent of (re)moved endnode
bool lefty; //true if (re)moved endnode was left child
Node::Chroma colour; //(re)moved endnode colour
mSize--;
if( delme == mFirst ) {
if( delme == mLast ) {
//special case, deleted == only element in tree
mFirst = 0;
mLast = 0;
} else
mFirst = walkRight(delme);
} else if( delme == mLast) mLast = walkLeft(delme);
//if not end node swap for predecessor
if( delme->left && delme->right) {
Node* predecessor = walkLeft(delme);
colour = predecessor->getColour();
child = predecessor->left; //predecessor can't have a right child
if( predecessor == predecessor->getParent()->left ) lefty = true;
else lefty = false;
//fix up parent's link
if( delme == mRoot )
mRoot = predecessor;
else if( delme == delme->getParent()->left ) {
delme->getParent()->left = predecessor;
} else {
delme->getParent()->right = predecessor;
}
//if delme is one level above predecessor we have to be
//careful linking left as it could create a circular link
//and a link to the deleted item
if( predecessor != delme->left ) {
//fix up chidren's link
delme->left->setParent( predecessor );
//fix predecessors link
predecessor->left = delme->left;
parent = predecessor->getParent();
} else { //predecessor is erased node's child
parent = predecessor;
//leave old left child links intact
}
//common bits
//fix childrens links
delme->right->setParent( predecessor );
//fix predecessor's links
predecessor->setColour( delme->getColour() );
predecessor->setParent( delme->getParent() );
predecessor->right = delme->right;
}
else { //end node
if( delme->left ) child = delme->left;
else child = delme->right;
parent = delme->getParent();
colour = delme->getColour();
if( parent && (delme == parent->left) ) lefty = true;
else lefty = false;
}
//delete delme;
mem.destroy( delme );
mem.deallocate( delme, 1 );
//handle simple cases
if( !parent ) {
//root with up to 1 child
if( child ) {
mRoot = child;
mRoot->setParent( 0 );
mRoot->setBlack();
} else {
mRoot = 0;
}
} else if( colour == Node::red ) {
//red end node cant have a single child node or it would have violated
//red-red rule or black height rule removing it doesn't change black
//height so we are done
if( lefty ) parent->left = 0;
else parent->right = 0;
} else if( child ) {
//black end node may have a single child, in which case it has to be
//red and we can fix up the black height easily
if( lefty ) {
parent->left = child;
} else { //righty
parent->right = child;
}
child->setParent( parent );
child->setBlack();
} else {
//black node with no children,
if( lefty ) parent->left = 0;
else parent->right = 0;
//(re)moving this will cause black height problem do some operations
//to keep rb tree valid
doubleBlackTransform( parent,lefty );
}
return;
}
/* ------------------------------------------------------------------
* DoubleBlackTransform
* Fix double-black node to rebalance the tree after delete
*
* references: backs of lots of matchboxes :)
*
* (this doesn't touch key or type, can the compiler figure out it can use one
* block of code for all template instantiations or does it need to be coded
* in a non template base class?)
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
void
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::doubleBlackTransform(
Node* parent, bool lefty )
{
for( ;; ) {
Node* sibling;
Node *x,*y,*z,*b,*c;
if( lefty ) {
sibling = parent->right;
} else { //righty
sibling = parent->left;
}
if( sibling->isBlack() ) {
if( ( sibling->right && sibling->right->isRed() ) ||
( sibling->left && sibling->left->isRed() ) ) {
//main case 1 sibling black, at least one nephew red we can fix this
//case
/*
* case a case b case c case d
* Z(*) Z(*) X(*) X(*)
* / \\ / \\ // \ // \
* X(b) d(bb) Y(b) d(bb) a(bb) Y(b) a(bb) Z(b)
* / \ / \ / \ / \
* a(*) Y(r) X(r) c(*) b(*) Z(r) Y(r) d(*)
* / \ / \ / \ / \
* b(b) c(b) a(b) b(b) c(b) d(b) b(b) c(b)
*
* Transform to this:
* Y(*)
* / \
* X(b) Z(b)
* / \ / \
* a(*) b(*) c(*) d(*)
*
* where double black goes black & new root takes old root colour note
* nodes a,b,c may be null (leafs)
*/
if( sibling->right && sibling->right->isRed() ) {
if( lefty ) { // case 1 c
x = parent;
y = sibling;
z = sibling->right;
b = y->left;
c = z->left;
} else { // case 1 a
z = parent;
x = sibling;
y = sibling->right;
b = y->left;
c = y->right;
}
} else { // sibling->left && sibling->left->colour == red
if( lefty ) { // case 1 d
x = parent;
z = sibling;
y = sibling->left;
b = y->left;
c = y->right;
} else { // case 1 b
z = parent;
y = sibling;
x = sibling->left;
b = x->right;
c = y->right;
}
}
// finish off case 1 by relinking to correct sturcture
y->setParent( parent->getParent() );
if( parent == mRoot ) mRoot = y;
else{ //link grandparent back to y;
if( parent == parent->getParent()->left )
parent->getParent()->left = y;
else parent->getParent()->right = y;
}
y->setColour( parent->getColour() );
y->left = x;
y->right = z;
x->setParent( y );
x->setBlack();
x->right = b; // x->left is unchanged as a
if( b ) b->setParent( x );
z->setParent( y );
z->setBlack();
z->left = c; // z->right is unchanged as d
if( c ) c->setParent( z );
return;
} else { //nephews both black
if( parent->isRed() ){
//main case 2: sibling black, two black nephews, parent red we can fix
//this case
/*
* case a case b
* Z(r) X(r)
* / \\ // \
* X(b) d(bb) a(bb) Z(b)
* / \ / \
* a(b) b(b) b(b) d(b)
*
* Recolour to this:
* Z(b) X(b)
* / \ / \
* X(r) d(b) a(b) Z(r)
* / \ / \
* a(b) b(b) b(b) d(b)
*
*/
parent->setBlack();
sibling->setRed();
return;
} else { //parent black
//main case 3: sibling black, two black nephews, parent black
/*
* case a case b
* Z(b) X(b)
* / \\ // \
* X(b) d(bb) a(bb) Z(b)
* / \ / \
* a(b) b(b) b(b) d(b)
*
* Recolour to propergate double black:
* || ||
* Z(bb) X(bb)
* / \ / \
* X(r) d(b) a(b) Z(r)
* / \ / \
* a(b) b(b) b(b) d(b)
*
* Not much we can do - propergate double black If double black has
* properaged to to root just set it black as we have acheived balance
* (higher order special cases may be possible eg node a has two red
* children but probably not worth the extra code to check?)
*/
sibling->setRed();
if( parent == mRoot ) {
parent->setBlack();
return;
}
Node* grandparent = parent->getParent();
if( parent == grandparent->left) lefty = true;
else lefty = false;
//loop to top of doubleBlackTransform with new parent
//(replaces recursion) doubleBlackTransform(grandparent,
//lefty); return;
parent = grandparent;
}
} //end main case 2/3
} else {
//main case 4: red sibling
/*
* case a case b
* Z(b) X(b)
* / \\ // \
* X(r) d(bb) a(bb) Z(r)
* / \ / \
* a(b) b(b) c(b) d(b)
*
* Recolour to propergate double black:
* X(b) Z(b)
* / \ / \
* a(b) Z(r) X(r) d(b)
* / \\ // \
* b(b) d(bb) a(bb) c(b)
*
* This is an annoying one! Note, a and b must have children (ie a/b
* can't be null/leaves) or the black height doesn't add up. Double
* black stays with the same node but restructure so we can use one of
* the previous cases (1 or 2) where the sibling is black.
*/
//common bits
if( parent == mRoot ) {
mRoot = sibling;
sibling->setParent( 0 );
} else if ( parent == parent->getParent()->left ) {
parent->getParent()->left = sibling;
sibling->setParent( parent->getParent() );
} else {//parent is a righty
parent->getParent()->right = sibling;
sibling->setParent( parent->getParent() );
}
parent->setRed();
sibling->setBlack();
if( lefty ) {
//case b
x = parent;
c = sibling->left;
z = sibling;
x->right = c;
c->setParent( x );
x->setParent( z );
z->left = x;
//a & d stay linked to the same nodes
} else { //righty
//case a
z = parent;
b = sibling->right;
x = sibling;
z->left = b;
b->setParent( z );
z->setParent( x );
x->right = z;
//a & d stay linked to the same nodes
}
//now try again and case will be 1, 2, or 3 note old parent is
//still parent of double black and left/right position of double
//black hasn't changed recursion has been replaced with the for
//loop doubleBlackTransform(parent,lefty); return;
}
}//end for( ever )
}
/* ------------------------------------------------------------------
* unbalancedInsert( value_type const & )
*
* like find but create new node after last node visited if cant find an
* existing key
*/
template< class Key, class Compare, class Allocator, class ValueWrapper>
std::pair< typename RedBlackTree< Key,
Compare,
Allocator,
ValueWrapper >::iterator, bool >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::unbalancedInsert(
value_type const & v)
{
if( mRoot==0 ) { //special case nothing exists yet
mRoot = mem.allocate( 1 );
try{
mem.construct( mRoot, Node( v, 0, Node::black ) );
} catch( ... ) {
mem.deallocate( mRoot, 1 );
mRoot = 0;
throw;
}
mFirst = mRoot;
mLast = mRoot;
mSize++;
return( std::pair<iterator, bool>( iterator(this, mRoot), true ) );
}
Node* n = mRoot;
Node* notLT = 0;
Node* last = n;
bool LtLast;
while( n ) {
if( cmp(keyGetter( v ), keyGetter( n->value ) ) ) {
last = n;
LtLast = true;
n = n->left;
} else {
last = n;
LtLast = false;
notLT = n;
n = n->right;
}
}
// the last node the key is not less than (if any) may be equal, in which
// case it was found
if( notLT &&
!( cmp( keyGetter( notLT->value ), keyGetter( v ) ) ) ) {
// !(a<b) & !(b<a) then a==b
return( std::pair<iterator,bool>( iterator(this, notLT), false ) );
}
// else insert the new node with parent as last node travelled to
Node* newnode = mem.allocate( 1 );
try {
mem.construct( newnode, Node( v, last, Node::red ) );
} catch( ... ) {
mem.deallocate( newnode, 1 );
throw;
}
mSize++;
if( LtLast ) {
last->left = newnode;
if( last == mFirst ) mFirst = newnode;
} else {
last->right = newnode;
if( last == mLast ) mLast = newnode;
}
return( std::pair<iterator,bool>( iterator(this, newnode), true ) );
}
/* ------------------------------------------------------------------
* insert( value_type const & )
*
* inserts v into the tree if it doesn't exist already and maintains balance
* returns a pair containing iterator with key equivelent to that of v and a
* bool that is true if v was inserted or false if the key already existed
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
std::pair< typename RedBlackTree< Key,
Compare,
Allocator,
ValueWrapper >::iterator, bool >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::insert(
value_type const & v)
{
pair< iterator, bool > inserted = unbalancedInsert( v );
if( inserted.second ) {
Node* n = inserted.first.getNodePtr();
if( n != mRoot ) {
//do some operations to keep rb tree valid
insBalTransform( n );
}
// else if n==mRoot it has been inserted as single black node and
// there is nothing else to do
}
return inserted;
}
/* ------------------------------------------------------------------
* insert( iterator hint, value_type const &)
*
* inserts v into the tree if it doesn't exist already and maintains ballance
* returns a pair containing iterator with key equivelent to that of v and a
* bool that is true if v was inserted or false if the key already existed
* Written in the spirit of N1780 (not strictly standard compliant?)
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
std::pair< typename RedBlackTree< Key,
Compare,
Allocator,
ValueWrapper >::iterator, bool >
RedBlackTree< Key, Compare, Allocator, ValueWrapper >::insert(
iterator hint, value_type const & v )
{
pair< iterator, bool > inserted;
iterator b4hint;
if( mSize &&
( hint == end() || cmp( keyGetter(v), keyGetter(*hint) ) ) ) {
//at this point tree isn't empty and key is before hint
b4hint = hint;
if( hint == begin() ||
cmp( keyGetter( *(--b4hint) ), keyGetter( v ) ) ) {
//at this point key is also before begin or after (hint-1) so hint
//is good now, either hint->left or (hint-1)->right must have a
//unused leaf node where the new node belongs
Node* parent;
bool lefty = true;
if( hint != end() && hint.getNodePtr()->left == 0 ) {
parent = hint.getNodePtr();
} else {
parent = b4hint.getNodePtr();
lefty = false;
}
//create the new node
Node* newnode = mem.allocate( 1 );
try {
mem.construct( newnode, Node(v, parent, Node::red) );
} catch( ... ) {
mem.deallocate( newnode, 1 );
throw;
}
mSize++;
//fix up pointers
if( lefty ) {
parent->left = newnode;
if( parent == mFirst ) mFirst = newnode;
} else {
parent->right = newnode;
if( parent == mLast ) mLast = newnode;
}
inserted = make_pair( iterator(this, newnode), true );
} else inserted = unbalancedInsert( v ); //hint bad (or key already exists)
} else inserted = unbalancedInsert( v ); //hint is bad or tree is empty
if( inserted.second ) {
Node* n = inserted.first.getNodePtr();
if( n != mRoot ) {
//do some operations to keep rb tree valid
insBalTransform(n);
}
// else if n==mRoot it has been inserted as single black node and
// there is nothing else to do
}
return inserted;
}
/* ================================================================== */
/* ==================================================================
* MLRBTNode
* sub-node type that forms a linked list and is stored in the
* rbtree node to create the MultiListRBTree
*/
template< class ValueType >
struct MLRBTNode{
MLRBTNode* fwd;
MLRBTNode* bwd;
ValueType value;
MLRBTNode() {}
MLRBTNode( ValueType v ) : value( v ) { }
};
/* ==================================================================
* ValueWrappers for MultiListRBTree
*
* pairs for multimap, plain Keys for multiset wraps up the rbtree type
* (pointer to the list) and knows how to get a key out of it
*/
template< class Key, class Type >
struct ListTreePairWrapper{
//this is the value_type actually contained in the container
typedef pair< Key const, Type > value_type;
Key const& operator()( value_type const & v ) const
{ return( v.first ); }
struct TreeWrapper{
//this is the rbtree value_type (pointer to list)
typedef MLRBTNode< pair< Key const, Type > >* value_type;
Key const& operator()( value_type const & v ) const
{ return( v->value.first ); }
};
};
template< class Key >
struct ListTreeKeyWrapper{
//this is the value_type actually contained in the container
typedef Key value_type;
Key const& operator()( value_type const & v ) const
{ return( v ); }
struct TreeWrapper{
//this is the rbtree value_type (pointer to list)
typedef MLRBTNode< Key >* value_type;
Key const& operator()( value_type const & v ) const
{ return( v->value); }
};
};
/* ==================================================================
* MultiListRBTree
*
* Adds linked list to redblack tree to build a multimap/set. handles the list
* operations in this class rather than using a full blown (or even a cut down
* one) list object in tree node. This should save a little memory. Note for a
* low number of repetitions of each key this alogorithm will use more memory
* than holding the repeated nodes directly in tree for this algorithm p = 4 +
* 2n ; c = 1 for tree only algo p = 3n ; c = n where p is num of pointers, c
* is num of colour enums, n is num of key repetitions so if c uses same space
* as p (likely due to alignment?) this algo is better if n >=3 This algo
* should have slightly faster find (+ insert/delete) operations
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
class MultiListRBTree{
public:
typedef ValueWrapper::value_type value_type;
typedef unsigned int size_type;
typedef Key key_type;
private:
typedef RedBlackTree< Key, Compare, Allocator, ValueWrapper::TreeWrapper > tree_type;
typedef MLRBTNode< value_type > node_type;
Allocator::rebind< node_type >::other mem; //moved up here to stop crash
public:
MultiListRBTree(Compare c, Allocator a)
: mSize( 0 ), mTree( tree_type( c, a ) ), mem( a )
{ }
MultiListRBTree( MultiListRBTree const & );
~MultiListRBTree();
Allocator get_allocator() const
{ Allocator a(mem); return( a ); }
MultiListRBTree& operator=( MultiListRBTree const & );
/* ------------------------------------------------------------------
* iterators
*/
class iterator_base;
friend class iterator_base;
class iterator_base{
public:
iterator_base& operator++()
{
if( self == (*tit)->bwd ) { //if last element in list
++tit;
if( tit != mlt->mTree.end() ) self = *tit; //move on to first list node in next tree node
else self = 0; //signals end iterator
} else {
self = self->fwd;
}
return( *this );
}
iterator_base& operator--()
{
if( self == 0 || self == (*tit) ) {
//if first element in list or end of list
--tit; //move back to last list node in
self = (*tit)->bwd; //previous tree node
} else {
self = self->bwd;
}
return( *this );
}
value_type& operator*()
{ return( self->value ); }
value_type* operator->()
{ return( &(self->value) ); }
bool operator==( iterator_base const & that )
{ return( self == that.self ); }
bool operator!=( iterator_base const & that )
{ return( self != that.self ); }
iterator_base const & operator=( iterator_base const & that )
{
tit = that.tit;
mlt = that.mlt;
self = that.self;
return( *this );
}
protected:
friend class MultiListRBTree;
iterator_base()
{ }
iterator_base( iterator_base const & x )
: tit( x.tit ), mlt( x.mlt ), self( x.self )
{ }
iterator_base( MultiListRBTree const* m, tree_type::iterator const &i )
: mlt( m ), tit( i )
{ ( tit != (mlt->mTree).end() ) ? self = (*tit) : self = 0; }
iterator_base( MultiListRBTree const* m,
tree_type::iterator const & i,
node_type* n )
: mlt( m ), tit( i ), self( n )
{ }
tree_type::iterator tit;
MultiListRBTree const* mlt;
node_type* self;
};
class iterator : public iterator_base{
public:
iterator() : iterator_base() {}
iterator( iterator const & i ) : iterator_base(i) {}
iterator( MultiListRBTree const* m, tree_type::iterator const & i)
: iterator_base( m, i )
{ }
iterator( MultiListRBTree const* m,
tree_type::iterator const & i,
node_type* n )
: iterator_base( m, i, n )
{ }
iterator& operator++()
{ return( (iterator&)iterator_base::operator++() ); }
iterator& operator--()
{ return( (iterator&)iterator_base::operator--() ); }
iterator& operator++( int )
{ iterator i(*this); operator++(); return( i ); }
iterator& operator--( int )
{ iterator i(*this); operator--(); return( i ); }
};
class const_iterator : public iterator_base{
public:
const_iterator() : iterator_base() {}
const_iterator( const_iterator const & i ) : iterator_base(i) {}
const_iterator( iterator const & i ) : iterator_base(i) {}
const_iterator( MultiListRBTree const* m, tree_type::iterator const & i)
: iterator_base( m, i )
{ }
const_iterator( MultiListRBTree const* m,
tree_type::iterator const & i,
node_type* n )
: iterator_base( m, i, n )
{ }
const_iterator& operator++()
{ return( (const_iterator&)iterator_base::operator++() ); }
const_iterator& operator--()
{ return( (const_iterator&)iterator_base::operator--() ); }
const_iterator& operator++( int )
{ const_iterator i(*this); operator++(); return( i ); }
const_iterator& operator--( int )
{ const_iterator i(*this); operator--(); return( i ); }
};
iterator begin()
{ return( iterator( this, mTree.begin() ) ); }
iterator end()
{ return( iterator( this, mTree.end() ) ); }
// note use const_cast<> so calls version of mTree.end()/begin() that
// return an iterator not a const_iterator for interal use within the
// iterator of this class. mTree still doesn't get modified.
const_iterator begin() const
{ return( const_iterator( this, const_cast<tree_type*>(&mTree)->begin() ) ); }
const_iterator end() const
{ return( const_iterator( this, const_cast<tree_type*>(&mTree)->end() ) ); }
//capacity
size_type size() { return( mSize ); }
bool empty() { return( !mSize ); }
//modifiers
iterator insert( value_type const & );
iterator insert( iterator, value_type const & );
void erase( iterator );
size_type erase( key_type const & );
void clear();
//operations
iterator find( key_type const & );
size_type count( key_type const & );
iterator upper_bound( key_type const & );
const_iterator upper_bound( key_type const & x) const;
iterator lower_bound( key_type const & );
const_iterator lower_bound( key_type const & x) const;
std::pair< iterator, iterator > equal_range( key_type const & x )
{ return( make_pair( lower_bound(x), upper_bound(x) ) ); }
std::pair< const_iterator, const_iterator > equal_range( key_type const & x ) const
{ return( make_pair( lower_bound(x), upper_bound(x) ) ); }
//owstl extentions
bool _Sane();
private:
size_type mSize;
tree_type mTree; //this is the tree that holds the lists
Compare cmp;
ValueWrapper keyGetter;
};
/* ------------------------------------------------------------------
* copy ctor
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::MultiListRBTree(
MultiListRBTree< Key, Compare, Allocator, ValueWrapper > const & that )
: mTree( that.mTree ), mem( that.mem )
{
// pointer to old list elements is copied by rbtree copy ctor and the
// pointers will still link back to the old list elements so now make
// copies of new list elments and fixup pointers
tree_type::iterator it;
tree_type::const_iterator it2;
try {
for( it = mTree.begin(), it2 = that.mTree.begin();
it != mTree.end();
++it, ++it2 ) {
//special case, copy the first element in the list
try {
*it = mem.allocate( 1 );
try {
mem.construct( *it, **it2 );
} catch( ... ) {
mem.deallocate( *it, 1 );
throw;
}
} catch( ... ) {
//signal no first element to rewind logic
*it = 0;
throw;
}
//copy the rest of the list (if they exist)
node_type* start = *it2;
node_type* o = start->fwd;
node_type* n = *it;
while( o != start ) {
try {
//allocate the next node
n->fwd = mem.allocate( 1 );
try {
//o already points to the next node
mem.construct( n->fwd, *o );
} catch( ... ) {
mem.deallocate( n->fwd, 1 );
throw;
}
} catch( ... ) {
//finish off the links so can do a generic rewind
n->fwd = *it;
(*it)->bwd = n;
throw;
}
n->fwd->bwd = n;
n = n->fwd;
o = o->fwd;
}
n->fwd = *it;
(*it)->bwd = n;
}
} catch( ... ) {
//the copy either completely succeeds or completely fails so rewind
//the nodes added so far:
for( ; it != mTree.begin(); --it ) {
if( *it == 0 ) continue;
node_type* n = *it;
node_type* delme;
node_type* end = n;
do {
delme = n;
n = n->fwd;
mem.destroy( delme );
mem.deallocate( delme, 1 );
} while( n != end );
}
mTree.clear();
throw;
}
//success
mSize = that.mSize;
}
/* ------------------------------------------------------------------
* operator=( that )
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >&
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::operator=(
MultiListRBTree const & that )
{
clear();
new ( this ) MultiListRBTree(that);
return( *this );
}
/* ------------------------------------------------------------------
* insert( value_type const & )
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::iterator
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::insert(
value_type const & x )
{
node_type* n;
pair< tree_type::iterator, bool > ans;
n = mem.allocate( 1 );
try {
mem.construct( n, node_type(x) );
} catch( ... ) {
mem.deallocate( n, 1 );
throw;
}
try {
ans = mTree.insert( n );
} catch( ... ) {
mem.destroy( n );
mem.deallocate( n, 1 );
throw;
}
if( ans.second ) { //insert happened
n->fwd = n;
n->bwd = n;
} else { //already inserted
node_type* o = *ans.first; //get pointer to already inserted node
n->bwd = o->bwd; //fix up links so as to add new node
n->fwd = o; //to end of list
o->bwd->fwd = n;
o->bwd = n;
}
mSize++;
return iterator( this, ans.first, n );
}
/* ------------------------------------------------------------------
* insert( iterator hint, value_type const & )
* Insert as close to as before hint as possible. In the spirit of
* N1780 (Comments on LWG issue 233, Howard E. Hinnant, 23/04/2005)
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::iterator
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::insert(
iterator hint, value_type const & v )
{
//!!!!I'm not happy with this function and it needs redesigning when I
//have time...!!!
//To insert x at p:
// if p == end || x <= *p
// if p == begin || x >= *(p-1)
// insert x before p
// else
// insert x before upper_bound(x)
// else
// insert x before lower_bound(x)
iterator pos;
if( mSize == 0 ) {
//cout<<"pos = end\n";
pos = end();
} else {
if( hint == end() || !cmp( keyGetter( *hint ), keyGetter( v ) ) ) {
// !(hint < v) == v <= hint
iterator b4hint = hint;
if( hint == begin() || !cmp( keyGetter( v ), keyGetter( *(--b4hint) ) ) ) {
// !(v < hint) == v >= hint
//insert before hint
//cout<<"pos = hint\n";
pos = hint;
} else {
//insert before upper_bound
//cout<<"pos = upper\n";
pos = upper_bound( keyGetter(v) );
}
} else {
//insert before lower_bound
//cout<<"pos = lower "<<keyGetter( *hint )<<"\n";
pos = lower_bound( keyGetter(v) );
}
}
node_type* n;
pair< tree_type::iterator, bool> ans;
n = mem.allocate( 1 );
try {
mem.construct( n, node_type(v) );
} catch( ... ) {
mem.deallocate( n, 1 );
throw;
}
try {
//insert into tree. to do: rewrite rbtree hint insert so it doesn't
//need to recheck the hint pos
ans = mTree.insert( pos.tit, n );
} catch( ... ) {
mem.destroy( n );
mem.deallocate( n, 1 );
throw;
}
//insert node
if( ans.second ) {
//only node in list
//cout<<"only node in list\n";
n->fwd = n;
n->bwd = n;
} else {
if( pos == end() || cmp( keyGetter( v ), keyGetter( *pos ) ) ) {
//insert at end of previous list
//cout<<"insert at end\n";
--pos;
n->bwd = pos.self;
n->fwd = pos.self->fwd;
pos.self->fwd->bwd = n;
pos.self->fwd = n;
} else {
//cout<<"insert before hint\n";
//insert in list before hint
if( *(pos.tit) == pos.self ) *(pos.tit) = n;
n->bwd = pos.self->bwd;
n->fwd = pos.self;
pos.self->bwd->fwd = n;
pos.self->bwd = n;
}
}
++mSize;
return( iterator(this, ans.first, n) );
}
/* ------------------------------------------------------------------
* dtor
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::~MultiListRBTree( )
{
clear();
}
/* ------------------------------------------------------------------
* clear()
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
void MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::clear( )
{
for( tree_type::iterator i = mTree.begin(); i != mTree.end(); ++i ) {
node_type* n = *i;
node_type* delme;
node_type* end = n;
do {
delme = n;
n = n->fwd;
mem.destroy( delme );
mem.deallocate( delme, 1 );
} while( n != end );
}
mTree.clear();
mSize = 0;
}
/* ------------------------------------------------------------------
* _Sane()
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
bool MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::_Sane( )
{
if( !mTree._Sane() ) return false;
//do more tests here
return true;
}
/* ------------------------------------------------------------------
* find()
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::iterator
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::find(
key_type const & k )
{
return iterator( this, mTree.find( k ) );
}
/* ------------------------------------------------------------------
* count( key_type )
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::size_type
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::count(
key_type const & k )
{
tree_type::iterator tit = mTree.find( k );
if( tit == mTree.end() ) return 0;
node_type* start = *tit;
node_type* n = start;
size_type c = 0;
do {
n = n->fwd;
++c;
} while( n != start );
return( c );
}
/* ------------------------------------------------------------------
* erase( iterator )
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
void MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::erase(
iterator it )
{
node_type* n = it.self;
if( n == n->fwd ) { //if only element in list
mTree.erase( it.tit );
} else if( *(it.tit) == n ) { //if master element in list & >1 element
n->bwd->fwd = n->fwd; //relink to remove n
n->fwd->bwd = n->bwd;
*(it.tit) = n->fwd; //set tree to hold new master element
} else { //if not master element & >1 element
n->bwd->fwd = n->fwd; //relink to remove n
n->fwd->bwd = n->bwd;
}
mem.destroy( n );
mem.deallocate( n, 1 );
--mSize;
}
/* ------------------------------------------------------------------
* erase( key_type )
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::size_type
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::erase(
key_type const & k )
{
iterator it = find( k );
node_type* n = it.self;
node_type* delme;
node_type* end = n;
size_type c = 0;
do {
delme = n;
n = n->fwd;
mem.destroy( delme );
mem.deallocate( delme, 1 );
++c;
--mSize;
} while( n != end );
mTree.erase( it.tit );
return( c );
}
/* ------------------------------------------------------------------
* lower_bound( key_type )
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::iterator
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::lower_bound(
key_type const & k )
{
tree_type::iterator tit = mTree.lower_bound( k );
node_type* n = (tit == mTree.end()) ? 0 : *tit;
return( iterator( this, tit, n ) );
}
/* ------------------------------------------------------------------
* lower_bound( key_type ) const
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::const_iterator
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::lower_bound(
key_type const & k ) const
{
return( const_cast<MultiListRBTree*>(this)->lower_bound( k ) );
}
/* ------------------------------------------------------------------
* upper_bound( key_type )
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::iterator
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::upper_bound(
key_type const & k )
{
tree_type::iterator tit = mTree.upper_bound( k );
node_type* n = (tit == mTree.end()) ? 0 : *tit;
return( iterator( this, tit, n ) );
}
/* ------------------------------------------------------------------
* upper_bound( key_type ) const
*/
template< class Key, class Compare, class Allocator, class ValueWrapper >
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::const_iterator
MultiListRBTree< Key, Compare, Allocator, ValueWrapper >::upper_bound(
key_type const & k ) const
{
return( const_cast<MultiListRBTree*>(this)->upper_bound( k ) );
}
} // namespace _ow
} // namespace std
#endif