1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the text module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include <private/qtools_p.h>
31
#include "qfragmentmap_p.h"
36
#define F(x) (*fragment(x))
37
#define X (*fragment(x))
38
#define Y (*fragment(y))
39
#define Z (*fragment(z))
40
#define W (*fragment(w))
41
#define N (*fragment(n))
42
#define P (*fragment(p))
43
#define PP (*fragment(pp))
46
#define PMDEBUG qDebug
47
void QFragmentMap::inorder(uint x, int level) {
49
inorder(X.left, level + 1);
50
for (int i = 0; i < level; ++i)
52
std::cout << "this=" << x << " Key=" << key(x) << " size_left=" << X.size_left
54
<< " textPos=" << X.position << (X.color == Red ? " Red" : " Black")
57
inorder(X.right, level + 1);
59
void QFragmentMap::check()
61
Q_ASSERT((head->node_count == 0 && head->root == 0)
62
|| (head->node_count != 0 && head->root != 0 && F(head->root).parent == 0));
64
ConstIterator it = begin();
66
for (; it != end(); ++it) {
67
Q_ASSERT(key == it.key());
72
#define PMDEBUG if(0)qDebug
73
inline void inorder() {}
74
inline void check() {}
77
#define TAG(a,b,c,d) (((quint32)a) << 24) | (((quint32)b) << 16) | (((quint32)c) << 8) | d;
79
QFragmentMapData::QFragmentMapData(uint fs)
81
fragmentSize = qMax<uint>(fs, sizeof(Header));
85
void QFragmentMapData::init()
87
fragments = (char *)malloc(64*fragmentSize);
88
head->tag = TAG('p', 'm', 'a', 'p');
93
// mark all items to the right as unused
94
F(head->freelist).right = 0;
96
for (uint i = 1; i < head->allocated; ++i)
97
F(i).parent = 0xdeadbeef;
101
QFragmentMapData::~QFragmentMapData()
106
uint QFragmentMapData::createFragment()
108
Q_ASSERT(head->freelist <= head->allocated);
110
uint freePos = head->freelist;
111
if (freePos == head->allocated) {
112
// need to create some free space
113
uint needed = qAllocMore((freePos+1)*fragmentSize, 0);
114
Q_ASSERT(needed/fragmentSize > head->allocated);
115
fragments = (char *)realloc(fragments, needed);
116
head->allocated = needed/fragmentSize;
117
F(freePos).right = 0;
119
for (uint i = freePos; i < head->allocated; ++i)
120
F(i).parent = 0xdeadbeef;
124
uint nextPos = F(freePos).right;
127
if (nextPos < head->allocated)
128
F(nextPos).right = 0;
131
head->freelist = nextPos;
134
Q_ASSERT(F(freePos).parent == 0xdeadbeef);
135
F(freePos).parent = 0;
136
if (nextPos < head->allocated) {
137
Q_ASSERT(F(nextPos).parent == 0xdeadbeef);
143
PMDEBUG("===> createFragment at %d", freePos);
147
void QFragmentMapData::freeFragment(uint i)
149
PMDEBUG("===> freeFragment at %d", i);
151
Q_ASSERT(F(i).parent != 0xdeadbeef);
152
if (head->freelist < head->allocated) {
153
Q_ASSERT(F(head->freelist).parent == 0xdeadbeef);
155
F(i).parent = 0xdeadbeef;
157
F(i).right = head->freelist;
164
uint QFragmentMapData::next(uint n) const {
172
while (N.parent && n == Y.right) {
181
uint QFragmentMapData::previous(uint n) const {
183
return maximum(root());
191
while (N.parent && n == Y.left) {
208
void QFragmentMapData::rotateLeft(uint x)
212
PMDEBUG(" rotateLeft on x=%d (y=%d, p=%d)", x, y, p);
218
F(Y.left).parent = x;
225
Q_ASSERT(head->root == x);
228
else if (x == P.left)
233
Y.size_left += X.size_left + X.size;
247
void QFragmentMapData::rotateRight(uint x)
251
PMDEBUG(" rotateRight on x=%d (y=%d, p=%d)", x, y, p);
256
F(Y.right).parent = x;
263
Q_ASSERT(head->root == x);
266
else if (x == P.right)
271
X.size_left -= Y.size_left + Y.size;
278
void QFragmentMapData::rebalance(uint x)
282
PMDEBUG(" -> rebalance x=%d", x);
285
while (X.parent && F(X.parent).color == Red) {
291
if (y && Y.color == Red) {
311
if (y && Y.color == Red) {
331
F(root()).color = Black;
336
uint QFragmentMapData::erase_single(uint z)
338
uint w = previous(z);
345
} else if (!Y.right) {
354
PMDEBUG("removeAndRebalance on %d (x=%d, y=%d)", z, x, y);
358
F(Z.left).parent = y;
360
Y.size_left = Z.size_left;
378
F(Z.right).parent = y;
381
N.size_left -= Y.size;
396
Q_ASSERT(head->root == z);
398
} else if (F(zp).left == z) {
400
F(zp).size_left -= Z.size;
422
Q_ASSERT(head->root == z);
424
} else if (P.left == z) {
426
P.size_left -= Z.size;
435
PMDEBUG("reducing size_left of %d by %d", N.parent, Z.size);
436
P.size_left -= Z.size;
442
PMDEBUG("after removal");
447
if (Y.color != Red) {
448
while (X.parent && (x == 0 || X.color == Black)) {
451
if (W.color == Red) {
457
if ((W.left == 0 || F(W.left).color == Black) &&
458
(W.right == 0 || F(W.right).color == Black)) {
463
if (W.right == 0 || F(W.right).color == Black) {
465
F(W.left).color = Black;
467
rotateRight(P.right);
473
F(W.right).color = Black;
479
if (W.color == Red) {
485
if ((W.right == 0 || F(W.right).color == Black) &&
486
(W.left == 0 || F(W.left).color == Black)) {
491
if (W.left == 0 || F(W.left).color == Black) {
493
F(W.right).color = Black;
501
F(W.left).color = Black;
511
PMDEBUG("after rebalance");
518
uint QFragmentMapData::findNode(int k) const
524
if (sizeLeft(x) <= s) {
525
if (s < sizeLeft(x) + size(x))
527
s -= sizeLeft(x) + size(x);
536
uint QFragmentMapData::insert_single(int key, uint length)
538
Q_ASSERT(!findNode(key) || (int)this->position(findNode(key)) == key);
540
uint z = createFragment();
547
PMDEBUG("inserting with key %d", key);
551
Q_ASSERT(!x || X.parent == 0);
558
// PMDEBUG("x=%p: x->size_left=%d, key=%d, s=%d", x, x->size_left, x->key(), s);
559
if (s <= X.size_left) {
563
s -= X.size_left + X.size;
569
// PMDEBUG(" y=%p: y->size_left=%d, y->key=%d s=%d", y, y->size_left, y ? y->key() : -1, s);
575
// PMDEBUG("inserting left");
577
Y.size_left = Z.size;
579
// PMDEBUG("inserting right");
582
while (y && Y.parent) {
585
P.size_left += Z.size;
588
// PMDEBUG("before rebalance");
593
PMDEBUG("end insert\n");
599
int QFragmentMapData::length() const {
600
uint root = this->root();
601
return root ? sizeLeft(root) + size(root) + sizeRight(root) : 0;