1
Fork 0
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:
Richard Brooksby 2014-03-12 13:26:20 +00:00
commit 6f9ee39419
13 changed files with 1949 additions and 980 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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>

View file

@ -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);
}
}

View file

@ -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

View file

@ -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"

View file

@ -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>";

File diff suppressed because it is too large Load diff

View file

@ -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
View 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. 197200.
*/
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
View 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.
*/

View file

@ -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/