Example #1
0
Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth,
                      TreeDescribeFunction nodeDescribe)
{
  Res res;

  if (!TESTT(SplayTree, splay))
    return ResFAIL;
  if (stream == NULL)
    return ResFAIL;
  if (nodeDescribe == NULL)
    return ResFAIL;

  res = WriteF(stream, depth,
               "Splay $P {\n", (WriteFP)splay,
               "  compare $F\n", (WriteFF)splay->compare,
               "  nodeKey $F\n", (WriteFF)splay->nodeKey,
               "  updateNode $F\n", (WriteFF)splay->updateNode,
               NULL);
  if (res != ResOK)
    return res;

  if (SplayTreeRoot(splay) != TreeEMPTY) {
    res = WriteF(stream, depth, "  tree ", NULL);
    if (res != ResOK)
      return res;
    res = SplayNodeDescribe(SplayTreeRoot(splay), stream, nodeDescribe);
    if (res != ResOK)
      return res;
  }

  res = WriteF(stream, depth, "\n} Splay $P\n", (WriteFP)splay, NULL);
  return res;
}
Example #2
0
static Tree SplayTreeSuccessor(SplayTree splay)
{
  Tree oldRoot, newRoot;

  AVERT(SplayTree, splay);
  AVER(!SplayTreeIsEmpty(splay));

  oldRoot = SplayTreeRoot(splay);

  if (!TreeHasRight(oldRoot))
    return TreeEMPTY; /* No successor */

  /* temporarily chop off the left half-tree, inclusive of root */
  SplayTreeSetRoot(splay, TreeRight(oldRoot));
  TreeSetRight(oldRoot, TreeEMPTY);
  (void)SplaySplay(splay, NULL, compareLess);
  newRoot = SplayTreeRoot(splay);
  AVER(newRoot != TreeEMPTY);
  AVER(TreeLeft(newRoot) == TreeEMPTY);
  TreeSetLeft(newRoot, oldRoot);
  splay->updateNode(splay, oldRoot);
  splay->updateNode(splay, newRoot);

  return newRoot;
}
Example #3
0
Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay,
                    SplayTestNodeFunction testNode,
                    SplayTestTreeFunction testTree,
                    void *closureP, Size closureS)
{
  SplayFindClosureStruct closureStruct;
  Bool found;

  AVER(nodeReturn != NULL);
  AVERT(SplayTree, splay);
  AVER(FUNCHECK(testNode));
  AVER(FUNCHECK(testTree));

  if (SplayTreeIsEmpty(splay) ||
      !testTree(splay, SplayTreeRoot(splay), closureP, closureS))
    return FALSE; /* no suitable nodes in tree */

  closureStruct.p = closureP;
  closureStruct.s = closureS;
  closureStruct.testNode = testNode;
  closureStruct.testTree = testTree;
  closureStruct.splay = splay;
  closureStruct.found = FALSE;

  found = SplaySplay(splay, &closureStruct,
                     SplayFindFirstCompare) == CompareEQUAL &&
          closureStruct.found;

  while (!found) {
    Tree oldRoot, newRoot;
    
    /* FIXME: Rename to "seen" and "not yet seen" or something. */
    oldRoot = SplayTreeRoot(splay);
    newRoot = TreeRight(oldRoot);

    if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, closureP, closureS))
      return FALSE; /* no suitable nodes in the rest of the tree */
  
    /* Temporarily chop off the left half-tree, inclusive of root,
       so that the search excludes any nodes we've seen already. */
    SplayTreeSetRoot(splay, newRoot);
    TreeSetRight(oldRoot, TreeEMPTY);

    found = SplaySplay(splay, &closureStruct,
                       SplayFindFirstCompare) == CompareEQUAL &&
            closureStruct.found;

    /* Restore the left tree, then rotate left so that the node we
       just splayed is at the root.  Update both. */
    newRoot = SplayTreeRoot(splay);
    TreeSetRight(oldRoot, newRoot);
    SplayTreeSetRoot(splay, oldRoot);
    TreeRotateLeft(&splay->root);
    splay->updateNode(splay, oldRoot);
    splay->updateNode(splay, newRoot);
  }

  *nodeReturn = SplayTreeRoot(splay);
  return TRUE;
}
Example #4
0
Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
                   SplayTestNodeFunction testNode,
                   SplayTestTreeFunction testTree,
                   void *testClosure)
{
  SplayFindClosureStruct closureStruct;
  Bool found;

  AVER_CRITICAL(nodeReturn != NULL);
  AVERT_CRITICAL(SplayTree, splay);
  AVER_CRITICAL(FUNCHECK(testNode));
  AVER_CRITICAL(FUNCHECK(testTree));

  if (SplayTreeIsEmpty(splay) ||
      !testTree(splay, SplayTreeRoot(splay), testClosure))
    return FALSE; /* no suitable nodes in tree */

  closureStruct.testClosure = testClosure;
  closureStruct.testNode = testNode;
  closureStruct.testTree = testTree;
  closureStruct.splay = splay;

  found = SplaySplay(splay, &closureStruct,
                     SplayFindLastCompare) == CompareEQUAL &&
          closureStruct.found;

  while (!found) {
    Tree oldRoot, newRoot;
    
    oldRoot = SplayTreeRoot(splay);
    newRoot = TreeLeft(oldRoot);

    if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, testClosure))
      return FALSE; /* no suitable nodes in the rest of the tree */
  
    /* Temporarily chop off the right half-tree, inclusive of root,
       so that the search excludes any nodes we've seen already. */
    SplayTreeSetRoot(splay, newRoot);
    TreeSetLeft(oldRoot, TreeEMPTY);

    found = SplaySplay(splay, &closureStruct,
                       SplayFindLastCompare) == CompareEQUAL &&
            closureStruct.found;

    /* Restore the right tree, then rotate right so that the node we
       just splayed is at the root.  Update both. */
    newRoot = SplayTreeRoot(splay);
    TreeSetLeft(oldRoot, newRoot);
    SplayTreeSetRoot(splay, oldRoot);
    TreeRotateRight(&splay->root);
    splay->updateNode(splay, oldRoot);
    splay->updateNode(splay, newRoot);
  }

  *nodeReturn = SplayTreeRoot(splay);
  return TRUE;
}
Bool SplayFindLast(SplayNode *nodeReturn, SplayTree tree,
                   SplayTestNodeMethod testNode,
                   SplayTestTreeMethod testTree,
                   void *closureP, unsigned long closureS)
{
    SplayNode node;
    SplayFindClosureStruct closureStruct;

    AVER(nodeReturn != NULL);
    AVERT(SplayTree, tree);
    AVER(FUNCHECK(testNode));
    AVER(FUNCHECK(testTree));

    node = SplayTreeRoot(tree);

    if (node == NULL || !(*testTree)(tree, node, closureP, closureS))
        return FALSE; /* no suitable nodes in tree */

    closureStruct.p = closureP;
    closureStruct.s = closureS;
    closureStruct.testNode = testNode;
    closureStruct.testTree = testTree;
    closureStruct.tree = tree;

    if (SplaySplay(&node, tree, (void *)&closureStruct,
                   &SplayFindLastCompare)) {
        *nodeReturn = node;
        return TRUE;
    } else {
        return FALSE;
    }
}
static SplayNode SplayTreeSuccessor(SplayTree tree, void *key) {
    SplayNode oldRoot, newRoot;

    AVERT(SplayTree, tree);

    oldRoot = SplayTreeRoot(tree);
    AVERT(SplayNode, oldRoot);

    if (SplayNodeRightChild(oldRoot) == NULL) {
        newRoot = NULL; /* No successor */
    } else {
        /* temporarily chop off the left half-tree, inclusive of root */
        SplayTreeSetRoot(tree, SplayNodeRightChild(oldRoot));
        SplayNodeSetRightChild(oldRoot, NULL);
        if (SplaySplay(&newRoot, tree, key, tree->compare)) {
            NOTREACHED; /* Another matching node found */
        } else {
            AVER(SplayNodeLeftChild(newRoot) == NULL);
            SplayNodeSetLeftChild(newRoot, oldRoot);
        }

        if (tree->updateNode != NULL) {
            SplayNodeUpdate(tree, oldRoot);
            SplayNodeUpdate(tree, newRoot);
        }
    }

    return newRoot;
}
Example #7
0
static Compare SplaySplay(SplayTree splay, TreeKey key,
                          TreeCompareFunction compare)
{
  Compare cmp;
  SplayStateStruct stateStruct;

#ifdef SPLAY_DEBUG
  Count count = SplayDebugCount(splay);
#endif

  /* Short-circuit common cases.  Splay trees often bring recently
     acccessed nodes to the root. */
  if (SplayTreeIsEmpty(splay) ||
      compare(SplayTreeRoot(splay), key) == CompareEQUAL)
    return CompareEQUAL;

  if (SplayHasUpdate(splay)) {
    cmp = SplaySplitRev(&stateStruct, splay, key, compare);
    SplayAssembleRev(splay, &stateStruct);
  } else {
    cmp = SplaySplitDown(&stateStruct, splay, key, compare);
    SplayAssembleDown(splay, &stateStruct);
  }

  SplayTreeSetRoot(splay, stateStruct.middle);

#ifdef SPLAY_DEBUG
  AVER(count == SplayDebugCount(splay));
#endif

  return cmp;
}
Res SplayTreeInsert(SplayTree tree, SplayNode node, void *key) {
    SplayNode neighbour;

    AVERT(SplayTree, tree);
    AVERT(SplayNode, node);
    AVER(SplayNodeLeftChild(node) == NULL);
    AVER(SplayNodeRightChild(node) == NULL);

    if (SplayTreeRoot(tree) == NULL) {
        SplayTreeSetRoot(tree, node);
    } else if (SplaySplay(&neighbour, tree, key, tree->compare)) {
        return ResFAIL;
    } else {
        AVER(SplayTreeRoot(tree) == neighbour);
        switch(SplayCompare(tree, key, neighbour)) {

        case CompareGREATER: { /* left neighbour */
            SplayTreeSetRoot(tree, node);
            SplayNodeSetRightChild(node, SplayNodeRightChild(neighbour));
            SplayNodeSetLeftChild(node, neighbour);
            SplayNodeSetRightChild(neighbour, NULL);
        }
        break;

        case CompareLESS: { /* right neighbour */
            SplayTreeSetRoot(tree, node);
            SplayNodeSetLeftChild(node, SplayNodeLeftChild(neighbour));
            SplayNodeSetRightChild(node, neighbour);
            SplayNodeSetLeftChild(neighbour, NULL);
        }
        break;

        case CompareEQUAL:
        default: {
            NOTREACHED;
        }
        break;
        }

        if (tree->updateNode != NULL) {
            SplayNodeUpdate(tree, neighbour);
            SplayNodeUpdate(tree, node);
        }
    }

    return ResOK;
}
Example #9
0
Bool SplayTreeInsert(SplayTree splay, Tree node)
{
  Tree neighbour;

  AVERT(SplayTree, splay);
  AVERT(Tree, node);
  AVER(TreeLeft(node) == TreeEMPTY);
  AVER(TreeRight(node) == TreeEMPTY);

  if (SplayTreeIsEmpty(splay)) {
    SplayTreeSetRoot(splay, node);
    return TRUE;
  }
  
  switch (SplaySplay(splay, splay->nodeKey(node), splay->compare)) {
  default:
    NOTREACHED;
    /* fall through */
  case CompareEQUAL: /* duplicate node */
    return FALSE;
    
  case CompareGREATER: /* left neighbour is at root */
    neighbour = SplayTreeRoot(splay);
    SplayTreeSetRoot(splay, node);
    TreeSetRight(node, TreeRight(neighbour));
    TreeSetLeft(node, neighbour);
    TreeSetRight(neighbour, TreeEMPTY);
    break;

  case CompareLESS: /* right neighbour is at root */
    neighbour = SplayTreeRoot(splay);
    SplayTreeSetRoot(splay, node);
    TreeSetLeft(node, TreeLeft(neighbour));
    TreeSetRight(node, neighbour);
    TreeSetLeft(neighbour, TreeEMPTY);
    break;
  }

  splay->updateNode(splay, neighbour);
  splay->updateNode(splay, node);
  return TRUE;
}
Example #10
0
Bool SplayTreeFind(Tree *nodeReturn, SplayTree splay, TreeKey key) {
  AVERT(SplayTree, splay);
  AVER(nodeReturn != NULL);

  if (SplayTreeIsEmpty(splay))
    return FALSE;

  if (SplaySplay(splay, key, splay->compare) != CompareEQUAL)
    return FALSE;

  *nodeReturn = SplayTreeRoot(splay);
  return TRUE;
}
Example #11
0
Bool SplayTreeDelete(SplayTree splay, Tree node)
{
  Tree leftLast;
  Compare cmp;

  AVERT(SplayTree, splay);
  AVERT(Tree, node);

  if (SplayTreeIsEmpty(splay))
    return FALSE;

  cmp = SplaySplay(splay, splay->nodeKey(node), splay->compare);
  AVER(cmp != CompareEQUAL || SplayTreeRoot(splay) == node);

  if (cmp != CompareEQUAL) {
    return FALSE;
  } else if (!TreeHasLeft(node)) {
    SplayTreeSetRoot(splay, TreeRight(node));
    TreeClearRight(node);
  } else if (!TreeHasRight(node)) {
    SplayTreeSetRoot(splay, TreeLeft(node));
    TreeClearLeft(node);
  } else {
    Tree rightHalf = TreeRight(node);
    TreeClearRight(node);
    SplayTreeSetRoot(splay, TreeLeft(node));
    TreeClearLeft(node);
    (void)SplaySplay(splay, NULL, compareGreater);
    leftLast = SplayTreeRoot(splay);
    AVER(leftLast != TreeEMPTY);
    AVER(!TreeHasRight(leftLast));
    TreeSetRight(leftLast, rightHalf);
    splay->updateNode(splay, leftLast);
  }

  TreeFinish(node);

  return TRUE;
}
Example #12
0
void SplayNodeRefresh(SplayTree splay, Tree node)
{
  Compare cmp;

  AVERT(SplayTree, splay);
  AVERT(Tree, node);
  AVER(!SplayTreeIsEmpty(splay)); /* must contain node, at least */

  cmp = SplaySplay(splay, splay->nodeKey(node), splay->compare);
  AVER(cmp == CompareEQUAL);
  AVER(SplayTreeRoot(splay) == node);

  splay->updateNode(splay, node);
}
SplayNode SplayTreeFirst(SplayTree tree, void *zeroKey) {
    SplayNode node;
    AVERT(SplayTree, tree);

    if (SplayTreeRoot(tree) == NULL) {
        node = NULL;
    } else if (SplaySplay(&node, tree, zeroKey, tree->compare)) {
        NOTREACHED;
    } else {
        AVER(SplayNodeLeftChild(node) == NULL);
    }

    return node;
}
Bool SplayRoot(SplayNode *nodeReturn, SplayTree tree)
{
    SplayNode node;

    AVER(nodeReturn != NULL);
    AVERT(SplayTree, tree);

    node = SplayTreeRoot(tree);
    if (node == NULL)
        return FALSE;
    else {
        *nodeReturn = node;
        return TRUE;
    }
}
Res SplayTreeDescribe(SplayTree tree, mps_lib_FILE *stream,
                      SplayNodeDescribeMethod nodeDescribe) {
    Res res;

#if defined(AVER_AND_CHECK)
    if (!SplayTreeCheck(tree)) return ResFAIL;
    if (stream == NULL) return ResFAIL;
    if (!FUNCHECK(nodeDescribe)) return ResFAIL;
#endif

    res = WriteF(stream,
                 "Splay $P {\n", (WriteFP)tree,
                 "  compare $F\n", (WriteFF)tree->compare,
                 NULL);
    if (res != ResOK) return res;

    if (SplayTreeRoot(tree) != NULL) {
        res = SplayNodeDescribe(SplayTreeRoot(tree), stream, nodeDescribe);
        if (res != ResOK) return res;
    }

    res = WriteF(stream, "\n}\n", NULL);
    return res;
}
Example #16
0
Tree SplayTreeFirst(SplayTree splay) {
  Tree node;

  AVERT(SplayTree, splay);

  if (SplayTreeIsEmpty(splay))
    return TreeEMPTY;

  (void)SplaySplay(splay, NULL, compareLess);
  node = SplayTreeRoot(splay);
  AVER(node != TreeEMPTY);
  AVER(TreeLeft(node) == TreeEMPTY);

  return node;
}
Example #17
0
Tree SplayTreeNext(SplayTree splay, TreeKey oldKey) {
  AVERT(SplayTree, splay);

  if (SplayTreeIsEmpty(splay))
    return TreeEMPTY;
  
  /* Make old node the root.  Probably already is.  We don't mind if the
     node has been deleted, or replaced by a node with the same key. */
  switch (SplaySplay(splay, oldKey, splay->compare)) {
  default:
    NOTREACHED;
    /* defensive fall-through */
  case CompareLESS:
    return SplayTreeRoot(splay);

  case CompareGREATER:
  case CompareEQUAL:
    return SplayTreeSuccessor(splay);
  }
}
static Bool SplaySplay(SplayNode *nodeReturn, SplayTree tree,
                       void *key, SplayCompareMethod compareMethod) {
    /* The sides structure avoids a boundary case in SplayLink* */
    SplayNodeStruct sides; /* rightTop and leftTop */
    SplayNode top, leftLast, rightFirst;
    Bool found;
    Compare compareTop;

    AVERT(SplayTree, tree);
    AVER(nodeReturn != NULL);
    AVER(FUNCHECK(compareMethod));

    top = SplayTreeRoot(tree); /* will be copied back at end */

    if (top == NULL) {
        *nodeReturn = NULL;
        return FALSE;
    }

    /* short-circuit case where node is already top */
    compareTop = (*compareMethod)(key, top);
    if (compareTop == CompareEQUAL) {
        *nodeReturn = top;
        return TRUE;
    }

    SplayNodeInit(&sides); /* left and right trees now NULL */
    leftLast = &sides;
    rightFirst = &sides;

    while(TRUE) {
        /* compareTop is already initialised above. */
        switch(compareTop) {

        case CompareLESS: {
            SplayNode topLeft = SplayNodeLeftChild(top);
            if (topLeft == NULL) {
                found = FALSE;
                goto assemble;
            } else {
                Compare compareTopLeft = (*compareMethod)(key, topLeft);

                switch(compareTopLeft) {

                case CompareEQUAL: {                 /* zig */
                    SplayLinkRight(&top, &rightFirst);
                    found = TRUE;
                    goto assemble;
                    } /* break; */

                case CompareLESS: {                  /* zig-zig */
                    if (SplayNodeLeftChild(topLeft) == NULL)
                        goto terminalZig;
                    SplayRotateRight(&top, tree);
                    SplayLinkRight(&top, &rightFirst);
                }
                break;

                case CompareGREATER: {               /* zig-zag */
                    if (SplayNodeRightChild(topLeft) == NULL)
                        goto terminalZig;
                    SplayLinkRight(&top, &rightFirst);
                    SplayLinkLeft(&top, &leftLast);
                }
                break;

                default: {
                    NOTREACHED;
                }
                break;
                }
            }
        }
        break;

        case CompareGREATER: {
            SplayNode topRight = SplayNodeRightChild(top);
            if (topRight == NULL) {
                found = FALSE;
                goto assemble;
            } else {
                Compare compareTopRight = (*compareMethod)(key, topRight);

                switch(compareTopRight) {

                case CompareEQUAL: {                 /* zag */
                    SplayLinkLeft(&top, &leftLast);
                    found = TRUE;
                    goto assemble;
                    } /* break; */

                case CompareGREATER: {               /* zag-zag */
                    if (SplayNodeRightChild(topRight) == NULL)
                        goto terminalZag;
                    SplayRotateLeft(&top, tree);
                    SplayLinkLeft(&top, &leftLast);
                }
                break;

                case CompareLESS: {                  /* zag-zig */
                    if (SplayNodeLeftChild(topRight) == NULL)
                        goto terminalZag;
                    SplayLinkLeft(&top, &leftLast);
                    SplayLinkRight(&top, &rightFirst);
                }
                break;

                default: {
                    NOTREACHED;
                }
                break;
                }
            }
        }
        break;

        case CompareEQUAL: {
            found = TRUE;
            goto assemble;
            } /* break; */

        default: {
            NOTREACHED;
        }
        break;
        }
        compareTop = (*compareMethod)(key, top);
    } /* end while(TRUE) */

terminalZig:
    SplayLinkRight(&top, &rightFirst);
    found = FALSE;
    goto assemble;

terminalZag:
    SplayLinkLeft(&top, &leftLast);
    found = FALSE;
    goto assemble;

assemble:
    SplayAssemble(tree, top,
                  SplayNodeRightChild(&sides), leftLast,
                  SplayNodeLeftChild(&sides), rightFirst);

    SplayTreeSetRoot(tree, top);
    *nodeReturn = top;

    return found;
}
Example #19
0
Count SplayDebugCount(SplayTree splay)
{
  AVERT(SplayTree, splay);
  return TreeDebugCount(SplayTreeRoot(splay), splay->compare, splay->nodeKey);
}
Example #20
0
static Compare SplaySplitRev(SplayStateStruct *stateReturn,
                             SplayTree splay, TreeKey key,
                             TreeCompareFunction compare)
{
  Tree middle, leftLast, rightFirst;
  Compare cmp;

  AVERT(SplayTree, splay);
  AVER(FUNCHECK(compare));
  AVER(!SplayTreeIsEmpty(splay));
  
  leftLast = TreeEMPTY;
  rightFirst = TreeEMPTY;
  middle = SplayTreeRoot(splay);
  for (;;) {
    cmp = compare(middle, key);
    switch(cmp) {
    default:
      NOTREACHED;
      /* defensive fall-through */
    case CompareEQUAL:
      goto stop;

    case CompareLESS:
      if (!TreeHasLeft(middle))
        goto stop;
      middle = SplayZigRev(middle, &rightFirst);
      cmp = compare(middle, key);
      switch(cmp) {
      default:
        NOTREACHED;
        /* defensive fall-through */
      case CompareEQUAL:
        goto stop;
      case CompareLESS:
        if (!TreeHasLeft(middle))
          goto stop;
        middle = SplayZigZigRev(middle, &rightFirst);
        splay->updateNode(splay, TreeRight(rightFirst));
        break;
      case CompareGREATER:
        if (!TreeHasRight(middle))
          goto stop;
        middle = SplayZagRev(middle, &leftLast);
        break;
      }
      break;

    case CompareGREATER:
      if (!TreeHasRight(middle))
        goto stop;
      middle = SplayZagRev(middle, &leftLast);
      cmp = compare(middle, key);
      switch(cmp) {
      default:
        NOTREACHED;
        /* defensive fall-through */
      case CompareEQUAL:
        goto stop;
      case CompareGREATER:
        if (!TreeHasRight(middle))
          goto stop;
        middle = SplayZagZagRev(middle, &leftLast);
        splay->updateNode(splay, TreeLeft(leftLast));
        break;
      case CompareLESS:
        if (!TreeHasLeft(middle))
          goto stop;
        middle = SplayZigRev(middle, &rightFirst);
        break;
      }
      break;
    }
  }

stop:
  stateReturn->middle = middle;
  stateReturn->leftLast = leftLast;
  stateReturn->rightFirst = rightFirst;
  return cmp;
}
Example #21
0
static Compare SplaySplitDown(SplayStateStruct *stateReturn,
                              SplayTree splay, TreeKey key,
                              TreeCompareFunction compare)
{
  TreeStruct sentinel;
  Tree middle, leftLast, rightFirst, leftPrev, rightNext;
  Compare cmp;

  AVERT(SplayTree, splay);
  AVER(FUNCHECK(compare));
  AVER(!SplayTreeIsEmpty(splay));
  AVER(!SplayHasUpdate(splay));
  
  TreeInit(&sentinel);
  leftLast = &sentinel;
  rightFirst = &sentinel;
  middle = SplayTreeRoot(splay);
  for (;;) {
    cmp = compare(middle, key);
    switch(cmp) {
    default:
      NOTREACHED;
      /* defensive fall-through */
    case CompareEQUAL:
      goto stop;

    case CompareLESS:
      if (!TreeHasLeft(middle))
        goto stop;
      middle = SplayZig(middle, &rightFirst, &rightNext);
      cmp = compare(middle, key);
      switch(cmp) {
      default:
        NOTREACHED;
        /* defensive fall-through */
      case CompareEQUAL:
        goto stop;
      case CompareLESS:
        if (!TreeHasLeft(middle))
          goto stop;
        middle = SplayZigZig(middle, &rightFirst, rightNext);
        break;
      case CompareGREATER:
        if (!TreeHasRight(middle))
          goto stop;
        middle = SplayZag(middle, &leftLast, &leftPrev);
        break;
      }
      break;

    case CompareGREATER:
      if (!TreeHasRight(middle))
        goto stop;
      middle = SplayZag(middle, &leftLast, &leftPrev);
      cmp = compare(middle, key);
      switch(cmp) {
      default:
        NOTREACHED;
        /* defensive fall-through */
      case CompareEQUAL:
        goto stop;
      case CompareGREATER:
        if (!TreeHasRight(middle))
          goto stop;
        middle = SplayZagZag(middle, &leftLast, leftPrev);
        break;
      case CompareLESS:
        if (!TreeHasLeft(middle))
          goto stop;
        middle = SplayZig(middle, &rightFirst, &rightNext);
        break;
      }
      break;
    }
  }

stop:
  stateReturn->middle = middle;
  stateReturn->left = TreeRight(&sentinel);
  stateReturn->leftLast = leftLast == &sentinel ? TreeEMPTY : leftLast;
  stateReturn->right = TreeLeft(&sentinel);
  stateReturn->rightFirst = rightFirst == &sentinel ? TreeEMPTY : rightFirst;
  return cmp;
}