1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt3Support module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "q3gdict.h"
43 #include "q3ptrlist.h"
44 #include "qstring.h"
45 #include "qdatastream.h"
46 #include <ctype.h>
47
48 QT_BEGIN_NAMESPACE
49
50 /*!
51 \class Q3GDict
52 \reentrant
53 \brief The Q3GDict class is an internal class for implementing QDict template classes.
54
55 \internal
56
57 Q3GDict is a strictly internal class that acts as a base class for the
58 \link collection.html collection classes\endlink QDict and QIntDict.
59
60 Q3GDict has some virtual functions that can be reimplemented to customize
61 the subclasses.
62 \list
63 \i read() reads a collection/dictionary item from a QDataStream.
64 \i write() writes a collection/dictionary item to a QDataStream.
65 \endlist
66 Normally, you do not have to reimplement any of these functions.
67 */
68
69 static const int op_find = 0;
70 static const int op_insert = 1;
71 static const int op_replace = 2;
72
73
74 class Q3GDItList : public Q3PtrList<Q3GDictIterator>
75 {
76 public:
Q3GDItList()77 Q3GDItList() : Q3PtrList<Q3GDictIterator>() {}
Q3GDItList(const Q3GDItList & list)78 Q3GDItList(const Q3GDItList &list) : Q3PtrList<Q3GDictIterator>(list) {}
~Q3GDItList()79 ~Q3GDItList() { clear(); }
operator =(const Q3GDItList & list)80 Q3GDItList &operator=(const Q3GDItList &list)
81 { return (Q3GDItList&)Q3PtrList<Q3GDictIterator>::operator=(list); }
82 };
83
84
85 /*****************************************************************************
86 Default implementation of special and virtual functions
87 *****************************************************************************/
88
89 /*!
90 Returns the hash key for \a key, when key is a string.
91 */
92
hashKeyString(const QString & key)93 int Q3GDict::hashKeyString(const QString &key)
94 {
95 #if defined(QT_CHECK_NULL)
96 if (key.isNull())
97 qWarning("Q3GDict::hashKeyString: Invalid null key");
98 #endif
99 int i;
100 register uint h=0;
101 uint g;
102 const QChar *p = key.unicode();
103 if (cases) { // case sensitive
104 for (i=0; i<(int)key.length(); i++) {
105 h = (h<<4) + p[i].cell();
106 if ((g = h & 0xf0000000))
107 h ^= g >> 24;
108 h &= ~g;
109 }
110 } else { // case insensitive
111 for (i=0; i<(int)key.length(); i++) {
112 h = (h<<4) + p[i].lower().cell();
113 if ((g = h & 0xf0000000))
114 h ^= g >> 24;
115 h &= ~g;
116 }
117 }
118 int index = h;
119 if (index < 0) // adjust index to table size
120 index = -index;
121 return index;
122 }
123
124 /*!
125 Returns the hash key for \a key, which is a C string.
126 */
127
hashKeyAscii(const char * key)128 int Q3GDict::hashKeyAscii(const char *key)
129 {
130 #if defined(QT_CHECK_NULL)
131 if (key == 0)
132 qWarning("Q3GDict::hashAsciiKey: Invalid null key");
133 #endif
134 register const char *k = key;
135 register uint h=0;
136 uint g;
137 if (cases) { // case sensitive
138 while (*k) {
139 h = (h<<4) + *k++;
140 if ((g = h & 0xf0000000))
141 h ^= g >> 24;
142 h &= ~g;
143 }
144 } else { // case insensitive
145 while (*k) {
146 h = (h<<4) + tolower((uchar) *k);
147 if ((g = h & 0xf0000000))
148 h ^= g >> 24;
149 h &= ~g;
150 k++;
151 }
152 }
153 int index = h;
154 if (index < 0) // adjust index to table size
155 index = -index;
156 return index;
157 }
158
159 #ifndef QT_NO_DATASTREAM
160
161 /*!
162 \overload
163 Reads a collection/dictionary item from the stream \a s and returns a
164 reference to the stream.
165
166 The default implementation sets \a item to 0.
167
168 \sa write()
169 */
170
read(QDataStream & s,Q3PtrCollection::Item & item)171 QDataStream& Q3GDict::read(QDataStream &s, Q3PtrCollection::Item &item)
172 {
173 item = 0;
174 return s;
175 }
176
177 /*!
178 \overload
179 Writes a collection/dictionary item to the stream \a s and returns a
180 reference to the stream.
181
182 \sa read()
183 */
184
write(QDataStream & s,Q3PtrCollection::Item) const185 QDataStream& Q3GDict::write(QDataStream &s, Q3PtrCollection::Item) const
186 {
187 return s;
188 }
189 #endif //QT_NO_DATASTREAM
190
191 /*****************************************************************************
192 Q3GDict member functions
193 *****************************************************************************/
194
195 /*!
196 Constructs a dictionary.
197
198 \a len is the initial size of the dictionary.
199 The key type is \a kt which may be \c StringKey, \c AsciiKey,
200 \c IntKey or \c PtrKey. The case-sensitivity of lookups is set with
201 \a caseSensitive. Keys are copied if \a copyKeys is true.
202 */
203
Q3GDict(uint len,KeyType kt,bool caseSensitive,bool copyKeys)204 Q3GDict::Q3GDict(uint len, KeyType kt, bool caseSensitive, bool copyKeys)
205 {
206 init(len, kt, caseSensitive, copyKeys);
207 }
208
209
init(uint len,KeyType kt,bool caseSensitive,bool copyKeys)210 void Q3GDict::init(uint len, KeyType kt, bool caseSensitive, bool copyKeys)
211 {
212 vlen = len ? len : 17;
213 vec = new Q3BaseBucket *[ vlen ];
214
215 Q_CHECK_PTR(vec);
216 memset((char*)vec, 0, vlen*sizeof(Q3BaseBucket*));
217 numItems = 0;
218 iterators = 0;
219 // The caseSensitive and copyKey options don't make sense for
220 // all dict types.
221 switch ((keytype = (uint)kt)) {
222 case StringKey:
223 cases = caseSensitive;
224 copyk = false;
225 break;
226 case AsciiKey:
227 cases = caseSensitive;
228 copyk = copyKeys;
229 break;
230 default:
231 cases = false;
232 copyk = false;
233 break;
234 }
235 }
236
237
238 /*!
239 Constructs a copy of \a dict.
240 */
241
Q3GDict(const Q3GDict & dict)242 Q3GDict::Q3GDict(const Q3GDict & dict)
243 : Q3PtrCollection(dict)
244 {
245 init(dict.vlen, (KeyType)dict.keytype, dict.cases, dict.copyk);
246 Q3GDictIterator it(dict);
247 while (it.get()) { // copy from other dict
248 switch (keytype) {
249 case StringKey:
250 look_string(it.getKeyString(), it.get(), op_insert);
251 break;
252 case AsciiKey:
253 look_ascii(it.getKeyAscii(), it.get(), op_insert);
254 break;
255 case IntKey:
256 look_int(it.getKeyInt(), it.get(), op_insert);
257 break;
258 case PtrKey:
259 look_ptr(it.getKeyPtr(), it.get(), op_insert);
260 break;
261 }
262 ++it;
263 }
264 }
265
266
267 /*!
268 Removes all items from the dictionary and destroys it.
269 */
270
~Q3GDict()271 Q3GDict::~Q3GDict()
272 {
273 clear(); // delete everything
274 delete [] vec;
275 if (!iterators) // no iterators for this dict
276 return;
277 Q3GDictIterator *i = iterators->first();
278 while (i) { // notify all iterators that
279 i->dict = 0; // this dict is deleted
280 i = iterators->next();
281 }
282 delete iterators;
283 }
284
285
286 /*!
287 Assigns \a dict to this dictionary.
288 */
289
operator =(const Q3GDict & dict)290 Q3GDict &Q3GDict::operator=(const Q3GDict &dict)
291 {
292 if (&dict == this)
293 return *this;
294 clear();
295 Q3GDictIterator it(dict);
296 while (it.get()) { // copy from other dict
297 switch (keytype) {
298 case StringKey:
299 look_string(it.getKeyString(), it.get(), op_insert);
300 break;
301 case AsciiKey:
302 look_ascii(it.getKeyAscii(), it.get(), op_insert);
303 break;
304 case IntKey:
305 look_int(it.getKeyInt(), it.get(), op_insert);
306 break;
307 case PtrKey:
308 look_ptr(it.getKeyPtr(), it.get(), op_insert);
309 break;
310 }
311 ++it;
312 }
313 return *this;
314 }
315
316 /*!
317 \fn uint Q3GDict::count() const
318
319 Returns the number of items in the dictionary.
320 */
321
322 /*!
323 \fn uint Q3GDict::size() const
324
325 Returns the size of the hash array.
326 */
327
328 /*!
329 The do-it-all function; \a op is one of op_find, op_insert, op_replace.
330 The key is \a key and the item is \a d.
331 */
332
look_string(const QString & key,Q3PtrCollection::Item d,int op)333 Q3PtrCollection::Item Q3GDict::look_string(const QString &key, Q3PtrCollection::Item d,
334 int op)
335 {
336 Q3StringBucket *n = 0;
337 int index = hashKeyString(key) % vlen;
338 if (op == op_find) { // find
339 if (cases) {
340 n = (Q3StringBucket*)vec[index];
341 while(n != 0) {
342 if (key == n->getKey())
343 return n->getData(); // item found
344 n = (Q3StringBucket*)n->getNext();
345 }
346 } else {
347 QString k = key.lower();
348 n = (Q3StringBucket*)vec[index];
349 while(n != 0) {
350 if (k == n->getKey().lower())
351 return n->getData(); // item found
352 n = (Q3StringBucket*)n->getNext();
353 }
354 }
355 return 0; // not found
356 }
357 if (op == op_replace) { // replace
358 if (vec[index] != 0) // maybe something there
359 remove_string(key);
360 }
361 // op_insert or op_replace
362 n = new Q3StringBucket(key,newItem(d),vec[index]);
363 Q_CHECK_PTR(n);
364 #if defined(QT_CHECK_NULL)
365 if (n->getData() == 0)
366 qWarning("QDict: Cannot insert null item");
367 #endif
368 vec[index] = n;
369 numItems++;
370 return n->getData();
371 }
372
look_ascii(const char * key,Q3PtrCollection::Item d,int op)373 Q3PtrCollection::Item Q3GDict::look_ascii(const char *key, Q3PtrCollection::Item d, int op)
374 {
375 Q3AsciiBucket *n;
376 int index = hashKeyAscii(key) % vlen;
377 if (op == op_find) { // find
378 if (cases) {
379 for (n=(Q3AsciiBucket*)vec[index]; n;
380 n=(Q3AsciiBucket*)n->getNext()) {
381 if (qstrcmp(n->getKey(),key) == 0)
382 return n->getData(); // item found
383 }
384 } else {
385 for (n=(Q3AsciiBucket*)vec[index]; n;
386 n=(Q3AsciiBucket*)n->getNext()) {
387 if (qstricmp(n->getKey(),key) == 0)
388 return n->getData(); // item found
389 }
390 }
391 return 0; // not found
392 }
393 if (op == op_replace) { // replace
394 if (vec[index] != 0) // maybe something there
395 remove_ascii(key);
396 }
397 // op_insert or op_replace
398 n = new Q3AsciiBucket(copyk ? qstrdup(key) : key,newItem(d),vec[index]);
399 Q_CHECK_PTR(n);
400 #if defined(QT_CHECK_NULL)
401 if (n->getData() == 0)
402 qWarning("QAsciiDict: Cannot insert null item");
403 #endif
404 vec[index] = n;
405 numItems++;
406 return n->getData();
407 }
408
look_int(long key,Q3PtrCollection::Item d,int op)409 Q3PtrCollection::Item Q3GDict::look_int(long key, Q3PtrCollection::Item d, int op)
410 {
411 Q3IntBucket *n;
412 int index = (int)((ulong)key % vlen); // simple hash
413 if (op == op_find) { // find
414 for (n=(Q3IntBucket*)vec[index]; n;
415 n=(Q3IntBucket*)n->getNext()) {
416 if (n->getKey() == key)
417 return n->getData(); // item found
418 }
419 return 0; // not found
420 }
421 if (op == op_replace) { // replace
422 if (vec[index] != 0) // maybe something there
423 remove_int(key);
424 }
425 // op_insert or op_replace
426 n = new Q3IntBucket(key,newItem(d),vec[index]);
427 Q_CHECK_PTR(n);
428 #if defined(QT_CHECK_NULL)
429 if (n->getData() == 0)
430 qWarning("QIntDict: Cannot insert null item");
431 #endif
432 vec[index] = n;
433 numItems++;
434 return n->getData();
435 }
436
look_ptr(void * key,Q3PtrCollection::Item d,int op)437 Q3PtrCollection::Item Q3GDict::look_ptr(void *key, Q3PtrCollection::Item d, int op)
438 {
439 Q3PtrBucket *n;
440 int index = (int)((quintptr)key % vlen); // simple hash
441 if (op == op_find) { // find
442 for (n=(Q3PtrBucket*)vec[index]; n;
443 n=(Q3PtrBucket*)n->getNext()) {
444 if (n->getKey() == key)
445 return n->getData(); // item found
446 }
447 return 0; // not found
448 }
449 if (op == op_replace) { // replace
450 if (vec[index] != 0) // maybe something there
451 remove_ptr(key);
452 }
453 // op_insert or op_replace
454 n = new Q3PtrBucket(key,newItem(d),vec[index]);
455 Q_CHECK_PTR(n);
456 #if defined(QT_CHECK_NULL)
457 if (n->getData() == 0)
458 qWarning("Q3PtrDict: Cannot insert null item");
459 #endif
460 vec[index] = n;
461 numItems++;
462 return n->getData();
463 }
464
465
466 /*!
467 Changes the size of the hashtable to \a newsize.
468 The contents of the dictionary are preserved,
469 but all iterators on the dictionary become invalid.
470 */
resize(uint newsize)471 void Q3GDict::resize(uint newsize)
472 {
473 // Save old information
474 Q3BaseBucket **old_vec = vec;
475 uint old_vlen = vlen;
476 bool old_copyk = copyk;
477
478 vec = new Q3BaseBucket *[vlen = newsize];
479 Q_CHECK_PTR(vec);
480 memset((char*)vec, 0, vlen*sizeof(Q3BaseBucket*));
481 numItems = 0;
482 copyk = false;
483
484 // Reinsert every item from vec, deleting vec as we go
485 for (uint index = 0; index < old_vlen; index++) {
486 switch (keytype) {
487 case StringKey:
488 {
489 Q3StringBucket *n=(Q3StringBucket *)old_vec[index];
490 while (n) {
491 look_string(n->getKey(), n->getData(), op_insert);
492 Q3StringBucket *t=(Q3StringBucket *)n->getNext();
493 delete n;
494 n = t;
495 }
496 }
497 break;
498 case AsciiKey:
499 {
500 Q3AsciiBucket *n=(Q3AsciiBucket *)old_vec[index];
501 while (n) {
502 look_ascii(n->getKey(), n->getData(), op_insert);
503 Q3AsciiBucket *t=(Q3AsciiBucket *)n->getNext();
504 delete n;
505 n = t;
506 }
507 }
508 break;
509 case IntKey:
510 {
511 Q3IntBucket *n=(Q3IntBucket *)old_vec[index];
512 while (n) {
513 look_int(n->getKey(), n->getData(), op_insert);
514 Q3IntBucket *t=(Q3IntBucket *)n->getNext();
515 delete n;
516 n = t;
517 }
518 }
519 break;
520 case PtrKey:
521 {
522 Q3PtrBucket *n=(Q3PtrBucket *)old_vec[index];
523 while (n) {
524 look_ptr(n->getKey(), n->getData(), op_insert);
525 Q3PtrBucket *t=(Q3PtrBucket *)n->getNext();
526 delete n;
527 n = t;
528 }
529 }
530 break;
531 }
532 }
533 delete [] old_vec;
534
535 // Restore state
536 copyk = old_copyk;
537
538 // Invalidate all iterators, since order is lost
539 if (iterators && iterators->count()) {
540 Q3GDictIterator *i = iterators->first();
541 while (i) {
542 i->toFirst();
543 i = iterators->next();
544 }
545 }
546 }
547
548 /*!
549 Unlinks the bucket with the specified key (and specified data pointer,
550 if it is set).
551 */
552
unlink_common(int index,Q3BaseBucket * node,Q3BaseBucket * prev)553 void Q3GDict::unlink_common(int index, Q3BaseBucket *node, Q3BaseBucket *prev)
554 {
555 if (iterators && iterators->count()) { // update iterators
556 Q3GDictIterator *i = iterators->first();
557 while (i) { // invalidate all iterators
558 if (i->curNode == node) // referring to pending node
559 i->operator++();
560 i = iterators->next();
561 }
562 }
563 if (prev) // unlink node
564 prev->setNext(node->getNext());
565 else
566 vec[index] = node->getNext();
567 numItems--;
568 }
569
unlink_string(const QString & key,Q3PtrCollection::Item d)570 Q3StringBucket *Q3GDict::unlink_string(const QString &key, Q3PtrCollection::Item d)
571 {
572 if (numItems == 0) // nothing in dictionary
573 return 0;
574 Q3StringBucket *n;
575 Q3StringBucket *prev = 0;
576 int index = hashKeyString(key) % vlen;
577 if (cases) {
578 for (n=(Q3StringBucket*)vec[index]; n;
579 n=(Q3StringBucket*)n->getNext()) {
580 bool found = (key == n->getKey());
581 if (found && d)
582 found = (n->getData() == d);
583 if (found) {
584 unlink_common(index,n,prev);
585 return n;
586 }
587 prev = n;
588 }
589 } else {
590 QString k = key.lower();
591 for (n=(Q3StringBucket*)vec[index]; n;
592 n=(Q3StringBucket*)n->getNext()) {
593 bool found = (k == n->getKey().lower());
594 if (found && d)
595 found = (n->getData() == d);
596 if (found) {
597 unlink_common(index,n,prev);
598 return n;
599 }
600 prev = n;
601 }
602 }
603 return 0;
604 }
605
unlink_ascii(const char * key,Q3PtrCollection::Item d)606 Q3AsciiBucket *Q3GDict::unlink_ascii(const char *key, Q3PtrCollection::Item d)
607 {
608 if (numItems == 0) // nothing in dictionary
609 return 0;
610 Q3AsciiBucket *n;
611 Q3AsciiBucket *prev = 0;
612 int index = hashKeyAscii(key) % vlen;
613 for (n=(Q3AsciiBucket *)vec[index]; n; n=(Q3AsciiBucket *)n->getNext()) {
614 bool found = (cases ? qstrcmp(n->getKey(),key)
615 : qstricmp(n->getKey(),key)) == 0;
616 if (found && d)
617 found = (n->getData() == d);
618 if (found) {
619 unlink_common(index,n,prev);
620 return n;
621 }
622 prev = n;
623 }
624 return 0;
625 }
626
unlink_int(long key,Q3PtrCollection::Item d)627 Q3IntBucket *Q3GDict::unlink_int(long key, Q3PtrCollection::Item d)
628 {
629 if (numItems == 0) // nothing in dictionary
630 return 0;
631 Q3IntBucket *n;
632 Q3IntBucket *prev = 0;
633 int index = (int)((ulong)key % vlen);
634 for (n=(Q3IntBucket *)vec[index]; n; n=(Q3IntBucket *)n->getNext()) {
635 bool found = (n->getKey() == key);
636 if (found && d)
637 found = (n->getData() == d);
638 if (found) {
639 unlink_common(index,n,prev);
640 return n;
641 }
642 prev = n;
643 }
644 return 0;
645 }
646
unlink_ptr(void * key,Q3PtrCollection::Item d)647 Q3PtrBucket *Q3GDict::unlink_ptr(void *key, Q3PtrCollection::Item d)
648 {
649 if (numItems == 0) // nothing in dictionary
650 return 0;
651 Q3PtrBucket *n;
652 Q3PtrBucket *prev = 0;
653 int index = (int)((quintptr)key % vlen);
654 for (n=(Q3PtrBucket *)vec[index]; n; n=(Q3PtrBucket *)n->getNext()) {
655 bool found = (n->getKey() == key);
656 if (found && d)
657 found = (n->getData() == d);
658 if (found) {
659 unlink_common(index,n,prev);
660 return n;
661 }
662 prev = n;
663 }
664 return 0;
665 }
666
667
668 /*!
669 Removes the item with the specified \a key. If \a item is not null,
670 the remove will match the \a item as well (used to remove an
671 item when several items have the same key).
672 */
673
remove_string(const QString & key,Q3PtrCollection::Item item)674 bool Q3GDict::remove_string(const QString &key, Q3PtrCollection::Item item)
675 {
676 Q3StringBucket *n = unlink_string(key, item);
677 if (n) {
678 deleteItem(n->getData());
679 delete n;
680 return true;
681 } else {
682 return false;
683 }
684 }
685
remove_ascii(const char * key,Q3PtrCollection::Item item)686 bool Q3GDict::remove_ascii(const char *key, Q3PtrCollection::Item item)
687 {
688 Q3AsciiBucket *n = unlink_ascii(key, item);
689 if (n) {
690 if (copyk)
691 delete [] (char *)n->getKey();
692 deleteItem(n->getData());
693 delete n;
694 }
695 return n != 0;
696 }
697
remove_int(long key,Q3PtrCollection::Item item)698 bool Q3GDict::remove_int(long key, Q3PtrCollection::Item item)
699 {
700 Q3IntBucket *n = unlink_int(key, item);
701 if (n) {
702 deleteItem(n->getData());
703 delete n;
704 }
705 return n != 0;
706 }
707
remove_ptr(void * key,Q3PtrCollection::Item item)708 bool Q3GDict::remove_ptr(void *key, Q3PtrCollection::Item item)
709 {
710 Q3PtrBucket *n = unlink_ptr(key, item);
711 if (n) {
712 deleteItem(n->getData());
713 delete n;
714 }
715 return n != 0;
716 }
717
take_string(const QString & key)718 Q3PtrCollection::Item Q3GDict::take_string(const QString &key)
719 {
720 Q3StringBucket *n = unlink_string(key);
721 Item d;
722 if (n) {
723 d = n->getData();
724 delete n;
725 } else {
726 d = 0;
727 }
728 return d;
729 }
730
take_ascii(const char * key)731 Q3PtrCollection::Item Q3GDict::take_ascii(const char *key)
732 {
733 Q3AsciiBucket *n = unlink_ascii(key);
734 Item d;
735 if (n) {
736 if (copyk)
737 delete [] (char *)n->getKey();
738 d = n->getData();
739 delete n;
740 } else {
741 d = 0;
742 }
743 return d;
744 }
745
take_int(long key)746 Q3PtrCollection::Item Q3GDict::take_int(long key)
747 {
748 Q3IntBucket *n = unlink_int(key);
749 Item d;
750 if (n) {
751 d = n->getData();
752 delete n;
753 } else {
754 d = 0;
755 }
756 return d;
757 }
758
take_ptr(void * key)759 Q3PtrCollection::Item Q3GDict::take_ptr(void *key)
760 {
761 Q3PtrBucket *n = unlink_ptr(key);
762 Item d;
763 if (n) {
764 d = n->getData();
765 delete n;
766 } else {
767 d = 0;
768 }
769 return d;
770 }
771
772 /*!
773 Removes all items from the dictionary.
774 */
clear()775 void Q3GDict::clear()
776 {
777 if (!numItems)
778 return;
779 numItems = 0; // disable remove() function
780 for (uint j=0; j<vlen; j++) { // destroy hash table
781 if (vec[j]) {
782 switch (keytype) {
783 case StringKey:
784 {
785 Q3StringBucket *n=(Q3StringBucket *)vec[j];
786 while (n) {
787 Q3StringBucket *next = (Q3StringBucket*)n->getNext();
788 deleteItem(n->getData());
789 delete n;
790 n = next;
791 }
792 }
793 break;
794 case AsciiKey:
795 {
796 Q3AsciiBucket *n=(Q3AsciiBucket *)vec[j];
797 while (n) {
798 Q3AsciiBucket *next = (Q3AsciiBucket*)n->getNext();
799 if (copyk)
800 delete [] (char *)n->getKey();
801 deleteItem(n->getData());
802 delete n;
803 n = next;
804 }
805 }
806 break;
807 case IntKey:
808 {
809 Q3IntBucket *n=(Q3IntBucket *)vec[j];
810 while (n) {
811 Q3IntBucket *next = (Q3IntBucket*)n->getNext();
812 deleteItem(n->getData());
813 delete n;
814 n = next;
815 }
816 }
817 break;
818 case PtrKey:
819 {
820 Q3PtrBucket *n=(Q3PtrBucket *)vec[j];
821 while (n) {
822 Q3PtrBucket *next = (Q3PtrBucket*)n->getNext();
823 deleteItem(n->getData());
824 delete n;
825 n = next;
826 }
827 }
828 break;
829 }
830 vec[j] = 0; // detach list of buckets
831 }
832 }
833 if (iterators && iterators->count()) { // invalidate all iterators
834 Q3GDictIterator *i = iterators->first();
835 while (i) {
836 i->curNode = 0;
837 i = iterators->next();
838 }
839 }
840 }
841
842 /*!
843 Outputs debug statistics.
844 */
statistics() const845 void Q3GDict::statistics() const
846 {
847 #if defined(QT_DEBUG)
848 QString line;
849 line.fill(QLatin1Char('-'), 60);
850 double real, ideal;
851 qDebug("%s", line.ascii());
852 qDebug("DICTIONARY STATISTICS:");
853 if (count() == 0) {
854 qDebug("Empty!");
855 qDebug("%s", line.ascii());
856 return;
857 }
858 real = 0.0;
859 ideal = (float)count()/(2.0*size())*(count()+2.0*size()-1);
860 uint i = 0;
861 while (i<size()) {
862 Q3BaseBucket *n = vec[i];
863 int b = 0;
864 while (n) { // count number of buckets
865 b++;
866 n = n->getNext();
867 }
868 real = real + (double)b * ((double)b+1.0)/2.0;
869 char buf[80], *pbuf;
870 if (b > 78)
871 b = 78;
872 pbuf = buf;
873 while (b--)
874 *pbuf++ = '*';
875 *pbuf = '\0';
876 qDebug("%s", buf);
877 i++;
878 }
879 qDebug("Array size = %d", size());
880 qDebug("# items = %d", count());
881 qDebug("Real dist = %g", real);
882 qDebug("Rand dist = %g", ideal);
883 qDebug("Real/Rand = %g", real/ideal);
884 qDebug("%s", line.ascii());
885 #endif // QT_DEBUG
886 }
887
888
889 /*****************************************************************************
890 Q3GDict stream functions
891 *****************************************************************************/
892 #ifndef QT_NO_DATASTREAM
operator >>(QDataStream & s,Q3GDict & dict)893 QDataStream &operator>>(QDataStream &s, Q3GDict &dict)
894 {
895 return dict.read(s);
896 }
897
operator <<(QDataStream & s,const Q3GDict & dict)898 QDataStream &operator<<(QDataStream &s, const Q3GDict &dict)
899 {
900 return dict.write(s);
901 }
902
903 #if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0 >= 50190001)
904 #pragma message disable narrowptr
905 #endif
906
907 /*!
908 Reads a dictionary from the stream \a s.
909 */
910
read(QDataStream & s)911 QDataStream &Q3GDict::read(QDataStream &s)
912 {
913 uint num;
914 s >> num; // read number of items
915 clear(); // clear dict
916 while (num--) { // read all items
917 Item d;
918 switch (keytype) {
919 case StringKey:
920 {
921 QString k;
922 s >> k;
923 read(s, d);
924 look_string(k, d, op_insert);
925 }
926 break;
927 case AsciiKey:
928 {
929 char *k;
930 s >> k;
931 read(s, d);
932 look_ascii(k, d, op_insert);
933 if (copyk)
934 delete [] k;
935 }
936 break;
937 case IntKey:
938 {
939 Q_UINT32 k;
940 s >> k;
941 read(s, d);
942 look_int(k, d, op_insert);
943 }
944 break;
945 case PtrKey:
946 {
947 Q_UINT32 k;
948 s >> k;
949 read(s, d);
950 // ### cannot insert 0 - this renders the thing
951 // useless since all pointers are written as 0,
952 // but hey, serializing pointers? can it be done
953 // at all, ever?
954 if (k)
955 look_ptr((void *)(ulong)k, d, op_insert);
956 }
957 break;
958 }
959 }
960 return s;
961 }
962
963 /*!
964 Writes the dictionary to the stream \a s.
965 */
966
write(QDataStream & s) const967 QDataStream& Q3GDict::write(QDataStream &s) const
968 {
969 s << count(); // write number of items
970 uint i = 0;
971 while (i<size()) {
972 Q3BaseBucket *n = vec[i];
973 while (n) { // write all buckets
974 switch (keytype) {
975 case StringKey:
976 s << ((Q3StringBucket*)n)->getKey();
977 break;
978 case AsciiKey:
979 s << ((Q3AsciiBucket*)n)->getKey();
980 break;
981 case IntKey:
982 s << (Q_UINT32)((Q3IntBucket*)n)->getKey();
983 break;
984 case PtrKey:
985 s << (Q_UINT32)0; // ### cannot serialize a pointer
986 break;
987 }
988 write(s, n->getData()); // write data
989 n = n->getNext();
990 }
991 i++;
992 }
993 return s;
994 }
995 #endif //QT_NO_DATASTREAM
996
997 /*****************************************************************************
998 Q3GDictIterator member functions
999 *****************************************************************************/
1000
1001 /*!
1002 \class Q3GDictIterator
1003 \reentrant
1004 \brief The Q3GDictIterator class is an internal class for implementing QDictIterator and QIntDictIterator.
1005
1006 \internal
1007
1008 Q3GDictIterator is a strictly internal class that does the heavy work for
1009 QDictIterator and QIntDictIterator.
1010 */
1011
1012 /*!
1013 Constructs an iterator that operates on the dictionary \a d.
1014 */
1015
Q3GDictIterator(const Q3GDict & d)1016 Q3GDictIterator::Q3GDictIterator(const Q3GDict &d)
1017 {
1018 dict = (Q3GDict *)&d; // get reference to dict
1019 toFirst(); // set to first noe
1020 if (!dict->iterators) {
1021 dict->iterators = new Q3GDItList; // create iterator list
1022 Q_CHECK_PTR(dict->iterators);
1023 }
1024 dict->iterators->append(this); // attach iterator to dict
1025 }
1026
1027 /*!
1028 Constructs a copy of the iterator \a it.
1029 */
1030
Q3GDictIterator(const Q3GDictIterator & it)1031 Q3GDictIterator::Q3GDictIterator(const Q3GDictIterator &it)
1032 {
1033 dict = it.dict;
1034 curNode = it.curNode;
1035 curIndex = it.curIndex;
1036 if (dict)
1037 dict->iterators->append(this); // attach iterator to dict
1038 }
1039
1040 /*!
1041 Assigns a copy of the iterator \a it and returns a reference to this
1042 iterator.
1043 */
1044
operator =(const Q3GDictIterator & it)1045 Q3GDictIterator &Q3GDictIterator::operator=(const Q3GDictIterator &it)
1046 {
1047 if (dict) // detach from old dict
1048 dict->iterators->removeRef(this);
1049 dict = it.dict;
1050 curNode = it.curNode;
1051 curIndex = it.curIndex;
1052 if (dict)
1053 dict->iterators->append(this); // attach to new list
1054 return *this;
1055 }
1056
1057 /*!
1058 Destroys the iterator.
1059 */
1060
~Q3GDictIterator()1061 Q3GDictIterator::~Q3GDictIterator()
1062 {
1063 if (dict) // detach iterator from dict
1064 dict->iterators->removeRef(this);
1065 }
1066
1067
1068 /*!
1069 Sets the iterator to point to the first item in the dictionary.
1070 */
1071
toFirst()1072 Q3PtrCollection::Item Q3GDictIterator::toFirst()
1073 {
1074 if (!dict) {
1075 #if defined(QT_CHECK_NULL)
1076 qWarning("Q3GDictIterator::toFirst: Dictionary has been deleted");
1077 #endif
1078 return 0;
1079 }
1080 if (dict->count() == 0) { // empty dictionary
1081 curNode = 0;
1082 return 0;
1083 }
1084 register uint i = 0;
1085 register Q3BaseBucket **v = dict->vec;
1086 while (!(*v++))
1087 i++;
1088 curNode = dict->vec[i];
1089 curIndex = i;
1090 return curNode->getData();
1091 }
1092
1093
1094 /*!
1095 Moves to the next item (postfix).
1096 */
1097
operator ()()1098 Q3PtrCollection::Item Q3GDictIterator::operator()()
1099 {
1100 if (!dict) {
1101 #if defined(QT_CHECK_NULL)
1102 qWarning("Q3GDictIterator::operator(): Dictionary has been deleted");
1103 #endif
1104 return 0;
1105 }
1106 if (!curNode)
1107 return 0;
1108 Q3PtrCollection::Item d = curNode->getData();
1109 this->operator++();
1110 return d;
1111 }
1112
1113 /*!
1114 Moves to the next item (prefix).
1115 */
1116
operator ++()1117 Q3PtrCollection::Item Q3GDictIterator::operator++()
1118 {
1119 if (!dict) {
1120 #if defined(QT_CHECK_NULL)
1121 qWarning("Q3GDictIterator::operator++: Dictionary has been deleted");
1122 #endif
1123 return 0;
1124 }
1125 if (!curNode)
1126 return 0;
1127 curNode = curNode->getNext();
1128 if (!curNode) { // no next bucket
1129 register uint i = curIndex + 1; // look from next vec element
1130 register Q3BaseBucket **v = &dict->vec[i];
1131 while (i < dict->size() && !(*v++))
1132 i++;
1133 if (i == dict->size()) { // nothing found
1134 curNode = 0;
1135 return 0;
1136 }
1137 curNode = dict->vec[i];
1138 curIndex = i;
1139 }
1140 return curNode->getData();
1141 }
1142
1143 /*!
1144 Moves \a jumps positions forward.
1145 */
1146
operator +=(uint jumps)1147 Q3PtrCollection::Item Q3GDictIterator::operator+=(uint jumps)
1148 {
1149 while (curNode && jumps--)
1150 operator++();
1151 return curNode ? curNode->getData() : 0;
1152 }
1153
1154 QT_END_NAMESPACE
1155