Initial commit
This commit is contained in:
821
Include/ZUtil/ZKVTree.hpp
Normal file
821
Include/ZUtil/ZKVTree.hpp
Normal file
@@ -0,0 +1,821 @@
|
||||
/*
|
||||
ZKVTree.hpp
|
||||
Author: James Russell <jcrussell@762studios.com>
|
||||
Created: 3/22/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
ZKVTree defines a KV-Tree that uses strings as both keys and values. The model
|
||||
supported is hierarchical with no nesting limit, and individual nodes can be addressed
|
||||
directly or the tree can be iterated. This makes ZKVTree's typical use case as an
|
||||
in memory representation of hierarchical text formats such as XML and JSON, and can
|
||||
be used for simpler formats such as INI. When the layout and keys are known
|
||||
(such as with most INI files), lookup via path string is the easiest route. When the layout
|
||||
is not known (such as with an XML file with variable numbers of children and attributes),
|
||||
then iteration is the preferred method of getting access to the data.
|
||||
|
||||
Multiple nodes of the same name existing at the same level in the tree is supported.
|
||||
When a path is given that does not contain the number, then it is assumed to be
|
||||
referencing the first sibling node at that location (index 0).
|
||||
|
||||
Unnamed tree nodes are supported, with the key used to access those being omitted from the
|
||||
path string but the subscript being required.
|
||||
|
||||
If the tree has the following layout, with the values at each node contained
|
||||
in parenthesis:
|
||||
|
||||
Root
|
||||
|
|
||||
+-> A (0)
|
||||
| |
|
||||
| +-> B (8)
|
||||
| | |
|
||||
| | +-> c (16)
|
||||
| | +-> c (32)
|
||||
| | +-> (100)
|
||||
| | +-> (200)
|
||||
| |
|
||||
| +-> B (8)
|
||||
| | |
|
||||
| | +-> c (64)
|
||||
| | +-> d (128)
|
||||
| | +-> (10)
|
||||
| | +-> (20)
|
||||
| |
|
||||
| +-> b (5)
|
||||
| +-> b (10)
|
||||
| +-> c (15)
|
||||
| +-> d (20)
|
||||
|
|
||||
+-> B (8)
|
||||
| |
|
||||
| +-> c (50)
|
||||
| +-> d (100)
|
||||
|
|
||||
+-> a (1)
|
||||
+-> a (2)
|
||||
+-> a (3)
|
||||
+-> b (4)
|
||||
|
||||
Then valid path strings include (but are not limited to):
|
||||
|
||||
A.B - would get the value of node 'B[0]' (8) with parent node 'A[0]'
|
||||
A.B.c - would get the value of node 'c[0]' (16) with parent node 'A[0].B[0]'
|
||||
A.B.c[1] - would get the value of node 'c[1]' (32) with parent node 'A[0].B[0]'
|
||||
A.B[1].c - would get the value of node 'c[0]' (64) with parent node 'A[0].B[1]'
|
||||
A.B[1].c[1] - would get the value of node 'c[1]' (128) with parent node 'A[0].B[1]'
|
||||
A.b[1] - would get the value of node 'b[1]' (10) with parent node 'A[0]'
|
||||
B.c - would get the value of node 'c[0]' (50) with parent node 'B[0]'
|
||||
a - would get the value of node 'a[0]' (1) with root parent node ''
|
||||
a[2] - would get the value of node 'a[2]' (3) with root parent node ''
|
||||
|
||||
If this KVTree were to be iterated using ZKVTree::Iterator::Next(), a depth first
|
||||
traversal of the structure would take place, giving us the following order:
|
||||
|
||||
A
|
||||
A.B[0]
|
||||
A.B[0].c[0]
|
||||
A.B[0].c[1]
|
||||
A.B[0].[0]
|
||||
A.B[0].[1]
|
||||
A.B[1].c
|
||||
A.B[1].d
|
||||
A.B[1].[0]
|
||||
A.B[1].[1]
|
||||
A.b[0]
|
||||
A.b[1]
|
||||
A.c
|
||||
A.d
|
||||
B
|
||||
B.c
|
||||
B.d
|
||||
a[0]
|
||||
a[1]
|
||||
a[2]
|
||||
|
||||
A special syntax for accessing unnamed children is supported, which enables nested array behavior
|
||||
for values:
|
||||
|
||||
A.B[0][0] - would get the value of (unnamed) node '[0]' (100) with parent node 'A.B[0]'
|
||||
A.B[1][0] - would get the value of (unnamed) node '[0]' (10) with parent node 'A.B[0]'
|
||||
A.B[1][1] - would get the value of (unnamed) node '[1]' (20) with parent node 'A.B[1]'
|
||||
|
||||
Note that these are syntactic sugar for:
|
||||
|
||||
A.B[0].[0] (could also be expressed as A.B[0]. or A.B. due to the implicit [0])
|
||||
A.B[1].[0] (could also be expressed as A.B[1]. due to the implicit [0])
|
||||
A.B[1].[1]
|
||||
|
||||
License:
|
||||
|
||||
TODO
|
||||
*/
|
||||
|
||||
#ifndef _ZREGISTRY_H
|
||||
#define _ZREGISTRY_H
|
||||
|
||||
#include <SST/SST_Hash.h>
|
||||
|
||||
#include <ZSTL/ZHashMap.hpp>
|
||||
#include <ZSTL/ZString.hpp>
|
||||
#include <ZSTL/ZBasicStringAlgo.hpp>
|
||||
|
||||
#include <ZUtil/ZConcurrency.hpp>
|
||||
#include <ZUtil/ZSlabAllocator.hpp>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
//Valid path separator for ZKVTree
|
||||
#ifndef ZKVTREE_PATH_SEPARATOR
|
||||
#define ZKVTREE_PATH_SEPARATOR '.'
|
||||
#endif
|
||||
|
||||
//Default number of nodes preallocated
|
||||
#ifndef ZKVTREE_NODE_COUNT
|
||||
#define ZKVTREE_NODE_COUNT (128)
|
||||
#endif
|
||||
|
||||
//Invalid characters for a path ([] valid on subscript only)
|
||||
#define ZKVTREE_INVALID_PATH_CHARS "%[]"
|
||||
|
||||
/*
|
||||
ZKVTree class.
|
||||
*/
|
||||
class ZKVTree
|
||||
{
|
||||
public:
|
||||
//KVTree node structure
|
||||
struct Node
|
||||
{
|
||||
ZString Name; //Name of the node
|
||||
ZString Value; //Value held by this node
|
||||
Node* ParentNode; //Pointer to our parent node
|
||||
size_t Index; //Index of this node in the parent's children array
|
||||
ZArray< Node* > Children; //Children of this node
|
||||
|
||||
//Determines if this is the root node
|
||||
bool IsRootNode() const {
|
||||
if (ParentNode == NULL) {
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
//Finds the node with the given name in the child array
|
||||
Node* GetChildByName(const ZString& _name, size_t _start, size_t _end, size_t _subscript) const {
|
||||
for (size_t i = 0; i < Children.Size(); i++) {
|
||||
Node* child = Children.Data()[i];
|
||||
if (child->Name.Length() == (_end - _start)) {
|
||||
if (ZStringAlgo::Equal(child->Name, 0, child->Name.Length(), _name, _start, _end)) {
|
||||
if (_subscript-- == 0) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Finds the number of children with the given name
|
||||
size_t GetChildCountByName(const ZString& _name, size_t _start, size_t _end) const {
|
||||
size_t num = 0;
|
||||
for (size_t i = 0; i < Children.Size(); i++) {
|
||||
Node* child = Children.Data()[i];
|
||||
if (child->Name.Length() == (_end - _start)) {
|
||||
if (ZStringAlgo::Equal(child->Name, 0, child->Name.Length(), _name, _start, _end)) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
//Finds the index of the last occurrence of a node with the given name
|
||||
size_t GetLastIndexByName(const ZString& _name, size_t _start, size_t _end) const {
|
||||
size_t idx = 0;
|
||||
for (size_t i = 0; i < Children.Size(); i++) {
|
||||
Node* child = Children.Data()[i];
|
||||
if (child->Name.Length() == (_end - _start)) {
|
||||
if (ZStringAlgo::Equal(child->Name, 0, child->Name.Length(), _name, _start, _end)) {
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
//Gets the path to this node
|
||||
void GetPath(ZString& _out, Node* _end = NULL) const {
|
||||
if (this != _end && ParentNode != NULL) {
|
||||
ParentNode->GetPath(_out, _end);
|
||||
} else return;
|
||||
|
||||
if (!_out.Empty()) {
|
||||
_out.PushBack(ZKVTREE_PATH_SEPARATOR);
|
||||
}
|
||||
|
||||
if (!IsRootNode()) {
|
||||
size_t siblings = ParentNode->GetChildCountByName(Name, 0, Name.Length());
|
||||
size_t last_idx = ParentNode->GetLastIndexByName(Name, 0, Name.Length());
|
||||
|
||||
_out += Name;
|
||||
|
||||
if (ParentNode != _end) {
|
||||
ZString subscript;
|
||||
ZStringAlgo::BuildPrintf(subscript, "[%i]", siblings - (1 + last_idx - Index));
|
||||
|
||||
_out += subscript;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gets the simple path to this node (avoids [0] subscript)
|
||||
void GetSimplePath(ZString& _out, Node* _end = NULL) const {
|
||||
if (this != _end && ParentNode != NULL) {
|
||||
ParentNode->GetSimplePath(_out, _end);
|
||||
} else return;
|
||||
|
||||
if (!_out.Empty()) {
|
||||
_out.PushBack(ZKVTREE_PATH_SEPARATOR);
|
||||
}
|
||||
|
||||
if (!IsRootNode()) {
|
||||
size_t siblings = ParentNode->GetChildCountByName(Name, 0, Name.Length());
|
||||
size_t last_idx = ParentNode->GetLastIndexByName(Name, 0, Name.Length());
|
||||
|
||||
_out += Name;
|
||||
|
||||
if (ParentNode != _end && siblings - (1 + last_idx - Index) != 0) {
|
||||
ZString subscript;
|
||||
ZStringAlgo::BuildPrintf(subscript, "[%i]", siblings - (1 + last_idx - Index));
|
||||
|
||||
_out += subscript;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
KVTree iterator, used to directly iterate the nodes in the KVTree.
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
friend class ZKVTree;
|
||||
public:
|
||||
/*
|
||||
Parameterized Constructor.
|
||||
|
||||
@param _node - the node to start the iterator at
|
||||
@param _tree - the KVTree we are iterating (reference needed for locking / unlocking)
|
||||
*/
|
||||
Iterator(Node* _node, ZKVTree* _tree)
|
||||
: CurrentNode(_node), KVTree(_tree) { }
|
||||
|
||||
/*
|
||||
Copy Constructor.
|
||||
|
||||
@param _other - the other iterator
|
||||
*/
|
||||
Iterator(const Iterator& _other)
|
||||
:CurrentNode(_other.CurrentNode), KVTree(_other.KVTree) { }
|
||||
|
||||
/*
|
||||
Destructor. Releases the lock (when 'Lock' is destructed).
|
||||
*/
|
||||
~Iterator() { }
|
||||
|
||||
/*
|
||||
Gets the path to the current iterator location.
|
||||
|
||||
@return (ZString) - path to this node
|
||||
*/
|
||||
ZString GetPath() const
|
||||
{ ZString path; CurrentNode->GetPath(path); return path; }
|
||||
|
||||
/*
|
||||
Gets the path to the current iterator from an end node. If the end node
|
||||
is not on the parent path, functionally equivalent to GetPath.
|
||||
|
||||
@param _end - node we should get path from
|
||||
@return (ZString) - path to this node from provided node
|
||||
*/
|
||||
ZString GetPath(Iterator end) const
|
||||
{ ZString path; CurrentNode->GetPath(path, end.CurrentNode); return path; }
|
||||
|
||||
/*
|
||||
As GetPath, but avoids the [0] subscript.
|
||||
|
||||
@return (ZString) - path to this node
|
||||
*/
|
||||
ZString GetSimplePath() const
|
||||
{ ZString path; CurrentNode->GetSimplePath(path); return path; }
|
||||
|
||||
/*
|
||||
As GetPath, but avoids the [0] subscript.
|
||||
|
||||
@param _end - node we should get path from
|
||||
@return (ZString) - path to this node from provided node
|
||||
*/
|
||||
ZString GetSimplePath(Iterator end) const
|
||||
{ ZString path; CurrentNode->GetSimplePath(path, end.CurrentNode); return path; }
|
||||
|
||||
/*
|
||||
Gets a reference to the name of the current node.
|
||||
|
||||
@return (const ZString&) - reference to the name of the current node
|
||||
*/
|
||||
const ZString& GetName() const
|
||||
{ ZASSERT(!CurrentNode->IsRootNode(), "Cannot get name on root node!"); return CurrentNode->Name; }
|
||||
|
||||
/*
|
||||
Gets a reference to the value of the current node.
|
||||
|
||||
@return (ZString&) - reference to the value of the current node
|
||||
*/
|
||||
const ZString& GetValue() const
|
||||
{ ZASSERT(!CurrentNode->IsRootNode(), "Cannot get value on root node!"); return CurrentNode->Value; }
|
||||
|
||||
/*
|
||||
Gets the index of the current node (sibling index).
|
||||
|
||||
@return (size_t) - the index of the current node.
|
||||
*/
|
||||
size_t GetIndex() const
|
||||
{ return CurrentNode->Index; }
|
||||
|
||||
/*
|
||||
Gets the number of children contained by this node.
|
||||
*/
|
||||
size_t GetChildCount() const
|
||||
{ return CurrentNode->Children.Size(); }
|
||||
|
||||
/*
|
||||
Gets the number of children of this node with the given name.
|
||||
*/
|
||||
size_t GetChildCountByName(const ZString& _name) const
|
||||
{ return CurrentNode->GetChildCountByName(_name, 0, _name.Length()); }
|
||||
|
||||
/*
|
||||
Gets the index of the nth child of the given name (ZSTL::InvalidPos if not found).
|
||||
*/
|
||||
size_t GetChildIndexByName(const ZString& _name, size_t _n = 0) const
|
||||
{
|
||||
Node* childNode = CurrentNode->GetChildByName(_name, 0, _name.Length(), _n);
|
||||
|
||||
return (childNode == NULL ? ZSTL::InvalidPos : childNode->Index);
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the number of siblings to the current node, including the current node.
|
||||
*/
|
||||
size_t GetSiblingCount() const
|
||||
{
|
||||
if (CurrentNode->ParentNode == NULL)
|
||||
return 0;
|
||||
|
||||
return CurrentNode->ParentNode->Children.Size();
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the number of siblings to the current node with the given name (can
|
||||
include this node if name is equivalent).
|
||||
*/
|
||||
size_t GetSiblingCountByName(const ZString& _name) const
|
||||
{
|
||||
if (CurrentNode->ParentNode == NULL)
|
||||
return 0;
|
||||
|
||||
return CurrentNode->ParentNode->GetChildCountByName(_name, 0, _name.Length());
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the index of the nth sibling of the given name (ZSTL::InvalidPos if not found, can
|
||||
be the node this iterator points to).
|
||||
*/
|
||||
size_t GetSiblingIndexByName(const ZString& _name, size_t _n = 0) const
|
||||
{
|
||||
if (CurrentNode->ParentNode == NULL)
|
||||
return ZSTL::InvalidPos;
|
||||
|
||||
Node* siblingNode = CurrentNode->ParentNode->GetChildByName(_name, 0, _name.Length(), _n);
|
||||
|
||||
return (siblingNode == NULL ? ZSTL::InvalidPos : siblingNode->Index);
|
||||
}
|
||||
|
||||
//Checks to see if this is an end node
|
||||
bool CheckEnd()
|
||||
{ return CurrentNode->IsRootNode(); }
|
||||
|
||||
//Checks to see if we can move to the parent node
|
||||
bool CheckParent()
|
||||
{ return CurrentNode->ParentNode != NULL; }
|
||||
|
||||
//Checks to see if we can move to the child node
|
||||
bool CheckChild(size_t _index = 0)
|
||||
{ return _index < CurrentNode->Children.Size(); }
|
||||
|
||||
//Checks to see if we can move to the sibling node
|
||||
bool CheckSibling(size_t _index = 0)
|
||||
{ return CurrentNode->ParentNode != NULL && _index < CurrentNode->ParentNode->Children.Size() - 1; }
|
||||
|
||||
//Checks to see if we can move to the next sibling node
|
||||
bool CheckNextSibling()
|
||||
{ return CurrentNode->ParentNode != NULL && CurrentNode->Index < CurrentNode->ParentNode->Children.Size() - 1; }
|
||||
|
||||
//Checks to see if we can move to the previous sibling node
|
||||
bool CheckPrevSibling()
|
||||
{ return CurrentNode->Index > 0; }
|
||||
|
||||
/*
|
||||
Sets the value of the current node.
|
||||
|
||||
@param (ZString&) - value to set this node to
|
||||
*/
|
||||
void SetValue(const ZString& _value)
|
||||
{ CurrentNode->Value = _value; }
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::Next
|
||||
|
||||
This operation attempts to move this iterator to the first child of this node. If this
|
||||
is an invalid move, then it attempts to iterate to the next sibling. If this is invalid,
|
||||
it will attempt to iterate to the next sibling of the parent, and will continue to
|
||||
attempt this until it has either reached the end or it can do so.
|
||||
|
||||
This basically means using nothing but 'Next' from beginning to end will result in
|
||||
a depth-first traversal of the KVTree.
|
||||
|
||||
@return (Iterator&) - this iterator
|
||||
*/
|
||||
Iterator& Next()
|
||||
{
|
||||
if (CheckChild())
|
||||
Child();
|
||||
else if (CheckNextSibling())
|
||||
NextSibling();
|
||||
else {
|
||||
while (CurrentNode->ParentNode != NULL) {
|
||||
if (CheckParent()) {
|
||||
Parent();
|
||||
if (CheckNextSibling()) {
|
||||
NextSibling();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::Parent
|
||||
|
||||
This operation attempts to move the iterator to the parent node of this node.
|
||||
|
||||
@return (Iterator&) - this iterator
|
||||
*/
|
||||
Iterator& Parent()
|
||||
{
|
||||
if (CheckParent()) {
|
||||
CurrentNode = CurrentNode->ParentNode;
|
||||
} else *this = KVTree->End();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::Child
|
||||
|
||||
This operation moves the iterator to child node at the given index.
|
||||
|
||||
@param _index - the child number to move to
|
||||
@return (Iterator&) - this iterator
|
||||
*/
|
||||
Iterator& Child(size_t _index = 0)
|
||||
{
|
||||
if (CheckChild(_index)) {
|
||||
CurrentNode = CurrentNode->Children[_index];
|
||||
} else *this = KVTree->End();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::Sibling
|
||||
|
||||
This operation moves the iterator to the sibling node at the given index.
|
||||
|
||||
@param _index - the sibling index
|
||||
@return (Iterator&) - this iterator
|
||||
*/
|
||||
Iterator& Sibling(size_t _index = 0)
|
||||
{
|
||||
ZASSERT(CheckSibling(_index), "ZKVTree::Iterator unable to move to sibling node!");
|
||||
|
||||
if (CheckSibling(_index)) {
|
||||
CurrentNode = CurrentNode->ParentNode->Children[_index];
|
||||
} else *this = KVTree->End();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::PrevSibling
|
||||
|
||||
This operation moves the iterator to the previous sibling node of this node.
|
||||
|
||||
@return (Iterator&) - this iterator
|
||||
*/
|
||||
Iterator& PrevSibling()
|
||||
{
|
||||
if (CheckPrevSibling()) {
|
||||
CurrentNode = CurrentNode->ParentNode->Children[CurrentNode->Index - 1];
|
||||
} else *this = KVTree->End();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::NextSibling
|
||||
|
||||
This operation moves the iterator to the next sibling node of this node.
|
||||
|
||||
@return (Iterator&) - this iterator
|
||||
*/
|
||||
Iterator& NextSibling()
|
||||
{
|
||||
if (CheckNextSibling()) {
|
||||
CurrentNode = CurrentNode->ParentNode->Children[CurrentNode->Index + 1];
|
||||
} else *this = KVTree->End();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::ParentItr
|
||||
|
||||
This operation returns an iterator to the parent node.
|
||||
|
||||
@return (ZKVTree::Iterator) - iterator to the parent node
|
||||
*/
|
||||
Iterator ParentItr() const
|
||||
{
|
||||
ZASSERT(CurrentNode->ParentNode != NULL, "Unable to get KVTree parent!");
|
||||
|
||||
return Iterator(CurrentNode->ParentNode, KVTree);
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::ChildItr
|
||||
|
||||
This operation returns an iterator to the first child node of this iterator,
|
||||
or the end iterator if no child is found.
|
||||
|
||||
@param _index - the child node index to get an iterator to
|
||||
@return (Iterator) - iterator to the child node
|
||||
*/
|
||||
Iterator ChildItr() const
|
||||
{
|
||||
return ChildItr(0);
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::ChildItr
|
||||
|
||||
This operation returns an iterator to the child node at the given index.
|
||||
|
||||
@param _index - the child node index to get an iterator to
|
||||
@return (Iterator) - iterator to the child node
|
||||
*/
|
||||
Iterator ChildItr(size_t _index) const
|
||||
{
|
||||
if (_index == ZSTL::InvalidPos || _index >= CurrentNode->Children.Size()) {
|
||||
return KVTree->End();
|
||||
} else return Iterator(CurrentNode->Children.Data()[_index], KVTree);
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::ChildItr
|
||||
|
||||
This returns an iterator to the nth child of the given name.
|
||||
|
||||
@param _name - the name of the child to get an iterator to
|
||||
@param _n - the occurrence of the child to get (0 = first occurrence)
|
||||
@return (Iterator) - iterator to the child node
|
||||
*/
|
||||
Iterator ChildItr(const ZString& name, size_t _n = 0) const
|
||||
{
|
||||
return ChildItr(GetChildIndexByName(name, _n));
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::GetSibling
|
||||
|
||||
This operation returns an iterator to the sibling node at the given index.
|
||||
|
||||
@param _index - the child node index to get an iterator to
|
||||
@return (Iterator) - iterator to the child node
|
||||
*/
|
||||
Iterator SiblingItr(size_t _index) const
|
||||
{
|
||||
if (_index == ZSTL::InvalidPos || _index >= CurrentNode->ParentNode->Children.Size()) {
|
||||
return KVTree->End();
|
||||
} else return Iterator(CurrentNode->ParentNode->Children.Data()[_index], KVTree);
|
||||
}
|
||||
|
||||
/*
|
||||
public ZKVTree::Iterator::GetSibling
|
||||
|
||||
This operation returns an iterator to the nth sibling of the given name.
|
||||
|
||||
@param _name - the name of the sibling to get an iterator to
|
||||
@param _n - the occurrence of the sibling to get (0 = first occurrence)
|
||||
@return (Iterator) - iterator to the sibling node
|
||||
*/
|
||||
Iterator SiblingItr(const ZString& name, size_t _n = 0) const
|
||||
{
|
||||
return SiblingItr(GetSiblingIndexByName(name, _n));
|
||||
}
|
||||
|
||||
//Operator Overloads
|
||||
Iterator& operator ++ () { return Next(); }
|
||||
Iterator operator ++ (int) { Iterator itr = *this; Next(); return itr; }
|
||||
|
||||
Iterator& operator = (const Iterator& _other) { CurrentNode = _other.CurrentNode; KVTree = _other.KVTree; return *this; }
|
||||
|
||||
bool operator == (const Iterator& _other) const { return CurrentNode == _other.CurrentNode; }
|
||||
bool operator != (const Iterator& _other) const { return !(*this == _other); }
|
||||
|
||||
private:
|
||||
Node* CurrentNode; //Our current KVTree node
|
||||
ZKVTree* KVTree; //The KVTree we are iterating
|
||||
};
|
||||
|
||||
/*
|
||||
Constructor.
|
||||
*/
|
||||
ZKVTree();
|
||||
|
||||
/*
|
||||
Copy Constructor.
|
||||
*/
|
||||
ZKVTree(const ZKVTree& _other);
|
||||
|
||||
/*
|
||||
Destructor.
|
||||
*/
|
||||
~ZKVTree();
|
||||
|
||||
/*
|
||||
= operator. Performs a copy of node names and data.
|
||||
|
||||
@param _other - the KVTree to copy from
|
||||
*/
|
||||
ZKVTree& operator = (const ZKVTree& _other);
|
||||
|
||||
/*
|
||||
public ZKVTree::Add
|
||||
|
||||
Adds a node to the tree under the given parent node. The version that takes no parent path
|
||||
will add the child under the root node. The iterator returned is used to directly address the
|
||||
node.
|
||||
|
||||
The two parameter version of this function adds children to the root node.
|
||||
|
||||
@param _parent - the path to the parent node
|
||||
@param _itr - iterator to the parent node
|
||||
@param _name - the name of the child node
|
||||
@param _value - the value of the child node
|
||||
@return (Iterator) - iterator to the created node
|
||||
*/
|
||||
Iterator Add(const ZString& _name, const ZString& _value);
|
||||
Iterator Add(const ZString& _parent, const ZString& _name, const ZString& _value);
|
||||
Iterator Add(const Iterator& _itr, const ZString& _name, const ZString& _value);
|
||||
|
||||
/*
|
||||
public ZKVTree::Begin
|
||||
|
||||
Gets a ZKVTree::Iterator to the first child of the root node of this KVTree. If there
|
||||
are no children, returns ZKVTree::End().
|
||||
|
||||
@return (ZKVTree::Iterator) - iterator to the beginning of the KVTree (first child node)
|
||||
*/
|
||||
Iterator Begin() const;
|
||||
|
||||
/*
|
||||
public ZKVTree::Clear
|
||||
|
||||
Clears the KVTree of all values.
|
||||
|
||||
@return (void)
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/*
|
||||
public ZKVTree::End
|
||||
|
||||
Gets a ZKVTree::Iterator to the end of the KVTree.
|
||||
|
||||
@return (ZKVTree::Iterator) - iterator to the end of the KVTree
|
||||
*/
|
||||
const Iterator End() const;
|
||||
|
||||
/*
|
||||
public ZKVTree::Erase
|
||||
|
||||
Erases the node at the given position and all children.
|
||||
|
||||
@param _path - the path to the node
|
||||
@param _itr - iterator to the node (invalidated by this call)
|
||||
@return (void)
|
||||
*/
|
||||
void Erase(const ZString& _path);
|
||||
void Erase(const Iterator& _itr);
|
||||
|
||||
/*
|
||||
public ZKVTree::Find
|
||||
|
||||
Gets a ZKVTree::Iterator to the given element if found. Returns an iterator
|
||||
equivalent to ZKVTree::End() if not found.
|
||||
|
||||
@param _path - path to the node to get an iterator to
|
||||
@param _itr - parent iterator to search from (path will be searched from this node as root)
|
||||
@return (ZKVTree::Iterator) - iterator to value if found, End() otherwise
|
||||
*/
|
||||
Iterator Find(const ZString& _path) const;
|
||||
Iterator Find(const Iterator& _itr, const ZString& _path) const;
|
||||
|
||||
/*
|
||||
public ZKVTree::Get
|
||||
|
||||
Gets a value from the KVTree that held by the node at the provided path.
|
||||
|
||||
@param _path - the path to the node to get the value from (if no subscript, [0] is assumed)
|
||||
@return (const ZString&) - reference to the value held by the node at the provided path
|
||||
@assert - if no value exists at the provided path
|
||||
*/
|
||||
const ZString& Get(const ZString& _path) const;
|
||||
const ZString& Get(const Iterator& _itr, const ZString& _path);
|
||||
|
||||
/*
|
||||
public ZKVTree::Merge
|
||||
|
||||
Merges this KVTree with another, bringing in the values defined in the other
|
||||
KVTree.
|
||||
|
||||
@param _other - the KVTree to merge values from
|
||||
@param _overwrite - if true, values will be overwritten when a conflict occurs
|
||||
@return (void)
|
||||
*/
|
||||
void Merge(const ZKVTree& _other, bool _overwrite);
|
||||
|
||||
/*
|
||||
public ZKVTree::Put
|
||||
|
||||
Puts a node with the given value into the KVTree at the provided path. Will overwrite
|
||||
any existing value at that location.
|
||||
|
||||
If the path string has a child node that does not exist, it will be created so long as the
|
||||
subscript is for the next child node, i.e., if A.B.c[1] is passed in, it will be created so
|
||||
long as A.B.c[0] exists.
|
||||
|
||||
The iterator version overwrites the data at that location if the iterator was created by this
|
||||
tree, and will attempt to create it as above if not from this tree.
|
||||
|
||||
@param _path - the path to the KVTree value (if no index, [0] is assumed)
|
||||
@param _itr - iterator to the node to assign the value to (will overwrite)
|
||||
@param _value - the value to assign to the node
|
||||
@return (Iterator) - iterator to the created value
|
||||
*/
|
||||
Iterator Put(const ZString& _key, const ZString& _value);
|
||||
Iterator Put(const Iterator& _itr, const ZString& _value);
|
||||
|
||||
/*
|
||||
public ZKVTree::IsValidKeyName
|
||||
|
||||
Checks that a key name is able to be put into the KVTree.
|
||||
|
||||
This basically ensures that a key will be valid for use in pathing.
|
||||
A valid key name doesn't contain whitespace, square brackets, or periods.
|
||||
|
||||
@param _name - the name being considered for validity.
|
||||
@return (bool) - true if the keyname would be valid in a path, false otherwise
|
||||
*/
|
||||
bool IsValidKeyName( const ZString& _key ) const;
|
||||
|
||||
protected:
|
||||
ZSlabAllocator<Node, ZKVTREE_NODE_COUNT> NodeAllocator;
|
||||
|
||||
Node RootNode; // The root node of the KVTree (also acts as the end node)
|
||||
|
||||
//Gets a node from the KVTree given a path (NULL if not found)
|
||||
Node* GetFromPath(const ZString& _path) const;
|
||||
|
||||
//Creates all the nodes needed along a path to be able to get and set the value, returning the node
|
||||
Node* CreatePath(const ZString& _path);
|
||||
|
||||
//Helper function used to check in all nodes
|
||||
void NodeCheckIn(Node* _node);
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user