📄 qgdict.cpp
字号:
/************************************************************************ Copyright (C) 2000-2005 Trolltech AS. All rights reserved.**** This file is part of the Qtopia Environment.** ** This program is free software; you can redistribute it and/or modify it** under the terms of the GNU General Public License as published by the** Free Software Foundation; either version 2 of the License, or (at your** option) any later version.** ** A copy of the GNU GPL license version 2 is included in this package as ** LICENSE.GPL.**** This program is distributed in the hope that it will be useful, but** WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU General Public License for more details.**** In addition, as a special exception Trolltech gives permission to link** the code of this program with Qtopia applications copyrighted, developed** and distributed by Trolltech under the terms of the Qtopia Personal Use** License Agreement. You must comply with the GNU General Public License** in all respects for all of the code used other than the applications** licensed under the Qtopia Personal Use License Agreement. If you modify** this file, you may extend this exception to your version of the file,** but you are not obligated to do so. If you do not wish to do so, delete** this exception statement from your version.** ** See http://www.trolltech.com/gpl/ for GPL licensing information.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "qgdict.h"#include "qptrlist.h"#include "qstring.h"#include "qdatastream.h"#include <ctype.h>/*! \class QGDict \reentrant \ingroup collection \brief The QGDict class is an internal class for implementing QDict template classes. \internal QGDict is a strictly internal class that acts as a base class for the \link collection.html collection classes\endlink QDict and QIntDict. QGDict has some virtual functions that can be reimplemented to customize the subclasses. \list \i read() reads a collection/dictionary item from a QDataStream. \i write() writes a collection/dictionary item to a QDataStream. \endlist Normally, you do not have to reimplement any of these functions.*/static const int op_find = 0;static const int op_insert = 1;static const int op_replace = 2;class QGDItList : public QPtrList<QGDictIterator>{public: QGDItList() : QPtrList<QGDictIterator>() {} QGDItList( const QGDItList &list ) : QPtrList<QGDictIterator>(list) {} ~QGDItList() { clear(); } QGDItList &operator=(const QGDItList &list) { return (QGDItList&)QPtrList<QGDictIterator>::operator=(list); }};/***************************************************************************** Default implementation of special and virtual functions *****************************************************************************//*! Returns the hash key for \a key, when key is a string.*/int QGDict::hashKeyString( const QString &key ){#if defined(QT_CHECK_NULL) if ( key.isNull() ) qWarning( "QGDict::hashKeyString: Invalid null key" );#endif int i; register uint h=0; uint g; const QChar *p = key.unicode(); if ( cases ) { // case sensitive for ( i=0; i<(int)key.length(); i++ ) { h = (h<<4) + p[i].cell(); if ( (g = h & 0xf0000000) ) h ^= g >> 24; h &= ~g; } } else { // case insensitive for ( i=0; i<(int)key.length(); i++ ) { h = (h<<4) + p[i].lower().cell(); if ( (g = h & 0xf0000000) ) h ^= g >> 24; h &= ~g; } } int index = h; if ( index < 0 ) // adjust index to table size index = -index; return index;}/*! Returns the hash key for \a key, which is a C string.*/int QGDict::hashKeyAscii( const char *key ){#if defined(QT_CHECK_NULL) if ( key == 0 ) qWarning( "QGDict::hashAsciiKey: Invalid null key" );#endif register const char *k = key; register uint h=0; uint g; if ( cases ) { // case sensitive while ( *k ) { h = (h<<4) + *k++; if ( (g = h & 0xf0000000) ) h ^= g >> 24; h &= ~g; } } else { // case insensitive while ( *k ) { h = (h<<4) + tolower((uchar) *k); if ( (g = h & 0xf0000000) ) h ^= g >> 24; h &= ~g; k++; } } int index = h; if ( index < 0 ) // adjust index to table size index = -index; return index;}#ifndef QT_NO_DATASTREAM/*! \overload Reads a collection/dictionary item from the stream \a s and returns a reference to the stream. The default implementation sets \a item to 0. \sa write()*/QDataStream& QGDict::read( QDataStream &s, QPtrCollection::Item &item ){ item = 0; return s;}/*! \overload Writes a collection/dictionary item to the stream \a s and returns a reference to the stream. \sa read()*/QDataStream& QGDict::write( QDataStream &s, QPtrCollection::Item ) const{ return s;}#endif //QT_NO_DATASTREAM/***************************************************************************** QGDict member functions *****************************************************************************//*! Constructs a dictionary. \a len is the initial size of the dictionary. The key type is \a kt which may be \c StringKey, \c AsciiKey, \c IntKey or \c PtrKey. The case-sensitivity of lookups is set with \a caseSensitive. Keys are copied if \a copyKeys is TRUE.*/QGDict::QGDict( uint len, KeyType kt, bool caseSensitive, bool copyKeys ){ init( len, kt, caseSensitive, copyKeys );}void QGDict::init( uint len, KeyType kt, bool caseSensitive, bool copyKeys ){ vlen = len ? len : 17; vec = new QBaseBucket *[ vlen ]; Q_CHECK_PTR( vec ); memset( (char*)vec, 0, vlen*sizeof(QBaseBucket*) ); numItems = 0; iterators = 0; // The caseSensitive and copyKey options don't make sense for // all dict types. switch ( (keytype = (uint)kt) ) { case StringKey: cases = caseSensitive; copyk = FALSE; break; case AsciiKey: cases = caseSensitive; copyk = copyKeys; break; default: cases = FALSE; copyk = FALSE; break; }}/*! Constructs a copy of \a dict.*/QGDict::QGDict( const QGDict & dict ) : QPtrCollection( dict ){ init( dict.vlen, (KeyType)dict.keytype, dict.cases, dict.copyk ); QGDictIterator it( dict ); while ( it.get() ) { // copy from other dict switch ( keytype ) { case StringKey: look_string( it.getKeyString(), it.get(), op_insert ); break; case AsciiKey: look_ascii( it.getKeyAscii(), it.get(), op_insert ); break; case IntKey: look_int( it.getKeyInt(), it.get(), op_insert ); break; case PtrKey: look_ptr( it.getKeyPtr(), it.get(), op_insert ); break; } ++it; }}/*! Removes all items from the dictionary and destroys it.*/QGDict::~QGDict(){ clear(); // delete everything delete [] vec; if ( !iterators ) // no iterators for this dict return; QGDictIterator *i = iterators->first(); while ( i ) { // notify all iterators that i->dict = 0; // this dict is deleted i = iterators->next(); } delete iterators;}/*! Assigns \a dict to this dictionary.*/QGDict &QGDict::operator=( const QGDict &dict ){ if ( &dict == this ) return *this; clear(); QGDictIterator it( dict ); while ( it.get() ) { // copy from other dict switch ( keytype ) { case StringKey: look_string( it.getKeyString(), it.get(), op_insert ); break; case AsciiKey: look_ascii( it.getKeyAscii(), it.get(), op_insert ); break; case IntKey: look_int( it.getKeyInt(), it.get(), op_insert ); break; case PtrKey: look_ptr( it.getKeyPtr(), it.get(), op_insert ); break; } ++it; } return *this;}/*! \fn uint QGDict::count() const Returns the number of items in the dictionary.*//*! \fn uint QGDict::size() const Returns the size of the hash array.*//*! The do-it-all function; \a op is one of op_find, op_insert, op_replace. The key is \a key and the item is \a d.*/QPtrCollection::Item QGDict::look_string( const QString &key, QPtrCollection::Item d, int op ){ QStringBucket *n = 0; int index = hashKeyString(key) % vlen; if ( op == op_find ) { // find if ( cases ) { n = (QStringBucket*)vec[index]; while( n != 0 ) { if ( key == n->getKey() ) return n->getData(); // item found n = (QStringBucket*)n->getNext(); } } else { QString k = key.lower(); n = (QStringBucket*)vec[index]; while( n != 0 ) { if ( k == n->getKey().lower() ) return n->getData(); // item found n = (QStringBucket*)n->getNext(); } } return 0; // not found } if ( op == op_replace ) { // replace if ( vec[index] != 0 ) // maybe something there remove_string( key ); } // op_insert or op_replace n = new QStringBucket(key,newItem(d),vec[index]); Q_CHECK_PTR( n );#if defined(QT_CHECK_NULL) if ( n->getData() == 0 ) qWarning( "QDict: Cannot insert null item" );#endif vec[index] = n; numItems++; return n->getData();}QPtrCollection::Item QGDict::look_ascii( const char *key, QPtrCollection::Item d, int op ){ QAsciiBucket *n; int index = hashKeyAscii(key) % vlen; if ( op == op_find ) { // find if ( cases ) { for ( n=(QAsciiBucket*)vec[index]; n; n=(QAsciiBucket*)n->getNext() ) { if ( qstrcmp(n->getKey(),key) == 0 ) return n->getData(); // item found } } else { for ( n=(QAsciiBucket*)vec[index]; n; n=(QAsciiBucket*)n->getNext() ) { if ( qstricmp(n->getKey(),key) == 0 ) return n->getData(); // item found } } return 0; // not found } if ( op == op_replace ) { // replace if ( vec[index] != 0 ) // maybe something there remove_ascii( key ); } // op_insert or op_replace n = new QAsciiBucket(copyk ? qstrdup(key) : key,newItem(d),vec[index]); Q_CHECK_PTR( n );#if defined(QT_CHECK_NULL) if ( n->getData() == 0 ) qWarning( "QAsciiDict: Cannot insert null item" );#endif vec[index] = n; numItems++; return n->getData();}QPtrCollection::Item QGDict::look_int( long key, QPtrCollection::Item d, int op ){ QIntBucket *n; int index = (int)((ulong)key % vlen); // simple hash if ( op == op_find ) { // find for ( n=(QIntBucket*)vec[index]; n; n=(QIntBucket*)n->getNext() ) { if ( n->getKey() == key ) return n->getData(); // item found } return 0; // not found } if ( op == op_replace ) { // replace if ( vec[index] != 0 ) // maybe something there remove_int( key ); } // op_insert or op_replace n = new QIntBucket(key,newItem(d),vec[index]); Q_CHECK_PTR( n );#if defined(QT_CHECK_NULL) if ( n->getData() == 0 ) qWarning( "QIntDict: Cannot insert null item" );#endif vec[index] = n; numItems++; return n->getData();}QPtrCollection::Item QGDict::look_ptr( void *key, QPtrCollection::Item d, int op ){ QPtrBucket *n; int index = (int)((ulong)key % vlen); // simple hash if ( op == op_find ) { // find for ( n=(QPtrBucket*)vec[index]; n; n=(QPtrBucket*)n->getNext() ) { if ( n->getKey() == key ) return n->getData(); // item found } return 0; // not found } if ( op == op_replace ) { // replace if ( vec[index] != 0 ) // maybe something there remove_ptr( key ); } // op_insert or op_replace n = new QPtrBucket(key,newItem(d),vec[index]); Q_CHECK_PTR( n );#if defined(QT_CHECK_NULL) if ( n->getData() == 0 ) qWarning( "QPtrDict: Cannot insert null item" );#endif vec[index] = n; numItems++; return n->getData();}/*! Changes the size of the hashtable to \a newsize. The contents of the dictionary are preserved, but all iterators on the dictionary become invalid.*/void QGDict::resize( uint newsize ){ // Save old information QBaseBucket **old_vec = vec; uint old_vlen = vlen; bool old_copyk = copyk; vec = new QBaseBucket *[vlen = newsize]; Q_CHECK_PTR( vec ); memset( (char*)vec, 0, vlen*sizeof(QBaseBucket*) ); numItems = 0; copyk = FALSE; // Reinsert every item from vec, deleting vec as we go for ( uint index = 0; index < old_vlen; index++ ) { switch ( keytype ) { case StringKey: { QStringBucket *n=(QStringBucket *)old_vec[index]; while ( n ) { look_string( n->getKey(), n->getData(), op_insert ); QStringBucket *t=(QStringBucket *)n->getNext(); delete n; n = t; } } break; case AsciiKey: { QAsciiBucket *n=(QAsciiBucket *)old_vec[index]; while ( n ) { look_ascii( n->getKey(), n->getData(), op_insert ); QAsciiBucket *t=(QAsciiBucket *)n->getNext(); delete n; n = t; } } break; case IntKey: { QIntBucket *n=(QIntBucket *)old_vec[index]; while ( n ) { look_int( n->getKey(), n->getData(), op_insert ); QIntBucket *t=(QIntBucket *)n->getNext(); delete n; n = t; } } break; case PtrKey: { QPtrBucket *n=(QPtrBucket *)old_vec[index]; while ( n ) { look_ptr( n->getKey(), n->getData(), op_insert ); QPtrBucket *t=(QPtrBucket *)n->getNext(); delete n; n = t; } } break; } } delete [] old_vec; // Restore state copyk = old_copyk; // Invalidate all iterators, since order is lost if ( iterators && iterators->count() ) { QGDictIterator *i = iterators->first(); while ( i ) { i->toFirst(); i = iterators->next(); } }}/*! Unlinks the bucket with the specified key (and specified data pointer, if it is set).*/void QGDict::unlink_common( int index, QBaseBucket *node, QBaseBucket *prev ){ if ( iterators && iterators->count() ) { // update iterators QGDictIterator *i = iterators->first(); while ( i ) { // invalidate all iterators if ( i->curNode == node ) // referring to pending node i->operator++(); i = iterators->next(); } } if ( prev ) // unlink node prev->setNext( node->getNext() ); else vec[index] = node->getNext(); numItems--;}QStringBucket *QGDict::unlink_string( const QString &key, QPtrCollection::Item d ){ if ( numItems == 0 ) // nothing in dictionary return 0; QStringBucket *n; QStringBucket *prev = 0; int index = hashKeyString(key) % vlen; if ( cases ) { for ( n=(QStringBucket*)vec[index]; n; n=(QStringBucket*)n->getNext() ) { bool found = (key == n->getKey()); if ( found && d )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -