822 lines
23 KiB
C++
822 lines
23 KiB
C++
/*
|
|
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
|