NazaraEngine/thirdparty/src/newton/dContainers/dMap.h

1050 lines
21 KiB
C++

/* Copyright (c) <2003-2019> <Newton Game Dynamics>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely
*/
#ifndef __D_MAP__
#define __D_MAP__
template<class OBJECT, class KEY>
class dMap
{
public:
class dTreeNode
{
enum REDBLACK_COLOR
{
RED = true,
BLACK = false
};
dTreeNode (const KEY &key, dTreeNode* parentNode)
:m_info()
,m_key(key)
,m_left(nullptr)
,m_right(nullptr)
,m_parent(parentNode)
,m_color(false)
,m_inTree(false)
{
SetColor(RED);
SetInTreeFlag(true);
}
dTreeNode (const OBJECT &info, const KEY &key, dTreeNode* parentNode)
:m_info(info)
,m_key(key)
,m_left(nullptr)
,m_right(nullptr)
,m_parent(parentNode)
,m_color(false)
,m_inTree(false)
{
SetColor(RED);
SetInTreeFlag(true);
}
virtual ~dTreeNode ()
{
}
void SetInTreeFlag(bool flag)
{
m_inTree = flag;
}
bool GetColor() const
{
return m_color;
}
void SetColor(bool color)
{
m_color = color;
}
dTreeNode& operator= (dTreeNode& src)
{
dAssert (0);
return* this;
}
dTreeNode* GetLeft () const
{
return m_left;
}
dTreeNode* GetRight () const
{
return m_right;
}
dTreeNode* GetParent ()
{
return m_parent;
}
void SetLeft (dTreeNode* const node)
{
m_left = node;
}
void SetRight (dTreeNode* const node)
{
m_right = node;
}
void SetParent (dTreeNode* const node)
{
m_parent = node;
}
public:
const KEY& GetKey() const
{
return m_key;
}
OBJECT& GetInfo()
{
return m_info;
}
dTreeNode* Minimum() const
{
dTreeNode* ptr = (dTreeNode*)this;
for (; ptr->m_left; ptr = ptr->m_left);
return ptr;
}
dTreeNode* Next() const
{
if (m_right) {
return m_right->Minimum();
}
dTreeNode* node = (dTreeNode*)this;
dTreeNode* ptr = m_parent;
for (; ptr && node == ptr->m_right; ptr = ptr->m_parent) {
node = ptr;
}
return ptr;
}
void Unlink(dTreeNode** const head)
{
dTreeNode* const node = this;
node->SetInTreeFlag(false);
if (!node->m_left || !node->m_right) {
// y has a nullptr node as a child
dTreeNode* const endNode = node;
// x is y's only child
dTreeNode* child = endNode->m_right;
if (endNode->m_left) {
child = endNode->m_left;
}
// remove y from the parent chain
if (child) {
child->m_parent = endNode->m_parent;
}
if (endNode->m_parent) {
if (endNode == endNode->m_parent->m_left) {
endNode->m_parent->m_left = child;
} else {
endNode->m_parent->m_right = child;
}
} else {
*head = child;
}
if (endNode->GetColor() == BLACK) {
endNode->m_parent->RemoveFixup(child, head);
}
} else {
// find tree successor with a nullptr node as a child
dTreeNode* endNode = node->m_right;
while (endNode->m_left != nullptr) {
endNode = endNode->m_left;
}
// x is y's only child
dTreeNode* const child = endNode->m_right;
endNode->m_left = node->m_left;
node->m_left->m_parent = endNode;
dTreeNode* endNodeParent = endNode;
if (endNode != node->m_right) {
if (child) {
child->m_parent = endNode->m_parent;
}
endNode->m_parent->m_left = child;
endNode->m_right = node->m_right;
node->m_right->m_parent = endNode;
endNodeParent = endNode->m_parent;
}
if (node == *head) {
*head = endNode;
} else if (node == node->m_parent->m_left) {
node->m_parent->m_left = endNode;
} else {
node->m_parent->m_right = endNode;
}
endNode->m_parent = node->m_parent;
bool oldColor = endNode->GetColor();
endNode->SetColor(node->GetColor());
node->SetColor(oldColor);
if (oldColor == BLACK) {
endNodeParent->RemoveFixup(child, head);
}
}
}
void RotateLeft(dTreeNode** const head)
{
dTreeNode* const me = this;
dTreeNode* const child = me->m_right;
//dAssert(child);
me->m_right = child->m_left;
if (child->m_left != nullptr) {
child->m_left->m_parent = me;
}
if (child != nullptr) {
child->m_parent = me->m_parent;
}
if (me->m_parent) {
if (me == me->m_parent->m_left) {
me->m_parent->m_left = child;
} else {
me->m_parent->m_right = child;
}
} else {
*head = child;
}
// link child and me
child->m_left = me;
if (me != nullptr) {
me->m_parent = child;
}
}
// rotate node me to right *
void RotateRight(dTreeNode** const head)
{
dTreeNode* const me = this;
dTreeNode* const child = me->m_left;
//dAssert(child);
me->m_left = child->m_right;
if (child->m_right != nullptr) {
child->m_right->m_parent = me;
}
// establish child->m_parent link
if (child != nullptr) {
child->m_parent = me->m_parent;
}
if (me->m_parent) {
if (me == me->m_parent->m_right) {
me->m_parent->m_right = child;
} else {
me->m_parent->m_left = child;
}
} else {
*head = child;
}
// link me and child
child->m_right = me;
if (me != nullptr) {
me->m_parent = child;
}
}
void RemoveFixup(dTreeNode* const me, dTreeNode** const head)
{
dTreeNode* ptr = this;
dTreeNode* node = me;
while ((node != *head) && (!node || node->GetColor() == BLACK)) {
if (node == ptr->m_left) {
if (!ptr) {
return;
}
dTreeNode* tmp = ptr->m_right;
if (!tmp) {
return;
}
if (tmp->GetColor() == RED) {
tmp->SetColor(BLACK);
ptr->SetColor(RED);
ptr->RotateLeft(head);
tmp = ptr->m_right;
if (!tmp) {
return;
}
}
if ((!tmp->m_left || (tmp->m_left->GetColor() == BLACK)) &&
(!tmp->m_right || (tmp->m_right->GetColor() == BLACK))) {
tmp->SetColor(RED);
node = ptr;
ptr = ptr->m_parent;
continue;
} else if (!tmp->m_right || (tmp->m_right->GetColor() == BLACK)) {
tmp->m_left->SetColor(BLACK);
tmp->SetColor(RED);
tmp->RotateRight(head);
tmp = ptr->m_right;
//if (!ptr || !tmp) {
if (!tmp) {
return;
}
}
tmp->SetColor(ptr->GetColor());
if (tmp->m_right) {
tmp->m_right->SetColor(BLACK);
}
if (ptr) {
ptr->SetColor(BLACK);
ptr->RotateLeft(head);
}
node = *head;
} else {
if (!ptr) {
return;
}
dTreeNode* tmp = ptr->m_left;
if (!tmp) {
return;
}
if (tmp->GetColor() == RED) {
tmp->SetColor(BLACK);
ptr->SetColor(RED);
ptr->RotateRight(head);
tmp = ptr->m_left;
if (!tmp) {
return;
}
}
if ((!tmp->m_right || (tmp->m_right->GetColor() == BLACK)) &&
(!tmp->m_left || (tmp->m_left->GetColor() == BLACK))) {
tmp->SetColor(RED);
node = ptr;
ptr = ptr->m_parent;
continue;
} else if (!tmp->m_left || (tmp->m_left->GetColor() == BLACK)) {
tmp->m_right->SetColor(BLACK);
tmp->SetColor(RED);
tmp->RotateLeft(head);
tmp = ptr->m_left;
//if (!ptr || !tmp) {
if (!tmp) {
return;
}
}
tmp->SetColor(ptr->GetColor());
if (tmp->m_left) {
tmp->m_left->SetColor(BLACK);
}
if (ptr) {
ptr->SetColor(BLACK);
ptr->RotateRight(head);
}
node = *head;
}
}
if (node) {
node->SetColor(BLACK);
}
}
void InsertFixup(dTreeNode** const head)
{
dTreeNode* ptr = this;
// check Red-Black properties
//dAssert((ptr == *head) || ptr->m_parent);
while ((ptr != *head) && (ptr->m_parent->GetColor() == RED)) {
// we have a violation
//dAssert(ptr->m_parent);
//dAssert(ptr->m_parent->m_parent);
if (ptr->m_parent == ptr->m_parent->m_parent->m_left) {
dTreeNode* const tmp = ptr->m_parent->m_parent->m_right;
if (tmp && (tmp->GetColor() == RED)) {
// uncle is RED
ptr->m_parent->SetColor(BLACK);
tmp->SetColor(BLACK);
ptr->m_parent->m_parent->SetColor(RED);
ptr = ptr->m_parent->m_parent;
} else {
// uncle is BLACK
if (ptr == ptr->m_parent->m_right) {
// make ptr a left child
ptr = ptr->m_parent;
ptr->RotateLeft(head);
}
ptr->m_parent->SetColor(BLACK);
if (ptr->m_parent->m_parent) {
ptr->m_parent->m_parent->SetColor(RED);
ptr->m_parent->m_parent->RotateRight(head);
}
}
} else {
//dAssert (ptr->m_parent == ptr->m_parent->m_parent->m_right);
// mirror image of above code
dTreeNode* const tmp = ptr->m_parent->m_parent->m_left;
if (tmp && (tmp->GetColor() == RED)) {
//uncle is RED
ptr->m_parent->SetColor(BLACK);
tmp->SetColor(BLACK);
ptr->m_parent->m_parent->SetColor(RED);
ptr = ptr->m_parent->m_parent;
} else {
// uncle is BLACK
if (ptr == ptr->m_parent->m_left) {
ptr = ptr->m_parent;
ptr->RotateRight(head);
}
ptr->m_parent->SetColor(BLACK);
if (ptr->m_parent->m_parent->GetColor() == BLACK) {
ptr->m_parent->m_parent->SetColor(RED);
ptr->m_parent->m_parent->RotateLeft(head);
}
}
}
}
(*head)->SetColor(BLACK);
}
private:
OBJECT m_info;
KEY m_key;
dTreeNode* m_left;
dTreeNode* m_right;
dTreeNode* m_parent;
bool m_color;
bool m_inTree;
friend class dMap<OBJECT, KEY>;
};
class Iterator
{
public:
Iterator(const dMap<OBJECT,KEY> &me)
{
m_ptr = nullptr;
m_tree = &me;
}
~Iterator()
{
}
void Begin()
{
m_ptr = m_tree->Minimum();
}
void End()
{
m_ptr = m_tree->Maximum();
}
void Set (dTreeNode* const node)
{
m_ptr = node;
}
operator int() const
{
return m_ptr != nullptr;
}
void operator++ ()
{
//dAssert (m_ptr);
m_ptr = m_ptr->Next();
}
void operator++ (int)
{
//dAssert (m_ptr);
m_ptr = m_ptr->Next();
}
void operator-- ()
{
//dAssert (m_ptr);
m_ptr = m_ptr->Prev();
}
void operator-- (int)
{
//dAssert (m_ptr);
m_ptr = m_ptr->Prev();
}
OBJECT &operator* () const
{
return ((dTreeNode*)m_ptr)->GetInfo();
}
dTreeNode* GetNode() const
{
return (dTreeNode*)m_ptr;
}
KEY GetKey () const
{
dTreeNode* const tmp = (dTreeNode*)m_ptr;
return tmp ? tmp->GetKey() : KEY(0);
}
private:
dTreeNode* m_ptr;
const dMap* m_tree;
};
// ***********************************************************
// member functions
// ***********************************************************
public:
dMap ();
virtual ~dMap ();
operator int() const;
int GetCount() const;
dTreeNode* GetRoot () const;
dTreeNode* Minimum () const;
dTreeNode* Maximum () const;
dTreeNode* Find (KEY key) const;
dTreeNode* FindGreater (KEY key) const;
dTreeNode* FindGreaterEqual (KEY key) const;
dTreeNode* FindLessEqual (KEY key) const;
dTreeNode* GetNodeFromInfo (OBJECT &info) const;
dTreeNode* Insert (KEY key);
dTreeNode* Insert (const OBJECT &element, KEY key);
dTreeNode* Insert (const OBJECT &element, KEY key, bool& elementWasInTree);
dTreeNode* Insert (dTreeNode* const node, KEY key);
dTreeNode* Replace (OBJECT &element, KEY key);
dTreeNode* ReplaceKey (KEY oldKey, KEY newKey);
dTreeNode* ReplaceKey (dTreeNode* const node, KEY key);
void Unlink (dTreeNode* const node);
void Remove (KEY key);
void Remove (dTreeNode* const node);
void RemoveAll ();
bool SanityCheck () const;
// ***********************************************************
// member variables
// ***********************************************************
private:
void RemoveAllLow (dTreeNode* const root);
int CompareKeys (const KEY &key0, const KEY &key1) const;
bool SanityCheck (dTreeNode* const ptr, int height) const;
int m_count;
dTreeNode* m_head;
friend class dTreeNode;
};
template<class OBJECT, class KEY>
dMap<OBJECT, KEY>::dMap ()
{
m_count = 0;
m_head = nullptr;
}
template<class OBJECT, class KEY>
dMap<OBJECT, KEY>::~dMap ()
{
RemoveAll();
}
template<class OBJECT, class KEY>
dMap<OBJECT, KEY>::operator int() const
{
return m_head != nullptr;
}
template<class OBJECT, class KEY>
int dMap<OBJECT, KEY>::GetCount() const
{
return m_count;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Minimum () const
{
return m_head ? (dTreeNode*) m_head->Minimum() : nullptr;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Maximum () const
{
return m_head ? (dTreeNode*) m_head->Maximum() : nullptr;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::GetRoot () const
{
return m_head;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Find (KEY key) const
{
if (m_head == nullptr) {
return nullptr;
}
dTreeNode* ptr = m_head;
while (ptr != nullptr) {
int val = CompareKeys (ptr->m_key, key);
if (!val) {
break;
}
if (val < 0) {
ptr = ptr->GetLeft();
} else {
ptr = ptr->GetRight();
}
}
return ptr;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::GetNodeFromInfo (OBJECT &info) const
{
dTreeNode* node = (dTreeNode*) &info;
int offset = ((char*) &node->m_info) - ((char *) node);
node = (dTreeNode*) (((char *) node) - offset);
// dAssert (node->IsInTree ());
dAssert (&node->GetInfo () == &info);
return (node->IsInTree ()) ? node : nullptr;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::FindGreater (KEY key) const
{
if (m_head == nullptr) {
return nullptr;
}
dTreeNode* prev = nullptr;
dTreeNode* ptr = m_head;
int val = 0;
while (ptr != nullptr) {
val = CompareKeys (ptr->m_key, key);
if (!val) {
return (dTreeNode*) ptr->Next();
}
prev = ptr;
if (val < 0) {
ptr = ptr->GetLeft();
} else {
ptr = ptr->GetRight();
}
}
if (val > 0) {
while (prev->m_parent && (prev->m_parent->m_right == prev)) {
prev = prev->GetParent();
}
prev = prev->GetParent();
}
return (dTreeNode*) prev;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::FindGreaterEqual (KEY key) const
{
if (m_head == nullptr) {
return nullptr;
}
dTreeNode* prev = nullptr;
dTreeNode* ptr = m_head;
int val = 0;
while (ptr != nullptr) {
val = CompareKeys (ptr->m_key, key);
if (!val) {
return ptr;
}
prev = ptr;
if (val < 0) {
ptr = ptr->GetLeft();
} else {
ptr = ptr->GetRight();
}
}
if (val > 0) {
while (prev->m_parent && (prev->m_parent->m_right == prev)) {
prev = prev->GetParent();
}
prev = prev->GetParent();
}
return (dTreeNode*) prev;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::FindLessEqual (KEY key) const
{
if (m_head == nullptr) {
return nullptr;
}
dTreeNode* prev = nullptr;
dTreeNode* ptr = m_head;
int val = 0;
while (ptr != nullptr) {
val = CompareKeys (ptr->m_key, key);
if (!val) {
return ptr;
}
prev = ptr;
if (val < 0) {
ptr = ptr->GetLeft();
} else {
ptr = ptr->GetRight();
}
}
if (val < 0) {
while (prev->m_parent && (prev->m_parent->m_left == prev)) {
prev = prev->GetParent();
}
prev = prev->GetParent();
}
return (dTreeNode*) prev;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Insert (KEY key)
{
dTreeNode* parent = nullptr;
dTreeNode* ptr = m_head;
int val = 0;
while (ptr != nullptr) {
parent = ptr;
val = CompareKeys (ptr->m_key, key);
if (val < 0) {
ptr = ptr->GetLeft();
} else if (val > 0) {
ptr = ptr->GetRight();
} else {
return ptr;
}
}
m_count ++;
ptr = new dTreeNode (key, parent);
if (!parent) {
m_head = ptr;
} else {
if (val < 0) {
parent->m_left = ptr;
} else {
parent->m_right = ptr;
}
}
ptr->InsertFixup ((dTreeNode**)&m_head);
return ptr;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Insert (const OBJECT &element, KEY key, bool& elementWasInTree)
{
dTreeNode* parent = nullptr;
dTreeNode* ptr = m_head;
int val = 0;
elementWasInTree = false;
while (ptr != nullptr) {
parent = ptr;
val = CompareKeys (ptr->m_key, key);
if (val < 0) {
ptr = ptr->GetLeft();
} else if (val > 0) {
ptr = ptr->GetRight();
} else {
elementWasInTree = true;
return ptr;
}
}
m_count ++;
ptr = new dTreeNode (element, key, parent);
if (!parent) {
m_head = ptr;
} else {
if (val < 0) {
parent->m_left = ptr;
} else {
parent->m_right = ptr;
}
}
ptr->InsertFixup ((dTreeNode**)&m_head);
return ptr;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Insert (const OBJECT &element, KEY key)
{
bool foundState;
dTreeNode* node = Insert (element, key, foundState);
if (foundState) {
node = nullptr;
}
return node;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Insert (typename dMap<OBJECT, KEY>::dTreeNode* const node, KEY key)
{
int val = 0;
dTreeNode* ptr = m_head;
dTreeNode* parent = nullptr;
while (ptr != nullptr) {
parent = ptr;
val = CompareKeys (ptr->m_key, key);
if (val < 0) {
ptr = ptr->GetLeft();
} else if (val > 0) {
ptr = ptr->GetRight();
} else {
return nullptr;
}
}
m_count ++;
ptr = node;
ptr->m_key = key;
ptr->Initdata (parent);
if (!parent) {
m_head = ptr;
} else {
if (val < 0) {
parent->m_left = ptr;
} else {
parent->m_right = ptr;
}
}
ptr->InsertFixup ((dTreeNode**)&m_head);
return ptr;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::Replace (OBJECT &element, KEY key)
{
dTreeNode* parent = nullptr;
dTreeNode* ptr = m_head;
int val = 0;
while (ptr != nullptr) {
parent = ptr;
val = CompareKeys (ptr->m_key, key);
if (val == 0) {
ptr->m_info = element;
return ptr;
}
if (val < 0) {
ptr = ptr->GetLeft();
} else {
ptr = ptr->GetRight();
}
}
ptr = new dTreeNode (element, key, parent);
if (!parent) {
m_head = ptr;
} else {
if (val < 0) {
parent->m_left = ptr;
} else {
parent->m_right = ptr;
}
}
ptr->InsertFixup ((dTreeNode**)&m_head);
return ptr;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::ReplaceKey (typename dMap<OBJECT, KEY>::dTreeNode* node, KEY key)
{
Unlink(node);
dTreeNode* const ptr = Insert (node, key);
dAssert (ptr);
return ptr;
}
template<class OBJECT, class KEY>
typename dMap<OBJECT, KEY>::dTreeNode* dMap<OBJECT, KEY>::ReplaceKey (KEY oldKey, KEY newKey)
{
dTreeNode* const node = Find (oldKey);
return node ? ReplaceKey (node, newKey) : nullptr;
}
template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::Unlink (typename dMap<OBJECT, KEY>::dTreeNode* const node)
{
m_count --;
node->Unlink((dTreeNode** )&m_head);
}
template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::Remove (typename dMap<OBJECT, KEY>::dTreeNode* const node)
{
m_count --;
node->Unlink ((dTreeNode** )&m_head);
delete node;
}
template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::Remove (KEY key)
{
// find node in tree
dTreeNode* const node = Find (key);
if (node) {
Remove (node);
}
}
template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::RemoveAllLow (dTreeNode* const root)
{
if (root->m_left) {
RemoveAllLow((dTreeNode*)root->m_left);
}
if (root->m_right) {
RemoveAllLow ((dTreeNode*)root->m_right);
}
root->SetInTreeFlag(false);
delete root;
}
template<class OBJECT, class KEY>
void dMap<OBJECT, KEY>::RemoveAll ()
{
if (m_head) {
m_count = 0;
dTreeNode* root;
for (root = m_head; root->m_parent; root = (dTreeNode*)root->m_parent);
RemoveAllLow(root);
m_head = nullptr;
}
}
template<class OBJECT, class KEY>
bool dMap<OBJECT, KEY>::SanityCheck () const
{
return SanityCheck (m_head, 0);
}
template<class OBJECT, class KEY>
bool dMap<OBJECT, KEY>::SanityCheck (typename dMap<OBJECT, KEY>::dTreeNode* ptr, int height) const
{
if (!ptr) {
return true;
}
if (ptr->m_left) {
if (CompareKeys (ptr->m_key, ptr->GetLeft()->m_key) > 0) {
return false;
}
}
if (ptr->m_right) {
if (CompareKeys (ptr->m_key, ptr->GetRight()->m_key) < 0) {
return false;
}
}
if (ptr->GetColor() == dTreeNode::BLACK) {
height ++;
} else if (!((!ptr->m_left || (ptr->m_left->GetColor() == dTreeNode::BLACK)) &&
(!ptr->m_right || (ptr->m_right->GetColor() == dTreeNode::BLACK)))) {
return false;
}
if (!ptr->m_left && !ptr->m_right) {
int bh = 0;
for (dTreeNode* x = ptr; x; x = x->GetParent()) {
if (x->GetColor() == dTreeNode::BLACK) {
bh ++;
}
}
if (bh != height) {
return false;
}
}
if (ptr->m_left && !SanityCheck (ptr->GetLeft(), height)) {
return false;
}
if (ptr->m_right && !SanityCheck (ptr->GetRight(), height)) {
return false;
}
return true;
}
template<class OBJECT, class KEY>
int dMap<OBJECT, KEY>::CompareKeys (const KEY &key0, const KEY &key1) const
{
if (key1 < key0) {
return - 1;
}
if (key1 > key0) {
return 1;
}
return 0;
}
#endif