#include "protoTree.h"
#include "protoDebug.h"
#include <string.h>
#include <stdlib.h>
ProtoTree::Item::Item()
: bit(0), parent((Item*)NULL), left((Item*)NULL), right((Item*)NULL)
{
}
ProtoTree::Item::~Item()
{
}
unsigned int ProtoTree::Item::GetDepth() const
{
unsigned int depth = 0;
const Item* p = this;
while (NULL != (p = p->parent)) depth++;
return depth;
}
ProtoTree::ItemPool::ItemPool()
: head(NULL)
{
}
ProtoTree::ItemPool::~ItemPool()
{
Destroy();
}
void ProtoTree::ItemPool::Destroy()
{
Item* item;
while ((item = Get())) delete item;
}
ProtoTree::Item* ProtoTree::ItemPool::Get()
{
Item* item = head;
if (NULL != item) head = item->GetPoolNext();
return item;
}
void ProtoTree::ItemPool::Put(Item& item)
{
item.SetPoolNext(head);
head = &item;
}
ProtoTree::ProtoTree()
: root((Item*)NULL)
{
}
ProtoTree::~ProtoTree()
{
}
void ProtoTree::Empty()
{
root = (ProtoTree::Item*)NULL;
UpdateIterators(NULL, Iterator::EMPTY);
}
void ProtoTree::Destroy()
{
while (NULL != root)
{
Item* item = root;
Remove(*item);
delete item;
}
}
bool ProtoTree::PrefixIsEqual(const char* key,
unsigned int keysize,
const char* prefix,
unsigned int prefixSize,
Endian keyEndian)
{
if (prefixSize > keysize) return false;
unsigned int fullByteCount = (prefixSize >> 3);
unsigned int remBitCount = prefixSize & 0x07;
if (ENDIAN_BIG == keyEndian)
{
if (0 != remBitCount)
{
char remBitMask = (unsigned char)0xff << (8 - remBitCount);
if ((key[fullByteCount] & remBitMask) != (prefix[fullByteCount] & remBitMask))
return false;
}
}
else
{
key += (keysize >> 3);
if (0 != (keysize &0x07)) key++;
key -= fullByteCount;
if (0 != remBitCount)
{
char remBitMask = 0xff << (8 - remBitCount);
if ((key[0] & remBitMask) != (prefix[0] & remBitMask))
return false;
if (0 != fullByteCount)
return (0 == memcmp(key+1, prefix+1, fullByteCount));
else
return true;
}
}
if (0 != fullByteCount)
return (0 == memcmp(key, prefix, fullByteCount));
else
return true;
}
bool ProtoTree::KeysAreEqual(const char* key1,
const char* key2,
unsigned int keysize,
Endian keyEndian)
{
unsigned int fullByteCount = keysize >> 3;
unsigned int remBitCount = keysize & 0x07;
if (0 != remBitCount)
{
char remBitMask = 0xff << (8 - remBitCount);
if (ENDIAN_BIG == keyEndian)
{
if ((key1[fullByteCount] & remBitMask) != (key2[fullByteCount] & remBitMask))
return false;
}
else
{
if ((key1[0] & remBitMask) != (key2[0] & remBitMask))
return false;
if (0 != fullByteCount)
return (0 == memcmp(key1+1, key2+1, fullByteCount));
else
return true;
}
}
if (0 != fullByteCount)
return (0 == memcmp(key1, key2, fullByteCount));
else
return true;
}
bool ProtoTree::ItemsAreEqual(const Item& item1, const Item& item2)
{
unsigned int keysize = item1.GetKeysize();
if (item2.GetKeysize() != keysize) return false;
Endian keyEndian = item1.GetEndian();
if (keyEndian != item2.GetEndian())
{
PLOG(PL_WARN, "ProtoTree::ItemsAreEqual() mis-matched key endian?!\n");
ASSERT(0);
return false;
}
return KeysAreEqual(item1.GetKey(), item2.GetKey(), keysize, keyEndian);
}
bool ProtoTree::ItemIsEqual(const Item& item, const char* key, unsigned int keysize)
{
if (item.GetKeysize() != keysize) return false;
return KeysAreEqual(item.GetKey(), key, keysize, item.GetEndian());
}
bool ProtoTree::Bit(const char* key, unsigned int keysize, unsigned int index, Endian keyEndian)
{
if (index < keysize)
{
unsigned int byteIndex = index >> 3;
byteIndex = (ENDIAN_BIG == keyEndian) ? byteIndex : ((keysize - 1) >> 3) - byteIndex;
return (0 != (key[byteIndex] & (0x80 >> (index & 0x07))));
}
else if (index < (keysize + (sizeof(keysize) << 3)))
{
index -= keysize;
return (0 != (((char*)&keysize)[index >> 3] & (0x80 >> (index & 0x07))));
}
else
{
return false;
}
}
ProtoTree::Item* ProtoTree::GetFirstItem() const
{
if (NULL != root)
{
if (root->left == root->right)
{
return root;
}
else
{
Item* x = (root->left == root) ? root->right : root;
while (x->left->parent == x) x = x->left;
return (x->left);
}
}
return NULL;
}
ProtoTree::Item* ProtoTree::GetLastItem() const
{
if (NULL != root)
{
Item* x = (root->right == root) ? root->left : root;
Item* p;
do
{
p = x;
x = x->right;
} while (p == x->parent);
return x;
}
return NULL;
}
bool ProtoTree::Insert(ProtoTree::Item& item)
{
if (NULL != root)
{
const char* key = item.GetKey();
unsigned int keysize = item.GetKeysize();
Endian keyEndian = item.GetEndian();
Item* x = root;
Item* p;
do
{
p = x;
x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left;
} while (p == x->parent);
unsigned int dBit = 0;
unsigned int keysizeMin, indexMax;
if (keysize < x->GetKeysize())
{
keysizeMin = keysize;
indexMax = x->GetKeysize() + (sizeof(unsigned int) << 3);
}
else
{
keysizeMin = x->GetKeysize();
indexMax = keysize + (sizeof(unsigned int) << 3);
}
const char* ptr1 = key;
const char* ptr2 = x->GetKey();
ASSERT(x->GetEndian() == keyEndian);
if (ENDIAN_LITTLE == keyEndian)
{
ptr1 += ((keysize - 1) >> 3);
ptr2 += ((x->GetKeysize() - 1) >> 3);
}
unsigned int fullByteBits = keysizeMin & ~0x07;
while (dBit < fullByteBits)
{
if (*ptr1 != *ptr2)
{
unsigned char delta = *ptr1 ^ *ptr2;
ASSERT(0 != delta);
while (delta < 0x80)
{
delta <<= 1;
dBit++;
}
break;
}
if (ENDIAN_BIG == keyEndian)
{
ptr1++;
ptr2++;
}
else
{
ptr1--;
ptr2--;
}
dBit += 8;
}
ASSERT(dBit <= fullByteBits);
if (dBit == fullByteBits)
{
for (; dBit < indexMax; dBit++)
{
if (Bit(key, keysize, dBit, keyEndian) != Bit(x->GetKey(), x->GetKeysize(), dBit, keyEndian))
break;
}
if (dBit == indexMax)
{
PLOG(PL_WARN, "ProtoTree::Insert() Equivalent item already in tree!\n");
return false;
}
}
item.bit = dBit;
x = root;
do
{
p = x;
x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left;
} while ((x->bit < dBit) && (p == x->parent));
if (Bit(key, keysize, dBit, keyEndian))
{
ASSERT(NULL != x);
item.left = x;
item.right = &item;
}
else
{
item.left = &item;
item.right = x;
}
item.parent = p;
if (Bit(key, keysize, p->bit, keyEndian))
p->right = &item;
else
p->left = &item;
if (p == x->parent)
x->parent = &item;
}
else
{
root = &item;
item.parent = (Item*)NULL;
item.left = item.right = &item;
item.bit = 0;
}
UpdateIterators(&item, Iterator::INSERT);
return true;
}
ProtoTree::Item* ProtoTree::FindPredecessor(ProtoTree::Item& item) const
{
Item* x = &item;
Item* q;
const char* key = item.GetKey();
unsigned int keysize = item.GetKeysize();
Endian keyEndian = item.GetEndian();
do
{
q = x;
if (Bit(key, keysize, x->bit, keyEndian))
x = x->right;
else
x = x->left;
} while (x != &item);
return q;
}
void ProtoTree::Remove(ProtoTree::Item& item)
{
ASSERT(0 != item.GetKeysize());
if (((&item == item.left) || (&item == item.right)) && (NULL != item.parent))
{
Item* orphan = (&item == item.left) ? item.right : item.left;
if (item.parent->left == &item)
item.parent->left = orphan;
else
item.parent->right = orphan;
if (orphan->bit > item.parent->bit)
orphan->parent = item.parent;
}
else
{
const char* key = item.GetKey();
unsigned int keysize = item.GetKeysize();
Endian keyEndian = item.GetEndian();
Item* x = &item;
Item* q;
do
{
q = x;
if (Bit(key, keysize, x->bit, keyEndian))
x = x->right;
else
x = x->left;
} while (x != &item);
if (NULL != q->parent)
{
Item* s = NULL;
if (NULL == item.parent)
{
x = Bit(key, keysize, item.bit, keyEndian) ? item.left : item.right;
do
{
s = x;
if (Bit(key, keysize, x->bit, keyEndian))
x = x->right;
else
x = x->left;
} while (x != &item);
}
q->bit = item.bit;
Item* parent = q->parent;
Item* child = (q->left == &item) ? q->right : q->left;
ASSERT(NULL != child);
if (parent->left == q)
parent->left = child;
else
parent->right = child;
if (child->bit > parent->bit)
child->parent = parent;
ASSERT(q != NULL);
if (item.left->parent == &item)
item.left->parent = q;
if (item.right->parent == &item)
item.right->parent = q;
if (NULL != item.parent)
{
if (item.parent->left == &item)
item.parent->left = q;
else
item.parent->right = q;
}
else
{
ASSERT(s != NULL);
ASSERT(s != &item);
if (s->left == &item)
s->left = q;
else
s->right = q;
root = q;
}
if (NULL != item.parent)
ASSERT((&item != item.left) && (&item != item.right));
q->parent = item.parent;
q->left = (item.left == &item) ? q : item.left;
q->right = (item.right == &item) ? q : item.right;
}
else
{
ASSERT(q == &item);
Item* orphan = (q == q->left) ? q->right : q->left;
if (q == orphan)
{
root = (Item*)NULL;
}
else
{
root = orphan;
orphan->parent = NULL;
if (orphan->left == q)
orphan->left = orphan;
else
orphan->right = orphan;
orphan->bit = 0;
}
}
}
item.parent = item.left = item.right = (Item*)NULL;
UpdateIterators(&item, Iterator::REMOVE);
}
ProtoTree::Item* ProtoTree::RemoveRoot()
{
Item* item = root;
if (NULL != item) Remove(*item);
return item;
}
ProtoTree::Item* ProtoTree::Find(const char* key,
unsigned int keysize) const
{
Item* x = root;
if (NULL != x)
{
Endian keyEndian = x->GetEndian();
Item* p;
do
{
p = x;
x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left;
} while (x->parent == p);
return (ItemIsEqual(*x, key, keysize) ? x : NULL);
}
else
{
return (Item*)NULL;
}
}
ProtoTree::Item* ProtoTree::FindClosestMatch(const char* key,
unsigned int keysize) const
{
Item* x = root;
if (NULL != x)
{
Endian keyEndian = x->GetEndian();
Item* p;
do
{
p = x;
x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left;
} while ((x->parent == p) && (x->bit < keysize));
return x;
}
else
{
return (Item*)NULL;
}
}
ProtoTree::Item* ProtoTree::FindPrefix(const char* key,
unsigned int keysize) const
{
Item* x = root;
if (NULL != x)
{
Endian keyEndian = x->GetEndian();
Item* p;
do
{
p = x;
x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left;
} while ((x->parent == p) && (x->bit < keysize));
if (PrefixIsEqual(key, keysize, x->GetKey(), x->GetKeysize(), keyEndian))
return x;
}
return NULL;
}
ProtoTree::Item* ProtoTree::FindPrefixSubtree(const char* prefix,
unsigned int prefixSize) const
{
Item* x = root;
if (NULL != x)
{
Endian keyEndian = x->GetEndian();
Item* p;
do
{
p = x;
x = Bit(prefix, prefixSize, x->bit, keyEndian) ? x->right : x->left;
} while ((x->parent == p) && (x->bit < prefixSize));
if (PrefixIsEqual(x->GetKey(), x->GetKeysize(), prefix, prefixSize, keyEndian))
return x;
}
return (Item*)NULL;
}
ProtoTree::Iterator::Iterator(ProtoTree& theTree, bool reverse, ProtoTree::Item* cursor)
: ProtoIterable::Iterator(theTree), prefix_size(0), prefix_item(NULL)
{
if (NULL != cursor)
{
reversed = reverse;
SetCursor(*cursor);
}
else
{
Reset(reverse); }
}
ProtoTree::Iterator::~Iterator()
{
}
void ProtoTree::Iterator::Reset(bool reverse,
const char* prefix,
unsigned int prefixSize)
{
ProtoTree* tree = static_cast<ProtoTree*>(iterable);
prefix_size = 0;
prefix_item = prev = next = curr_hop = (Item*)NULL;
if ((NULL == tree) || (NULL == tree->root)) return;
if (0 != prefixSize)
{
if (NULL == prefix) return;
ProtoTree::Item* prefixItem = tree->FindPrefixSubtree(prefix, prefixSize);
if (NULL == prefixItem) return;
reversed = reverse ? false : true;
SetCursor(*prefixItem);
Endian keyEndian = prefixItem->GetEndian();
if (reverse)
{
ProtoTree::Item* lastItem;
while (NULL != (lastItem = GetNextItem()))
{
if (!tree->PrefixIsEqual(lastItem->GetKey(), lastItem->GetKeysize(), prefix, prefixSize, keyEndian))
break; }
if (NULL == lastItem) Reset(reverse);
}
else
{
ProtoTree::Item* firstItem;
while (NULL != (firstItem = GetPrevItem()))
{
if (!tree->PrefixIsEqual(firstItem->GetKey(), firstItem->GetKeysize(), prefix, prefixSize, keyEndian))
break; }
if (NULL == firstItem) Reset(reverse);
}
prefix_size = prefixSize;
prefix_item = prefixItem;
return;
}
if (reverse)
{
if (NULL != tree->root)
{
Item* x = (tree->root->right == tree->root) ? tree->root->left : tree->root;
Item* p;
do
{
p = x;
x = x->right;
} while (p == x->parent);
prev = x;
}
reversed = true;
}
else
{
if (NULL != tree->root)
{
if (tree->root->left == tree->root->right)
{
next = tree->root;
curr_hop = NULL;
}
else
{
Item* x = (tree->root->left == tree->root) ? tree->root->right : tree->root;
while (x->left->parent == x) x = x->left;
next = x->left;
if (x->right->parent == x)
{
x = x->right;
while (x->left->parent == x) x = x->left;
}
curr_hop = x;
}
}
reversed = false;
}
}
void ProtoTree::Iterator::SetCursor(ProtoTree::Item& item)
{
ProtoTree* tree = static_cast<ProtoTree*>(iterable);
unsigned int prefixSize = prefix_size;
ProtoTree::Item* prefixItem = prefix_item;
prefix_size = 0;
prefix_item = NULL;
if ((NULL== tree) || (NULL == tree->root))
{
prev = next = curr_hop = NULL;
}
else if (tree->root->left == tree->root->right)
{
ASSERT(&item == tree->root);
curr_hop = NULL;
if (reversed)
{
prev = NULL;
next = tree->root;
}
else
{
prev = tree->root;
next = NULL;
}
}
else if (reversed)
{
curr_hop = NULL;
prev = &item;
GetPrevItem(); }
else
{
reversed = true;
prev = &item;
GetPrevItem(); if (NULL == GetPrevItem())
{
Reset(false);
GetNextItem();
}
else
{
if ((&item != tree->root) || (item.right != &item))
{
curr_hop = tree->FindPredecessor(item);
}
else
{
ASSERT(&item == tree->root);
const char* key = item.GetKey();
unsigned int keysize = item.GetKeysize();
Endian keyEndian = item.GetEndian();
Item* s;
Item* x = tree->Bit(key, keysize, item.bit, keyEndian) ? item.left : item.right;
ASSERT((x == item.left) || (x == item.right));
do
{
s = x;
if (tree->Bit(key, keysize, x->bit, keyEndian))
x = x->right;
else
x = x->left;
} while (x != &item);
curr_hop = s;
}
reversed = false;
GetNextItem();
GetNextItem();
}
}
if (0 != prefixSize)
{
prefix_item = prefixItem;
prefix_size = prefixSize;
}
}
ProtoTree::Item* ProtoTree::Iterator::GetPrevItem()
{
if (NULL != prev)
{
ProtoTree* tree = static_cast<ProtoTree*>(iterable);
if (!reversed)
{
reversed = true;
unsigned savePrefixSize = prefix_size;
prefix_size = 0;
GetPrevItem();
prefix_size = savePrefixSize;
if (NULL == prev) return NULL;
}
Item* item = prev;
Endian keyEndian = item->GetEndian();
if (0 != prefix_size)
{
if ((NULL == prefix_item) ||
!tree->PrefixIsEqual(item->GetKey(), item->GetKeysize(), prefix_item->GetKey(), prefix_size, keyEndian))
{
prev = NULL;
return NULL;
}
}
Item* x;
if ((NULL == item->parent) && (item->right == item))
x = item->left;
else
x = item;
Item* q;
do
{
q = x;
if (tree->Bit(item->GetKey(), item->GetKeysize(), x->bit, keyEndian))
x = x->right;
else
x = x->left;
} while (x != prev);
if (q->right != item)
{
do
{
x = q;
q = q->parent;
} while ((NULL != q) && (x == q->left));
if ((NULL == q) || (NULL == q->parent))
{
if ((NULL == q) || (q->left == q))
{
prev = NULL;
}
else
{
Item* r = q;
x = q->left;
do
{
q = x;
if (tree->Bit(r->GetKey(), r->GetKeysize(), x->bit, keyEndian))
x = x->right;
else
x = x->left;
} while (x != r);
if (q->left != q)
{
q = q->left;
do
{
x = q;
q = q->right;
} while (x == q->parent);
}
prev = q;
}
next = item;
return item;
}
}
if (q->left->parent != q)
{
if ((NULL == q->left->parent) &&
(q->left->left != q->left) &&
tree->Bit(q->GetKey(), q->GetKeysize(), 0, keyEndian))
{
x = q->left->left;
do
{
q = x;
x = x->right;
} while (q == x->parent);
prev = x;
}
else
{
prev = q->left;
}
}
else
{
x = q->left;
do
{
q = x;
x = x->right;
} while (q == x->parent);
prev = x;
}
next = item;
return item;
}
else
{
return NULL;
}
}
ProtoTree::Item* ProtoTree::Iterator::PeekPrevItem()
{
if (reversed)
{
return prev;
}
else
{
Item* prevItem = GetPrevItem();
GetNextItem(); return prevItem;
}
}
ProtoTree::Item* ProtoTree::Iterator::GetNextItem()
{
if (NULL != next)
{
ProtoTree* tree = static_cast<ProtoTree*>(iterable);
if (reversed)
{
reversed = false;
SetCursor(*next);
if (NULL == next) return NULL;
}
Item* item = next;
Endian keyEndian = next->GetEndian();
if (NULL == curr_hop)
{
next = NULL;
}
else
{
Item* x = curr_hop;
if (((x->left != next) && (x->left->parent != x)) ||
(x->right->parent == x))
{
next = x->left;
if ((NULL == next->parent) &&
(tree->Bit(next->GetKey(), next->GetKeysize(), 0, keyEndian) != tree->Bit(x->GetKey(), x->GetKeysize(), 0, keyEndian)))
{
if (x->right == x)
{
next = x;
curr_hop = NULL;
}
else
{
x = x->right;
while (x->left->parent == x) x = x->left;
next = x->left;
if (x->right->parent == x)
{
x = x->right;
while (x->left->parent == x) x = x->left;
}
curr_hop = x;
}
}
else if (x->right->parent == x)
{
x = x->right;
while (x->left->parent == x) x = x->left;
curr_hop = x;
}
}
else {
next = x->right;
if ((NULL == next->parent) &&
(next->right != next) &&
(tree->Bit(x->GetKey(), x->GetKeysize(), 0, keyEndian) != tree->Bit(next->GetKey(), next->GetKeysize(), 0, keyEndian)))
{
x = next->right;
while (x->left->parent == x) x = x->left;
next = x->left;
if (x->right->parent == x)
{
x = x->right;
while (x->left->parent == x) x = x->left;
}
curr_hop = x;
}
else
{
Item* p = x->parent;
while ((p != NULL) && (p->right == x))
{
x = p;
p = x->parent;
}
if (NULL != p)
{
if ((NULL == p->parent) && (p->right == p))
{
p = NULL;
}
else if (p->right->parent == p)
{
Item* x = p->right;
while (x->left->parent == x) x = x->left;
p = x;
}
}
curr_hop = p;
}
}
} if (0 != prefix_size)
{
if ((NULL == prefix_item) ||
!tree->PrefixIsEqual(item->GetKey(), item->GetKeysize(), prefix_item->GetKey(), prefix_size, keyEndian))
return NULL;
}
prev = item;
return item;
}
else
{
return NULL;
} }
ProtoTree::Item* ProtoTree::Iterator::PeekNextItem()
{
if (reversed)
{
Item* nextItem = GetNextItem();
GetPrevItem(); return nextItem;
}
else
{
return next;
}
}
void ProtoTree::Iterator::Update(ProtoIterable::Item* theItem, Action theAction)
{
switch (theAction)
{
case INSERT:
{
Item* oldPrev = prev;
Item* oldNext = next;
Item* oldPrefixItem = prefix_item;
if (NULL != prefix_item)
{
Reset(reversed, prefix_item->GetKey(), prefix_size);
ASSERT(NULL != prefix_item); }
if (reversed)
{
if (NULL != oldNext)
SetCursor(*oldNext);
else if (NULL == prefix_item)
Reset(true);
}
else
{
if (NULL != oldPrev)
SetCursor(*oldPrev);
else if (NULL == oldPrefixItem)
Reset(false);
}
break;
}
case REMOVE:
{
Item* oldPrev = prev;
Item* oldNext = next;
if (static_cast<Item*>(theItem) == prefix_item)
{
Reset(reversed, prefix_item->GetKey(), prefix_size);
if (NULL == prefix_item)
break; }
if (reversed)
{
if (static_cast<Item*>(theItem) != oldNext)
{
if (NULL == oldNext)
{
if (NULL == prefix_item)
prev = next = NULL;
else
Reset(reversed, prefix_item->GetKey(), prefix_size);
}
else
{
SetCursor(*oldNext);
}
}
else
{
if (NULL == oldPrev)
{
if (NULL == prefix_item)
prev = next = NULL;
else
Reset(reversed, prefix_item->GetKey(), prefix_size);
}
else
{
if (NULL == prefix_item)
{
SetCursor(*oldPrev);
prev = oldPrev;
}
else
{
Reset(reversed, prefix_item->GetKey(), prefix_size);
}
}
}
}
else
{
if (static_cast<Item*>(theItem) != oldPrev)
{
if (NULL == oldPrev)
{
if (NULL == prefix_item)
prev = next = NULL;
else
Reset(reversed, prefix_item->GetKey(), prefix_size);
}
else
{
SetCursor(*oldPrev);
}
}
else
{
if (NULL == oldNext)
{
if (NULL == prefix_item)
prev = next = NULL;
else
Reset(reversed, prefix_item->GetKey(), prefix_size);
}
else
{
if (NULL == prefix_item)
{
SetCursor(*oldNext);
next = oldNext;
}
else
{
Reset(reversed, prefix_item->GetKey(), prefix_size);
}
}
}
}
break;
}
case EMPTY:
prev = next = prefix_item = NULL;
prefix_size = 0;
break;
case APPEND:
case PREPEND:
ASSERT(0);
break;
}
}
ProtoTree::SimpleIterator::SimpleIterator(ProtoTree& theTree)
: ProtoIterable::Iterator(theTree)
{
Reset();
}
ProtoTree::SimpleIterator::~SimpleIterator()
{
}
void ProtoTree::SimpleIterator::Reset()
{
ProtoTree* tree = static_cast<ProtoTree*>(iterable);
if (NULL != tree)
{
Item* x = tree->root;
if (NULL != x)
{
while (x->left->parent == x)
x = x->left;
}
next = x;
}
else
{
next = NULL;
}
}
ProtoTree::Item* ProtoTree::SimpleIterator::GetNextItem()
{
Item* i = next;
if (NULL != i)
{
if (i->right->parent == i)
{
Item* y = i->right;
while (y->left->parent == y) y = y->left;
if (y != i)
{
next = y;
return i;
}
}
Item* x = i;
Item* y = i->parent;
while ((NULL != y) && (y->right == x))
{
x = y;
y = y->parent;
}
next = y;
}
return i;
}
void ProtoTree::SimpleIterator::Update(ProtoIterable::Item* , Action )
{
Reset();
}
ProtoSortedTree::ProtoSortedTree(bool uniqueItemsOnly)
: unique_items_only(uniqueItemsOnly), positive_min(NULL)
{
}
ProtoSortedTree::~ProtoSortedTree()
{
}
bool ProtoSortedTree::Insert(Item& item)
{
ASSERT(0 != item.GetKeysize());
const char* key = item.GetKey();
unsigned int keysize = item.GetKeysize();
ProtoTree::Endian keyEndian = item.GetEndian();
Item* match = Find(key, keysize);
if (NULL == match)
{
item_tree.Insert(item);
ProtoTree::Iterator iterator(item_tree, true, &item);
match = static_cast<Item*>(iterator.PeekPrevItem());
if (NULL == match)
{
if (item_list.IsEmpty())
{
item_list.Append(item);
if (item.UseSignBit())
{
bool itemSign = item_tree.Bit(key, keysize, 0, keyEndian);
if (!itemSign) positive_min = &item;
}
}
else
{
bool useSignBit = item.UseSignBit();
ASSERT(useSignBit == GetHead()->UseSignBit());
if (useSignBit)
{
bool itemSign = item_tree.Bit(key, keysize, 0, keyEndian);
if (itemSign)
{
bool useComplement2 = item.UseComplement2();
ASSERT(useComplement2 == GetHead()->UseComplement2());
if (useComplement2)
{
item_list.Prepend(item);
}
else
{
item_list.Append(item);
}
}
else
{
Item* head = GetHead();
bool headSign = item_tree.Bit(head->GetKey(), head->GetKeysize(), 0, keyEndian);
if (headSign)
{
if (NULL != positive_min)
{
item_list.Insert(item, *positive_min);
}
else
{
item_list.Append(item);
}
positive_min = &item;
}
else
{
item_list.Prepend(item);
positive_min = &item;
}
}
}
else
{
item_list.Prepend(item);
} } }
else
{
bool useSignBit = item.UseSignBit();
ASSERT(useSignBit == match->UseSignBit());
if (useSignBit)
{
bool itemSign = item_tree.Bit(key, keysize, 0, keyEndian);
if (!itemSign)
{
Item* next = static_cast<Item*>(item_list.GetNextItem(*match));
if (NULL != next)
item_list.Insert(item, *next);
else
item_list.Append(item);
ASSERT(!item_tree.Bit(match->GetKey(), match->GetKeysize(), 0, keyEndian));
}
else
{
bool useComplement2 = item.UseComplement2();
ASSERT(useComplement2 == match->UseComplement2());
bool matchSign = item_tree.Bit(match->GetKey(), match->GetKeysize(), 0, keyEndian);
if (matchSign)
{
if (useComplement2)
{
Item* next = static_cast<Item*>(item_list.GetNextItem(*match));
if (NULL != next)
item_list.Insert(item, *next);
else
item_list.Append(item);
}
else
{
ProtoTree::Iterator iterator(item_tree, false, &item);
Item* prev = static_cast<Item*>(iterator.PeekNextItem());
if (NULL != prev)
{
Item* next = static_cast<Item*>(item_list.GetNextItem(*prev));
ASSERT(NULL != next);
item_list.Insert(item, *next);
}
else
{
item_list.Prepend(item);
}
}
}
else
{
if (useComplement2)
{
item_list.Prepend(item);
}
else
{
ASSERT(NULL != positive_min);
item_list.Insert(item, *positive_min);
}
}
}
}
else
{
Item* next = static_cast<Item*>(item_list.GetNextItem(*match));
if (NULL != next)
item_list.Insert(item, *next); else
item_list.Append(item);
} }
}
else if (match != &item)
{
if (unique_items_only) return false;
item_list.Insert(item, *match);
item.left = NULL; bool useSignBit = item.UseSignBit();
ASSERT(useSignBit == match->UseSignBit());
if (useSignBit && (match == positive_min))
positive_min = &item;
}
else
{
PLOG(PL_ERROR, "ProtoSortedTree::Insert() warning: item already in tree!\n");
}
return true;
}
void ProtoSortedTree::Prepend(Item& item)
{
item_list.Prepend(item);
}
void ProtoSortedTree::Append(Item& item)
{
item_list.Append(item);
}
void ProtoSortedTree::Remove(Item& item)
{
Item* prev = static_cast<Item*>(item_list.GetPrevItem(item));
if (&item == positive_min)
positive_min = static_cast<Item*>(item_list.GetNextItem(item));
item_list.Remove(item);
if (item.IsInTree())
{
item_tree.Remove(item);
item.left = NULL;
if ((NULL != prev) && !prev->IsInTree())
item_tree.Insert(*prev);
}
}
void ProtoSortedTree::Empty()
{
if (!IsEmpty())
{
item_tree.Empty();
item_list.Empty();
positive_min = NULL;
}
}
void ProtoSortedTree::EmptyToPool(ItemPool& itemPool)
{
if (!IsEmpty())
{
item_tree.Empty();
item_list.EmptyToPool(itemPool);
positive_min = NULL;
}
}
void ProtoSortedTree::Destroy()
{
if (!IsEmpty())
{
item_tree.Empty();
item_list.Destroy();
positive_min = NULL;
}
}
ProtoSortedTree::Item::Item()
{
}
ProtoSortedTree::Item::~Item()
{
}
ProtoSortedTree::Iterator::Iterator(ProtoSortedTree& theTree,
bool reverse,
const char* keyMin,
unsigned int keysize)
: tree(theTree), list_iterator(theTree.item_list, reverse)
{
Reset(reverse, keyMin, keysize);
}
ProtoSortedTree::Iterator::~Iterator()
{
}
void ProtoSortedTree::Iterator::Reset(bool reverse, const char* keyMin, unsigned int keysize)
{
list_iterator.Reset(reverse); if ((NULL != keyMin) && list_iterator.IsValid() && !tree.IsEmpty())
{
Item* match = tree.Find(keyMin, keysize);
if (NULL == match)
{
TempItem tmpItem(keyMin, keysize, tree.GetHead()->GetEndian());
tree.item_tree.Insert(tmpItem);
ProtoTree::Iterator iterator(tree.item_tree, reverse, &tmpItem);
match = reverse ? static_cast<Item*>(iterator.PeekPrevItem()) :
static_cast<Item*>(iterator.PeekNextItem());
tree.item_tree.Remove(tmpItem); }
if ((NULL != match) && !reverse)
{
ProtoTree::Iterator iterator(tree.item_tree, true, match);
Item* prev = static_cast<Item*>(iterator.PeekPrevItem());
if (NULL == prev)
match = tree.item_list.GetHead();
else
match = static_cast<Item*>(tree.item_list.GetNextItem(*prev));
}
list_iterator.SetCursor(match);
}
}
ProtoSortedTree::Iterator::TempItem::TempItem(const char* theKey, unsigned int theKeysize, ProtoTree::Endian keyEndian)
: key(theKey), keysize(theKeysize), key_endian(keyEndian)
{
}
ProtoSortedTree::Iterator::TempItem::~TempItem()
{
}