You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
4.9 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsStringTable.h"
#include "stdlib.h"
#if HS_BUILD_FOR_PS2 || __MWERKS__ || HS_BUILD_FOR_UNIX
#include <ctype.h>
#endif
//
// hsStringTable
//
hsStringTable::Node::Node(char c) : sib(0), kid(0), chr(c), data(0) {};
hsStringTable::Node::~Node() { };
void* hsStringTable::Node::GetData() { return data; }
void hsStringTable::Node::SetData(void* v) { data = v; }
hsStringTable::~hsStringTable()
{
RemoveNode(root.kid);
}
void hsStringTable::Reset()
{
RemoveNode(root.kid);
root.kid = nil;
}
//
// Find a the Node associated with a given string
//
hsStringTable::Node* hsStringTable::Find(const char* str)
{
return (str && *str) ? FindRecur(root.kid, str) : nil;
}
//
// Find the unique node matching the given prefix. Returns the node
// at the first point where a unique path can not be determined
// char* str is filled out with the matching path
//
hsStringTable::Node* hsStringTable::FindPartial(char* str, Int32 len) const
{
return (str && *str) ? FindPartialRecur(root.kid, str, len) : nil;
}
//
// Find and Add if needs a node for str and register it with data
//
void hsStringTable::Register(const char* str, void* data)
{
Node* node = FindRecur(root.kid, str, true);
if (!node)
{
node = AddRecur(&root, str);
}
node->SetData(data);
}
//
// Iterate through the tree and call the callback function on each child node
// of the fromNode (or the root if fromNode is nil)
//
hsBool hsStringTable::Iterate(hsStringTableCallback* callback, Node* fromNode)
{
if (!fromNode)
fromNode = &root;
return IterateRecur(fromNode->kid,callback);
}
//
// Recursively find node, create if needed?
//
hsStringTable::Node* hsStringTable::FindRecur(Node* root, const char* str, hsBool createIfNeeded)
{
if (!root || !str) return nil;
if (tolower(root->chr)==tolower(*str))
{
if (*(str+1))
{
Node* node = FindRecur(root->kid, str+1, createIfNeeded);
if (!node && createIfNeeded) node = AddRecur(root, str+1);
return node;
}
else
{
return root;
}
}
else
{
return FindRecur(root->sib,str,createIfNeeded);
}
}
//
// Recursively find the unique partial match
//
hsStringTable::Node* hsStringTable::FindPartialRecur(Node* root, char* str, Int32 len) const
{
if (!root || !str)
{
return nil;
}
if (tolower(root->chr)==tolower(*str))
{
if (len)
{
*str = root->chr;
}
if (*(str+1))
{
Node* node = FindPartialRecur(root->kid,str+1,len-1);
//if (!node) node = AddRecur(root,str+1);
return node;
}
else
{
return FindLeafRecur(root, str, len);
}
}
else
{
return FindPartialRecur(root->sib, str, len);
}
}
//
// Follow the current node as far as possible towards a unique leaf
//
hsStringTable::Node* hsStringTable::FindLeafRecur(Node* root, char* str, Int32 len) const
{
if (root->data || !root->kid || root->kid->sib)
{
if (len)
{
*(str+1) = 0;
}
return root;
}
else
{
if (len)
{
*(str+1) = len>1 ? root->kid->chr : 0;
}
return FindLeafRecur(root->kid,str+1,len-1);
}
}
//
// Add a string to the tree
//
hsStringTable::Node* hsStringTable::AddRecur(Node* root, const char* str)
{
Node* node = TRACKED_NEW Node(*str);
node->sib = root->kid;
root->kid = node;
if (*(str+1)) return AddRecur(node,str+1);
else return node;
}
//
// Remove a node recursive from the tree
//
void hsStringTable::RemoveNode(Node* root)
{
if (!root) return;
RemoveNode(root->kid);
RemoveNode(root->sib);
delete root;
}
//
// Recurse through tree and call callback on each node
//
hsBool hsStringTable::IterateRecur(Node* root, hsStringTableCallback* callback)
{
if (!root)
return true;
if (root->data)
{
if (!callback(root))
return false;
}
if (root->kid)
{
if (!IterateRecur(root->kid,callback))
return false;
}
if (root->sib)
{
if (!IterateRecur(root->sib,callback))
return false;
}
return true;
}