/////////////////////////////////////////////////////////////////////////// // 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 #endif #ifndef _ITERATOR_INCLUDED #include #endif #ifndef _FUNCTIONAL_INCLUDED #include #endif #ifndef _MEMORY_INCLUDED #include #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 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= 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(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(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 void RedBlackTree::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(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( 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(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(&mTree)->begin() ) ); } const_iterator end() const { return( const_iterator( this, const_cast(&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 "< 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(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(this)->upper_bound( k ) ); } } // namespace _ow } // namespace std #endif