source: trunk/src/gui/text/qfragmentmap_p.h@ 234

Last change on this file since 234 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 24.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QFRAGMENTMAP_P_H
43#define QFRAGMENTMAP_P_H
44
45//
46// W A R N I N G
47// -------------
48//
49// This file is not part of the Qt API. It exists purely as an
50// implementation detail. This header file may change from version to
51// version without notice, or even be removed.
52//
53// We mean it.
54//
55
56#include "QtCore/qglobal.h"
57#include <stdlib.h>
58#include <private/qtools_p.h>
59
60QT_BEGIN_NAMESPACE
61
62
63template <int N = 1>
64class QFragment
65{
66public:
67 quint32 parent;
68 quint32 left;
69 quint32 right;
70 quint32 color;
71 quint32 size_left_array[N];
72 quint32 size_array[N];
73 enum {size_array_max = N };
74};
75
76template <class Fragment>
77class QFragmentMapData
78{
79 enum Color { Red, Black };
80public:
81 QFragmentMapData();
82 ~QFragmentMapData();
83
84 void init();
85
86 class Header
87 {
88 public:
89 quint32 root; // this relies on being at the same position as parent in the fragment struct
90 quint32 tag;
91 quint32 freelist;
92 quint32 node_count;
93 quint32 allocated;
94 };
95
96
97 enum {fragmentSize = sizeof(Fragment) };
98
99
100 int length(uint field = 0) const;
101
102
103 inline Fragment *fragment(uint index) {
104 return (fragments + index);
105 }
106 inline const Fragment *fragment(uint index) const {
107 return (fragments + index);
108 }
109
110
111 inline Fragment &F(uint index) { return fragments[index] ; }
112 inline const Fragment &F(uint index) const { return fragments[index] ; }
113
114 inline bool isRoot(uint index) const {
115 return !fragment(index)->parent;
116 }
117
118 inline uint position(uint node, uint field = 0) const {
119 Q_ASSERT(field < Fragment::size_array_max);
120 const Fragment *f = fragment(node);
121 uint offset = f->size_left_array[field];
122 while (f->parent) {
123 uint p = f->parent;
124 f = fragment(p);
125 if (f->right == node)
126 offset += f->size_left_array[field] + f->size_array[field];
127 node = p;
128 }
129 return offset;
130 }
131 inline uint sizeRight(uint node, uint field = 0) const {
132 Q_ASSERT(field < Fragment::size_array_max);
133 uint sr = 0;
134 const Fragment *f = fragment(node);
135 node = f->right;
136 while (node) {
137 f = fragment(node);
138 sr += f->size_left_array[field] + f->size_array[field];
139 node = f->right;
140 }
141 return sr;
142 }
143 inline uint sizeLeft(uint node, uint field = 0) const {
144 Q_ASSERT(field < Fragment::size_array_max);
145 return fragment(node)->size_left_array[field];
146 }
147
148
149 inline uint size(uint node, uint field = 0) const {
150 Q_ASSERT(field < Fragment::size_array_max);
151 return fragment(node)->size_array[field];
152 }
153
154 inline void setSize(uint node, int new_size, uint field = 0) {
155 Q_ASSERT(field < Fragment::size_array_max);
156 Fragment *f = fragment(node);
157 int diff = new_size - f->size_array[field];
158 f->size_array[field] = new_size;
159 while (f->parent) {
160 uint p = f->parent;
161 f = fragment(p);
162 if (f->left == node)
163 f->size_left_array[field] += diff;
164 node = p;
165 }
166 }
167
168
169 uint findNode(int k, uint field = 0) const;
170
171 uint insert_single(int key, uint length);
172 uint erase_single(uint f);
173
174 uint minimum(uint n) const {
175 while (n && fragment(n)->left)
176 n = fragment(n)->left;
177 return n;
178 }
179
180 uint maximum(uint n) const {
181 while (n && fragment(n)->right)
182 n = fragment(n)->right;
183 return n;
184 }
185
186 uint next(uint n) const;
187 uint previous(uint n) const;
188
189 inline uint root() const {
190 Q_ASSERT(!head->root || !fragment(head->root)->parent);
191 return head->root;
192 }
193 inline void setRoot(uint new_root) {
194 Q_ASSERT(!head->root || !fragment(new_root)->parent);
195 head->root = new_root;
196 }
197
198 union {
199 Header *head;
200 Fragment *fragments;
201 };
202
203private:
204
205 void rotateLeft(uint x);
206 void rotateRight(uint x);
207 void rebalance(uint x);
208 void removeAndRebalance(uint z);
209
210 uint createFragment();
211 void freeFragment(uint f);
212
213};
214
215template <class Fragment>
216QFragmentMapData<Fragment>::QFragmentMapData()
217{
218 init();
219}
220
221template <class Fragment>
222void QFragmentMapData<Fragment>::init()
223{
224 fragments = (Fragment *)malloc(64*fragmentSize);
225 head->tag = (((quint32)'p') << 24) | (((quint32)'m') << 16) | (((quint32)'a') << 8) | 'p'; //TAG('p', 'm', 'a', 'p');
226 head->root = 0;
227 head->freelist = 1;
228 head->node_count = 0;
229 head->allocated = 64;
230 // mark all items to the right as unused
231 F(head->freelist).right = 0;
232}
233
234template <class Fragment>
235QFragmentMapData<Fragment>::~QFragmentMapData()
236{
237 free(head);
238}
239
240template <class Fragment>
241uint QFragmentMapData<Fragment>::createFragment()
242{
243 Q_ASSERT(head->freelist <= head->allocated);
244
245 uint freePos = head->freelist;
246 if (freePos == head->allocated) {
247 // need to create some free space
248 uint needed = qAllocMore((freePos+1)*fragmentSize, 0);
249 Q_ASSERT(needed/fragmentSize > head->allocated);
250 fragments = (Fragment *)realloc(fragments, needed);
251 head->allocated = needed/fragmentSize;
252 F(freePos).right = 0;
253 }
254
255 uint nextPos = F(freePos).right;
256 if (!nextPos) {
257 nextPos = freePos+1;
258 if (nextPos < head->allocated)
259 F(nextPos).right = 0;
260 }
261
262 head->freelist = nextPos;
263
264 ++head->node_count;
265
266 return freePos;
267}
268
269template <class Fragment>
270void QFragmentMapData<Fragment>::freeFragment(uint i)
271{
272 F(i).right = head->freelist;
273 head->freelist = i;
274
275 --head->node_count;
276}
277
278
279template <class Fragment>
280uint QFragmentMapData<Fragment>::next(uint n) const {
281 Q_ASSERT(n);
282 if (F(n).right) {
283 n = F(n).right;
284 while (F(n).left)
285 n = F(n).left;
286 } else {
287 uint y = F(n).parent;
288 while (F(n).parent && n == F(y).right) {
289 n = y;
290 y = F(y).parent;
291 }
292 n = y;
293 }
294 return n;
295}
296
297template <class Fragment>
298uint QFragmentMapData<Fragment>::previous(uint n) const {
299 if (!n)
300 return maximum(root());
301
302 if (F(n).left) {
303 n = F(n).left;
304 while (F(n).right)
305 n = F(n).right;
306 } else {
307 uint y = F(n).parent;
308 while (F(n).parent && n == F(y).left) {
309 n = y;
310 y = F(y).parent;
311 }
312 n = y;
313 }
314 return n;
315}
316
317
318/*
319 x y
320 \ / \
321 y --> x b
322 / \ \
323 a b a
324*/
325template <class Fragment>
326void QFragmentMapData<Fragment>::rotateLeft(uint x)
327{
328 uint p = F(x).parent;
329 uint y = F(x).right;
330
331
332 if (y) {
333 F(x).right = F(y).left;
334 if (F(y).left)
335 F(F(y).left).parent = x;
336 F(y).left = x;
337 F(y).parent = p;
338 } else {
339 F(x).right = 0;
340 }
341 if (!p) {
342 Q_ASSERT(head->root == x);
343 head->root = y;
344 }
345 else if (x == F(p).left)
346 F(p).left = y;
347 else
348 F(p).right = y;
349 F(x).parent = y;
350 for (uint field = 0; field < Fragment::size_array_max; ++field)
351 F(y).size_left_array[field] += F(x).size_left_array[field] + F(x).size_array[field];
352}
353
354
355/*
356 x y
357 / / \
358 y --> a x
359 / \ /
360 a b b
361*/
362template <class Fragment>
363void QFragmentMapData<Fragment>::rotateRight(uint x)
364{
365 uint y = F(x).left;
366 uint p = F(x).parent;
367
368 if (y) {
369 F(x).left = F(y).right;
370 if (F(y).right)
371 F(F(y).right).parent = x;
372 F(y).right = x;
373 F(y).parent = p;
374 } else {
375 F(x).left = 0;
376 }
377 if (!p) {
378 Q_ASSERT(head->root == x);
379 head->root = y;
380 }
381 else if (x == F(p).right)
382 F(p).right = y;
383 else
384 F(p).left = y;
385 F(x).parent = y;
386 for (uint field = 0; field < Fragment::size_array_max; ++field)
387 F(x).size_left_array[field] -= F(y).size_left_array[field] + F(y).size_array[field];
388}
389
390
391template <class Fragment>
392void QFragmentMapData<Fragment>::rebalance(uint x)
393{
394 F(x).color = Red;
395
396 while (F(x).parent && F(F(x).parent).color == Red) {
397 uint p = F(x).parent;
398 uint pp = F(p).parent;
399 Q_ASSERT(pp);
400 if (p == F(pp).left) {
401 uint y = F(pp).right;
402 if (y && F(y).color == Red) {
403 F(p).color = Black;
404 F(y).color = Black;
405 F(pp).color = Red;
406 x = pp;
407 } else {
408 if (x == F(p).right) {
409 x = p;
410 rotateLeft(x);
411 p = F(x).parent;
412 pp = F(p).parent;
413 }
414 F(p).color = Black;
415 if (pp) {
416 F(pp).color = Red;
417 rotateRight(pp);
418 }
419 }
420 } else {
421 uint y = F(pp).left;
422 if (y && F(y).color == Red) {
423 F(p).color = Black;
424 F(y).color = Black;
425 F(pp).color = Red;
426 x = pp;
427 } else {
428 if (x == F(p).left) {
429 x = p;
430 rotateRight(x);
431 p = F(x).parent;
432 pp = F(p).parent;
433 }
434 F(p).color = Black;
435 if (pp) {
436 F(pp).color = Red;
437 rotateLeft(pp);
438 }
439 }
440 }
441 }
442 F(root()).color = Black;
443}
444
445
446template <class Fragment>
447uint QFragmentMapData<Fragment>::erase_single(uint z)
448{
449 uint w = previous(z);
450 uint y = z;
451 uint x;
452 uint p;
453
454 if (!F(y).left) {
455 x = F(y).right;
456 } else if (!F(y).right) {
457 x = F(y).left;
458 } else {
459 y = F(y).right;
460 while (F(y).left)
461 y = F(y).left;
462 x = F(y).right;
463 }
464
465 if (y != z) {
466 F(F(z).left).parent = y;
467 F(y).left = F(z).left;
468 for (uint field = 0; field < Fragment::size_array_max; ++field)
469 F(y).size_left_array[field] = F(z).size_left_array[field];
470 if (y != F(z).right) {
471 /*
472 z y
473 / \ / \
474 a b a b
475 / /
476 ... --> ...
477 / /
478 y x
479 / \
480 0 x
481 */
482 p = F(y).parent;
483 if (x)
484 F(x).parent = p;
485 F(p).left = x;
486 F(y).right = F(z).right;
487 F(F(z).right).parent = y;
488 uint n = p;
489 while (n != y) {
490 for (uint field = 0; field < Fragment::size_array_max; ++field)
491 F(n).size_left_array[field] -= F(y).size_array[field];
492 n = F(n).parent;
493 }
494 } else {
495 /*
496 z y
497 / \ / \
498 a y --> a x
499 / \
500 0 x
501 */
502 p = y;
503 }
504 uint zp = F(z).parent;
505 if (!zp) {
506 Q_ASSERT(head->root == z);
507 head->root = y;
508 } else if (F(zp).left == z) {
509 F(zp).left = y;
510 for (uint field = 0; field < Fragment::size_array_max; ++field)
511 F(zp).size_left_array[field] -= F(z).size_array[field];
512 } else {
513 F(zp).right = y;
514 }
515 F(y).parent = zp;
516 // Swap the colors
517 uint c = F(y).color;
518 F(y).color = F(z).color;
519 F(z).color = c;
520 y = z;
521 } else {
522 /*
523 p p p p
524 / / \ \
525 z --> x z --> x
526 | |
527 x x
528 */
529 p = F(z).parent;
530 if (x)
531 F(x).parent = p;
532 if (!p) {
533 Q_ASSERT(head->root == z);
534 head->root = x;
535 } else if (F(p).left == z) {
536 F(p).left = x;
537 for (uint field = 0; field < Fragment::size_array_max; ++field)
538 F(p).size_left_array[field] -= F(z).size_array[field];
539 } else {
540 F(p).right = x;
541 }
542 }
543 uint n = z;
544 while (F(n).parent) {
545 uint p = F(n).parent;
546 if (F(p).left == n) {
547 for (uint field = 0; field < Fragment::size_array_max; ++field)
548 F(p).size_left_array[field] -= F(z).size_array[field];
549 }
550 n = p;
551 }
552
553 freeFragment(z);
554
555
556 if (F(y).color != Red) {
557 while (F(x).parent && (x == 0 || F(x).color == Black)) {
558 if (x == F(p).left) {
559 uint w = F(p).right;
560 if (F(w).color == Red) {
561 F(w).color = Black;
562 F(p).color = Red;
563 rotateLeft(p);
564 w = F(p).right;
565 }
566 if ((F(w).left == 0 || F(F(w).left).color == Black) &&
567 (F(w).right == 0 || F(F(w).right).color == Black)) {
568 F(w).color = Red;
569 x = p;
570 p = F(x).parent;
571 } else {
572 if (F(w).right == 0 || F(F(w).right).color == Black) {
573 if (F(w).left)
574 F(F(w).left).color = Black;
575 F(w).color = Red;
576 rotateRight(F(p).right);
577 w = F(p).right;
578 }
579 F(w).color = F(p).color;
580 F(p).color = Black;
581 if (F(w).right)
582 F(F(w).right).color = Black;
583 rotateLeft(p);
584 break;
585 }
586 } else {
587 uint w = F(p).left;
588 if (F(w).color == Red) {
589 F(w).color = Black;
590 F(p).color = Red;