remove tree.[ch] from trunk, it will be added back once the mpd-tree branch is
merged back into trunk git-svn-id: https://svn.musicpd.org/mpd/trunk@4535 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
980c717749
commit
7ad533cca5
673
src/tree.c
673
src/tree.c
@ -1,673 +0,0 @@
|
|||||||
/* the Music Player Daemon (MPD)
|
|
||||||
* (c)2006 by Warren Dukes (warren.dukes@gmail.com)
|
|
||||||
* This project's homepage is: http://www.musicpd.org
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tree.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifndef CHILDREN_PER_NODE
|
|
||||||
#define CHILDREN_PER_NODE 3
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DATA_PER_NODE (CHILDREN_PER_NODE-1)
|
|
||||||
|
|
||||||
#if CHILDREN_PER_NODE > 7
|
|
||||||
#define USE_BINARY_SEARCH 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/************************* DATA STRUCTURES **********************************/
|
|
||||||
|
|
||||||
struct _TreeNode
|
|
||||||
{
|
|
||||||
void * data[DATA_PER_NODE];
|
|
||||||
struct _TreeNode * parent;
|
|
||||||
short parentPos;
|
|
||||||
struct _TreeNode * children[CHILDREN_PER_NODE];
|
|
||||||
short dataCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _Tree
|
|
||||||
{
|
|
||||||
TreeCompareDataFunction compareData;
|
|
||||||
TreeFreeDataFunction freeData;
|
|
||||||
TreeNode * rootNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************* STATIC METHODS ***********************************/
|
|
||||||
|
|
||||||
static
|
|
||||||
TreeNode *
|
|
||||||
_MakeNode()
|
|
||||||
{
|
|
||||||
TreeNode * ret = malloc(sizeof(TreeNode));
|
|
||||||
memset(ret, 0, sizeof(TreeNode));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
_FindPosition(Tree * tree, TreeNode * node, void * data, int * pos)
|
|
||||||
{
|
|
||||||
#ifdef USE_BINARY_SEARCH
|
|
||||||
int low = 0;
|
|
||||||
int high = node->dataCount;
|
|
||||||
int cmp = -1;
|
|
||||||
|
|
||||||
while (high > low)
|
|
||||||
{
|
|
||||||
int cur = (high + low) >> 1;
|
|
||||||
cmp = tree->compareData(data, node->data[cur]);
|
|
||||||
if (cmp > 0)
|
|
||||||
{
|
|
||||||
low = cur+1;
|
|
||||||
}
|
|
||||||
else if (cmp < 0)
|
|
||||||
{
|
|
||||||
high = cur;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
low = cur;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*pos = low;
|
|
||||||
return (cmp == 0);
|
|
||||||
#else
|
|
||||||
int i = 0;
|
|
||||||
int cmp = -1;
|
|
||||||
for (;
|
|
||||||
i < node->dataCount &&
|
|
||||||
(cmp = tree->compareData(data, node->data[i])) > 0;
|
|
||||||
i++);
|
|
||||||
*pos = i;
|
|
||||||
return (cmp == 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
_Find(TreeIterator * iter, void * data)
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (_FindPosition(iter->tree, iter->node, data, &iter->which))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iter->node->children[iter->which])
|
|
||||||
{
|
|
||||||
iter->node = iter->node->children[iter->which];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _SetTreeIteratorToRoot(TreeIterator * iter, Tree * tree)
|
|
||||||
{
|
|
||||||
iter->tree = tree;
|
|
||||||
iter->node = tree->rootNode;
|
|
||||||
iter->which = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
TreeNode *
|
|
||||||
_SplitNode(TreeNode * node)
|
|
||||||
{
|
|
||||||
assert(node->dataCount == DATA_PER_NODE);
|
|
||||||
|
|
||||||
TreeNode * newNode = _MakeNode();
|
|
||||||
|
|
||||||
int i = DATA_PER_NODE/2;
|
|
||||||
int j = 0;
|
|
||||||
for (; i < DATA_PER_NODE; i++, j++)
|
|
||||||
{
|
|
||||||
newNode->data[j] = node->data[i];
|
|
||||||
newNode->children[j+1] = node->children[i+1];
|
|
||||||
if (newNode->children[j+1])
|
|
||||||
{
|
|
||||||
newNode->children[j+1]->parent = newNode;
|
|
||||||
newNode->children[j+1]->parentPos = j+1;
|
|
||||||
}
|
|
||||||
node->data[i] = NULL;
|
|
||||||
node->children[i+1] = NULL;
|
|
||||||
}
|
|
||||||
newNode->dataCount = (DATA_PER_NODE-DATA_PER_NODE/2);
|
|
||||||
node->dataCount -= (DATA_PER_NODE-DATA_PER_NODE/2);
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
_InsertNodeAndData(Tree * tree,
|
|
||||||
TreeNode * node,
|
|
||||||
int pos,
|
|
||||||
TreeNode * newNode,
|
|
||||||
void * data)
|
|
||||||
{
|
|
||||||
assert(node->dataCount < DATA_PER_NODE);
|
|
||||||
#ifdef TREE_DEBUG
|
|
||||||
assert(!newNode || tree->compareData(data, newNode->data[0]) < 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int j = node->dataCount;
|
|
||||||
for (; j > pos; j--)
|
|
||||||
{
|
|
||||||
node->data[j] = node->data[j-1];
|
|
||||||
node->children[j+1] = node->children[j];
|
|
||||||
if (node->children[j+1])
|
|
||||||
{
|
|
||||||
node->children[j+1]->parentPos = j+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TREE_DEBUG
|
|
||||||
assert(!node->children[pos] ||
|
|
||||||
tree->compareData(data, node->children[pos]->data[0]) > 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
node->data[pos] = data;
|
|
||||||
node->dataCount++;
|
|
||||||
|
|
||||||
node->children[pos+1] = newNode;
|
|
||||||
if (newNode)
|
|
||||||
{
|
|
||||||
newNode->parent = node;
|
|
||||||
newNode->parentPos = pos+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void *
|
|
||||||
_AddDataToSplitNodes(Tree * tree,
|
|
||||||
TreeNode * lessNode,
|
|
||||||
TreeNode * moreNode,
|
|
||||||
int pos,
|
|
||||||
TreeNode * newNode,
|
|
||||||
void * data)
|
|
||||||
{
|
|
||||||
#ifdef TREE_DEBUG
|
|
||||||
assert(newNode == NULL ||
|
|
||||||
tree->compareData(data, newNode->data[0]) < 0);
|
|
||||||
#endif
|
|
||||||
assert(moreNode->children[0] == NULL);
|
|
||||||
|
|
||||||
void * retData;
|
|
||||||
|
|
||||||
if (pos <= lessNode->dataCount)
|
|
||||||
{
|
|
||||||
_InsertNodeAndData(tree, lessNode, pos, newNode, data);
|
|
||||||
lessNode->dataCount--;
|
|
||||||
retData = lessNode->data[lessNode->dataCount];
|
|
||||||
lessNode->data[lessNode->dataCount] = NULL;
|
|
||||||
moreNode->children[0] =
|
|
||||||
lessNode->children[lessNode->dataCount+1];
|
|
||||||
if (moreNode->children[0])
|
|
||||||
{
|
|
||||||
moreNode->children[0]->parent = moreNode;
|
|
||||||
moreNode->children[0]->parentPos = 0;
|
|
||||||
}
|
|
||||||
lessNode->children[lessNode->dataCount+1] = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pos -= lessNode->dataCount;
|
|
||||||
retData = moreNode->data[0];
|
|
||||||
assert(!moreNode->children[0]);
|
|
||||||
assert(!moreNode->data[moreNode->dataCount]);
|
|
||||||
|
|
||||||
int j = 0;
|
|
||||||
for (; j < pos; j++)
|
|
||||||
{
|
|
||||||
moreNode->data[j] = moreNode->data[j+1];
|
|
||||||
moreNode->children[j] = moreNode->children[j+1];
|
|
||||||
if (moreNode->children[j])
|
|
||||||
{
|
|
||||||
moreNode->children[j]->parentPos = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(!moreNode->children[pos-1] ||
|
|
||||||
tree->compareData(data,
|
|
||||||
moreNode->children[pos-1]->data[0]) > 0);
|
|
||||||
|
|
||||||
moreNode->data[pos-1] = data;
|
|
||||||
moreNode->children[pos] = newNode;
|
|
||||||
if (newNode)
|
|
||||||
{
|
|
||||||
newNode->parent = moreNode;
|
|
||||||
newNode->parentPos = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retData;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
_InsertAt(TreeIterator * iter, void * data)
|
|
||||||
{
|
|
||||||
TreeNode * node = iter->node;
|
|
||||||
TreeNode * insertNode = NULL;
|
|
||||||
int pos = iter->which;
|
|
||||||
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
#ifdef TREE_DEBUG
|
|
||||||
assert((pos == node->dataCount ||
|
|
||||||
iter->tree->compareData(data, node->data[pos]) < 0));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// see if there's any NULL data in the current node
|
|
||||||
if (node->dataCount == DATA_PER_NODE)
|
|
||||||
{
|
|
||||||
// no open data slots, split this node!
|
|
||||||
TreeNode * newNode = _SplitNode(node);
|
|
||||||
|
|
||||||
// insert data in split nodes
|
|
||||||
data = _AddDataToSplitNodes(iter->tree,
|
|
||||||
node,
|
|
||||||
newNode,
|
|
||||||
pos,
|
|
||||||
insertNode,
|
|
||||||
data);
|
|
||||||
|
|
||||||
if (node->parent == NULL)
|
|
||||||
{
|
|
||||||
assert(node == iter->tree->rootNode);
|
|
||||||
iter->tree->rootNode = _MakeNode();
|
|
||||||
iter->tree->rootNode->children[0] = node;
|
|
||||||
node->parent = iter->tree->rootNode;
|
|
||||||
node->parentPos = 0;
|
|
||||||
iter->tree->rootNode->children[1] = newNode;
|
|
||||||
newNode->parent = iter->tree->rootNode;
|
|
||||||
newNode->parentPos = 1;
|
|
||||||
iter->tree->rootNode->data[0] = data;
|
|
||||||
iter->tree->rootNode->dataCount = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = node->parentPos;
|
|
||||||
node = node->parent;
|
|
||||||
insertNode = newNode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// insert the data and newNode
|
|
||||||
_InsertNodeAndData(iter->tree,
|
|
||||||
node,
|
|
||||||
pos,
|
|
||||||
insertNode,
|
|
||||||
data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
_MergeNodes(TreeNode * lessNode, TreeNode * moreNode)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
int j = lessNode->dataCount;
|
|
||||||
|
|
||||||
assert((lessNode->dataCount + moreNode->dataCount) <= DATA_PER_NODE);
|
|
||||||
assert(lessNode->children[j] == NULL);
|
|
||||||
|
|
||||||
for(; i < moreNode->dataCount; i++,j++)
|
|
||||||
{
|
|
||||||
assert(!lessNode->children[j]);
|
|
||||||
assert(!lessNode->data[j]);
|
|
||||||
lessNode->data[j] = moreNode->data[i];
|
|
||||||
lessNode->children[j] = moreNode->children[i];
|
|
||||||
if (lessNode->children[j])
|
|
||||||
{
|
|
||||||
lessNode->children[j]->parent = lessNode;
|
|
||||||
lessNode->children[j]->parentPos = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lessNode->children[j] = moreNode->children[i];
|
|
||||||
if (lessNode->children[j])
|
|
||||||
{
|
|
||||||
lessNode->children[j]->parent = lessNode;
|
|
||||||
lessNode->children[j]->parentPos = j;
|
|
||||||
}
|
|
||||||
lessNode->dataCount += i;
|
|
||||||
|
|
||||||
free(moreNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_DeleteAt(TreeIterator * iter)
|
|
||||||
{
|
|
||||||
TreeNode * node = iter->node;
|
|
||||||
int pos = iter->which;
|
|
||||||
void ** data = &(node->data[pos]);
|
|
||||||
void * dataToFree = *data;
|
|
||||||
|
|
||||||
{
|
|
||||||
// find the least greater than data to fill the whole!
|
|
||||||
if (node->children[pos+1])
|
|
||||||
{
|
|
||||||
TreeNode * child = node->children[++pos];
|
|
||||||
while (child->children[0])
|
|
||||||
{
|
|
||||||
pos = 0;
|
|
||||||
child = child->children[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
*data = child->data[0];
|
|
||||||
data = &(child->data[0]);
|
|
||||||
node = child;
|
|
||||||
}
|
|
||||||
// or the greatest lesser than data to fill the whole!
|
|
||||||
else if (node->children[pos])
|
|
||||||
{
|
|
||||||
TreeNode * child = node->children[pos];
|
|
||||||
while (child->children[child->dataCount])
|
|
||||||
{
|
|
||||||
pos = child->dataCount;
|
|
||||||
child = child->children[child->dataCount];
|
|
||||||
}
|
|
||||||
|
|
||||||
*data = child->data[child->dataCount-1];
|
|
||||||
data = &(child->data[child->dataCount-1]);
|
|
||||||
node = child;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pos = node->parentPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// move data nodes over, we're at a leaf node, so we can ignore
|
|
||||||
// children
|
|
||||||
int i = data - node->data;;
|
|
||||||
for (; i < node->dataCount-1; i++)
|
|
||||||
{
|
|
||||||
node->data[i] = node->data[i+1];
|
|
||||||
}
|
|
||||||
node->data[--node->dataCount] = NULL;
|
|
||||||
|
|
||||||
// merge the nodes from the bottom up which have too few data
|
|
||||||
while (node->dataCount < (DATA_PER_NODE/2))
|
|
||||||
{
|
|
||||||
// if we're not the root
|
|
||||||
if (node->parent)
|
|
||||||
{
|
|
||||||
TreeNode ** child = &(node->parent->children[pos]);
|
|
||||||
assert(node->parent->children[pos] == node);
|
|
||||||
|
|
||||||
// check siblings for extra data
|
|
||||||
if (pos < node->parent->dataCount &&
|
|
||||||
(*(child+1))->dataCount > (DATA_PER_NODE/2))
|
|
||||||
{
|
|
||||||
child++;
|
|
||||||
node->data[node->dataCount++] =
|
|
||||||
node->parent->data[pos];
|
|
||||||
node->children[node->dataCount] =
|
|
||||||
(*child)->children[0];
|
|
||||||
if (node->children[node->dataCount])
|
|
||||||
{
|
|
||||||
node->children[node->dataCount]->
|
|
||||||
parent = node;
|
|
||||||
node->children[node->dataCount]->
|
|
||||||
parentPos = node->dataCount;
|
|
||||||
}
|
|
||||||
node->parent->data[pos] =
|
|
||||||
(*child)->data[0];
|
|
||||||
int i = 0;
|
|
||||||
for(; i < (*child)->dataCount-1; i++)
|
|
||||||
{
|
|
||||||
(*child)->data[i] = (*child)->data[i+1];
|
|
||||||
(*child)->children[i] =
|
|
||||||
(*child)->children[i+1];
|
|
||||||
if ((*child)->children[i])
|
|
||||||
{
|
|
||||||
(*child)->children[i]->
|
|
||||||
parentPos = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(*child)->children[i] = (*child)->children[i+1];
|
|
||||||
if ((*child)->children[i])
|
|
||||||
{
|
|
||||||
(*child)->children[i]->parentPos = i;
|
|
||||||
}
|
|
||||||
(*child)->children[i+1] =NULL;
|
|
||||||
(*child)->data[i] = NULL;
|
|
||||||
(*child)->dataCount--;
|
|
||||||
}
|
|
||||||
else if (pos > 0 &&
|
|
||||||
(*(child-1))->dataCount>(DATA_PER_NODE/2))
|
|
||||||
{
|
|
||||||
child--;
|
|
||||||
int i = node->dataCount++;
|
|
||||||
for(; i > 0; i--)
|
|
||||||
{
|
|
||||||
node->data[i] = node->data[i-1];
|
|
||||||
node->children[i+1] = node->children[i];
|
|
||||||
if (node->children[i+1])
|
|
||||||
{
|
|
||||||
node->children[i+1]->parentPos =
|
|
||||||
i+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node->children[1] = node->children[0];
|
|
||||||
if (node->children[1])
|
|
||||||
{
|
|
||||||
node->children[1]->parentPos = 1;
|
|
||||||
}
|
|
||||||
node->data[0] = node->parent->data[pos-1];
|
|
||||||
node->children[0] =
|
|
||||||
(*child)->children[(*child)->dataCount];
|
|
||||||
if (node->children[0])
|
|
||||||
{
|
|
||||||
node->children[0]->parent = node;
|
|
||||||
node->children[0]->parentPos = 0;
|
|
||||||
}
|
|
||||||
node->parent->data[pos-1] =
|
|
||||||
(*child)->data[(*child)->dataCount-1];
|
|
||||||
(*child)->children[(*child)->dataCount--] =
|
|
||||||
NULL;
|
|
||||||
(*child)->data[(*child)->dataCount] = NULL;
|
|
||||||
}
|
|
||||||
// merge with one of our siblings
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pos < node->parent->dataCount)
|
|
||||||
{
|
|
||||||
child++;
|
|
||||||
assert(*child);
|
|
||||||
|
|
||||||
node->data[node->dataCount++] =
|
|
||||||
node->parent->data[pos];
|
|
||||||
|
|
||||||
_MergeNodes(node, *child);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(pos > 0);
|
|
||||||
child--;
|
|
||||||
assert(*child);
|
|
||||||
pos--;
|
|
||||||
|
|
||||||
(*child)->data[(*child)->dataCount++] =
|
|
||||||
node->parent->data[pos];
|
|
||||||
|
|
||||||
_MergeNodes(*child, node);
|
|
||||||
node = *child;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = pos;
|
|
||||||
for(; i < node->parent->dataCount-1; i++)
|
|
||||||
{
|
|
||||||
node->parent->data[i] =
|
|
||||||
node->parent->data[i+1];
|
|
||||||
node->parent->children[i+1] =
|
|
||||||
node->parent->children[i+2];
|
|
||||||
if (node->parent->children[i+1])
|
|
||||||
{
|
|
||||||
node->parent->children[i+1]->
|
|
||||||
parentPos = i+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node->parent->data[i] = NULL;
|
|
||||||
node->parent->children[i+1] = NULL;
|
|
||||||
node->parent->dataCount--;
|
|
||||||
|
|
||||||
node = node->parent;
|
|
||||||
pos = node->parentPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// this is a root node
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (node->dataCount == 0)
|
|
||||||
{
|
|
||||||
if (node->children[0])
|
|
||||||
{
|
|
||||||
node->children[0]->parent = NULL;
|
|
||||||
node->children[0]->parentPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
iter->tree->rootNode = node->children[0];
|
|
||||||
|
|
||||||
free(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iter->tree->freeData)
|
|
||||||
{
|
|
||||||
iter->tree->freeData(dataToFree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************* PUBLIC METHODS ***********************************/
|
|
||||||
|
|
||||||
Tree *
|
|
||||||
MakeTree(TreeCompareDataFunction compareData, TreeFreeDataFunction freeData)
|
|
||||||
{
|
|
||||||
Tree * ret = malloc(sizeof(Tree));
|
|
||||||
ret->compareData = compareData;
|
|
||||||
ret->freeData = freeData;
|
|
||||||
ret->rootNode = _MakeNode();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTreeIteratorToBegin(TreeIterator * iter, Tree * tree)
|
|
||||||
{
|
|
||||||
_SetTreeIteratorToRoot(iter, tree);
|
|
||||||
IncrementTreeIterator(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
int IsTreeIteratorAtEnd(const TreeIterator * iter)
|
|
||||||
{
|
|
||||||
return (iter->node == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IncrementTreeIterator(TreeIterator * iter)
|
|
||||||
{
|
|
||||||
while(iter->node)
|
|
||||||
{
|
|
||||||
if (iter->node->children[iter->which])
|
|
||||||
{
|
|
||||||
iter->node = iter->node->children[iter->which];
|
|
||||||
iter->which = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iter->which++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (iter->node && iter->which > iter->node->dataCount)
|
|
||||||
{
|
|
||||||
TreeNode * childNode = iter->node;
|
|
||||||
iter->node = childNode->parent;
|
|
||||||
if (iter->node)
|
|
||||||
{
|
|
||||||
for (iter->which = 0;
|
|
||||||
childNode !=
|
|
||||||
iter->node->children[iter->which];
|
|
||||||
iter->which++)
|
|
||||||
{
|
|
||||||
assert(iter->which <=
|
|
||||||
iter->node->dataCount);
|
|
||||||
}
|
|
||||||
iter->which++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iter->node &&
|
|
||||||
iter->which > 0 && iter->which <= iter->node->dataCount)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
GetDataFromTreeIterator(TreeIterator * iter)
|
|
||||||
{
|
|
||||||
assert(iter->node &&
|
|
||||||
iter->which > 0 &&
|
|
||||||
iter->which <= iter->node->dataCount);
|
|
||||||
return iter->node->data[iter->which-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
InsertIntoTree(Tree * tree, void * data)
|
|
||||||
{
|
|
||||||
TreeIterator iter;
|
|
||||||
_SetTreeIteratorToRoot(&iter, tree);
|
|
||||||
|
|
||||||
if (_Find(&iter, data))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_InsertAt(&iter, data);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
DeleteFromTree(Tree * tree, void * data)
|
|
||||||
{
|
|
||||||
TreeIterator iter;
|
|
||||||
_SetTreeIteratorToRoot(&iter, tree);
|
|
||||||
|
|
||||||
if (_Find(&iter, data))
|
|
||||||
{
|
|
||||||
_DeleteAt(&iter);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
49
src/tree.h
49
src/tree.h
@ -1,49 +0,0 @@
|
|||||||
/* the Music Player Daemon (MPD)
|
|
||||||
* (c)2006 by Warren Dukes (warren.dukes@gmail.com)
|
|
||||||
* This project's homepage is: http://www.musicpd.org
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TREE_H
|
|
||||||
#define TREE_H
|
|
||||||
|
|
||||||
typedef struct _Tree Tree;
|
|
||||||
typedef struct _TreeNode TreeNode;
|
|
||||||
typedef struct _TreeIterator TreeIterator;
|
|
||||||
|
|
||||||
struct _TreeIterator
|
|
||||||
{
|
|
||||||
Tree * tree;
|
|
||||||
TreeNode * node;
|
|
||||||
int which;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef int (*TreeCompareDataFunction)(const void * data1, const void * data2);
|
|
||||||
typedef void (*TreeFreeDataFunction)(void * data);
|
|
||||||
|
|
||||||
Tree * MakeTree(TreeCompareDataFunction compareFunc,
|
|
||||||
TreeFreeDataFunction freeData);
|
|
||||||
|
|
||||||
void SetTreeIteratorToBegin(TreeIterator * iter, Tree * tree);
|
|
||||||
int IsTreeIteratorAtEnd(const TreeIterator * iter);
|
|
||||||
void IncrementTreeIterator(TreeIterator * iter);
|
|
||||||
|
|
||||||
void * GetDataFromTreeIterator(TreeIterator * iter);
|
|
||||||
|
|
||||||
int InsertIntoTree(Tree * tree, void * data);
|
|
||||||
|
|
||||||
int DeleteFromTree(Tree * tree, void * data);
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue
Block a user