source: vendor/trolltech/current/src/tools/qgdict.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

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