mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-17 01:34:21 +00:00
Implementing pointer-reversing tree traversal that does not disturb the tree shape, unlike the splay tree traversal, which flattens the tree into a list. replacing cbsiterate with this, knocking about 25% off the runtime of the test case: xc/release/djbench -x 1234 --sshift 8 mvff
Copied from Perforce Change: 184444 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
4e1d9e6a96
commit
a52bb1d3ea
3 changed files with 188 additions and 16 deletions
|
|
@ -624,12 +624,35 @@ static Res cbsSplayNodeDescribe(Tree node, mps_lib_FILE *stream)
|
|||
* See <design/cbs/#function.cbs.iterate>.
|
||||
*/
|
||||
|
||||
typedef struct CBSIterateClosure {
|
||||
CBS cbs;
|
||||
CBSIterateMethod 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, CBSIterateMethod iterate,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Tree node;
|
||||
SplayTree tree;
|
||||
CBSBlock cbsBlock;
|
||||
CBSIterateClosure closure;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
|
|
@ -639,16 +662,13 @@ void CBSIterate(CBS cbs, CBSIterateMethod iterate,
|
|||
/* .splay-iterate.slow: We assume that splay tree iteration does */
|
||||
/* searches and meter it. */
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
node = SplayTreeFirst(tree);
|
||||
while(node != NULL) {
|
||||
RangeStruct range;
|
||||
cbsBlock = cbsBlockOfNode(node);
|
||||
RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock));
|
||||
if (!(*iterate)(cbs, &range, closureP, closureS))
|
||||
break;
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
node = SplayTreeNext(tree, keyOfCBSBlock(cbsBlock));
|
||||
}
|
||||
|
||||
closure.cbs = cbs;
|
||||
closure.iterate = iterate;
|
||||
closure.closureP = closureP;
|
||||
closure.closureS = closureS;
|
||||
TreeTraverse(SplayTreeRoot(tree), tree->compare, tree->nodeKey,
|
||||
CBSIterateVisit, &closure, 0);
|
||||
|
||||
cbsLeave(cbs);
|
||||
return;
|
||||
|
|
|
|||
152
mps/code/tree.c
152
mps/code/tree.c
|
|
@ -155,7 +155,7 @@ Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
|
|||
* <http://en.wikipedia.org/wiki/Tree_traversal#Morris_in-order_traversal_using_threading>
|
||||
*
|
||||
* The tree may not be modified during the traversal, and the traversal
|
||||
* must complete.
|
||||
* must complete. TODO: Is there a way to abort early?
|
||||
*/
|
||||
|
||||
void TreeTraverseMorris(Tree tree, TreeVisitor visit,
|
||||
|
|
@ -170,7 +170,7 @@ void TreeTraverseMorris(Tree tree, TreeVisitor visit,
|
|||
node = tree;
|
||||
while (node != TreeEMPTY) {
|
||||
if (node->left == TreeEMPTY) {
|
||||
visit(node, closureP, closureS);
|
||||
(void)visit(node, closureP, closureS);
|
||||
node = node->right;
|
||||
} else {
|
||||
Tree pre = node->left;
|
||||
|
|
@ -182,7 +182,7 @@ void TreeTraverseMorris(Tree tree, TreeVisitor visit,
|
|||
}
|
||||
if (pre->right == node) {
|
||||
pre->right = TreeEMPTY;
|
||||
visit(node, closureP, closureS);
|
||||
(void)visit(node, closureP, closureS);
|
||||
node = node->right;
|
||||
break;
|
||||
}
|
||||
|
|
@ -193,6 +193,101 @@ void TreeTraverseMorris(Tree tree, TreeVisitor visit,
|
|||
}
|
||||
|
||||
|
||||
/* TreeTraverse -- traverse tree using pointer reversal */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void TreeTraverse(Tree tree,
|
||||
TreeCompare compare,
|
||||
TreeKeyMethod key,
|
||||
TreeVisitor visit, void *closureP, Size closureS)
|
||||
{
|
||||
Tree parent, node;
|
||||
|
||||
AVER(TreeCheck(tree));
|
||||
AVER(FUNCHECK(visit));
|
||||
/* closureP, closureS arbitrary */
|
||||
|
||||
parent = TreeEMPTY;
|
||||
node = tree;
|
||||
|
||||
if (node == TreeEMPTY)
|
||||
return;
|
||||
|
||||
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;
|
||||
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;
|
||||
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
|
||||
|
|
@ -292,6 +387,57 @@ Tree TreeReverseRightSpine(Tree tree)
|
|||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
|
|
|
|||
|
|
@ -76,7 +76,11 @@ extern Compare TreeFind(Tree *treeReturn, Tree root,
|
|||
extern Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
|
||||
TreeKey key, TreeCompare compare);
|
||||
|
||||
typedef void TreeVisitor(Tree tree, void *closureP, Size closureS);
|
||||
typedef Bool TreeVisitor(Tree tree, void *closureP, Size closureS);
|
||||
extern void TreeTraverse(Tree tree,
|
||||
TreeCompare compare,
|
||||
TreeKeyMethod key,
|
||||
TreeVisitor visit, void *closureP, Size closureS);
|
||||
extern void TreeTraverseMorris(Tree tree, TreeVisitor visit,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
|
|
@ -84,6 +88,8 @@ 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 */
|
||||
|
|
|
|||
Loading…
Reference in a new issue