Files
GTASource/rage/scaleform/Src/GKernel/GRadixTree.h
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

415 lines
12 KiB
C++

/**********************************************************************
Filename : GRadixTree.h
Content : Template implementation for a simple radix tree.
Created : 2009
Authors : MaximShemanarev
Copyright : (c) 2001-2009 Scaleform Corp. All Rights Reserved.
Licensees may use this file in accordance with the valid Scaleform
Commercial License Agreement provided with the software.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
**********************************************************************/
#ifndef INC_GRadixTree_H
#define INC_GRadixTree_H
#include "GTypes.h"
// Intrusive radix tree adopted from Doug Lea malloc (public domain license).
// The tree works only with an integer key of UPInt type. The tree
// typically grows quickly to the number of bits in UPInt (32 or 64),
// but the tree height will never exceed this number. That is, it
// guarantees operation time of at most 32 or 64 operations respectively.
// In some sense it can be said that the access time is O(1), although
// the constant coefficient is rather hight.
//
// The tree requires the following accessor (as an example):
//
// struct TreeNodeAccessor
// {
// static UPInt GetKey (const TreeNode* n) { return n->Key; }
// static TreeNode* GetChild ( TreeNode* n, UPInt i) { return n->Child[i]; }
// static const TreeNode* GetChild (const TreeNode* n, UPInt i) { return n->Child[i]; }
// static TreeNode** GetChildPtr( TreeNode* n, UPInt i) { return &n->Child[i]; }
//
// static TreeNode* GetParent ( TreeNode* n) { return n->Parent; }
// static const TreeNode* GetParent (const TreeNode* n) { return n->Parent; }
//
// static void SetParent (TreeNode* n, TreeNode* p) { n->Parent = p; }
// static void SetChild (TreeNode* n, UPInt i, TreeNode* c) { n->Child[i] = c; }
// static void ClearLinks(TreeNode* n) { n->Parent = n->Child[0] = n->Child[1] = 0; }
//};
//
// Operations on the tree:
//
// T* Insert(T* node); // Returns NULL on success, or head node
// void Remove(T* node);
// const T* FindEqual(UPInt key) const;
// const T* FindGrEq (UPInt key) const;
// const T* FindLeEq (UPInt key) const;
//
//------------------------------------------------------------------------
template<class T, class Accessor> class GRadixTree
{
enum { KeyBits = 8*sizeof(UPInt) };
public:
GRadixTree() : Root(0) {}
void Clear() { Root = 0; }
// Insert node. Returns NULL on success, or the pointer to the
// node if the node with the same key already exists in the tree.
//--------------------------------------------------------------------
T* Insert(T* node)
{
T** root = &Root;
Accessor::ClearLinks(node);
if (Root == 0)
{
*root = node;
Accessor::SetParent(node, (T*)root);
}
else
{
UPInt key = Accessor::GetKey(node);
UPInt bits = key;
T* head = *root;
for (;;)
{
if (Accessor::GetKey(head) == key)
{
return head;
}
T** link = Accessor::GetChildPtr(head, (bits >> (KeyBits-1)) & 1);
bits <<= 1;
if (*link != 0)
{
head = *link;
}
else
{
*link = node;
Accessor::SetParent(node, head);
break;
}
}
}
return 0;
}
//--------------------------------------------------------------------
void Remove(T* node, T* rotor)
{
T* parent = Accessor::GetParent(node);
if (parent != 0)
{
T** root = &Root;
if (node == *root)
{
*root = rotor;
}
else
{
UPInt ic = Accessor::GetChild(parent, 0) != node;
Accessor::SetChild(parent, ic, rotor);
}
if (rotor != 0)
{
T* child;
Accessor::SetParent(rotor, parent);
if ((child = Accessor::GetChild(node, 0)) != 0)
{
Accessor::SetChild(rotor, 0, child);
Accessor::SetParent(child, rotor);
}
if ((child = Accessor::GetChild(node, 1)) != 0)
{
Accessor::SetChild(rotor, 1, child);
Accessor::SetParent(child, rotor);
}
}
}
Accessor::ClearLinks(node);
}
//--------------------------------------------------------------------
void Remove(T* node)
{
T* rotor;
T** rp;
if (((rotor = *(rp = Accessor::GetChildPtr(node, 1))) != 0) ||
((rotor = *(rp = Accessor::GetChildPtr(node, 0))) != 0))
{
T** cp;
while ((*(cp = Accessor::GetChildPtr(rotor, 1)) != 0) ||
(*(cp = Accessor::GetChildPtr(rotor, 0)) != 0))
{
rotor = *(rp = cp);
}
*rp = 0;
}
Remove(node, rotor);
}
//--------------------------------------------------------------------
const T* FindEqual(UPInt key) const
{
const T* node = Root;
UPInt bits = key;
while (node && Accessor::GetKey(node) != key)
{
node = Accessor::GetChild(node, (bits >> (KeyBits-1)) & 1);
bits <<= 1;
}
return node;
}
//--------------------------------------------------------------------
static const T* GetLeftmost(const T* node)
{
return Accessor::GetChild(node, Accessor::GetChild(node, 0) == 0);
}
//--------------------------------------------------------------------
static const T* GetRightmost(const T* node)
{
return Accessor::GetChild(node, Accessor::GetChild(node, 1) != 0);
}
//--------------------------------------------------------------------
const T* FindGrEq(UPInt key) const
{
const T* best = 0;
UPInt rkey = ~UPInt(0);
UPInt nkey;
UPInt diff;
const T* node = Root;
if (node != 0)
{
// Traverse tree looking for node with node->Key == key
//--------------------------
const T* rst = 0; // The deepest untaken right subtree
UPInt bits = key;
for (;;)
{
const T* rt;
nkey = Accessor::GetKey(node);
diff = nkey - key;
if (nkey >= key && diff < rkey)
{
best = node;
if ((rkey = diff) == 0)
{
return best;
}
}
rt = Accessor::GetChild(node, 1);
node = Accessor::GetChild(node, (bits >> (KeyBits-1)) & 1);
if (rt != 0 && rt != node)
{
rst = rt;
}
if (node == 0)
{
node = rst; // set node to least subtree holding Keys > key
break;
}
bits <<= 1;
}
}
while (node)
{
// Find smallest of subtree.
//------------------------
nkey = Accessor::GetKey(node);
diff = nkey - key;
if (nkey >= key && diff < rkey)
{
rkey = diff;
best = node;
}
node = GetLeftmost(node);
}
return best;
}
//--------------------------------------------------------------------
const T* FindLeEq(UPInt key) const
{
const T* best = 0;
UPInt rkey = ~UPInt(0);
UPInt nkey;
UPInt diff;
const T* node = Root;
if (node != 0)
{
// Traverse tree looking for node with node->Key == key
//--------------------------
const T* lst = 0; // The deepest untaken left subtree
UPInt bits = key;
for (;;)
{
const T* lt;
nkey = Accessor::GetKey(node);
diff = key - nkey;
if (nkey <= key && diff < rkey)
{
best = node;
if ((rkey = diff) == 0)
{
return best;
}
}
lt = Accessor::GetChild(node, 0);
node = Accessor::GetChild(node, (bits >> (KeyBits-1)) & 1);
if (lt != 0 && lt != node)
{
lst = lt;
}
if (node == 0)
{
node = lst; // set node to most subtree holding Keys < key
break;
}
bits <<= 1;
}
}
while (node)
{
// Find biggest of subtree.
//------------------------
nkey = Accessor::GetKey(node);
diff = key - nkey;
if (nkey <= key && diff < rkey)
{
rkey = diff;
best = node;
}
node = GetRightmost(node);
}
return best;
}
T* Root;
};
//------------------------------------------------------------------------
template<class T, class Accessor> class GRadixTreeMulti
{
public:
//--------------------------------------------------------------------
void Insert(T* node)
{
node->pPrev = node;
node->pNext = node;
T* head = Tree.Insert(node);
if (head)
{
// Insert node next to the head one:
// Before: head <----------------> next1 <----> next2...
// After: head <----> node <----> next1 <----> next2...
//------------------------
node->pNext = head->pNext;
node->pPrev = head;
head->pNext = node;
node->pNext->pPrev = node;
}
}
//--------------------------------------------------------------------
void Remove(T* node)
{
if (node->pPrev != node)
{
// The list isn't empty.
//------------------------
T* rotor;
T* f = node->pNext;
rotor = node->pPrev;
f->pPrev = rotor;
rotor->pNext = f;
Tree.Remove(node, rotor);
}
else
{
Tree.Remove(node);
}
}
//--------------------------------------------------------------------
const T* FindBestGrEq(UPInt key)
{
return Tree.FindGrEq(key);
}
//--------------------------------------------------------------------
const T* FindBestLeEq(UPInt key)
{
return Tree.FindLeEq(key);
}
//--------------------------------------------------------------------
T* PullBestGrEq(UPInt key)
{
T* node = (T*)Tree.FindGrEq(key);
if (node)
{
// Take the next node to reduce tree thrashing in Remove().
//------------------------
node = (T*)node->pNext;
Remove(node);
}
return node;
}
//--------------------------------------------------------------------
T* PullBestLeEq(UPInt key)
{
T* node = (T*)Tree.FindLeEq(key);
if (node)
{
// Take the next node to reduce tree thrashing in Remove().
//------------------------
node = (T*)node->pNext;
Remove(node);
}
return node;
}
GRadixTree<T, Accessor> Tree;
};
#endif