//
// $Id: Tree.m,v 1.24 2005/05/18 06:46:54 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#import "Tree.h"
#import "Macros.h"
#import "Pair.h"
#import "VectorJunior.h"
#import <Foundation/NSValue.h>
#import <limits.h>
#import <stddef.h>

@interface OLAssociativeIterator (PrivateMethods)

- (id) initWithNode: (OLTreeNode*)nde;
- (OLTreeNode*) node;
- (void) setNode: (OLTreeNode*)nde;

@end

@implementation OLTreeNode

+ (OLTreeNode*) decrement: (OLTreeNode*)node
{
    OLTreeNode* y;

    if (node->color == OLColor_Red && node->parent->parent == node)
    {
        node = node->right;
    }
    else if (node->left != nil)
    {
        y = node->left;
        while (y->right != nil)
            y = y->right;
        node = y;
    }
    else
    {
        y = node->parent;
        while (node == y->left)
        {
            node = y;
            y = y->parent;
        }
        node = y;
    }
    return node;
}

+ (OLTreeNode*) increment: (OLTreeNode*)node
{
    OLTreeNode* y;

    if (node->right != nil)
    {
        node = node->right;
        while (node->left != nil)
            node = node->left;
    }
    else
    {
        y = node->parent;
        while (node == y->right)
        {
            node = y;
            y = y->parent;
        }
        if (node->right != y)
            node = y;
    }
    return node;
}

+ (void) rebalance: (OLTreeNode*)node parent: (OLTreeNode**)root
{
    OLTreeNode* y;

    node->color = OLColor_Red;
    while (node != *root && node->parent->color == OLColor_Red)
    {
        if (node->parent == node->parent->parent->left)
        {
            y = node->parent->parent->right;
            if (y != nil && y->color == OLColor_Red)
            {
                node->parent->color = OLColor_Black;
                y->color = OLColor_Black;
                node->parent->parent->color = OLColor_Red;
                node = node->parent->parent;
            }
            else
            {
                if (node == node->parent->right)
                {
                    node = node->parent;
                    [OLTreeNode rotateLeft: node parent: root];
                }
                node->parent->color = OLColor_Black;
                node->parent->parent->color = OLColor_Red;
                [OLTreeNode rotateRight: node->parent->parent parent: root];
            }
        }
        else
        {
            y = node->parent->parent->left;
            if (y != nil && y->color == OLColor_Red)
            {
                node->parent->color = OLColor_Black;
                y->color = OLColor_Black;
                node->parent->parent->color = OLColor_Red;
                node = node->parent->parent;
            }
            else
            {
                if (node == node->parent->left)
                {
                    node = node->parent;
                    [OLTreeNode rotateRight: node parent: root];
                }
                node->parent->color = OLColor_Black;
                node->parent->parent->color = OLColor_Red;
                [OLTreeNode rotateLeft: node->parent->parent parent: root];
            }
        }
    }
    (*root)->color = OLColor_Black;
}

+ (OLTreeNode*) rebalanceForErase: (OLTreeNode*)node parent: (OLTreeNode**)root leftmost: (OLTreeNode**)leftmost rightmost: (OLTreeNode**)rightmost
{
    OLTreeNode* y = node;
    OLTreeNode* x = nil;
    OLTreeNode* xParent = nil;
    OLTreeNode* w;

    if (y->left == nil)
    {
        x = y->right;
    }
    else
    {
        if (y->right == nil)
        {
            x = y->left;
        }
        else
        {
            y = y->right;
            while (y->left != nil)
                y = y->left;
            x = y->right;
        }
    }
    if (y != node)
    {
        node->left->parent = y;
        y->left = node->left;
        if (y != node->right)
        {
            xParent = y->parent;
            if (node != nil)
                x->parent = y->parent;
            y->parent->left = x;
            y->right = node->right;
            node->right->parent = y;
        }
        else
        {
            xParent = y;
        }
        if (*root == node)
            *root = y;
        else if (node->parent->left == node)
            node->parent->left = y;
        else
            node->parent->right = y;
        y->parent = node->parent;
        OL_FAST_SWAP(y->color, node->color);
        y = node;
    }
    else
    {
        xParent = y->parent;
        if (x != nil)
            x->parent = y->parent;
        if (*root == node)
        {
            *root = x;
        }
        else
        {
            if (node->parent->left == node)
                node->parent->left = x;
            else
                node->parent->right = x;
        }
        if (*leftmost == node)
        {
            if (node->right == nil)
                *leftmost = node->parent;
            else
                *leftmost = [x minimum];
        }
        if (*rightmost == node)
        {
            if (node->left == nil)
                *rightmost = node->parent;
            else
                *rightmost = [x maximum];
        }
    }
    if (y->color != OLColor_Red)
    {
        while (x != *root && (x == nil || x->color == OLColor_Black))
        {
            if (x == xParent->left)
            {
                w = xParent->right;
                if (w->color == OLColor_Red)
                {
                    w->color = OLColor_Black;
                    xParent->color = OLColor_Red;
                    [OLTreeNode rotateLeft: xParent parent: root];
                    w = xParent->right;
                }
                if ((w->left == nil || w->left->color == OLColor_Black) &&
                    (w->right == nil || w->right->color == OLColor_Black))
                {
                    w->color = OLColor_Red;
                    x = xParent;
                    xParent = xParent->parent;
                }
                else
                {
                    if (w->right == nil || w->right->color == OLColor_Black)
                    {
                        if (w->left != nil)
                            w->left->color = OLColor_Black;
                        w->color = OLColor_Red;
                        [OLTreeNode rotateRight: w parent: root];
                        w = xParent->right;
                    }
                    w->color = xParent->color;
                    xParent->color = OLColor_Black;
                    if (w->right != nil)
                        w->right->color = OLColor_Black;
                    [OLTreeNode rotateLeft: xParent parent: root];
                    break;
                }
            }
            else
            {
                w = xParent->left;
                if (w->color == OLColor_Red)
                {
                    w->color = OLColor_Black;
                    xParent->color = OLColor_Red;
                    [OLTreeNode rotateRight: xParent parent: root];
                    w = xParent->left;
                }
                if ((w->right == nil || w->right->color == OLColor_Black) &&
                    (w->left == nil || w->left->color == OLColor_Black))
                {
                    w->color = OLColor_Red;
                    x = xParent;
                    xParent = xParent->parent;
                }
                else
                {
                    if (w->left == nil || w->left->color == OLColor_Black)
                    {
                        if (w->right != nil)
                            w->right->color = OLColor_Black;
                        w->color = OLColor_Red;
                        [OLTreeNode rotateLeft: w parent: root];
                        w = xParent->left;
                    }
                    w->color = xParent->color;
                    xParent->color = OLColor_Black;
                    if (w->left != nil)
                        w->left->color = OLColor_Black;
                    [OLTreeNode rotateRight: xParent parent: root];
                    break;
                }
            }
        }
        if (x != nil)
            x->color = OLColor_Black;
    }
    return y;
}

+ (void) rotateLeft: (OLTreeNode*)node parent: (OLTreeNode**)root
{
    OLTreeNode* y = node->right;

    node->right = y->left;
    if (y->left != nil)
        y->left->parent = node;
    y->parent = node->parent;
    if (node == *root)
        *root = y;
    else if (node == node->parent->left)
        node->parent->left = y;
    else
        node->parent->right = y;
    y->left = node;
    node->parent = y;
}

+ (void) rotateRight: (OLTreeNode*)node parent: (OLTreeNode**)root
{
    OLTreeNode* y = node->left;

    node->left = y->right;
    if (y->right != nil)
        y->right->parent = node;
    y->parent = node->parent;
    if (node == *root)
        *root = y;
    else if (node == node->parent->right)
        node->parent->right = y;
    else
        node->parent->left = y;
    y->right = node;
    node->parent = y;
}

- (id) init
{
    [super init];
    parent = nil;
    left = nil;
    right = nil;
    object = nil;
    color = OLColor_None;
    return self;
}

- (id) initWithTreeNode: (OLTreeNode*)node
{
    [super init];
    parent = node->parent;
    left = node->left;
    right = node->right;
    object = OBJ_RETAIN(node->object);
    color = node->color;
    return self;
}

- (void) dealloc
{
    if (object != nil)
        OBJ_RELEASE(object);
    [super dealloc];
}

- (id) copyWithAllocator: (OLAllocator*)alloc
{
    return [[alloc allocateObject: [OLTreeNode class]] initWithTreeNode: self];
}

- (id) copyWithZone: (NSZone*)zone
{
    return [[OLTreeNode allocWithZone: zone] initWithTreeNode: self];
}

- (OLTreeNode*) maximum
{
    OLTreeNode* node = self;

    while (node->right != NULL)
        node = node->right;
    return node;
}

- (OLTreeNode*) minimum;
{
    OLTreeNode* node = self;

    while (node->left != NULL)
        node = node->left;
    return node;
}

@end

@implementation OLAssociativeIterator (PrivateMethods)

- (id) initWithNode: (OLTreeNode*)nde
{
    [super init];
    node = nde;
    return self;
}

- (OLTreeNode*) node
{
    return node;
}

- (void) setNode: (OLTreeNode*)nde
{
    node = nde;
}

@end

@implementation OLTree

- (id) init
{
    OLAllocator* defAlloc = [OLAllocator defaultAllocator];
    OLLess* less = [[defAlloc allocateObject: [OLLess class]] init];

    [self initWithCompare: less allocator: defAlloc];
    [defAlloc deallocateObject: less];
    return self;
}

- (id) initWithAllocator: (OLAllocator*)alloc
{
    OLLess* less = [[alloc allocateObject: [OLLess class]] init];

    [self initWithCompare: less allocator: [OLAllocator defaultAllocator]];
    [allocator deallocateObject: less];
    return self;
}

- (id) initWithCompare: (OLCodableFunctor<OLBoolBinaryFunction>*)comp
{
    return [self initWithCompare: comp allocator: [OLAllocator defaultAllocator]];
}

- (id) initWithCompare: (OLCodableFunctor<OLBoolBinaryFunction>*)comp allocator: (OLAllocator*)alloc
{
    [super init];
    keyCompare = OBJ_RETAIN(comp);
    allocator = OBJ_RETAIN(alloc);
    header = [[allocator allocateObject: [OLTreeNode class]] init];
    header->color = OLColor_Red;
    header->parent = nil;
    header->left = header;
    header->right = header;
    nodeCount = 0;
    return self;
}

- (id) initWithTree: (OLTree*)tree
{
    [self initWithCompare: tree->keyCompare allocator: tree->allocator];
    if (tree->header->parent != nil)
    {
        header->parent = [self copyNodes: tree->header->parent to: header];
        header->left = [header->parent minimum];
        header->right = [header->parent maximum];
        nodeCount = tree->nodeCount;
    }
    return self;
}

- (void) dealloc
{
    [self clear];
    [allocator deallocateObject: header];
    OBJ_RELEASE(keyCompare);
    OBJ_RELEASE(allocator);
    [super dealloc];
}

- (OLAssociativeIterator*) begin
{
    return OBJ_COND_AUTORELEASE([self beginImpl]);
}

- (OLAssociativeIterator*) beginImpl
{
    return [[allocator allocateObject: [OLAssociativeIterator class]]
        initWithNode: header->left];
}

- (void) clear
{
    [self eraseAll: header->parent];
    header->left = header;
    header->parent = nil;
    header->right = header;
    nodeCount = 0;
}

- (OLTreeNode*) copyNodes: (OLTreeNode*)node to: (OLTreeNode*)dest
{
    OLTreeNode* top = [[allocator allocateObject: [OLTreeNode class]] initWithTreeNode: node];
    OLTreeNode* y;

    top->parent = dest;
    if (node->right != nil)
        top->right = [self copyNodes: node->right to: top];
    dest = top;
    node = node->left;
    while (node != nil)
    {
        y = [[allocator allocateObject: [OLTreeNode class]] initWithTreeNode: node];
        dest->left = y;
        y->parent = dest;
        if (node->right != nil)
            y->right = [self copyNodes: node->right to: y];
        dest = y;
        node = node->left;
    }
    return top;
}

- (id) copyWithAllocator: (OLAllocator*)alloc
{
    return [[allocator allocateObject: [OLTree class]] initWithTree: self];
}

- (id) copyWithZone: (NSZone*)zone
{
    return [[OLTree allocWithZone: zone] initWithTree: self];
}

- (unsigned) count: (id)key
{
    OLPair* p = [self equalRangeImpl: key];
    unsigned dist = [OLIterator distanceFrom: [p first] to: [p second] allocator: allocator];

    [allocator deallocateObject: p];
    return dist;
}

- (BOOL) empty
{
    return nodeCount == 0 ? YES : NO;
}

- (OLAssociativeIterator*) end
{
    return OBJ_COND_AUTORELEASE([self endImpl]);
}

- (OLAssociativeIterator*) endImpl
{
    return [[allocator allocateObject: [OLAssociativeIterator class]]
        initWithNode: header];
}

- (OLPair*) equalRange: (id)key
{
    return OBJ_COND_AUTORELEASE([self equalRangeImpl: key]);
}

- (OLPair*) equalRangeImpl: (id)key
{
    OLAssociativeIterator* lower = [self lowerBoundImpl: key];
    OLAssociativeIterator* upper = [self upperBoundImpl: key];
    OLPair* p = [[allocator allocateObject: [OLPair class]]
        initWithFirst: lower second: upper];

    [allocator deallocateObject: lower];
    [allocator deallocateObject: upper];
    return p;
}

- (void) erase: (OLAssociativeIterator*)where
{
    [self eraseImpl: [where node]];
}

- (void) eraseAll: (OLTreeNode*)node
{
    OLTreeNode* y;

    while (node != nil)
    {
        [self eraseAll: node->right];
        y = node->left;
        [allocator deallocateObject: node];
        node = y;
    }
}

- (void) eraseFrom: (OLAssociativeIterator*)first to: (OLAssociativeIterator*)last
{
    OLAssociativeIterator* firstCopy = [first copyWithAllocator: allocator];
    OLTreeNode* current;

    while (![firstCopy isEqual: last])
    {
        current = [firstCopy node];
        [firstCopy advance];
        [self eraseImpl: current];
    }
    [allocator deallocateObject: firstCopy];
}

- (void) eraseImpl: (OLTreeNode*)node
{
    OLTreeNode* nde = [OLTreeNode rebalanceForErase: node parent: &header->parent
        leftmost: &header->left rightmost: &header->right];

    [allocator deallocateObject: nde];
    nodeCount--;
}

- (unsigned) eraseKey: (id)key
{
    OLPair* p = [self equalRangeImpl: key];
    unsigned dist = [OLIterator distanceFrom: [p first] to: [p second] allocator: allocator];

    [self eraseFrom: [p first] to: [p second]];
    [allocator deallocateObject: p];
    return dist;
}

- (OLAssociativeIterator*) find: (id)key
{
    return OBJ_COND_AUTORELEASE([[allocator allocateObject: [OLAssociativeIterator class]]
        initWithNode: [self findImpl: key]]);
}

- (OLTreeNode*) findImpl: (id)key
{
    OLTreeNode* y = header;
    OLTreeNode* x = header->parent;

    while (x != nil)
    {
        if (![keyCompare performBinaryFunctionWithArg: [self keyOfValue: x->object] andArg: key])
        {
            y = x;
            x = x->left;
        }
        else
        {
            x = x->right;
        }
    }
    if (y == header ||
        [keyCompare performBinaryFunctionWithArg: key andArg: [self keyOfValue: y->object]])
    {
        y = header;
    }
    return y;
}

- (OLAllocator*) allocator
{
    return allocator;
}

- (OLAssociativeIterator*) insertEqual: (id)object
{
    return [self insertEqualImpl: object needIterator: YES];
}

- (OLAssociativeIterator*) insertEqualAt: (OLAssociativeIterator*)where value: (id)object
{
    OLTreeNode* whereNode = [where node];
    OLTreeNode* afterNode;
    OLTreeNode* beforeNode;
    BOOL storedComp;

    if (whereNode == header->left)
    {
        if (nodeCount == 0)
            return [self insertEqual: object];
        if (![keyCompare performBinaryFunctionWithArg: [self keyOfValue: whereNode->object]
                andArg: [self keyOfValue: object]])
        {
            return [self insertImplHint1: whereNode where: whereNode value: object hint2: nil];
        }
        else
        {
            if (nodeCount == 1)
                return [self insertImplHint1: nil where: whereNode value: object hint2: nil];
            afterNode = [[where advance] node];
            [where setNode: whereNode];
            if (afterNode == header ||
                ![keyCompare performBinaryFunctionWithArg: [self keyOfValue: afterNode->object]
                    andArg: [self keyOfValue: object]])
            {
                if (whereNode->right == nil)
                {
                    return [self insertImplHint1: nil where: whereNode
                        value: object hint2: whereNode];
                }
                else
                {
                    return [self insertImplHint1: afterNode where: afterNode
                        value: object hint2: nil];
                }
            }
            else
            {
                return [self insertEqual: object];
            }
        }
    }
    else if (whereNode == header)
    {
        if (![keyCompare performBinaryFunctionWithArg: [self keyOfValue: object]
                andArg: [self keyOfValue: header->right->object]])
        {
            return [self insertImplHint1: nil where: header->right
                value: object hint2: whereNode];
        }
        else
        {
            return [self insertEqual: object];
        }
    }
    else
    {
        beforeNode = [[where reverse] node];
        [where setNode: whereNode];
        storedComp = [keyCompare
            performBinaryFunctionWithArg: [self keyOfValue: whereNode->object]
            andArg: [self keyOfValue: object]];
        if (!storedComp &&
            ![keyCompare performBinaryFunctionWithArg: [self keyOfValue: object]
                andArg: [self keyOfValue: beforeNode->object]])
        {
            if (beforeNode->right == nil)
            {
                return [self insertImplHint1: nil where: beforeNode
                    value: object hint2: beforeNode];
            }
            else
            {
                return [self insertImplHint1: whereNode where: whereNode
                    value: object hint2: nil];
            }
        }
        else
        {
            afterNode = [[where advance] node];
            [where setNode: whereNode];
            if (storedComp &&
                (afterNode == header ||
                 ![keyCompare performBinaryFunctionWithArg: [self keyOfValue: afterNode->object]
                      andArg: [self keyOfValue: object]]))
            {
                if (whereNode->right == nil)
                {
                    return [self insertImplHint1: nil where: whereNode
                        value: object hint2: whereNode];
                }
                else
                {
                    return [self insertImplHint1: afterNode where: afterNode
                        value: object hint2: nil];
                }
            }
            else
            {
                return [self insertEqual: object];
            }
        }
    }
    // Just to make the compiler happy
    return nil;
}

- (void) insertEqualFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    OLForwardIterator* firstCopy = [first copyWithAllocator: allocator];

    for ( ; ![firstCopy isEqual: last]; [firstCopy advance])
        [self insertEqualImpl: [firstCopy dereference] needIterator: NO];
    [allocator deallocateObject: firstCopy];
}

- (OLAssociativeIterator*) insertEqualImpl: (id)object needIterator: (BOOL)needItor
{
    OLTreeNode* y = header;
    OLTreeNode* x = header->parent;

    while (x != nil)
    {
        y = x;
        x = [keyCompare performBinaryFunctionWithArg: [self keyOfValue: object]
                andArg: [self keyOfValue: x->object]] ?
            x->left : x->right;
    }
    return [self insertImplHint1: x where: y value: object hint2: nil needIterator: needItor];
}

- (OLAssociativeIterator*) insertImplHint1: (OLTreeNode*)x where: (OLTreeNode*)y value: (id)object hint2: (OLTreeNode*)h2
{
    return [self insertImplHint1: x where: y value: object hint2: h2 needIterator: YES autorelease: YES];
}

- (OLAssociativeIterator*) insertImplHint1: (OLTreeNode*)x where: (OLTreeNode*)y value: (id)object hint2: (OLTreeNode*)h2 needIterator: (BOOL)needItor
{
    return [self insertImplHint1: x where: y value: object hint2: h2 needIterator: YES autorelease: YES];
}

- (OLAssociativeIterator*) insertImplHint1: (OLTreeNode*)x where: (OLTreeNode*)y value: (id)object hint2: (OLTreeNode*)h2 needIterator: (BOOL)needItor autorelease: (BOOL)autorel
{
    OLTreeNode* z = [[allocator allocateObject: [OLTreeNode class]] init];
    OLAssociativeIterator* itor;

    z->object = OBJ_RETAIN(object);
    if (y == header ||
        (h2 == nil &&
        (x != nil ||
        [keyCompare performBinaryFunctionWithArg: [self keyOfValue: object]
            andArg: [self keyOfValue: y->object]])))
    {
        y->left = z;
        if (y == header)
        {
            header->parent = z;
            header->right = z;
        }
        else if (y == header->left)
        {
            header->left = z;
        }
    }
    else
    {
        y->right = z;
        if (y == header->right)
            header->right = z;
    }
    z->parent = y;
    [OLTreeNode rebalance: z parent: &header->parent];
    nodeCount++;
    itor = needItor ?
        [[allocator allocateObject: [OLAssociativeIterator class]] initWithNode: z] : nil;
    if (itor && autorel)
        OBJ_COND_AUTORELEASE(itor);
    return itor;
}

- (OLPair*) insertUnique: (id)object
{
    BOOL result;
    OLAssociativeIterator* itor = [self insertUniqueImpl: object
        success: &result needIterator: YES];
    NSNumber* num = [[allocator allocateObject: [NSNumber class]] initWithBool: result];
    OLPair* p = OBJ_COND_AUTORELEASE([[allocator allocateObject: [OLPair class]]
        initWithFirst: itor second: num]);

    [allocator deallocateObject: num];
    [allocator deallocateObject: itor];
    return p;
}

- (OLAssociativeIterator*) insertUniqueAt: (OLAssociativeIterator*)where value: (id)object
{
    OLTreeNode* whereNode = [where node];
    OLTreeNode* afterNode;
    OLTreeNode* beforeNode;
    BOOL compWhereObj;
    BOOL compObjWhere;

    if (whereNode == header->left)
    {
        if (nodeCount == 0)
        {
            return OBJ_COND_AUTORELEASE(
                [self insertUniqueImpl: object success: NULL needIterator: YES]);
        }
        if ([keyCompare performBinaryFunctionWithArg: [self keyOfValue: object]
                andArg: [self keyOfValue: whereNode->object]])
        {
            return [self insertImplHint1: whereNode where: whereNode
                value: object hint2: nil];
        }
        else
        {
            compWhereObj = [keyCompare
                performBinaryFunctionWithArg: [self keyOfValue: whereNode->object]
                andArg: [self keyOfValue: object]];
            if (!compWhereObj)
                return OBJ_COND_AUTORELEASE([where copyWithAllocator: allocator]);
            afterNode = [[where advance] node];
            [where setNode: whereNode];
            if (afterNode == header)
            {
                return [self insertImplHint1: nil where: whereNode
                    value: object hint2: whereNode];
            }
            if ([keyCompare performBinaryFunctionWithArg: [self keyOfValue: object]
                    andArg: [self keyOfValue: afterNode->object]])
            {
                if (whereNode->right == nil)
                {
                    return [self insertImplHint1: nil where: whereNode
                        value: object hint2: whereNode];
                }
                else
                {
                    return [self insertImplHint1: afterNode where: afterNode
                        value: object hint2: nil];
                }
            }
            else
            {
                return OBJ_COND_AUTORELEASE(
                    [self insertUniqueImpl: object success: NULL needIterator: YES]);
            }
        }
    }
    else if (whereNode = header)
    {
        if ([keyCompare performBinaryFunctionWithArg: [self keyOfValue: header->right->object]
                andArg: [self keyOfValue: object]])
        {
            return [self insertImplHint1: nil where: header->right
                value: object hint2: whereNode];
        }
        else
        {
            return OBJ_COND_AUTORELEASE(
                [self insertUniqueImpl: object success: NULL needIterator: YES]);
        }
    }
    else
    {
        beforeNode = [[where reverse] node];
        [where setNode: whereNode];
        compObjWhere = [keyCompare performBinaryFunctionWithArg: [self keyOfValue: object]
            andArg: [self keyOfValue: whereNode->object]];
        if (compObjWhere &&
            [keyCompare performBinaryFunctionWithArg: [self keyOfValue: beforeNode->object]
                andArg: [self keyOfValue: object]])
        {
            if (beforeNode->right == nil)
            {
                return [self insertImplHint1: nil where: beforeNode
                    value: object hint2: beforeNode];
            }
            else
            {
                return [self insertImplHint1: whereNode where: whereNode
                    value: object hint2: nil];
            }
        }
        else
        {
            afterNode = [[where advance] node];
            [where setNode: whereNode];
            compWhereObj = !compObjWhere;
            if (!compObjWhere)
            {
                compWhereObj =
                    [keyCompare performBinaryFunctionWithArg: [self keyOfValue: whereNode->object]
                        andArg: [self keyOfValue: object]];
            }
            if (!compObjWhere &&
                compWhereObj &&
                (afterNode == header ||
                 [keyCompare performBinaryFunctionWithArg: [self keyOfValue: object]
                    andArg: [self keyOfValue: afterNode->object]]))
            {
                if (whereNode->right == nil)
                {
                    return [self insertImplHint1: nil where: whereNode
                        value: object hint2: whereNode];
                }
                else
                {
                    return [self insertImplHint1: afterNode where: afterNode
                        value: object hint2: nil];
                }
            }
            else
            {
                if (compObjWhere == compWhereObj)
                {
                    return OBJ_COND_AUTORELEASE([where copyWithAllocator: allocator]);
                }
                else
                {
                    return OBJ_COND_AUTORELEASE(
                        [self insertUniqueImpl: object success: NULL needIterator: YES]);
                }
            }
        }
    }
}

- (void) insertUniqueFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    OLForwardIterator* firstCopy = [first copyWithAllocator: allocator];

    for ( ; ![firstCopy isEqual: last]; [firstCopy advance])
        [self insertUniqueImpl: [firstCopy dereference] success: NULL needIterator: NO];
    [allocator deallocateObject: firstCopy];
}

- (OLAssociativeIterator*) insertUniqueImpl: (id)object success: (BOOL*)result needIterator: (BOOL)needItor
{
    OLTreeNode* y = header;
    OLTreeNode* x = header->parent;
    BOOL comp = YES;
    OLAssociativeIterator* itor;
    OLTreeNode* j;

    while (x != nil)
    {
        y = x;
        comp = [keyCompare performBinaryFunctionWithArg: [self keyOfValue: object]
            andArg: [self keyOfValue: x->object]];
        x = comp ? x->left : x->right;
    }
    j = y;
    if (comp)
    {
        if (j == header->left)
        {
            itor = [self insertImplHint1: y where: y
                value: object hint2: nil needIterator: needItor autorelease: NO];
            if (result != NULL)
                *result = YES;
            return itor;
        }
        else
        {
            j = [OLTreeNode decrement: j];
        }
    }
    if ([keyCompare performBinaryFunctionWithArg: [self keyOfValue: j->object]
            andArg: [self keyOfValue: object]])
    {
        itor = [self insertImplHint1: x where: y
            value: object hint2: nil needIterator: needItor autorelease: NO];
        if (result != NULL)
            *result = YES;
    }
    else
    {
        itor = needItor ?
            [[allocator allocateObject: [OLAssociativeIterator class]]
                    initWithNode: j] : nil;
        if (result != NULL)
            *result = NO;
    }
    return itor;
}

- (BOOL) isEqualNonUnique: (id)object
{
    OLTree* other;
    OLAssociativeIterator* myCur;
    OLAssociativeIterator* myEnd;
    OLAssociativeIterator* lower;
    OLAssociativeIterator* upper;
    OLVectorJunior* scratch;
    id nextKey;
    id curKey = nil;
    BOOL equal = YES;

    if (![object isKindOfClass: [OLTree class]])
        return NO;
    other = (OLTree*)object;
    if (nodeCount != other->nodeCount)
        return NO;
    myCur = [self beginImpl];
    myEnd = [self endImpl];
    scratch = [[allocator allocateObject: [OLVectorJunior class]]
        initWithAllocator: allocator];
    for ( ; ![myCur isEqual: myEnd]; [myCur advance])
    {
        nextKey = [self keyOfValue: [myCur dereference]];
        if (curKey == nil || ![curKey isEqual: nextKey])
        {
            curKey = nextKey;
            lower = [other lowerBoundImpl: curKey];
            upper = [other upperBoundImpl: curKey];
            [scratch clear];
            for ( ; ![lower isEqual: upper]; [lower advance])
                [scratch pushBack: [other valueOfValue: [lower dereference]]];
            [other->allocator deallocateObject: lower];
            [other->allocator deallocateObject: upper];
        }
        if (![scratch checkAndClear: [self valueOfValue: [myCur dereference]]])
        {
            equal = NO;
            break;
        }
    }
    [allocator deallocateObject: myCur];
    [allocator deallocateObject: myEnd];
    [allocator deallocateObject: scratch];
    return equal;
}

- (BOOL) isEqualUnique: (id)object
{
    OLTree* right;
    OLAssociativeIterator* myBegin;
    OLAssociativeIterator* itsBegin;
    OLAssociativeIterator* myEnd;
    BOOL equal = YES;

    if (![object isKindOfClass: [OLTree class]])
        return NO;
    right = (OLTree*)object;
    if (nodeCount != right->nodeCount)
        return NO;
    myBegin = [self beginImpl];
    itsBegin = [right beginImpl];
    myEnd = [self endImpl];
    for ( ; ![myBegin isEqual: myEnd]; [myBegin advance], [itsBegin advance])
    {
        if (![[myBegin dereference] isEqual: [itsBegin dereference]])
        {
            equal = NO;
            break;
        }
    }
    [allocator deallocateObject: myBegin];
    [allocator deallocateObject: itsBegin];
    [allocator deallocateObject: myEnd];
    return equal;
}

- (OLCodableFunctor<OLBoolBinaryFunction>*) keyComp
{
    return keyCompare;
}

- (id) keyOfValue: (id)value
{
    return value;
}

- (OLAssociativeIterator*) lowerBound: (id)key
{
    return OBJ_COND_AUTORELEASE([self lowerBoundImpl: key]);
}

- (OLAssociativeIterator*) lowerBoundImpl: (id)key
{
    OLTreeNode* y = header;
    OLTreeNode* x = header->parent;

    while (x != nil)
    {
        if (![keyCompare performBinaryFunctionWithArg: [self keyOfValue: x->object] andArg: key])
        {
            y = x;
            x = x->left;
        }
        else
        {
            x = x->right;
        }
    }
    return [[allocator allocateObject: [OLAssociativeIterator class]]
        initWithNode: y];
}

- (unsigned) maxSize
{
    return UINT_MAX;
}

- (OLReverseBidiIterator*) rbegin
{
    OLAssociativeIterator* itor = [self endImpl];
    OLReverseBidiIterator* rev = OBJ_COND_AUTORELEASE([[allocator allocateObject:
        [OLReverseBidiIterator class]] initWithIterator: itor]);

    [allocator deallocateObject: itor];
    return rev;
}

- (OLReverseBidiIterator*) rend
{
    OLAssociativeIterator* itor = [self beginImpl];
    OLReverseBidiIterator* rev = OBJ_COND_AUTORELEASE([[allocator allocateObject:
        [OLReverseBidiIterator class]] initWithIterator: itor]);

    [allocator deallocateObject: itor];
    return rev;
}

- (unsigned) size
{
    return nodeCount;
}

- (void) swap: (OLTree*)tree
{
    OL_PREPARE_SLOW_SWAP;
    OLTree* tmp;

    if (self != tree)
    {
        if ([allocator isEqual: tree->allocator])
        {
            OL_SLOW_SWAP(header, tree->header);
            OL_SLOW_SWAP(keyCompare, tree->keyCompare);
            OL_FAST_SWAP(nodeCount, tree->nodeCount);
        }
        else
        {
            tmp = [[allocator allocateObject: [OLTree class]] initWithTree: self];
            [self clear];
            header->parent = [self copyNodes: tree->header->parent to: header];
            header->left = [header->parent minimum];
            header->right = [header->parent maximum];
            nodeCount = tree->nodeCount;
            [tree clear];
            tree->header->parent = [self copyNodes: tmp->header->parent to: tree->header];
            tree->header->left = [tree->header->parent minimum];
            tree->header->right = [tree->header->parent maximum];
            tree->nodeCount = tmp->nodeCount;
            [allocator deallocateObject: tmp];
        }
    }
}

- (OLAssociativeIterator*) upperBound: (id)key
{
    return OBJ_COND_AUTORELEASE([self upperBoundImpl: key]);
}

- (OLAssociativeIterator*) upperBoundImpl: (id)key
{
    OLTreeNode* y = header;
    OLTreeNode* x = header->parent;

    while (x != nil)
    {
        if ([keyCompare performBinaryFunctionWithArg: key andArg: [self keyOfValue: x->object]])
        {
            y = x;
            x = x->left;
        }
        else
        {
            x = x->right;
        }
    }
    return [[allocator allocateObject: [OLAssociativeIterator class]]
        initWithNode: y];
}

- (id) valueOfValue: (id)value
{
    return value;
}

@end

@implementation OLTreeMap

- (void) assignEqualKey: (id)key value: (id)val
{
    OLPair* p = [[allocator allocateObject: [OLPair class]]
        initWithFirst: key second: val];
    [self insertEqualImpl: p needIterator: NO];
    [allocator deallocateObject: p];
}

- (void) assignUniqueKey: (id)key value: (id)val
{
    OLTreeNode* node = [self findImpl: key];
    OLPair* p;

    if (node == header)
    {
        p = [[allocator allocateObject: [OLPair class]]
            initWithFirst: key second: val];
        [self insertUniqueImpl: p success: NULL needIterator: NO];
        [allocator deallocateObject: p];
    }
    else
    {
        [node->object setSecond: val];
    }
}

- (id) findValue: (id)key
{
    id object = [self findImpl: key]->object;

    return (object == nil) ? nil : [object second];
}

- (id) keyOfValue: (id)value
{
    return [value first];
}

- (id) valueOfValue: (id)value
{
    return [value second];
}

@end
