mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-05 11:21:04 -08:00
Merging branch/2014-02-22/splay-tune into master.
Copied from Perforce Change: 184745 ServerID: perforce.ravenbrook.com
This commit is contained in:
commit
6f9ee39419
13 changed files with 1949 additions and 980 deletions
283
mps/code/cbs.c
283
mps/code/cbs.c
|
|
@ -23,7 +23,7 @@ SRCID(cbs, "$Id$");
|
|||
|
||||
typedef struct CBSBlockStruct *CBSBlock;
|
||||
typedef struct CBSBlockStruct {
|
||||
SplayNodeStruct splayNode;
|
||||
TreeStruct node;
|
||||
Addr base;
|
||||
Addr limit;
|
||||
Size maxSize; /* accurate maximum block size of sub-tree */
|
||||
|
|
@ -34,11 +34,11 @@ typedef struct CBSBlockStruct {
|
|||
#define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit)
|
||||
|
||||
|
||||
#define cbsOfSplayTree(tree) PARENT(CBSStruct, splayTree, (tree))
|
||||
#define cbsBlockOfSplayNode(node) PARENT(CBSBlockStruct, splayNode, (node))
|
||||
#define splayTreeOfCBS(tree) (&((cbs)->splayTree))
|
||||
#define splayNodeOfCBSBlock(block) (&((block)->splayNode))
|
||||
#define keyOfCBSBlock(block) ((void *)&((block)->base))
|
||||
#define cbsOfTree(_tree) TREE_ELT(CBS, tree, _tree)
|
||||
#define cbsBlockOfNode(_node) PARENT(CBSBlockStruct, node, _node)
|
||||
#define treeOfCBS(cbs) (&((cbs)->tree))
|
||||
#define nodeOfCBSBlock(block) (&((block)->node))
|
||||
#define keyOfCBSBlock(block) (&((block)->base))
|
||||
|
||||
|
||||
/* cbsEnter, cbsLeave -- Avoid re-entrance
|
||||
|
|
@ -73,8 +73,8 @@ Bool CBSCheck(CBS cbs)
|
|||
/* See .enter-leave.simple. */
|
||||
CHECKS(CBS, cbs);
|
||||
CHECKL(cbs != NULL);
|
||||
CHECKL(SplayTreeCheck(splayTreeOfCBS(cbs)));
|
||||
/* nothing to check about splayTreeSize */
|
||||
CHECKD(SplayTree, treeOfCBS(cbs));
|
||||
/* nothing to check about treeSize */
|
||||
CHECKD(Pool, cbs->blockPool);
|
||||
CHECKL(BoolCheck(cbs->fastFind));
|
||||
CHECKL(BoolCheck(cbs->inCBS));
|
||||
|
|
@ -89,7 +89,7 @@ static Bool CBSBlockCheck(CBSBlock block)
|
|||
/* See .enter-leave.simple. */
|
||||
UNUSED(block); /* Required because there is no signature */
|
||||
CHECKL(block != NULL);
|
||||
CHECKL(SplayNodeCheck(splayNodeOfCBSBlock(block)));
|
||||
CHECKL(TreeCheck(nodeOfCBSBlock(block)));
|
||||
|
||||
/* If the block is in the middle of being deleted, */
|
||||
/* the pointers will be equal. */
|
||||
|
|
@ -99,24 +99,21 @@ static Bool CBSBlockCheck(CBSBlock block)
|
|||
}
|
||||
|
||||
|
||||
/* cbsSplayCompare -- Compare key to [base,limit)
|
||||
/* cbsCompare -- Compare key to [base,limit)
|
||||
*
|
||||
* See <design/splay/#type.splay.compare.method>
|
||||
*/
|
||||
|
||||
static Compare cbsSplayCompare(void *key, SplayNode node)
|
||||
static Compare cbsCompare(Tree node, TreeKey key)
|
||||
{
|
||||
Addr base1, base2, limit2;
|
||||
CBSBlock cbsBlock;
|
||||
|
||||
/* NULL key compares less than everything. */
|
||||
if (key == NULL)
|
||||
return CompareLESS;
|
||||
|
||||
AVER(node != NULL);
|
||||
AVER(node != TreeEMPTY);
|
||||
|
||||
base1 = *(Addr *)key;
|
||||
cbsBlock = cbsBlockOfSplayNode(node);
|
||||
cbsBlock = cbsBlockOfNode(node);
|
||||
base2 = cbsBlock->base;
|
||||
limit2 = cbsBlock->limit;
|
||||
|
||||
|
|
@ -128,37 +125,42 @@ static Compare cbsSplayCompare(void *key, SplayNode node)
|
|||
return CompareEQUAL;
|
||||
}
|
||||
|
||||
static TreeKey cbsKey(Tree node)
|
||||
{
|
||||
return keyOfCBSBlock(cbsBlockOfNode(node));
|
||||
}
|
||||
|
||||
|
||||
/* cbsTestNode, cbsTestTree -- test for nodes larger than the S parameter */
|
||||
|
||||
static Bool cbsTestNode(SplayTree tree, SplayNode node,
|
||||
static Bool cbsTestNode(SplayTree tree, Tree node,
|
||||
void *closureP, Size size)
|
||||
{
|
||||
CBSBlock block;
|
||||
|
||||
AVERT(SplayTree, tree);
|
||||
AVERT(SplayNode, node);
|
||||
AVERT(Tree, node);
|
||||
AVER(closureP == NULL);
|
||||
AVER(size > 0);
|
||||
AVER(cbsOfSplayTree(tree)->fastFind);
|
||||
AVER(cbsOfTree(tree)->fastFind);
|
||||
|
||||
block = cbsBlockOfSplayNode(node);
|
||||
block = cbsBlockOfNode(node);
|
||||
|
||||
return CBSBlockSize(block) >= size;
|
||||
}
|
||||
|
||||
static Bool cbsTestTree(SplayTree tree, SplayNode node,
|
||||
static Bool cbsTestTree(SplayTree tree, Tree node,
|
||||
void *closureP, Size size)
|
||||
{
|
||||
CBSBlock block;
|
||||
|
||||
AVERT(SplayTree, tree);
|
||||
AVERT(SplayNode, node);
|
||||
AVERT(Tree, node);
|
||||
AVER(closureP == NULL);
|
||||
AVER(size > 0);
|
||||
AVER(cbsOfSplayTree(tree)->fastFind);
|
||||
AVER(cbsOfTree(tree)->fastFind);
|
||||
|
||||
block = cbsBlockOfSplayNode(node);
|
||||
block = cbsBlockOfNode(node);
|
||||
|
||||
return block->maxSize >= size;
|
||||
}
|
||||
|
|
@ -166,31 +168,26 @@ static Bool cbsTestTree(SplayTree tree, SplayNode node,
|
|||
|
||||
/* cbsUpdateNode -- update size info after restructuring */
|
||||
|
||||
static void cbsUpdateNode(SplayTree tree, SplayNode node,
|
||||
SplayNode leftChild, SplayNode rightChild)
|
||||
static void cbsUpdateNode(SplayTree tree, Tree node)
|
||||
{
|
||||
Size maxSize;
|
||||
CBSBlock block;
|
||||
|
||||
AVERT(SplayTree, tree);
|
||||
AVERT(SplayNode, node);
|
||||
if (leftChild != NULL)
|
||||
AVERT(SplayNode, leftChild);
|
||||
if (rightChild != NULL)
|
||||
AVERT(SplayNode, rightChild);
|
||||
AVER(cbsOfSplayTree(tree)->fastFind);
|
||||
AVERT(Tree, node);
|
||||
AVER(cbsOfTree(tree)->fastFind);
|
||||
|
||||
block = cbsBlockOfSplayNode(node);
|
||||
block = cbsBlockOfNode(node);
|
||||
maxSize = CBSBlockSize(block);
|
||||
|
||||
if (leftChild != NULL) {
|
||||
Size size = cbsBlockOfSplayNode(leftChild)->maxSize;
|
||||
if (TreeHasLeft(node)) {
|
||||
Size size = cbsBlockOfNode(TreeLeft(node))->maxSize;
|
||||
if (size > maxSize)
|
||||
maxSize = size;
|
||||
}
|
||||
|
||||
if (rightChild != NULL) {
|
||||
Size size = cbsBlockOfSplayNode(rightChild)->maxSize;
|
||||
if (TreeHasRight(node)) {
|
||||
Size size = cbsBlockOfNode(TreeRight(node))->maxSize;
|
||||
if (size > maxSize)
|
||||
maxSize = size;
|
||||
}
|
||||
|
|
@ -218,8 +215,10 @@ Res CBSInit(Arena arena, CBS cbs, void *owner, Align alignment,
|
|||
if (ArgPick(&arg, args, MPS_KEY_CBS_EXTEND_BY))
|
||||
extendBy = arg.val.size;
|
||||
|
||||
SplayTreeInit(splayTreeOfCBS(cbs), &cbsSplayCompare,
|
||||
fastFind ? &cbsUpdateNode : NULL);
|
||||
SplayTreeInit(treeOfCBS(cbs),
|
||||
cbsCompare,
|
||||
cbsKey,
|
||||
fastFind ? cbsUpdateNode : SplayTrivUpdate);
|
||||
MPS_ARGS_BEGIN(pcArgs) {
|
||||
MPS_ARGS_ADD(pcArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSBlockStruct));
|
||||
MPS_ARGS_ADD(pcArgs, MPS_KEY_EXTEND_BY, extendBy);
|
||||
|
|
@ -227,13 +226,13 @@ Res CBSInit(Arena arena, CBS cbs, void *owner, Align alignment,
|
|||
} MPS_ARGS_END(pcArgs);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
cbs->splayTreeSize = 0;
|
||||
cbs->treeSize = 0;
|
||||
|
||||
cbs->fastFind = fastFind;
|
||||
cbs->alignment = alignment;
|
||||
cbs->inCBS = TRUE;
|
||||
|
||||
METER_INIT(cbs->splaySearch, "size of splay tree", (void *)cbs);
|
||||
METER_INIT(cbs->treeSearch, "size of tree", (void *)cbs);
|
||||
|
||||
cbs->sig = CBSSig;
|
||||
|
||||
|
|
@ -254,11 +253,11 @@ void CBSFinish(CBS cbs)
|
|||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
|
||||
METER_EMIT(&cbs->splaySearch);
|
||||
METER_EMIT(&cbs->treeSearch);
|
||||
|
||||
cbs->sig = SigInvalid;
|
||||
|
||||
SplayTreeFinish(splayTreeOfCBS(cbs));
|
||||
SplayTreeFinish(treeOfCBS(cbs));
|
||||
PoolDestroy(cbs->blockPool);
|
||||
}
|
||||
|
||||
|
|
@ -272,16 +271,15 @@ void CBSFinish(CBS cbs)
|
|||
|
||||
static void cbsBlockDelete(CBS cbs, CBSBlock block)
|
||||
{
|
||||
Res res;
|
||||
Bool b;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
AVERT(CBSBlock, block);
|
||||
|
||||
METER_ACC(cbs->splaySearch, cbs->splayTreeSize);
|
||||
res = SplayTreeDelete(splayTreeOfCBS(cbs), splayNodeOfCBSBlock(block),
|
||||
keyOfCBSBlock(block));
|
||||
AVER(res == ResOK); /* Must be possible to delete node */
|
||||
STATISTIC(--cbs->splayTreeSize);
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
b = SplayTreeDelete(treeOfCBS(cbs), nodeOfCBSBlock(block));
|
||||
AVER(b); /* expect block to be in the tree */
|
||||
STATISTIC(--cbs->treeSize);
|
||||
|
||||
/* make invalid */
|
||||
block->limit = block->base;
|
||||
|
|
@ -302,8 +300,7 @@ static void cbsBlockShrunk(CBS cbs, CBSBlock block, Size oldSize)
|
|||
AVER(oldSize > newSize);
|
||||
|
||||
if (cbs->fastFind) {
|
||||
SplayNodeRefresh(splayTreeOfCBS(cbs), splayNodeOfCBSBlock(block),
|
||||
keyOfCBSBlock(block));
|
||||
SplayNodeRefresh(treeOfCBS(cbs), nodeOfCBSBlock(block));
|
||||
AVER(CBSBlockSize(block) <= block->maxSize);
|
||||
}
|
||||
}
|
||||
|
|
@ -319,14 +316,13 @@ static void cbsBlockGrew(CBS cbs, CBSBlock block, Size oldSize)
|
|||
AVER(oldSize < newSize);
|
||||
|
||||
if (cbs->fastFind) {
|
||||
SplayNodeRefresh(splayTreeOfCBS(cbs), splayNodeOfCBSBlock(block),
|
||||
keyOfCBSBlock(block));
|
||||
SplayNodeRefresh(treeOfCBS(cbs), nodeOfCBSBlock(block));
|
||||
AVER(CBSBlockSize(block) <= block->maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
/* cbsBlockAlloc -- allocate a new block and set its base and limit,
|
||||
but do not insert it into the splay tree yet */
|
||||
but do not insert it into the tree yet */
|
||||
|
||||
static Res cbsBlockAlloc(CBSBlock *blockReturn, CBS cbs, Range range)
|
||||
{
|
||||
|
|
@ -344,7 +340,7 @@ static Res cbsBlockAlloc(CBSBlock *blockReturn, CBS cbs, Range range)
|
|||
goto failPoolAlloc;
|
||||
block = (CBSBlock)p;
|
||||
|
||||
SplayNodeInit(splayNodeOfCBSBlock(block));
|
||||
TreeInit(nodeOfCBSBlock(block));
|
||||
block->base = RangeBase(range);
|
||||
block->limit = RangeLimit(range);
|
||||
block->maxSize = CBSBlockSize(block);
|
||||
|
|
@ -358,30 +354,30 @@ failPoolAlloc:
|
|||
return res;
|
||||
}
|
||||
|
||||
/* cbsBlockInsert -- insert a block into the splay tree */
|
||||
/* cbsBlockInsert -- insert a block into the tree */
|
||||
|
||||
static void cbsBlockInsert(CBS cbs, CBSBlock block)
|
||||
{
|
||||
Res res;
|
||||
Bool b;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
AVERT(CBSBlock, block);
|
||||
|
||||
METER_ACC(cbs->splaySearch, cbs->splayTreeSize);
|
||||
res = SplayTreeInsert(splayTreeOfCBS(cbs), splayNodeOfCBSBlock(block),
|
||||
keyOfCBSBlock(block));
|
||||
AVER(res == ResOK);
|
||||
STATISTIC(++cbs->splayTreeSize);
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
b = SplayTreeInsert(treeOfCBS(cbs), nodeOfCBSBlock(block));
|
||||
AVER(b);
|
||||
STATISTIC(++cbs->treeSize);
|
||||
}
|
||||
|
||||
|
||||
/* cbsInsertIntoTree -- Insert a range into the splay tree */
|
||||
/* cbsInsertIntoTree -- Insert a range into the tree */
|
||||
|
||||
static Res cbsInsertIntoTree(Range rangeReturn, CBS cbs, Range range)
|
||||
{
|
||||
Bool b;
|
||||
Res res;
|
||||
Addr base, limit, newBase, newLimit;
|
||||
SplayNode leftSplay, rightSplay;
|
||||
Tree leftSplay, rightSplay;
|
||||
CBSBlock leftCBS, rightCBS;
|
||||
Bool leftMerge, rightMerge;
|
||||
Size oldSize;
|
||||
|
|
@ -394,35 +390,36 @@ static Res cbsInsertIntoTree(Range rangeReturn, CBS cbs, Range range)
|
|||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
||||
METER_ACC(cbs->splaySearch, cbs->splayTreeSize);
|
||||
res = SplayTreeNeighbours(&leftSplay, &rightSplay,
|
||||
splayTreeOfCBS(cbs), (void *)&base);
|
||||
if (res != ResOK)
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
b = SplayTreeNeighbours(&leftSplay, &rightSplay, treeOfCBS(cbs), &base);
|
||||
if (!b) {
|
||||
res = ResFAIL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* The two cases below are not quite symmetrical, because base was
|
||||
* passed into the call to SplayTreeNeighbours(), but limit was not.
|
||||
* So we know that if there is a left neighbour, then leftCBS->limit
|
||||
* <= base (this is ensured by cbsSplayCompare, which is the
|
||||
* comparison method on the splay tree). But if there is a right
|
||||
* <= base (this is ensured by cbsCompare, which is the
|
||||
* comparison method on the tree). But if there is a right
|
||||
* neighbour, all we know is that base < rightCBS->base. But for the
|
||||
* range to fit, we need limit <= rightCBS->base too. Hence the extra
|
||||
* check and the possibility of failure in the second case.
|
||||
*/
|
||||
if (leftSplay == NULL) {
|
||||
if (leftSplay == TreeEMPTY) {
|
||||
leftCBS = NULL;
|
||||
leftMerge = FALSE;
|
||||
} else {
|
||||
leftCBS = cbsBlockOfSplayNode(leftSplay);
|
||||
leftCBS = cbsBlockOfNode(leftSplay);
|
||||
AVER(leftCBS->limit <= base);
|
||||
leftMerge = leftCBS->limit == base;
|
||||
}
|
||||
|
||||
if (rightSplay == NULL) {
|
||||
if (rightSplay == TreeEMPTY) {
|
||||
rightCBS = NULL;
|
||||
rightMerge = FALSE;
|
||||
} else {
|
||||
rightCBS = cbsBlockOfSplayNode(rightSplay);
|
||||
rightCBS = cbsBlockOfNode(rightSplay);
|
||||
if (rightCBS != NULL && limit > CBSBlockLimit(rightCBS)) {
|
||||
res = ResFAIL;
|
||||
goto fail;
|
||||
|
|
@ -493,13 +490,13 @@ Res CBSInsert(Range rangeReturn, CBS cbs, Range range)
|
|||
}
|
||||
|
||||
|
||||
/* cbsDeleteFromTree -- delete blocks from the splay tree */
|
||||
/* cbsDeleteFromTree -- delete blocks from the tree */
|
||||
|
||||
static Res cbsDeleteFromTree(Range rangeReturn, CBS cbs, Range range)
|
||||
{
|
||||
Res res;
|
||||
CBSBlock cbsBlock;
|
||||
SplayNode splayNode;
|
||||
Tree node;
|
||||
Addr base, limit, oldBase, oldLimit;
|
||||
Size oldSize;
|
||||
|
||||
|
|
@ -511,11 +508,12 @@ static Res cbsDeleteFromTree(Range rangeReturn, CBS cbs, Range range)
|
|||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
||||
METER_ACC(cbs->splaySearch, cbs->splayTreeSize);
|
||||
res = SplayTreeSearch(&splayNode, splayTreeOfCBS(cbs), (void *)&base);
|
||||
if (res != ResOK)
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
if (!SplayTreeFind(&node, treeOfCBS(cbs), (void *)&base)) {
|
||||
res = ResFAIL;
|
||||
goto failSplayTreeSearch;
|
||||
cbsBlock = cbsBlockOfSplayNode(splayNode);
|
||||
}
|
||||
cbsBlock = cbsBlockOfNode(node);
|
||||
|
||||
if (limit > cbsBlock->limit) {
|
||||
res = ResFAIL;
|
||||
|
|
@ -597,7 +595,8 @@ static Res cbsBlockDescribe(CBSBlock block, mps_lib_FILE *stream)
|
|||
{
|
||||
Res res;
|
||||
|
||||
if (stream == NULL) return ResFAIL;
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
"[$P,$P) {$U}",
|
||||
|
|
@ -608,49 +607,80 @@ static Res cbsBlockDescribe(CBSBlock block, mps_lib_FILE *stream)
|
|||
return res;
|
||||
}
|
||||
|
||||
static Res cbsSplayNodeDescribe(SplayNode splayNode, mps_lib_FILE *stream)
|
||||
static Res cbsSplayNodeDescribe(Tree node, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
|
||||
if (splayNode == NULL) return ResFAIL;
|
||||
if (stream == NULL) return ResFAIL;
|
||||
if (node == TreeEMPTY)
|
||||
return ResFAIL;
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
|
||||
res = cbsBlockDescribe(cbsBlockOfSplayNode(splayNode), stream);
|
||||
res = cbsBlockDescribe(cbsBlockOfNode(node), stream);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* CBSIterate -- Iterate all blocks in CBS
|
||||
/* CBSIterate -- iterate over all blocks in CBS
|
||||
*
|
||||
* Applies a visitor to all isolated contiguous ranges in a CBS.
|
||||
* It receives a pointer, ``Size`` closure pair to pass on to the
|
||||
* visitor function, and an visitor function to invoke on every range
|
||||
* in address order. If the visitor returns ``FALSE``, then the iteration
|
||||
* is terminated.
|
||||
*
|
||||
* The visitor function may not modify the CBS during the iteration.
|
||||
* This is because CBSIterate uses TreeTraverse, which does not permit
|
||||
* modification, for speed and to avoid perturbing the splay tree balance.
|
||||
*
|
||||
* This is not necessarily efficient.
|
||||
* See <design/cbs/#function.cbs.iterate>.
|
||||
*/
|
||||
|
||||
void CBSIterate(CBS cbs, CBSIterateMethod iterate,
|
||||
typedef struct CBSIterateClosure {
|
||||
CBS cbs;
|
||||
CBSVisitor iterate;
|
||||
void *closureP;
|
||||
Size closureS;
|
||||
} CBSIterateClosure;
|
||||
|
||||
static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS)
|
||||
{
|
||||
CBSIterateClosure *closure = closureP;
|
||||
RangeStruct range;
|
||||
CBSBlock cbsBlock;
|
||||
CBS cbs = closure->cbs;
|
||||
|
||||
UNUSED(closureS);
|
||||
|
||||
cbsBlock = cbsBlockOfNode(tree);
|
||||
RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock));
|
||||
if (!closure->iterate(cbs, &range, closure->closureP, closure->closureS))
|
||||
return FALSE;
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CBSIterate(CBS cbs, CBSVisitor visitor,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
SplayNode splayNode;
|
||||
SplayTree splayTree;
|
||||
CBSBlock cbsBlock;
|
||||
SplayTree tree;
|
||||
CBSIterateClosure closure;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
AVER(FUNCHECK(iterate));
|
||||
AVER(FUNCHECK(visitor));
|
||||
|
||||
splayTree = splayTreeOfCBS(cbs);
|
||||
tree = treeOfCBS(cbs);
|
||||
/* .splay-iterate.slow: We assume that splay tree iteration does */
|
||||
/* searches and meter it. */
|
||||
METER_ACC(cbs->splaySearch, cbs->splayTreeSize);
|
||||
splayNode = SplayTreeFirst(splayTree, NULL);
|
||||
while(splayNode != NULL) {
|
||||
RangeStruct range;
|
||||
cbsBlock = cbsBlockOfSplayNode(splayNode);
|
||||
RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock));
|
||||
if (!(*iterate)(cbs, &range, closureP, closureS))
|
||||
break;
|
||||
METER_ACC(cbs->splaySearch, cbs->splayTreeSize);
|
||||
splayNode = SplayTreeNext(splayTree, splayNode, keyOfCBSBlock(cbsBlock));
|
||||
}
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
|
||||
closure.cbs = cbs;
|
||||
closure.iterate = visitor;
|
||||
closure.closureP = closureP;
|
||||
closure.closureS = closureS;
|
||||
(void)TreeTraverse(SplayTreeRoot(tree), tree->compare, tree->nodeKey,
|
||||
cbsIterateVisit, &closure, 0);
|
||||
|
||||
cbsLeave(cbs);
|
||||
return;
|
||||
|
|
@ -722,7 +752,7 @@ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn,
|
|||
Res res;
|
||||
res = cbsDeleteFromTree(oldRangeReturn, cbs, rangeReturn);
|
||||
/* Can't have run out of memory, because all our callers pass in
|
||||
blocks that were just found in the splay tree, and we only
|
||||
blocks that were just found in the tree, and we only
|
||||
deleted from one end of the block, so cbsDeleteFromTree did not
|
||||
need to allocate a new block. */
|
||||
AVER(res == ResOK);
|
||||
|
|
@ -736,7 +766,7 @@ Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn,
|
|||
CBS cbs, Size size, FindDelete findDelete)
|
||||
{
|
||||
Bool found;
|
||||
SplayNode node;
|
||||
Tree node;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
|
|
@ -748,13 +778,13 @@ Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn,
|
|||
AVER(cbs->fastFind);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
METER_ACC(cbs->splaySearch, cbs->splayTreeSize);
|
||||
found = SplayFindFirst(&node, splayTreeOfCBS(cbs), &cbsTestNode,
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
found = SplayFindFirst(&node, treeOfCBS(cbs), &cbsTestNode,
|
||||
&cbsTestTree, NULL, size);
|
||||
if (found) {
|
||||
CBSBlock block;
|
||||
RangeStruct range;
|
||||
block = cbsBlockOfSplayNode(node);
|
||||
block = cbsBlockOfNode(node);
|
||||
AVER(CBSBlockSize(block) >= size);
|
||||
RangeInit(&range, CBSBlockBase(block), CBSBlockLimit(block));
|
||||
AVER(RangeSize(&range) >= size);
|
||||
|
|
@ -773,7 +803,7 @@ Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn,
|
|||
CBS cbs, Size size, FindDelete findDelete)
|
||||
{
|
||||
Bool found;
|
||||
SplayNode node;
|
||||
Tree node;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
|
|
@ -785,13 +815,13 @@ Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn,
|
|||
AVER(cbs->fastFind);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
METER_ACC(cbs->splaySearch, cbs->splayTreeSize);
|
||||
found = SplayFindLast(&node, splayTreeOfCBS(cbs), &cbsTestNode,
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
found = SplayFindLast(&node, treeOfCBS(cbs), &cbsTestNode,
|
||||
&cbsTestTree, NULL, size);
|
||||
if (found) {
|
||||
CBSBlock block;
|
||||
RangeStruct range;
|
||||
block = cbsBlockOfSplayNode(node);
|
||||
block = cbsBlockOfNode(node);
|
||||
AVER(CBSBlockSize(block) >= size);
|
||||
RangeInit(&range, CBSBlockBase(block), CBSBlockLimit(block));
|
||||
AVER(RangeSize(&range) >= size);
|
||||
|
|
@ -810,8 +840,6 @@ Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn,
|
|||
CBS cbs, Size size, FindDelete findDelete)
|
||||
{
|
||||
Bool found = FALSE;
|
||||
SplayNode root;
|
||||
Bool notEmpty;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
|
|
@ -821,20 +849,19 @@ Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn,
|
|||
AVER(cbs->fastFind);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
notEmpty = SplayRoot(&root, splayTreeOfCBS(cbs));
|
||||
if (notEmpty) {
|
||||
if (!SplayTreeIsEmpty(treeOfCBS(cbs))) {
|
||||
RangeStruct range;
|
||||
CBSBlock block;
|
||||
SplayNode node = NULL; /* suppress "may be used uninitialized" */
|
||||
Tree node = TreeEMPTY; /* suppress "may be used uninitialized" */
|
||||
Size maxSize;
|
||||
|
||||
maxSize = cbsBlockOfSplayNode(root)->maxSize;
|
||||
maxSize = cbsBlockOfNode(SplayTreeRoot(treeOfCBS(cbs)))->maxSize;
|
||||
if (maxSize >= size) {
|
||||
METER_ACC(cbs->splaySearch, cbs->splayTreeSize);
|
||||
found = SplayFindFirst(&node, splayTreeOfCBS(cbs), &cbsTestNode,
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
found = SplayFindFirst(&node, treeOfCBS(cbs), &cbsTestNode,
|
||||
&cbsTestTree, NULL, maxSize);
|
||||
AVER(found); /* maxSize is exact, so we will find it. */
|
||||
block = cbsBlockOfSplayNode(node);
|
||||
block = cbsBlockOfNode(node);
|
||||
AVER(CBSBlockSize(block) >= maxSize);
|
||||
RangeInit(&range, CBSBlockBase(block), CBSBlockLimit(block));
|
||||
AVER(RangeSize(&range) >= maxSize);
|
||||
|
|
@ -857,8 +884,10 @@ Res CBSDescribe(CBS cbs, mps_lib_FILE *stream)
|
|||
{
|
||||
Res res;
|
||||
|
||||
if (!TESTT(CBS, cbs)) return ResFAIL;
|
||||
if (stream == NULL) return ResFAIL;
|
||||
if (!TESTT(CBS, cbs))
|
||||
return ResFAIL;
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
"CBS $P {\n", (WriteFP)cbs,
|
||||
|
|
@ -866,14 +895,14 @@ Res CBSDescribe(CBS cbs, mps_lib_FILE *stream)
|
|||
" blockPool: $P\n", (WriteFP)cbs->blockPool,
|
||||
" fastFind: $U\n", (WriteFU)cbs->fastFind,
|
||||
" inCBS: $U\n", (WriteFU)cbs->inCBS,
|
||||
" splayTreeSize: $U\n", (WriteFU)cbs->splayTreeSize,
|
||||
" treeSize: $U\n", (WriteFU)cbs->treeSize,
|
||||
NULL);
|
||||
if (res != ResOK) return res;
|
||||
|
||||
res = SplayTreeDescribe(splayTreeOfCBS(cbs), stream, &cbsSplayNodeDescribe);
|
||||
res = SplayTreeDescribe(treeOfCBS(cbs), stream, &cbsSplayNodeDescribe);
|
||||
if (res != ResOK) return res;
|
||||
|
||||
res = METER_WRITE(cbs->splaySearch, stream);
|
||||
res = METER_WRITE(cbs->treeSearch, stream);
|
||||
if (res != ResOK) return res;
|
||||
|
||||
res = WriteF(stream, "}\n", NULL);
|
||||
|
|
|
|||
|
|
@ -17,21 +17,21 @@
|
|||
|
||||
|
||||
typedef struct CBSStruct *CBS;
|
||||
typedef Bool (*CBSIterateMethod)(CBS cbs, Range range,
|
||||
void *closureP, Size closureS);
|
||||
typedef Bool (*CBSVisitor)(CBS cbs, Range range,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
|
||||
#define CBSSig ((Sig)0x519CB599) /* SIGnature CBS */
|
||||
|
||||
typedef struct CBSStruct {
|
||||
SplayTreeStruct splayTree;
|
||||
Count splayTreeSize;
|
||||
SplayTreeStruct tree;
|
||||
Count treeSize;
|
||||
Pool blockPool;
|
||||
Align alignment;
|
||||
Bool fastFind;
|
||||
Bool inCBS; /* prevent reentrance */
|
||||
/* meters for sizes of search structures at each op */
|
||||
METER_DECL(splaySearch);
|
||||
METER_DECL(treeSearch);
|
||||
Sig sig; /* sig at end because embeded */
|
||||
} CBSStruct;
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ extern void CBSFinish(CBS cbs);
|
|||
|
||||
extern Res CBSInsert(Range rangeReturn, CBS cbs, Range range);
|
||||
extern Res CBSDelete(Range rangeReturn, CBS cbs, Range range);
|
||||
extern void CBSIterate(CBS cbs, CBSIterateMethod iterate,
|
||||
extern void CBSIterate(CBS cbs, CBSVisitor visitor,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
extern Res CBSDescribe(CBS cbs, mps_lib_FILE *stream);
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ MPMCOMMON = abq.c arena.c arenacl.c arenavm.c arg.c boot.c bt.c \
|
|||
freelist.c global.c ld.c locus.c message.c meter.c mpm.c mpsi.c \
|
||||
pool.c poolabs.c poolmfs.c poolmrg.c poolmv.c protocol.c range.c \
|
||||
ref.c reserv.c ring.c root.c sa.c sac.c seg.c shield.c splay.c ss.c \
|
||||
table.c trace.c traceanc.c tract.c walk.c
|
||||
table.c trace.c traceanc.c tract.c tree.c walk.c
|
||||
MPM = $(MPMCOMMON) $(MPMPF)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ MPMCOMMON = <abq> <arena> <arenacl> <arenavm> <arg> <boot> <bt> \
|
|||
<mpsi> <mpsiw3> <pool> <poolabs> <poolmfs> <poolmrg> <poolmv2> \
|
||||
<poolmv> <protocol> <protw3> <range> <ref> <reserv> <ring> <root> \
|
||||
<sa> <sac> <seg> <shield> <splay> <ss> <table> <thw3> <trace> \
|
||||
<traceanc> <tract> <vmw3> <walk>
|
||||
<traceanc> <tract> <tree> <vmw3> <walk>
|
||||
PLINTH = <mpsliban> <mpsioan>
|
||||
AMC = <poolamc>
|
||||
AMS = <poolams> <poolamsi>
|
||||
|
|
|
|||
|
|
@ -22,11 +22,12 @@ typedef struct tagStruct {
|
|||
/* We don't want to pay the expense of a sig in every tag */
|
||||
Addr addr;
|
||||
Size size;
|
||||
SplayNodeStruct splayNode;
|
||||
TreeStruct treeStruct;
|
||||
char userdata[1 /* actually variable length */];
|
||||
} tagStruct;
|
||||
|
||||
#define SplayNode2Tag(node) PARENT(tagStruct, splayNode, (node))
|
||||
#define TagTree(tag) (&(tag)->treeStruct)
|
||||
#define TagOfTree(tree) TREE_ELT(tag, treeStruct, tree)
|
||||
|
||||
typedef tagStruct *Tag;
|
||||
|
||||
|
|
@ -43,22 +44,27 @@ static void TagTrivInit(void* tag, va_list args)
|
|||
|
||||
/* TagComp -- splay comparison function for address ordering of tags */
|
||||
|
||||
static Compare TagComp(void *key, SplayNode node)
|
||||
static Compare TagCompare(Tree node, TreeKey key)
|
||||
{
|
||||
Addr addr1, addr2;
|
||||
|
||||
addr1 = *(Addr *)key;
|
||||
addr2 = SplayNode2Tag(node)->addr;
|
||||
addr2 = TagOfTree(node)->addr;
|
||||
if (addr1 < addr2)
|
||||
return CompareLESS;
|
||||
else if (addr1 > addr2) {
|
||||
/* Check key is not inside the object of this tag */
|
||||
AVER_CRITICAL(AddrAdd(addr2, SplayNode2Tag(node)->size) <= addr1);
|
||||
AVER_CRITICAL(AddrAdd(addr2, TagOfTree(node)->size) <= addr1);
|
||||
return CompareGREATER;
|
||||
} else
|
||||
return CompareEQUAL;
|
||||
}
|
||||
|
||||
static TreeKey TagKey(Tree node)
|
||||
{
|
||||
return &TagOfTree(node)->addr;
|
||||
}
|
||||
|
||||
|
||||
/* PoolDebugMixinCheck -- check a PoolDebugMixin */
|
||||
|
||||
|
|
@ -74,7 +80,7 @@ Bool PoolDebugMixinCheck(PoolDebugMixin debug)
|
|||
CHECKD(Pool, debug->tagPool);
|
||||
CHECKL(COMPATTYPE(Addr, void*)); /* tagPool relies on this */
|
||||
/* Nothing to check about missingTags */
|
||||
CHECKL(SplayTreeCheck(&debug->index));
|
||||
CHECKD(SplayTree, &debug->index);
|
||||
}
|
||||
UNUSED(debug); /* see <code/mpm.c#check.unused> */
|
||||
return TRUE;
|
||||
|
|
@ -193,7 +199,7 @@ static Res DebugPoolInit(Pool pool, ArgList args)
|
|||
if (res != ResOK)
|
||||
goto tagFail;
|
||||
debug->missingTags = 0;
|
||||
SplayTreeInit(&debug->index, TagComp, NULL);
|
||||
SplayTreeInit(&debug->index, TagCompare, TagKey, SplayTrivUpdate);
|
||||
}
|
||||
|
||||
debug->sig = PoolDebugMixinSig;
|
||||
|
|
@ -429,6 +435,7 @@ static Res tagAlloc(PoolDebugMixin debug,
|
|||
{
|
||||
Tag tag;
|
||||
Res res;
|
||||
Bool b;
|
||||
Addr addr;
|
||||
|
||||
UNUSED(pool);
|
||||
|
|
@ -443,10 +450,10 @@ static Res tagAlloc(PoolDebugMixin debug,
|
|||
}
|
||||
tag = (Tag)addr;
|
||||
tag->addr = new; tag->size = size;
|
||||
SplayNodeInit(&tag->splayNode);
|
||||
TreeInit(TagTree(tag));
|
||||
/* In the future, we might call debug->tagInit here. */
|
||||
res = SplayTreeInsert(&debug->index, &tag->splayNode, (void *)&new);
|
||||
AVER(res == ResOK);
|
||||
b = SplayTreeInsert(&debug->index, TagTree(tag));
|
||||
AVER(b);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
|
@ -455,25 +462,25 @@ static Res tagAlloc(PoolDebugMixin debug,
|
|||
|
||||
static void tagFree(PoolDebugMixin debug, Pool pool, Addr old, Size size)
|
||||
{
|
||||
SplayNode node;
|
||||
Tree node;
|
||||
Tag tag;
|
||||
Res res;
|
||||
Bool b;
|
||||
|
||||
AVERT(PoolDebugMixin, debug);
|
||||
AVERT(Pool, pool);
|
||||
AVER(size > 0);
|
||||
|
||||
res = SplayTreeSearch(&node, &debug->index, (void *)&old);
|
||||
if (res != ResOK) {
|
||||
if (!SplayTreeFind(&node, &debug->index, &old)) {
|
||||
AVER(debug->missingTags > 0);
|
||||
debug->missingTags--;
|
||||
return;
|
||||
}
|
||||
tag = SplayNode2Tag(node);
|
||||
tag = TagOfTree(node);
|
||||
AVER(tag->size == size);
|
||||
res = SplayTreeDelete(&debug->index, node, (void *)&old);
|
||||
AVER(res == ResOK);
|
||||
SplayNodeFinish(node);
|
||||
AVER(tag->addr == old);
|
||||
b = SplayTreeDelete(&debug->index, node);
|
||||
AVER(b); /* expect tag to be in the tree */
|
||||
TreeFinish(node);
|
||||
PoolFree(debug->tagPool, (Addr)tag, debug->tagSize);
|
||||
}
|
||||
|
||||
|
|
@ -554,10 +561,8 @@ typedef void (*ObjectsStepMethod)(Addr addr, Size size, Format fmt,
|
|||
|
||||
static void TagWalk(Pool pool, ObjectsStepMethod step, void *p)
|
||||
{
|
||||
SplayNode node;
|
||||
Tree node;
|
||||
PoolDebugMixin debug;
|
||||
Addr dummy = NULL; /* Breaks <design/type/#addr.use>, but it's */
|
||||
/* only temporary until SplayTreeFirst is fixed. */
|
||||
|
||||
AVERT(Pool, pool);
|
||||
AVERT(ObjectsStepMethod, step);
|
||||
|
|
@ -567,12 +572,12 @@ static void TagWalk(Pool pool, ObjectsStepMethod step, void *p)
|
|||
AVER(debug != NULL);
|
||||
AVERT(PoolDebugMixin, debug);
|
||||
|
||||
node = SplayTreeFirst(&debug->index, (void *)&dummy);
|
||||
node = SplayTreeFirst(&debug->index);
|
||||
while (node != NULL) {
|
||||
Tag tag = SplayNode2Tag(node);
|
||||
Tag tag = TagOfTree(node);
|
||||
|
||||
step(tag->addr, tag->size, NULL, pool, &tag->userdata, p);
|
||||
node = SplayTreeNext(&debug->index, node, (void *)&tag->addr);
|
||||
node = SplayTreeNext(&debug->index, &tag->addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,14 @@ enum BoolEnum {
|
|||
};
|
||||
|
||||
|
||||
typedef int Compare;
|
||||
enum {
|
||||
CompareLESS = -1,
|
||||
CompareEQUAL = 0,
|
||||
CompareGREATER = 1
|
||||
};
|
||||
|
||||
|
||||
/* SrcId -- source identification
|
||||
*
|
||||
* Every C source file should start with a SRCID declaration to
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@
|
|||
#include "dbgpooli.c"
|
||||
#include "boot.c"
|
||||
#include "meter.c"
|
||||
#include "tree.c"
|
||||
#include "splay.c"
|
||||
#include "cbs.c"
|
||||
#include "ss.c"
|
||||
|
|
|
|||
|
|
@ -1278,6 +1278,8 @@
|
|||
3104B02F156D39F2000A585A /* amssshe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amssshe.c; sourceTree = "<group>"; };
|
||||
3104B03D156D3AD7000A585A /* segsmss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = segsmss; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3107DC4E173B03D100F705C8 /* arg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = arg.h; sourceTree = "<group>"; };
|
||||
310F5D7118B6675F007EFCBC /* tree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tree.c; sourceTree = "<group>"; };
|
||||
310F5D7218B6675F007EFCBC /* tree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tree.h; sourceTree = "<group>"; };
|
||||
3112ED3A18ABC57F00CC531A /* sa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sa.h; sourceTree = "<group>"; };
|
||||
3112ED3B18ABC75200CC531A /* sa.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sa.c; sourceTree = "<group>"; };
|
||||
3114A590156E913C001E0AA3 /* locv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locv; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -2195,6 +2197,8 @@
|
|||
31EEAC30156AB2F200714D05 /* ring.c */,
|
||||
311F2F7317398B7100C15B6A /* ring.h */,
|
||||
31EEAC1C156AB2B200714D05 /* root.c */,
|
||||
3112ED3B18ABC75200CC531A /* sa.c */,
|
||||
3112ED3A18ABC57F00CC531A /* sa.h */,
|
||||
31EEAC31156AB2F200714D05 /* sac.c */,
|
||||
311F2F7417398B7100C15B6A /* sac.h */,
|
||||
311F2F7517398B8E00C15B6A /* sc.h */,
|
||||
|
|
@ -2209,10 +2213,10 @@
|
|||
31EEAC1F156AB2B200714D05 /* traceanc.c */,
|
||||
31EEAC0D156AB27B00714D05 /* tract.c */,
|
||||
311F2F7A17398B8E00C15B6A /* tract.h */,
|
||||
310F5D7118B6675F007EFCBC /* tree.c */,
|
||||
310F5D7218B6675F007EFCBC /* tree.h */,
|
||||
31EEAC44156AB32500714D05 /* version.c */,
|
||||
31EEAC0E156AB27B00714D05 /* walk.c */,
|
||||
3112ED3A18ABC57F00CC531A /* sa.h */,
|
||||
3112ED3B18ABC75200CC531A /* sa.c */,
|
||||
);
|
||||
name = "MPM Core";
|
||||
sourceTree = "<group>";
|
||||
|
|
|
|||
1617
mps/code/splay.c
1617
mps/code/splay.c
File diff suppressed because it is too large
Load diff
|
|
@ -10,75 +10,67 @@
|
|||
#define splay_h
|
||||
|
||||
#include "mpmtypes.h" /* for Res, etc. */
|
||||
#include "tree.h"
|
||||
|
||||
|
||||
typedef struct SplayTreeStruct *SplayTree;
|
||||
typedef struct SplayNodeStruct *SplayNode;
|
||||
typedef unsigned Compare;
|
||||
typedef Compare (*SplayCompareMethod)(void *key, SplayNode node);
|
||||
typedef Bool (*SplayTestNodeMethod)(SplayTree tree, SplayNode node,
|
||||
void *closureP, Size closureS);
|
||||
typedef Bool (*SplayTestTreeMethod)(SplayTree tree, SplayNode node,
|
||||
void *closureP, Size closureS);
|
||||
typedef void (*SplayUpdateNodeMethod)(SplayTree tree, SplayNode node,
|
||||
SplayNode leftChild,
|
||||
SplayNode rightChild);
|
||||
typedef Res (*SplayNodeDescribeMethod)(SplayNode node, mps_lib_FILE *stream);
|
||||
enum {
|
||||
CompareLESS = 1,
|
||||
CompareEQUAL,
|
||||
CompareGREATER
|
||||
};
|
||||
|
||||
typedef Bool (*SplayTestNodeMethod)(SplayTree splay, Tree node,
|
||||
void *closureP, Size closureS);
|
||||
typedef Bool (*SplayTestTreeMethod)(SplayTree splay, Tree node,
|
||||
void *closureP, Size closureS);
|
||||
typedef Res (*SplayNodeDescribeMethod)(Tree node, mps_lib_FILE *stream);
|
||||
|
||||
typedef void (*SplayUpdateNodeMethod)(SplayTree splay, Tree node);
|
||||
extern void SplayTrivUpdate(SplayTree splay, Tree node);
|
||||
|
||||
#define SplayTreeSig ((Sig)0x5195B1A1) /* SIGnature SPLAY */
|
||||
|
||||
typedef struct SplayTreeStruct {
|
||||
SplayCompareMethod compare;
|
||||
Sig sig;
|
||||
TreeCompare compare;
|
||||
TreeKeyMethod nodeKey;
|
||||
SplayUpdateNodeMethod updateNode;
|
||||
SplayNode root;
|
||||
Tree root;
|
||||
} SplayTreeStruct;
|
||||
|
||||
typedef struct SplayNodeStruct {
|
||||
SplayNode left;
|
||||
SplayNode right;
|
||||
} SplayNodeStruct;
|
||||
#define SplayTreeRoot(splay) RVALUE((splay)->root)
|
||||
#define SplayTreeIsEmpty(splay) (SplayTreeRoot(splay) == TreeEMPTY)
|
||||
|
||||
|
||||
extern Bool SplayTreeCheck(SplayTree tree);
|
||||
extern Bool SplayNodeCheck(SplayNode node);
|
||||
extern void SplayTreeInit(SplayTree tree, SplayCompareMethod compare,
|
||||
extern Bool SplayTreeCheck(SplayTree splay);
|
||||
extern void SplayTreeInit(SplayTree splay,
|
||||
TreeCompare compare,
|
||||
TreeKeyMethod nodeKey,
|
||||
SplayUpdateNodeMethod updateNode);
|
||||
extern void SplayNodeInit(SplayNode node);
|
||||
extern void SplayNodeFinish(SplayNode node);
|
||||
extern void SplayTreeFinish(SplayTree tree);
|
||||
extern void SplayTreeFinish(SplayTree splay);
|
||||
|
||||
extern Res SplayTreeInsert(SplayTree tree, SplayNode node, void *key);
|
||||
extern Res SplayTreeDelete(SplayTree tree, SplayNode node, void *key);
|
||||
extern Bool SplayTreeInsert(SplayTree splay, Tree node);
|
||||
extern Bool SplayTreeDelete(SplayTree splay, Tree node);
|
||||
|
||||
extern Res SplayTreeSearch(SplayNode *nodeReturn,
|
||||
SplayTree tree, void *key );
|
||||
extern Res SplayTreeNeighbours(SplayNode *leftReturn,
|
||||
SplayNode *rightReturn,
|
||||
SplayTree tree, void *key);
|
||||
extern Bool SplayTreeFind(Tree *nodeReturn, SplayTree splay, TreeKey key);
|
||||
|
||||
extern SplayNode SplayTreeFirst(SplayTree tree, void *zeroKey);
|
||||
extern SplayNode SplayTreeNext(SplayTree tree, SplayNode oldNode,
|
||||
void *oldKey);
|
||||
extern Bool SplayTreeNeighbours(Tree *leftReturn,
|
||||
Tree *rightReturn,
|
||||
SplayTree splay, TreeKey key);
|
||||
|
||||
extern Bool SplayFindFirst(SplayNode *nodeReturn, SplayTree tree,
|
||||
extern Tree SplayTreeFirst(SplayTree splay);
|
||||
extern Tree SplayTreeNext(SplayTree splay, TreeKey oldKey);
|
||||
|
||||
extern Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
|
||||
SplayTestNodeMethod testNode,
|
||||
SplayTestTreeMethod testTree,
|
||||
void *closureP, Size closureS);
|
||||
extern Bool SplayFindLast(SplayNode *nodeReturn, SplayTree tree,
|
||||
extern Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
|
||||
SplayTestNodeMethod testNode,
|
||||
SplayTestTreeMethod testTree,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
extern void SplayNodeRefresh(SplayTree tree, SplayNode node, void *key);
|
||||
extern void SplayNodeRefresh(SplayTree splay, Tree node);
|
||||
|
||||
extern Res SplayTreeDescribe(SplayTree tree, mps_lib_FILE *stream,
|
||||
extern Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream,
|
||||
SplayNodeDescribeMethod nodeDescribe);
|
||||
|
||||
extern Bool SplayRoot(SplayNode *nodeReturn, SplayTree tree);
|
||||
extern void SplayDebugUpdate(SplayTree splay, Tree tree);
|
||||
|
||||
|
||||
#endif /* splay_h */
|
||||
|
|
|
|||
533
mps/code/tree.c
Normal file
533
mps/code/tree.c
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
/* tree.c: BINARY TREE IMPLEMENTATION
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (C) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* Simple binary trees with utilities, for use as building blocks.
|
||||
* Keep it simple, like Rings (see ring.h).
|
||||
*
|
||||
* The performance requirements on tree implementation will depend on
|
||||
* how each individual function is applied in the MPS.
|
||||
*
|
||||
* .note.stack: It's important that the MPS have a bounded stack
|
||||
* size, and this is a problem for tree algorithms. Basically,
|
||||
* we have to avoid recursion. TODO: Design documentation for this
|
||||
* requirement, meanwhile see job003651 and job003640.
|
||||
*/
|
||||
|
||||
#include "tree.h"
|
||||
#include "mpm.h"
|
||||
|
||||
SRCID(tree, "$Id$");
|
||||
|
||||
|
||||
Bool TreeCheck(Tree tree)
|
||||
{
|
||||
if (tree != TreeEMPTY) {
|
||||
CHECKL(tree != NULL);
|
||||
CHECKL(tree->left == TreeEMPTY || tree->left != NULL);
|
||||
CHECKL(tree->right == TreeEMPTY || tree->right != NULL);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool TreeCheckLeaf(Tree tree)
|
||||
{
|
||||
CHECKL(TreeCheck(tree));
|
||||
CHECKL(tree != TreeEMPTY);
|
||||
CHECKL(tree->left == TreeEMPTY);
|
||||
CHECKL(tree->right == TreeEMPTY);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* TreeDebugCount -- count and check order of tree
|
||||
*
|
||||
* This function may be called from a debugger or temporarily inserted
|
||||
* during development to check a tree's integrity. It may not be called
|
||||
* from the production MPS because it uses indefinite stack depth.
|
||||
* See .note.stack.
|
||||
*/
|
||||
|
||||
static Count TreeDebugCountBetween(Tree node,
|
||||
TreeCompare compare, TreeKeyMethod key,
|
||||
TreeKey min, TreeKey max)
|
||||
{
|
||||
if (node == TreeEMPTY)
|
||||
return 0;
|
||||
AVERT(Tree, node);
|
||||
AVER(min == NULL || compare(node, min) != CompareGREATER);
|
||||
AVER(max == NULL || compare(node, max) != CompareLESS);
|
||||
return TreeDebugCountBetween(TreeLeft(node), compare, key, min, key(node)) +
|
||||
1 +
|
||||
TreeDebugCountBetween(TreeRight(node), compare, key, key(node), max);
|
||||
}
|
||||
|
||||
Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key)
|
||||
{
|
||||
AVERT(Tree, tree);
|
||||
return TreeDebugCountBetween(tree, compare, key, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
#if 0 /* This code is not currently in use in the MPS */
|
||||
|
||||
/* TreeFind -- search for a node matching the key
|
||||
*
|
||||
* If a matching node is found, sets *treeReturn to that node and returns
|
||||
* CompareEQUAL. Otherwise returns values useful for inserting a node with
|
||||
* the key. If the tree is empty, returns CompareEQUAL and sets *treeReturn
|
||||
* to NULL. Otherwise, sets *treeReturn to a potential parent for the new
|
||||
* node and returns CompareLESS if the new node should be its left child,
|
||||
* or CompareGREATER for its right.
|
||||
*/
|
||||
|
||||
Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)
|
||||
{
|
||||
Tree node, parent;
|
||||
Compare cmp = CompareEQUAL;
|
||||
|
||||
AVERT(Tree, root);
|
||||
AVER(treeReturn != NULL);
|
||||
AVER(FUNCHECK(compare));
|
||||
/* key is arbitrary */
|
||||
|
||||
parent = NULL;
|
||||
node = root;
|
||||
while (node != TreeEMPTY) {
|
||||
parent = node;
|
||||
cmp = compare(node, key);
|
||||
switch (cmp) {
|
||||
case CompareLESS:
|
||||
node = node->left;
|
||||
break;
|
||||
case CompareEQUAL:
|
||||
*treeReturn = node;
|
||||
return cmp;
|
||||
case CompareGREATER:
|
||||
node = node->right;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED;
|
||||
*treeReturn = NULL;
|
||||
return cmp;
|
||||
}
|
||||
}
|
||||
|
||||
*treeReturn = parent;
|
||||
return cmp;
|
||||
}
|
||||
|
||||
|
||||
/* TreeInsert -- insert a node into a tree
|
||||
*
|
||||
* If the key doesn't exist in the tree, inserts a node as a leaf of the
|
||||
* tree, returning the resulting tree in *treeReturn, and returns TRUE.
|
||||
* Otherwise, *treeReturn points to the existing matching node, the tree
|
||||
* is not modified, and returns FALSE.
|
||||
*/
|
||||
|
||||
Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
|
||||
TreeKey key, TreeCompare compare)
|
||||
{
|
||||
Tree parent;
|
||||
Compare cmp;
|
||||
|
||||
AVER(treeReturn != NULL);
|
||||
AVER(Tree, root);
|
||||
AVER(TreeCheckLeaf(node));
|
||||
AVER(FUNCHECK(compare));
|
||||
/* key is arbitrary */
|
||||
|
||||
cmp = TreeFind(&parent, root, key, compare);
|
||||
switch (cmp) {
|
||||
case CompareLESS:
|
||||
parent->left = node;
|
||||
break;
|
||||
case CompareEQUAL:
|
||||
if (parent != NULL) {
|
||||
*treeReturn = parent;
|
||||
return FALSE;
|
||||
}
|
||||
AVER(root == TreeEMPTY);
|
||||
root = node;
|
||||
break;
|
||||
case CompareGREATER:
|
||||
parent->right = node;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED;
|
||||
*treeReturn = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*treeReturn = root;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* TreeTraverseMorris -- traverse tree inorder in constant space
|
||||
*
|
||||
* The tree may not be accessed or modified during the traversal, and
|
||||
* the traversal must complete in order to repair the tree.
|
||||
*
|
||||
* The visitor should return FALSE to terminate the traversal early,
|
||||
* in which case FALSE is returned.
|
||||
*
|
||||
* TreeTraverse is generally superior if comparisons are cheap, but
|
||||
* TreeTraverseMorris does not require any comparison function.
|
||||
*
|
||||
* <http://en.wikipedia.org/wiki/Tree_traversal#Morris_in-order_traversal_using_threading>
|
||||
*
|
||||
* Joseph M. Morris (1979). "Traversing Binary Trees Simply and Cheaply".
|
||||
* Information Processing Letters 9:5 pp. 197–200.
|
||||
*/
|
||||
|
||||
Bool TreeTraverseMorris(Tree tree, TreeVisitor visit,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Tree node;
|
||||
Bool visiting = TRUE;
|
||||
|
||||
AVERT(Tree, tree);
|
||||
AVER(FUNCHECK(visit));
|
||||
/* closureP, closureS arbitrary */
|
||||
|
||||
node = tree;
|
||||
while (node != TreeEMPTY) {
|
||||
if (node->left == TreeEMPTY) {
|
||||
if (visiting)
|
||||
visiting = visit(node, closureP, closureS);
|
||||
node = node->right;
|
||||
} else {
|
||||
Tree pre = node->left;
|
||||
for (;;) {
|
||||
if (pre->right == TreeEMPTY) {
|
||||
pre->right = node;
|
||||
node = node->left;
|
||||
break;
|
||||
}
|
||||
if (pre->right == node) {
|
||||
pre->right = TreeEMPTY;
|
||||
if (visiting)
|
||||
visiting = visit(node, closureP, closureS);
|
||||
else if (node == tree)
|
||||
return FALSE;
|
||||
node = node->right;
|
||||
break;
|
||||
}
|
||||
pre = pre->right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return visiting;
|
||||
}
|
||||
|
||||
#endif /* not currently in use */
|
||||
|
||||
|
||||
/* TreeTraverse -- traverse tree in-order using pointer reversal
|
||||
*
|
||||
* The tree may not be accessed or modified during the traversal, and
|
||||
* the traversal must complete in order to repair the tree.
|
||||
*
|
||||
* The visitor should return FALSE to terminate the traversal early,
|
||||
* in which case FALSE is returned.
|
||||
*
|
||||
* TreeTraverseMorris is an alternative when no cheap comparison is available.
|
||||
*/
|
||||
|
||||
static Tree stepDownLeft(Tree node, Tree *parentIO)
|
||||
{
|
||||
Tree parent = *parentIO;
|
||||
Tree child = TreeLeft(node);
|
||||
TreeSetLeft(node, parent);
|
||||
*parentIO = node;
|
||||
return child;
|
||||
}
|
||||
|
||||
static Tree stepDownRight(Tree node, Tree *parentIO)
|
||||
{
|
||||
Tree parent = *parentIO;
|
||||
Tree child = TreeRight(node);
|
||||
TreeSetRight(node, parent);
|
||||
*parentIO = node;
|
||||
return child;
|
||||
}
|
||||
|
||||
static Tree stepUpRight(Tree node, Tree *parentIO)
|
||||
{
|
||||
Tree parent = *parentIO;
|
||||
Tree grandparent = TreeLeft(parent);
|
||||
TreeSetLeft(parent, node);
|
||||
*parentIO = grandparent;
|
||||
return parent;
|
||||
}
|
||||
|
||||
static Tree stepUpLeft(Tree node, Tree *parentIO)
|
||||
{
|
||||
Tree parent = *parentIO;
|
||||
Tree grandparent = TreeRight(parent);
|
||||
TreeSetRight(parent, node);
|
||||
*parentIO = grandparent;
|
||||
return parent;
|
||||
}
|
||||
|
||||
Bool TreeTraverse(Tree tree,
|
||||
TreeCompare compare,
|
||||
TreeKeyMethod key,
|
||||
TreeVisitor visit, void *closureP, Size closureS)
|
||||
{
|
||||
Tree parent, node;
|
||||
|
||||
AVERT(Tree, tree);
|
||||
AVER(FUNCHECK(visit));
|
||||
/* closureP, closureS arbitrary */
|
||||
|
||||
parent = TreeEMPTY;
|
||||
node = tree;
|
||||
|
||||
if (node == TreeEMPTY)
|
||||
return TRUE;
|
||||
|
||||
down:
|
||||
if (TreeHasLeft(node)) {
|
||||
node = stepDownLeft(node, &parent);
|
||||
AVER(compare(parent, key(node)) == CompareLESS);
|
||||
goto down;
|
||||
}
|
||||
if (!visit(node, closureP, closureS))
|
||||
goto abort;
|
||||
if (TreeHasRight(node)) {
|
||||
node = stepDownRight(node, &parent);
|
||||
AVER(compare(parent, key(node)) != CompareLESS);
|
||||
goto down;
|
||||
}
|
||||
|
||||
up:
|
||||
if (parent == TreeEMPTY)
|
||||
return TRUE;
|
||||
if (compare(parent, key(node)) != CompareLESS) {
|
||||
node = stepUpLeft(node, &parent);
|
||||
goto up;
|
||||
}
|
||||
node = stepUpRight(node, &parent);
|
||||
if (!visit(node, closureP, closureS))
|
||||
goto abort;
|
||||
if (!TreeHasRight(node))
|
||||
goto up;
|
||||
node = stepDownRight(node, &parent);
|
||||
goto down;
|
||||
|
||||
abort:
|
||||
if (parent == TreeEMPTY)
|
||||
return FALSE;
|
||||
if (compare(parent, key(node)) != CompareLESS)
|
||||
node = stepUpLeft(node, &parent);
|
||||
else
|
||||
node = stepUpRight(node, &parent);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
|
||||
/* TreeRotateLeft -- Rotate right child edge of node
|
||||
*
|
||||
* Rotates node, right child of node, and left child of right
|
||||
* child of node, leftwards in the order stated. Preserves tree
|
||||
* ordering.
|
||||
*/
|
||||
|
||||
void TreeRotateLeft(Tree *treeIO)
|
||||
{
|
||||
Tree tree, right;
|
||||
|
||||
AVER(treeIO != NULL);
|
||||
tree = *treeIO;
|
||||
AVERT(Tree, tree);
|
||||
right = TreeRight(tree);
|
||||
AVERT(Tree, right);
|
||||
|
||||
TreeSetRight(tree, TreeLeft(right));
|
||||
TreeSetLeft(right, tree);
|
||||
|
||||
*treeIO = right;
|
||||
}
|
||||
|
||||
|
||||
/* TreeRotateRight -- Rotate left child edge of node
|
||||
*
|
||||
* Rotates node, left child of node, and right child of left
|
||||
* child of node, leftwards in the order stated. Preserves tree
|
||||
* ordering.
|
||||
*/
|
||||
|
||||
void TreeRotateRight(Tree *treeIO) {
|
||||
Tree tree, left;
|
||||
|
||||
AVER(treeIO != NULL);
|
||||
tree = *treeIO;
|
||||
AVERT(Tree, tree);
|
||||
left = TreeLeft(tree);
|
||||
AVERT(Tree, left);
|
||||
|
||||
TreeSetLeft(*treeIO, TreeRight(left));
|
||||
TreeSetRight(left, *treeIO);
|
||||
|
||||
*treeIO = left;
|
||||
}
|
||||
|
||||
|
||||
/* TreeReverseLeftSpine -- reverse the pointers on the right spine
|
||||
*
|
||||
* Descends the left spine of a tree, updating each node's left child
|
||||
* to point to its parent instead. The root's left child is set to
|
||||
* TreeEMPTY. Returns the leftmost child, or TreeEMPTY if the tree
|
||||
* was empty.
|
||||
*/
|
||||
|
||||
Tree TreeReverseLeftSpine(Tree tree)
|
||||
{
|
||||
Tree node, parent;
|
||||
|
||||
AVERT(Tree, tree);
|
||||
|
||||
parent = TreeEMPTY;
|
||||
node = tree;
|
||||
while (node != TreeEMPTY) {
|
||||
Tree child = TreeLeft(node);
|
||||
TreeSetLeft(node, parent);
|
||||
parent = node;
|
||||
node = child;
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
/* TreeReverseRightSpine -- reverse the pointers on the right spine
|
||||
*
|
||||
* Descends the right spine of a tree, updating each node's right child
|
||||
* to point to its parent instead. The root's right child is set to
|
||||
* TreeEMPTY. Returns the rightmost child or TreeEMPTY if the tree
|
||||
* was empty.
|
||||
*/
|
||||
|
||||
Tree TreeReverseRightSpine(Tree tree)
|
||||
{
|
||||
Tree node, parent;
|
||||
|
||||
AVERT(Tree, tree);
|
||||
|
||||
parent = TreeEMPTY;
|
||||
node = tree;
|
||||
while (node != TreeEMPTY) {
|
||||
Tree child = TreeRight(node);
|
||||
TreeSetRight(node, parent);
|
||||
parent = node;
|
||||
node = child;
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
#if 0 /* This code is currently not in use in the MPS */
|
||||
|
||||
|
||||
/* TreeToVine -- unbalance a tree into a single right spine */
|
||||
|
||||
Count TreeToVine(Tree *link)
|
||||
{
|
||||
Count count = 0;
|
||||
|
||||
AVER(link != NULL);
|
||||
AVERT(Tree, *link);
|
||||
|
||||
while (*link != TreeEMPTY) {
|
||||
while (TreeHasLeft(*link))
|
||||
TreeRotateRight(link);
|
||||
link = &((*link)->right);
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* TreeBalance -- rebalance a tree
|
||||
*
|
||||
* Linear time, constant space rebalance.
|
||||
*
|
||||
* Quentin F. Stout and Bette L. Warren,
|
||||
* "Tree Rebalancing in Optimal Time and Space",
|
||||
* Communications of the ACM, Vol. 29, No. 9 (September 1986), p. 902-908
|
||||
*/
|
||||
|
||||
void TreeBalance(Tree *treeIO)
|
||||
{
|
||||
Count depth;
|
||||
|
||||
AVER(treeIO != NULL);
|
||||
AVERT(Tree, *treeIO);
|
||||
|
||||
depth = TreeToVine(treeIO);
|
||||
|
||||
if (depth > 2) {
|
||||
Count n = depth - 1;
|
||||
do {
|
||||
Count m = n / 2, i;
|
||||
Tree *link = treeIO;
|
||||
for (i = 0; i < m; ++i) {
|
||||
TreeRotateLeft(link);
|
||||
link = &((*link)->right);
|
||||
}
|
||||
n = n - m - 1;
|
||||
} while (n > 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* not currently in use in the MPS */
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
* included in the distribution or be available for no more than the cost
|
||||
* of distribution plus a nominal fee, and must be freely redistributable
|
||||
* under reasonable conditions. For an executable file, complete source
|
||||
* code means the source code for all modules it contains. It does not
|
||||
* include source code for modules or files that typically accompany the
|
||||
* major components of the operating system on which the executable file
|
||||
* runs.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
166
mps/code/tree.h
Normal file
166
mps/code/tree.h
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/* tree.h: BINARY TREE HEADER
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (C) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* Simple binary trees with utilities, for use as building blocks.
|
||||
* Keep it simple, like Rings (see ring.h).
|
||||
*/
|
||||
|
||||
#ifndef tree_h
|
||||
#define tree_h
|
||||
|
||||
#include "check.h"
|
||||
#include "mpmtypes.h"
|
||||
|
||||
|
||||
/* TreeStruct -- binary tree structure
|
||||
*
|
||||
* The tree structure is used in a field in other structures in order
|
||||
* to link them together in a binary tree.
|
||||
*/
|
||||
|
||||
typedef struct TreeStruct *Tree;
|
||||
typedef struct TreeStruct {
|
||||
Tree left, right;
|
||||
} TreeStruct;
|
||||
|
||||
|
||||
/* TreeKey and TreeCompare -- ordered binary trees
|
||||
*
|
||||
* Binary trees are almost always ordered, and these types provide the
|
||||
* abstraction for ordering. A TreeCompare method returns whether a key
|
||||
* is less than, equal to, or greater than the key in a tree node. A
|
||||
* TreeKeyMethod extracts a key from a node, depending on how TreeStruct
|
||||
* is embedded within its parent structure.
|
||||
*/
|
||||
|
||||
typedef void *TreeKey;
|
||||
typedef Compare (*TreeCompare)(Tree tree, TreeKey key);
|
||||
typedef TreeKey (*TreeKeyMethod)(Tree tree);
|
||||
|
||||
|
||||
/* TreeEMPTY -- the empty tree
|
||||
*
|
||||
* TreeEMPTY is the tree with no nodes, and hence unable to satisfy its
|
||||
* olfactory senses. Empty trees should not be represented with NULL,
|
||||
* as this is ambiguous. However, TreeEMPTY is in fact a null pointer for
|
||||
* performance. To check whether you have it right, try temporarily
|
||||
* defining TreeEMPTY to (Tree)1 or similar.
|
||||
*/
|
||||
|
||||
#define TreeEMPTY ((Tree)0)
|
||||
|
||||
extern Bool TreeCheck(Tree tree);
|
||||
extern Bool TreeCheckLeaf(Tree tree);
|
||||
extern Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key);
|
||||
|
||||
#define TreeInit(tree) \
|
||||
BEGIN \
|
||||
Tree _tree = (tree); \
|
||||
AVER(_tree != NULL); \
|
||||
_tree->left = TreeEMPTY; \
|
||||
_tree->right = TreeEMPTY; \
|
||||
AVERT(Tree, _tree); \
|
||||
END
|
||||
|
||||
#define TreeFinish(tree) \
|
||||
BEGIN \
|
||||
Tree _tree = (tree); \
|
||||
AVERT(Tree, _tree); \
|
||||
END
|
||||
|
||||
#define TREE_ELT(type, field, node) \
|
||||
PARENT(type ## Struct, field, node)
|
||||
|
||||
#define TreeLeft(tree) RVALUE((tree)->left)
|
||||
|
||||
#define TreeRight(tree) RVALUE((tree)->right)
|
||||
|
||||
#define TreeSetLeft(tree, child) \
|
||||
BEGIN \
|
||||
(tree)->left = (child); \
|
||||
END
|
||||
|
||||
#define TreeSetRight(tree, child) \
|
||||
BEGIN \
|
||||
(tree)->right = (child); \
|
||||
END
|
||||
|
||||
#define TreeClearLeft(tree) \
|
||||
BEGIN \
|
||||
(tree)->left = TreeEMPTY; \
|
||||
END
|
||||
|
||||
#define TreeClearRight(tree) \
|
||||
BEGIN \
|
||||
(tree)->right = TreeEMPTY; \
|
||||
END
|
||||
|
||||
#define TreeHasLeft(tree) (TreeLeft(tree) != TreeEMPTY)
|
||||
#define TreeHasRight(tree) (TreeRight(tree) != TreeEMPTY)
|
||||
|
||||
extern Compare TreeFind(Tree *treeReturn, Tree root,
|
||||
TreeKey key, TreeCompare compare);
|
||||
|
||||
extern Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
|
||||
TreeKey key, TreeCompare compare);
|
||||
|
||||
typedef Bool TreeVisitor(Tree tree, void *closureP, Size closureS);
|
||||
extern Bool TreeTraverse(Tree tree,
|
||||
TreeCompare compare,
|
||||
TreeKeyMethod key,
|
||||
TreeVisitor visit, void *closureP, Size closureS);
|
||||
extern Bool TreeTraverseMorris(Tree tree, TreeVisitor visit,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
extern void TreeRotateLeft(Tree *nodeIO);
|
||||
extern void TreeRotateRight(Tree *nodeIO);
|
||||
extern Tree TreeReverseLeftSpine(Tree tree);
|
||||
extern Tree TreeReverseRightSpine(Tree tree);
|
||||
extern Count TreeToVine(Tree *treeIO);
|
||||
extern void TreeBalance(Tree *treeIO);
|
||||
|
||||
|
||||
#endif /* tree_h */
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
* included in the distribution or be available for no more than the cost
|
||||
* of distribution plus a nominal fee, and must be freely redistributable
|
||||
* under reasonable conditions. For an executable file, complete source
|
||||
* code means the source code for all modules it contains. It does not
|
||||
* include source code for modules or files that typically accompany the
|
||||
* major components of the operating system on which the executable file
|
||||
* runs.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
|
@ -21,8 +21,8 @@ implementation.
|
|||
|
||||
_`.readership`: This document is intended for any MM developer.
|
||||
|
||||
_`.source`: The primary sources for this design are paper.st85(0) and
|
||||
paper.sleator96(0). Also as CBS is a client, design.mps.cbs. As
|
||||
_`.source`: The primary sources for this design are [ST85]_ and
|
||||
[Sleator96]_. Also as CBS is a client, design.mps.cbs. As
|
||||
PoolMVFF is an indirect client, design.mps.poolmvff(1). Also, as
|
||||
PoolMV2 is an (obsolescent?) indirect client, design.mps.poolmv2.
|
||||
|
||||
|
|
@ -153,22 +153,23 @@ the root of the splay tree. It is intended that the
|
|||
`.usage.client-tree`_ for an example). No convenience functions are
|
||||
provided for allocation or deallocation.
|
||||
|
||||
``typedef struct SplayNodeStruct SplayNodeStruct``
|
||||
``typedef struct SplayNodeStruct *SplayNode``
|
||||
``typedef struct TreeStruct TreeStruct``
|
||||
``typedef struct TreeStruct *Tree``
|
||||
|
||||
_`.type.splay.node`: ``SplayNode`` is the type of a node of the splay
|
||||
tree. ``SplayNodeStruct`` contains no fields to store the key
|
||||
_`.type.splay.node`: ``Tree`` is the type of a binary tree, used as the
|
||||
representation of the nodes of the splay tree.
|
||||
``Tree`` contains no fields to store the key
|
||||
associated with the node, or the client property. Again, it is
|
||||
intended that the ``SplayNodeStruct`` can be embedded in another
|
||||
intended that the ``TreeStruct`` can be embedded in another
|
||||
structure, and that this is how the association will be made (see
|
||||
`.usage.client-node`_ for an example). No convenience functions are
|
||||
provided for allocation or deallocation.
|
||||
|
||||
``typedef Compare (*SplayCompareMethod)(void *key, SplayNode node)``
|
||||
``typedef Compare (*TreeCompare)(Tree tree, TreeKey key)``
|
||||
|
||||
_`.type.splay.compare.method`: A function of type
|
||||
``SplayCompareMethod`` is required to compare ``key`` with the key the
|
||||
client associates with that splay tree node ``node``, and return the
|
||||
``TreeCompare`` is required to compare ``key`` with the key the
|
||||
client associates with that splay tree node ``tree``, and return the
|
||||
appropriate Compare value (see `.usage.compare`_ for an example). The
|
||||
function compares a key with a node, rather than a pair of keys or
|
||||
nodes as might seem more obvious. This is because the details of the
|
||||
|
|
@ -176,7 +177,7 @@ mapping between nodes and keys is left to the client (see
|
|||
`.type.splay.node`_), and the splaying operations compare keys with
|
||||
nodes (see `.impl.splay`_).
|
||||
|
||||
``typedef Res (*SplayNodeDescribeMethod)(SplayNode node, mps_lib_FILE *stream)``
|
||||
``typedef Res (*SplayNodeDescribeMethod)(Tree tree, mps_lib_FILE *stream)``
|
||||
|
||||
_`.type.splay.node.describe.method`: A function of type
|
||||
``SplayNodeDescribeMethod`` is required to write (via ``WriteF()``) a
|
||||
|
|
@ -184,7 +185,7 @@ client-oriented representation of the splay node. The output should be
|
|||
non-empty, short, and without return characters. This is provided for
|
||||
debugging purposes only.
|
||||
|
||||
``typedef Bool (*SplayTestNodeMethod)(SplayTree tree, SplayNode node, void *closureP, unsigned long closureS)``
|
||||
``typedef Bool (*SplayTestNodeMethod)(SplayTree splay, Tree tree, void *closureP, unsigned long closureS)``
|
||||
|
||||
_`.type.splay.test.node.method`: A function of type
|
||||
``SplayTestNodeMethod`` required to determine whether the node itself
|
||||
|
|
@ -193,7 +194,7 @@ meets some client determined property (see `.prop`_ and
|
|||
``closureS`` describe the environment for the function (see
|
||||
`.function.splay.find.first`_ and `.function.splay.find.last`_).
|
||||
|
||||
``typedef Bool (*SplayTestTreeMethod)(SplayTree tree, SplayNode node, void *closureP, unsigned long closureS)``
|
||||
``typedef Bool (*SplayTestTreeMethod)(SplayTree splay, Tree tree, void *closureP, unsigned long closureS)``
|
||||
|
||||
_`.type.splay.test.tree.method`: A function of type
|
||||
``SplayTestTreeMethod`` is required to determine whether any of the
|
||||
|
|
@ -206,14 +207,13 @@ return ``TRUE``. Parameters ``closureP`` and ``closureS`` describe the
|
|||
environment for the function (see `.function.splay.find.first`_ and
|
||||
`.function.splay.find.last`_).
|
||||
|
||||
``typedef void (*SplayUpdateNodeMethod)(SplayTree tree, SplayNode node, SplayNode leftChild, SplayNode rightChild)``
|
||||
``typedef void (*SplayUpdateNodeMethod)(SplayTree splay, Tree tree)``
|
||||
|
||||
_`.type.splay.update.node.method`: A function of type
|
||||
``SplayUpdateNodeMethod`` is required to update any client
|
||||
datastructures associated with a node to maintain some client
|
||||
determined property (see `.prop`_) given that the children of the node
|
||||
have changed. If the node does not have one or both children, then
|
||||
``NULL`` will be passed as the relevant parameter. (See
|
||||
have changed. (See
|
||||
`.usage.callback`_ for an example)
|
||||
|
||||
|
||||
|
|
@ -228,19 +228,19 @@ methods invoked by the splay module (`.type.splay.compare.method`_,
|
|||
`.type.splay.update.node.method`_) do not call functions of the splay
|
||||
module.
|
||||
|
||||
``Bool SplayTreeCheck(SplayTree tree)``
|
||||
``Bool SplayTreeCheck(SplayTree splay)``
|
||||
|
||||
_`.function.splay.tree.check`: This is a check function for the
|
||||
SplayTree type (see guide.impl.c.adt.method.check &
|
||||
design.mps.check(0)).
|
||||
|
||||
``Bool SplayNodeCheck(SplayNode node)``
|
||||
``Bool SplayNodeCheck(Tree tree)``
|
||||
|
||||
_`.function.splay.node.check`: This is a check function for the
|
||||
``SplayNode`` type (see guide.impl.c.adt.method.check &
|
||||
``Tree`` type (see guide.impl.c.adt.method.check &
|
||||
design.mps.check(0)).
|
||||
|
||||
``void SplayTreeInit(SplayTree tree, SplayCompareMethod compare, SplayUpdateNodeMethod updateNode)``
|
||||
``void SplayTreeInit(SplayTree splay, SplayCompareMethod compare, SplayUpdateNodeMethod updateNode)``
|
||||
|
||||
_`.function.splay.tree.init`: This function initialises a
|
||||
``SplayTree`` (see guide.impl.c.adt.method.init). It requires a
|
||||
|
|
@ -249,85 +249,66 @@ _`.function.splay.tree.init`: This function initialises a
|
|||
implement a total ordering is undefined. It also requires an
|
||||
``updateNode`` method, which will be used to keep client properties up
|
||||
to date when the tree structure changes; the value
|
||||
``SplayTrivUpdateNode`` may be used for this method if there is no
|
||||
``SplayTrivUpdate`` may be used for this method if there is no
|
||||
need to maintain client properties. (See `.usage.initialization`_ for
|
||||
an example use).
|
||||
|
||||
``void SplayTreeFinish(SplayTree tree)``
|
||||
``void SplayTreeFinish(SplayTree splay)``
|
||||
|
||||
_`.function.splay.tree.finish`: This function clears the fields of a
|
||||
``SplayTree`` (see guide.impl.c.adt.method.finish). Note that it does
|
||||
not attempt to finish or deallocate any associated ``SplayNode``
|
||||
not attempt to finish or deallocate any associated ``Tree``
|
||||
objects; clients wishing to destroy a non-empty ``SplayTree`` must
|
||||
first explicitly descend the tree and call ``SplayNodeFinish()`` on
|
||||
each node from the bottom up.
|
||||
|
||||
``void SplayNodeInit(SplayNode node)``
|
||||
|
||||
_`.function.splay.node.init`: This function initialises a
|
||||
``SplayNode`` (see guide.impl.c.adt.method.init).
|
||||
|
||||
``void SplayNodeFinish(SplayNode node)``
|
||||
|
||||
_`.function.splay.node.finish`: This function clears the fields of a
|
||||
``SplayNode`` (see guide.impl.c.adt.method.finish). Note that it does
|
||||
not attempt to finish or deallocate any referenced ``SplayNode``
|
||||
objects (see.function.splay.tree.finish).
|
||||
|
||||
``Bool SplayRoot(SplayNode *nodeReturn, SplayTree tree)``
|
||||
|
||||
_`.function.splay.root`: This function returns the root node of the
|
||||
tree, if any (see `.req.root`_). If the tree is empty, ``FALSE`` is
|
||||
returned and ``*nodeReturn`` is not changed. Otherwise, ``TRUE`` is
|
||||
returned and ``*nodeReturn`` is set to the root.
|
||||
|
||||
``Res SplayTreeInsert(SplayTree tree, SplayNode node, void *key)``
|
||||
``Bool SplayTreeInsert(SplayTree splay, Tree tree, void *key)``
|
||||
|
||||
_`.function.splay.tree.insert`: This function is used to insert into a
|
||||
splay tree a new node which is associated with the supplied key (see
|
||||
`.req.add`_). It first splays the tree at the key. If an attempt is
|
||||
made to insert a node that compares ``CompareEQUAL`` to an existing
|
||||
node in the tree, then ``ResFAIL`` will be returned and the node will
|
||||
node in the tree, then ``FALSE`` will be returned and the node will
|
||||
not be inserted. (See `.usage.insert`_ for an example use).
|
||||
|
||||
``Res SplayTreeDelete(SplayTree tree, SplayNode node, void *key)``
|
||||
``Bool SplayTreeDelete(SplayTree splay, Tree tree, void *key)``
|
||||
|
||||
_`.function.splay.tree.delete`: This function is used to delete from a
|
||||
splay tree a node which is associated with the supplied key (see
|
||||
`.req.remove`_). If the tree does not contain the given node, or the
|
||||
given node does not compare ``CompareEQUAL`` with the given key, then
|
||||
``ResFAIL`` will be returned, and the node will not be deleted. The
|
||||
``FALSE`` will be returned, and the node will not be deleted. The
|
||||
function first splays the tree at the given key. (See `.usage.delete`_
|
||||
for an example use).
|
||||
|
||||
``Res SplayTreeSearch(SplayNode *nodeReturn, SplayTree tree, void *key)``
|
||||
``Bool SplayTreeFind(Tree *nodeReturn, SplayTree splay, void *key)``
|
||||
|
||||
_`.function.splay.tree.search`: This function searches the splay tree
|
||||
for a node that compares ``CompareEQUAL`` to the given key (see
|
||||
`.req.locate`_). It splays the tree at the key. It returns ``ResFAIL``
|
||||
`.req.locate`_). It splays the tree at the key. It returns ``FALSE``
|
||||
if there is no such node in the tree, otherwise ``*nodeReturn`` will
|
||||
be set to the node.
|
||||
|
||||
``Res SplayTreeNeighbours(SplayNode *leftReturn, SplayNode *rightReturn, SplayTree tree, void *key)``
|
||||
``Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn, SplayTree splay, void *key)``
|
||||
|
||||
_`.function.splay.tree.neighbours`: This function searches a splay
|
||||
tree for the two nodes that are the neighbours of the given key (see
|
||||
`.req.neighbours`_). It splays the tree at the key. ``*leftReturn``
|
||||
will be the neighbour which compares less than the key if such a
|
||||
neighbour exists; otherwise it will be ``NULL``. ``*rightReturn`` will
|
||||
neighbour exists; otherwise it will be ``TreeEMPTY``. ``*rightReturn`` will
|
||||
be the neighbour which compares greater than the key if such a
|
||||
neighbour exists; otherwise it will be ``NULL``. The function returns
|
||||
``ResFAIL`` if any node in the tree compares ``CompareEQUAL`` with the
|
||||
neighbour exists; otherwise it will be ``TreeEMPTY``. The function returns
|
||||
``FALSE`` if any node in the tree compares ``CompareEQUAL`` with the
|
||||
given key. (See `.usage.insert`_ for an example use).
|
||||
|
||||
``SplayNode SplayTreeFirst(SplayTree tree, void *zeroKey)``
|
||||
``Tree SplayTreeFirst(SplayTree splay, void *zeroKey)``
|
||||
|
||||
_`.function.splay.tree.first`: This function splays the tree at the
|
||||
first node, and returns that node (see `.req.iterate`_). The supplied
|
||||
key should compare ``CompareLESS`` with all nodes in the tree. It will
|
||||
return ``NULL`` if the tree has no nodes.
|
||||
return ``TreeEMPTY`` if the tree has no nodes.
|
||||
|
||||
``SplayNode SplayTreeNext(SplayTree tree, SplayNode oldNode, void *oldKey)``
|
||||
``Tree SplayTreeNext(SplayTree splay, Tree oldNode, void *oldKey)``
|
||||
|
||||
_`.function.splay.tree.next`: This function receives a node and key
|
||||
and returns the successor node to that node (see `.req.iterate`_).
|
||||
|
|
@ -342,14 +323,14 @@ tree was previously beneficially balanced for a small working set of
|
|||
accesses, then this local optimization will be lost. (see
|
||||
`.future.parent`_).
|
||||
|
||||
``Res SplayTreeDescribe(SplayTree tree, mps_lib_FILE *stream, SplayNodeDescribeMethod nodeDescribe)``
|
||||
``Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, SplayNodeDescribeMethod nodeDescribe)``
|
||||
|
||||
_`.function.splay.tree.describe`: This function prints (using
|
||||
``WriteF``) to the stream a textual representation of the given splay
|
||||
tree, using ``nodeDescribe`` to print client-oriented representations
|
||||
of the nodes (see `.req.debug`_).
|
||||
|
||||
``Bool SplayFindFirst(SplayNode *nodeReturn, SplayTree tree, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, unsigned long closureS)``
|
||||
``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, unsigned long closureS)``
|
||||
|
||||
_`.function.splay.find.first`: ``SplayFindFirst()`` finds the first node
|
||||
in the tree that satisfies some client property (as determined by the
|
||||
|
|
@ -360,7 +341,7 @@ closure environments. If there is no satisfactory node, then ``FALSE``
|
|||
is returned, otherwise ``*nodeReturn`` is set to the node. (See
|
||||
`.usage.delete`_ for an example use).
|
||||
|
||||
``Bool SplayFindFirst(SplayNode *nodeReturn, SplayTree tree, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, unsigned long closureS)``
|
||||
``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, unsigned long closureS)``
|
||||
|
||||
_`.function.splay.find.last`: ``SplayFindLast()`` finds the last node
|
||||
in the tree that satisfies some client property (as determined by the
|
||||
|
|
@ -370,7 +351,7 @@ the ``testNode`` and ``testTree`` methods which may use the values as
|
|||
closure environments. If there is no satisfactory node, then ``FALSE``
|
||||
is returned, otherwise ``*nodeReturn`` is set to the node.
|
||||
|
||||
``void SplayNodeRefresh(SplayTree tree, SplayNode node, void *key)``
|
||||
``void SplayNodeRefresh(SplayTree splay, Tree tree, void *key)``
|
||||
|
||||
_`.function.splay.node.refresh`: ``SplayNodeRefresh()`` must be called
|
||||
whenever the client property (see `.prop`_) at a node changes (see
|
||||
|
|
@ -462,10 +443,10 @@ _`.usage.client-tree`: Tree structure to embed a ``SplayTree`` (see
|
|||
/* no obvious client fields for this simple example */
|
||||
} FreeTreeStruct;
|
||||
|
||||
_`.usage.client-node`: Node structure to embed a SplayNode (see `.type.splay.node`_)::
|
||||
_`.usage.client-node`: Node structure to embed a Tree (see `.type.splay.node`_)::
|
||||
|
||||
typedef struct FreeBlockStruct {
|
||||
SplayNodeStruct splayNode; /* embedded splay node */
|
||||
TreeStruct treeStruct; /* embedded splay node */
|
||||
Addr base; /* base address of block is also the key */
|
||||
Size size; /* size of block is also the client property */
|
||||
Size maxSize; /* cached value for maximum size in subtree */
|
||||
|
|
@ -474,26 +455,25 @@ _`.usage.client-node`: Node structure to embed a SplayNode (see `.type.splay.nod
|
|||
_`.usage.callback`: updateNode callback method (see
|
||||
`.type.splay.update.node.method`_)::
|
||||
|
||||
void FreeBlockUpdateNode(SplayTree tree, SplayNode node,
|
||||
SplayNode leftChild, SplayNode rightChild)
|
||||
void FreeBlockUpdateNode(SplayTree splay, Tree tree)
|
||||
{
|
||||
/* Compute the maximum size of any block in this subtree. */
|
||||
/* The value to cache is the maximum of the size of this block, */
|
||||
/* the cached value for the left subtree (if any) and the cached */
|
||||
/* value of the right subtree (if any) */
|
||||
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(node);
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(tree);
|
||||
|
||||
Size maxSize = freeNode.size;
|
||||
|
||||
if(leftChild != NULL) {
|
||||
FreeBlock leftNode = FreeBlockOfSplayNode(leftChild);
|
||||
if (TreeHasLeft(tree)) {
|
||||
FreeBlock leftNode = FreeBlockOfSplayNode(TreeLeft(tree));
|
||||
if(leftNode.maxSize > maxSize)
|
||||
maxSize = leftNode->maxSize;
|
||||
}
|
||||
|
||||
if(rightChild != NULL) {
|
||||
FreeBlock rightNode = FreeBlockOfSplayNode(rightChild);
|
||||
if (TreeHasRight(tree)) {
|
||||
FreeBlock rightNode = FreeBlockOfSplayNode(TreeRight(tree));
|
||||
if(rightNode.maxSize > maxSize)
|
||||
maxSize = rightNode->maxSize;
|
||||
}
|
||||
|
|
@ -503,9 +483,9 @@ _`.usage.callback`: updateNode callback method (see
|
|||
|
||||
_`.usage.compare`: Comparison function (see `.type.splay.compare.method`_)::
|
||||
|
||||
Compare FreeBlockCompare(void *key, SplayNode node) {
|
||||
Compare FreeBlockCompare(Tree tree, TreeKey key) {
|
||||
Addr base1, base2, limit2;
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(node);
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(tree);
|
||||
|
||||
base1 = (Addr *)key;
|
||||
base2 = freeNode->base;
|
||||
|
|
@ -522,27 +502,27 @@ _`.usage.compare`: Comparison function (see `.type.splay.compare.method`_)::
|
|||
_`.usage.test.tree`: Test tree function (see
|
||||
`.type.splay.test.tree.method`_)::
|
||||
|
||||
Bool FreeBlockTestTree(SplayTree tree, SplayNode node
|
||||
Bool FreeBlockTestTree(SplayTree splay, Tree tree
|
||||
void *closureP, unsigned long closureS) {
|
||||
/* Closure environment has wanted size as value of closureS. */
|
||||
/* Look at the cached value for the node to see if any */
|
||||
/* blocks in the subtree are big enough. */
|
||||
|
||||
Size size = (Size)closureS;
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(node);
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(tree);
|
||||
return freeNode->maxSize >= size;
|
||||
}
|
||||
|
||||
_`.usage.test.node`: Test node function (see
|
||||
`.type.splay.test.node.method`_)::
|
||||
|
||||
Bool FreeBlockTestNode(SplayTree tree, SplayNode node
|
||||
Bool FreeBlockTestNode(SplayTree splay, Tree tree
|
||||
void *closureP, unsigned long closureS) {
|
||||
/* Closure environment has wanted size as value of closureS. */
|
||||
/* Look at the size of the node to see if is big enough. */
|
||||
|
||||
Size size = (Size)closureS;
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(node);
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(tree);
|
||||
return freeNode->size >= size;
|
||||
}
|
||||
|
||||
|
|
@ -559,7 +539,7 @@ tree, merging it with an existing block if possible::
|
|||
|
||||
void FreeTreeInsert(FreeTree tree, Addr base, Addr limit) {
|
||||
SplayTree splayTree = &tree->splayTree;
|
||||
SplayNode leftNeighbour, rightNeighbour;
|
||||
Tree leftNeighbour, rightNeighbour;
|
||||
void *key = (void *)base; /* use the base of the block as the key */
|
||||
Res res;
|
||||
|
||||
|
|
@ -570,7 +550,7 @@ tree, merging it with an existing block if possible::
|
|||
|
||||
/* Look to see if the neighbours are contiguous. */
|
||||
|
||||
if (leftNeighbour != NULL &&
|
||||
if (leftNeighbour != TreeEMPTY &&
|
||||
FreeBlockLimitOfSplayNode(leftNeighbour) == base) {
|
||||
/* Inserted block is contiguous with left neighbour, so merge it. */
|
||||
/* The client housekeeping is left as an exercise to the reader. */
|
||||
|
|
@ -578,7 +558,7 @@ tree, merging it with an existing block if possible::
|
|||
/* property of the splay node. See `.function.splay.node.refresh`_ */
|
||||
SplayNodeRefresh(tree, leftNeighbour, key);
|
||||
|
||||
} else if (rightNeighbour != NULL &&
|
||||
} else if (rightNeighbour != TreeEMPTY &&
|
||||
FreeBlockBaseOfSplayNode(rightNeighbour) == limit) {
|
||||
/* Inserted block is contiguous with right neighbour, so merge it. */
|
||||
/* The client housekeeping is left as an exercise to the reader. */
|
||||
|
|
@ -607,7 +587,7 @@ block::
|
|||
Bool FreeTreeAllocate(Addr *baseReturn, Size *sizeReturn,
|
||||
FreeTree tree, Size size) {
|
||||
SplayTree splayTree = &tree->splayTree;
|
||||
SplayNode splayNode;
|
||||
Tree splayNode;
|
||||
Bool found;
|
||||
|
||||
/* look for the first node of at least the given size. */
|
||||
|
|
@ -663,7 +643,7 @@ descended, whilst looking for the node.
|
|||
|
||||
_`.impl.splay`: The key to the operation of the splay tree is the
|
||||
internal function ``SplaySplay()``. It searches the tree for a node
|
||||
with a given key and returns whether it suceeded. In the process, it
|
||||
with a given key. In the process, it
|
||||
brings the found node, or an arbitrary neighbour if not found, to the
|
||||
root of the tree. This "bring-to-root" operation is performed top-down
|
||||
during the search, and it is not the simplest possible bring-to-root
|
||||
|
|
@ -878,7 +858,7 @@ protocol error. The cases it doesn't handle will result in undefined
|
|||
behaviour and probably cause an ``AVER`` to fire. These are:
|
||||
|
||||
_`.error.bad-pointer`: Passing an invalid pointer in place of a
|
||||
``SplayTree`` or ``SplayNode``.
|
||||
``SplayTree`` or ``Tree``.
|
||||
|
||||
_`.error.bad-compare`: Initialising a ``SplayTree`` with a compare
|
||||
function that is not a valid compare function, or which doesn't
|
||||
|
|
@ -893,10 +873,6 @@ _`.error.out-of-stack`: Stack exhaustion under ``SplayTreeDescribe()``.
|
|||
Future
|
||||
------
|
||||
|
||||
_`.future.tree`: It would be possible to split the splay tree module
|
||||
into two: one that implements binary trees; and one that implements
|
||||
splay trees on top of a binary tree.
|
||||
|
||||
_`.future.parent`: The iterator could be made more efficient (in an
|
||||
amortized sense) if it didn't splay at each node. To implement this
|
||||
(whilst meeting `.req.stack`_) we really need parent pointers from the
|
||||
|
|
@ -908,10 +884,17 @@ and right-child, and the right-sibling/parent between right-sibling
|
|||
and parent. One could either use the comparator to make these
|
||||
distinctions, or steal some bits from the pointers.
|
||||
|
||||
_`.future.reverse`: The assembly phase could be made more efficient if
|
||||
the link left and link right operations were modified to add to the
|
||||
left and right trees with pointers reversed. This would remove the
|
||||
need for the assembly phase to reverse them.
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
.. [ST85] "Self-Adjusting Binary Search Trees"; Daniel Dominic Sleator,
|
||||
Robert Endre Tarjan; AT&T Bell Laboratories, Murray Hill, NJ; 1985-07;
|
||||
Journal of the ACM, Vol. 32, Num. 3, pp. 652-686, July 1985;
|
||||
<http://www.cs.cmu.edu/~sleator/papers/self-adjusting.pdf>.
|
||||
|
||||
.. [Sleator96] "Splay Trees"; Daniel Dominic Sleator; CMU, 22/02/96;
|
||||
CMU 15-211; <http://langevin.usc.edu/BST/Sleator-SplayTrees.ps>.
|
||||
|
||||
|
||||
Document History
|
||||
|
|
@ -928,6 +911,11 @@ Document History
|
|||
|
||||
- 2002-06-07 RB_ Converted from MMInfo database design document.
|
||||
|
||||
- 2014-02-22 RB_ Fixing abuses of Res and ResFAIL.
|
||||
|
||||
- 2014-03-11 RB_ Updating in response to code review. Removing
|
||||
.future.tree and .future.reverse, both now implemented.
|
||||
|
||||
.. _RB: http://www.ravenbrook.com/consultants/rb/
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue