/*
         x          y
        /          / \
       y    -->   a   x
      / \            /
     a   b          b
*/
void QFragmentMapData::rotateRight(uint x)
{
    uint y = X.left;
    uint p = X.parent;
    PMDEBUG("    rotateRight on x=%d (y=%d, p=%d)", x, y, p);

    if (y) {
        X.left = Y.right;
        if (Y.right)
            F(Y.right).parent = x;
        Y.right = x;
        Y.parent = p;
    } else {
        X.left = 0;
    }
    if (!p) {
        Q_ASSERT(head->root == x);
        head->root = y;
    }
    else if (x == P.right)
        P.right = y;
    else
        P.left = y;
    X.parent = y;
    X.size_left -= Y.size_left + Y.size;
    X.weight_left -= Y.weight_left + 1;

    inorder();
    check();
}
void QFragmentMapData::rebalance(uint x)
{
    X.color = Red;

    PMDEBUG("  -> rebalance x=%d", x);
    inorder();

    while (X.parent && F(X.parent).color == Red) {
        uint p = X.parent;
        uint pp = P.parent;
        Q_ASSERT(pp);
        if (p == PP.left) {
            uint y = PP.right;
            if (y && Y.color == Red) {
                P.color = Black;
                Y.color = Black;
                PP.color = Red;
                x = pp;
            } else {
                if (x == P.right) {
                    x = p;
                    rotateLeft(x);
                    p = X.parent;
                    pp = P.parent;
                }
                P.color = Black;
                if (pp) {
                    PP.color = Red;
                    rotateRight(pp);
                }
            }
        } else {
            uint y = PP.left;
            if (y && Y.color == Red) {
                P.color = Black;
                Y.color = Black;
                PP.color = Red;
                x = pp;
            } else {
                if (x == P.left) {
                    x = p;
                    rotateRight(x);
                    p = X.parent;
                    pp = P.parent;
                }
                P.color = Black;
                if (pp) {
                    PP.color = Red;
                    rotateLeft(pp);
                }
            }
        }
    }
    F(root()).color = Black;
    check();
}
void QFragmentMapData::freeFragment(uint i)
{
    PMDEBUG("===> freeFragment at %d", i);
#ifndef QT_NO_DEBUG
    Q_ASSERT(F(i).parent != 0xdeadbeef);
    if (head->freelist < head->allocated) {
        Q_ASSERT(F(head->freelist).parent == 0xdeadbeef);
    }
    F(i).parent = 0xdeadbeef;
#endif
    F(i).right = head->freelist;
    head->freelist = i;

    --head->node_count;
}
Esempio n. 4
0
void QTextDocumentPrivate::appendUndoItem(const QTextUndoCommand &c)
{
    PMDEBUG("appendUndoItem, command=%d enabled=%d", c.command, undoEnabled);
    if (!undoEnabled)
        return;
    if (undoState < undoStack.size())
        truncateUndoStack();

    if (!undoStack.isEmpty() && modified) {
        QTextUndoCommand &last = undoStack[undoState - 1];
        if (last.tryMerge(c))
            return;
    }
    if (modifiedState > undoState)
        modifiedState = -1;
    undoStack.append(c);
    undoState++;
    emitUndoAvailable(true);
    emitRedoAvailable(false);
    emit document()->undoCommandAdded();
}
uint QFragmentMapData::createFragment()
{
    Q_ASSERT(head->freelist <= head->allocated);

    uint freePos = head->freelist;
    if (freePos == head->allocated) {
        // need to create some free space
        uint needed = qAllocMore((freePos+1)*fragmentSize, 0);
        Q_ASSERT(needed/fragmentSize > head->allocated);
        fragments = (char *)realloc(fragments, needed);
        head->allocated = needed/fragmentSize;
        F(freePos).right = 0;
#ifndef QT_NO_DEBUG
        for (uint i = freePos; i < head->allocated; ++i)
            F(i).parent = 0xdeadbeef;
#endif
    }

    uint nextPos = F(freePos).right;
    if (!nextPos) {
        nextPos = freePos+1;
        if (nextPos < head->allocated)
            F(nextPos).right = 0;
    }

    head->freelist = nextPos;

#ifndef QT_NO_DEBUG
    Q_ASSERT(F(freePos).parent == 0xdeadbeef);
    F(freePos).parent = 0;
    if (nextPos < head->allocated) {
        Q_ASSERT(F(nextPos).parent == 0xdeadbeef);
    }
#endif

    ++head->node_count;

    PMDEBUG("===> createFragment at %d", freePos);
    return freePos;
}
uint QFragmentMapData::insert_single(int key, uint length)
{
    Q_ASSERT(!findNode(key) || (int)this->position(findNode(key)) == key);

    uint z = createFragment();

    Z.size = length;
    Z.left = 0;
    Z.right = 0;
    Z.size_left = 0;
    Z.weight_left = 0;

    PMDEBUG("inserting with key %d", key);
    uint y = 0;
    uint x = root();

    Q_ASSERT(!x || X.parent == 0);

    uint s = key;
//     inorder();
    bool right = false;
    while (x) {
        y = x;
//          PMDEBUG("x=%p: x->size_left=%d, key=%d, s=%d", x, x->size_left, x->key(), s);
        if (s <= X.size_left) {
            x = X.left;
            right = false;
        } else {
            s -= X.size_left + X.size;
            x = X.right;
            right = true;
        }
    }
//     if (y)
//         PMDEBUG("  y=%p: y->size_left=%d, y->key=%d s=%d", y, y->size_left, y ? y->key() : -1, s);

    Z.parent = y;
    if (!y) {
        head->root = z;
    } else if (!right) {
//          PMDEBUG("inserting left");
        Y.left = z;
        Y.size_left = Z.size;
        Y.weight_left = 1;
    } else {
//          PMDEBUG("inserting right");
        Y.right = z;
    }
    while (y && Y.parent) {
        uint p = Y.parent;
        if (P.left == y) {
            P.size_left += Z.size;
            P.weight_left += 1;
        }
        y = p;
    }
//     PMDEBUG("before rebalance");
//     inorder();
    rebalance(z);

    inorder();
    PMDEBUG("end insert\n");

    return z;
}
uint QFragmentMapData::erase_single(uint z)
{
    uint w = previous(z);
    uint y = z;
    uint x;
    uint p;

    if (!Y.left) {
        x = Y.right;
    } else if (!Y.right) {
        x = Y.left;
    } else {
        y = Y.right;
        while (Y.left)
            y = Y.left;
        x = Y.right;
    }

    PMDEBUG("removeAndRebalance on %d (x=%d, y=%d)", z, x, y);
    inorder();

    if (y != z) {
        F(Z.left).parent = y;
        Y.left = Z.left;
        Y.size_left = Z.size_left;
        Y.weight_left = Z.weight_left;
        if (y != Z.right) {
            /*
                     z                y
                    / \              / \
                   a   b            a   b
                      /                /
                    ...     -->      ...
                    /                /
                   y                x
                  / \
                 0   x
             */
            p = Y.parent;
            if (x)
                X.parent = p;
            P.left = x;
            Y.right = Z.right;
            F(Z.right).parent = y;
            uint n = p;
            while (n != y) {
                N.size_left -= Y.size;
                N.weight_left -= 1;
                n = N.parent;
            }
        } else {
            /*
                     z                y
                    / \              / \
                   a   y     -->    a   x
                      / \
                     0   x
             */
            p = y;
        }
        uint zp = Z.parent;
        if (!zp) {
            Q_ASSERT(head->root == z);
            head->root = y;
        } else if (F(zp).left == z) {
            F(zp).left = y;
            F(zp).size_left -= Z.size;
            F(zp).weight_left -= 1;
        } else {
            F(zp).right = y;
        }
        Y.parent = zp;
        // Swap the colors
        uint c = Y.color;
        Y.color = Z.color;
        Z.color = c;
        y = z;
    } else {
        /*
                p          p            p          p
               /          /              \          \
              z    -->   x                z  -->     x
              |                           |
              x                           x
         */
        p = Z.parent;
        if (x)
            X.parent = p;
        if (!p) {
            Q_ASSERT(head->root == z);
            head->root = x;
        } else if (P.left == z) {
            P.left = x;
            P.size_left -= Z.size;
            P.weight_left -= 1;
        } else {
            P.right = x;
        }
    }
    uint n = z;
    while (N.parent) {
        uint p = N.parent;
        if (P.left == n) {
            PMDEBUG("reducing size_left of %d by %d", N.parent, Z.size);
            P.size_left -= Z.size;
            P.weight_left -= 1;
        }
        n = p;
    }

    freeFragment(z);
    PMDEBUG("after removal");
    inorder();
    check();


    if (Y.color != Red) {
        while (X.parent && (x == 0 || X.color == Black)) {
            if (x == P.left) {
                uint w = P.right;
                if (W.color == Red) {
                    W.color = Black;
                    P.color = Red;
                    rotateLeft(p);
                    w = P.right;
                }
                if ((W.left == 0 || F(W.left).color == Black) &&
                    (W.right == 0 || F(W.right).color == Black)) {
                    W.color = Red;
                    x = p;
                    p = X.parent;
                } else {
                    if (W.right == 0 || F(W.right).color == Black) {
                        if (W.left)
                            F(W.left).color = Black;
                        W.color = Red;
                        rotateRight(P.right);
                        w = P.right;
                    }
                    W.color = P.color;
                    P.color = Black;
                    if (W.right)
                        F(W.right).color = Black;
                    rotateLeft(p);
                    break;
                }
            } else {
                uint w = P.left;
                if (W.color == Red) {
                    W.color = Black;
                    P.color = Red;
                    rotateRight(p);
                    w = P.left;
                }
                if ((W.right == 0 || F(W.right).color == Black) &&
                    (W.left == 0 || F(W.left).color == Black)) {
                    W.color = Red;
                    x = p;
                    p = X.parent;
                } else {
                    if (W.left == 0 || F(W.left).color == Black) {
                        if (W.right)
                            F(W.right).color = Black;
                        W.color = Red;
                        rotateLeft(P.left);
                        w = P.left;
                    }
                    W.color = P.color;
                    P.color = Black;
                    if (W.left)
                        F(W.left).color = Black;
                    rotateRight(p);
                    break;
                }
            }
        }
        if (x)
            X.color = Black;
    }

    PMDEBUG("after rebalance");
    inorder();
    check();

    return w;
}
Esempio n. 8
0
int QTextDocumentPrivate::undoRedo(bool undo)
{
    PMDEBUG("%s, undoState=%d, undoStack size=%d", undo ? "undo:" : "redo:", undoState, undoStack.size());
    if (!undoEnabled || (undo && undoState == 0) || (!undo && undoState == undoStack.size()))
        return -1;

    undoEnabled = false;
    beginEditBlock();
    while (1) {
        if (undo)
            --undoState;
        QTextUndoCommand &c = undoStack[undoState];
        int resetBlockRevision = c.pos;

	switch(c.command) {
        case QTextUndoCommand::Inserted:
            remove(c.pos, c.length, (QTextUndoCommand::Operation)c.operation);
            PMDEBUG("   erase: from %d, length %d", c.pos, c.length);
            c.command = QTextUndoCommand::Removed;
	    break;
        case QTextUndoCommand::Removed:
            PMDEBUG("   insert: format %d (from %d, length %d, strpos=%d)", c.format, c.pos, c.length, c.strPos);
            insert_string(c.pos, c.strPos, c.length, c.format, (QTextUndoCommand::Operation)c.operation);
            c.command = QTextUndoCommand::Inserted;
	    break;
	case QTextUndoCommand::BlockInserted:
	case QTextUndoCommand::BlockAdded:
            remove_block(c.pos, &c.blockFormat, c.command, (QTextUndoCommand::Operation)c.operation);
            PMDEBUG("   blockremove: from %d", c.pos);
	    if (c.command == QTextUndoCommand::BlockInserted)
		c.command = QTextUndoCommand::BlockRemoved;
	    else
		c.command = QTextUndoCommand::BlockDeleted;
	    break;
	case QTextUndoCommand::BlockRemoved:
	case QTextUndoCommand::BlockDeleted:
            PMDEBUG("   blockinsert: charformat %d blockformat %d (pos %d, strpos=%d)", c.format, c.blockFormat, c.pos, c.strPos);
            insert_block(c.pos, c.strPos, c.format, c.blockFormat, (QTextUndoCommand::Operation)c.operation, c.command);
            resetBlockRevision += 1;
	    if (c.command == QTextUndoCommand::BlockRemoved)
		c.command = QTextUndoCommand::BlockInserted;
	    else
		c.command = QTextUndoCommand::BlockAdded;
	    break;
	case QTextUndoCommand::CharFormatChanged: {
            resetBlockRevision = -1; // ## TODO
            PMDEBUG("   charFormat: format %d (from %d, length %d)", c.format, c.pos, c.length);
            FragmentIterator it = find(c.pos);
            Q_ASSERT(!it.atEnd());

            int oldFormat = it.value()->format;
            setCharFormat(c.pos, c.length, formats.charFormat(c.format));
            c.format = oldFormat;
	    break;
	}
	case QTextUndoCommand::BlockFormatChanged: {
            resetBlockRevision = -1; // ## TODO
            PMDEBUG("   blockformat: format %d pos %d", c.format, c.pos);
            QTextBlock it = blocksFind(c.pos);
            Q_ASSERT(it.isValid());

            int oldFormat = block(it)->format;
            block(it)->format = c.format;
            QTextBlockGroup *oldGroup = qobject_cast<QTextBlockGroup *>(objectForFormat(formats.blockFormat(oldFormat)));
            QTextBlockGroup *group = qobject_cast<QTextBlockGroup *>(objectForFormat(formats.blockFormat(c.format)));
            c.format = oldFormat;
            if (group != oldGroup) {
                if (oldGroup)
                    oldGroup->blockRemoved(it);
                if (group)
                    group->blockInserted(it);
            } else if (group) {
                group->blockFormatChanged(it);
            }
            documentChange(it.position(), it.length());
	    break;
	}
	case QTextUndoCommand::GroupFormatChange: {
            resetBlockRevision = -1; // ## TODO
            PMDEBUG("   group format change");
            QTextObject *object = objectForIndex(c.objectIndex);
            int oldFormat = formats.objectFormatIndex(c.objectIndex);
            changeObjectFormat(object, c.format);
            c.format = oldFormat;
	    break;
	}
	case QTextUndoCommand::Custom:
            resetBlockRevision = -1; // ## TODO
            if (undo)
                c.custom->undo();
            else
                c.custom->redo();
	    break;
	default:
	    Q_ASSERT(false);
        }

        if (resetBlockRevision >= 0) {
            int b = blocks.findNode(resetBlockRevision);
            QTextBlockData *B = blocks.fragment(b);
            B->revision = c.revision;
        }

        if (undo) {
            if (undoState == 0 || !undoStack[undoState-1].block)
                break;
        } else {
            ++undoState;
            if (undoState == undoStack.size() || !undoStack[undoState-1].block)
                break;
        }
    }
    undoEnabled = true;
    int editPos = -1;
    if (docChangeFrom >= 0) {
        editPos = qMin(docChangeFrom + docChangeLength, length() - 1);
    }
    endEditBlock();
    emitUndoAvailable(isUndoAvailable());
    emitRedoAvailable(isRedoAvailable());
    return editPos;
}