You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1152 lines
26 KiB
1152 lines
26 KiB
/****************************************************************************
|
|
**
|
|
** Implementation of QGDict and QGDictIterator classes
|
|
**
|
|
** Created : 920529
|
|
**
|
|
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
|
|
**
|
|
** This file is part of the tools module of the Qt GUI Toolkit.
|
|
**
|
|
** This file may be used under the terms of the GNU General
|
|
** Public License versions 2.0 or 3.0 as published by the Free
|
|
** Software Foundation and appearing in the files LICENSE.GPL2
|
|
** and LICENSE.GPL3 included in the packaging of this file.
|
|
** Alternatively you may (at your option) use any later version
|
|
** of the GNU General Public License if such license has been
|
|
** publicly approved by Trolltech ASA (or its successors, if any)
|
|
** and the KDE Free Qt Foundation.
|
|
**
|
|
** Please review the following information to ensure GNU General
|
|
** Public Licensing requirements will be met:
|
|
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
|
|
** If you are unsure which license is appropriate for your use, please
|
|
** review the following information:
|
|
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
|
|
** or contact the sales department at sales@trolltech.com.
|
|
**
|
|
** This file may be used under the terms of the Q Public License as
|
|
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
|
|
** included in the packaging of this file. Licensees holding valid Qt
|
|
** Commercial licenses may use this file in accordance with the Qt
|
|
** Commercial License Agreement provided with the Software.
|
|
**
|
|
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
|
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
|
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
|
|
** herein.
|
|
**
|
|
**********************************************************************/
|
|
|
|
#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;
|
|
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
|
|
const char *k = key;
|
|
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 )
|
|
found = (n->getData() == d);
|
|
if ( found ) {
|
|
unlink_common(index,n,prev);
|
|
return n;
|
|
}
|
|
prev = n;
|
|
}
|
|
} else {
|
|
QString k = key.lower();
|
|
for ( n=(QStringBucket*)vec[index]; n;
|
|
n=(QStringBucket*)n->getNext() ) {
|
|
bool found = (k == n->getKey().lower());
|
|
if ( found && d )
|
|
found = (n->getData() == d);
|
|
if ( found ) {
|
|
unlink_common(index,n,prev);
|
|
return n;
|
|
}
|
|
prev = n;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
QAsciiBucket *QGDict::unlink_ascii( const char *key, QPtrCollection::Item d )
|
|
{
|
|
if ( numItems == 0 ) // nothing in dictionary
|
|
return 0;
|
|
QAsciiBucket *n;
|
|
QAsciiBucket *prev = 0;
|
|
int index = hashKeyAscii(key) % vlen;
|
|
for ( n=(QAsciiBucket *)vec[index]; n; n=(QAsciiBucket *)n->getNext() ) {
|
|
bool found = (cases ? qstrcmp(n->getKey(),key)
|
|
: qstricmp(n->getKey(),key)) == 0;
|
|
if ( found && d )
|
|
found = (n->getData() == d);
|
|
if ( found ) {
|
|
unlink_common(index,n,prev);
|
|
return n;
|
|
}
|
|
prev = n;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
QIntBucket *QGDict::unlink_int( long key, QPtrCollection::Item d )
|
|
{
|
|
if ( numItems == 0 ) // nothing in dictionary
|
|
return 0;
|
|
QIntBucket *n;
|
|
QIntBucket *prev = 0;
|
|
int index = (int)((ulong)key % vlen);
|
|
for ( n=(QIntBucket *)vec[index]; n; n=(QIntBucket *)n->getNext() ) {
|
|
bool found = (n->getKey() == key);
|
|
if ( found && d )
|
|
found = (n->getData() == d);
|
|
if ( found ) {
|
|
unlink_common(index,n,prev);
|
|
return n;
|
|
}
|
|
prev = n;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
QPtrBucket *QGDict::unlink_ptr( void *key, QPtrCollection::Item d )
|
|
{
|
|
if ( numItems == 0 ) // nothing in dictionary
|
|
return 0;
|
|
QPtrBucket *n;
|
|
QPtrBucket *prev = 0;
|
|
int index = (int)((ulong)key % vlen);
|
|
for ( n=(QPtrBucket *)vec[index]; n; n=(QPtrBucket *)n->getNext() ) {
|
|
bool found = (n->getKey() == key);
|
|
if ( found && d )
|
|
found = (n->getData() == d);
|
|
if ( found ) {
|
|
unlink_common(index,n,prev);
|
|
return n;
|
|
}
|
|
prev = n;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
Removes the item with the specified \a key. If \a item is not null,
|
|
the remove will match the \a item as well (used to remove an
|
|
item when several items have the same key).
|
|
*/
|
|
|
|
bool QGDict::remove_string( const QString &key, QPtrCollection::Item item )
|
|
{
|
|
QStringBucket *n = unlink_string( key, item );
|
|
if ( n ) {
|
|
deleteItem( n->getData() );
|
|
delete n;
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
bool QGDict::remove_ascii( const char *key, QPtrCollection::Item item )
|
|
{
|
|
QAsciiBucket *n = unlink_ascii( key, item );
|
|
if ( n ) {
|
|
if ( copyk )
|
|
delete [] (char *)n->getKey();
|
|
deleteItem( n->getData() );
|
|
delete n;
|
|
}
|
|
return n != 0;
|
|
}
|
|
|
|
bool QGDict::remove_int( long key, QPtrCollection::Item item )
|
|
{
|
|
QIntBucket *n = unlink_int( key, item );
|
|
if ( n ) {
|
|
deleteItem( n->getData() );
|
|
delete n;
|
|
}
|
|
return n != 0;
|
|
}
|
|
|
|
bool QGDict::remove_ptr( void *key, QPtrCollection::Item item )
|
|
{
|
|
QPtrBucket *n = unlink_ptr( key, item );
|
|
if ( n ) {
|
|
deleteItem( n->getData() );
|
|
delete n;
|
|
}
|
|
return n != 0;
|
|
}
|
|
|
|
QPtrCollection::Item QGDict::take_string( const QString &key )
|
|
{
|
|
QStringBucket *n = unlink_string( key );
|
|
Item d;
|
|
if ( n ) {
|
|
d = n->getData();
|
|
delete n;
|
|
} else {
|
|
d = 0;
|
|
}
|
|
return d;
|
|
}
|
|
|
|
QPtrCollection::Item QGDict::take_ascii( const char *key )
|
|
{
|
|
QAsciiBucket *n = unlink_ascii( key );
|
|
Item d;
|
|
if ( n ) {
|
|
if ( copyk )
|
|
delete [] (char *)n->getKey();
|
|
d = n->getData();
|
|
delete n;
|
|
} else {
|
|
d = 0;
|
|
}
|
|
return d;
|
|
}
|
|
|
|
QPtrCollection::Item QGDict::take_int( long key )
|
|
{
|
|
QIntBucket *n = unlink_int( key );
|
|
Item d;
|
|
if ( n ) {
|
|
d = n->getData();
|
|
delete n;
|
|
} else {
|
|
d = 0;
|
|
}
|
|
return d;
|
|
}
|
|
|
|
QPtrCollection::Item QGDict::take_ptr( void *key )
|
|
{
|
|
QPtrBucket *n = unlink_ptr( key );
|
|
Item d;
|
|
if ( n ) {
|
|
d = n->getData();
|
|
delete n;
|
|
} else {
|
|
d = 0;
|
|
}
|
|
return d;
|
|
}
|
|
|
|
/*!
|
|
Removes all items from the dictionary.
|
|
*/
|
|
void QGDict::clear()
|
|
{
|
|
if ( !numItems )
|
|
return;
|
|
numItems = 0; // disable remove() function
|
|
for ( uint j=0; j<vlen; j++ ) { // destroy hash table
|
|
if ( vec[j] ) {
|
|
switch ( keytype ) {
|
|
case StringKey:
|
|
{
|
|
QStringBucket *n=(QStringBucket *)vec[j];
|
|
while ( n ) {
|
|
QStringBucket *next = (QStringBucket*)n->getNext();
|
|
deleteItem( n->getData() );
|
|
delete n;
|
|
n = next;
|
|
}
|
|
}
|
|
break;
|
|
case AsciiKey:
|
|
{
|
|
QAsciiBucket *n=(QAsciiBucket *)vec[j];
|
|
while ( n ) {
|
|
QAsciiBucket *next = (QAsciiBucket*)n->getNext();
|
|
if ( copyk )
|
|
delete [] (char *)n->getKey();
|
|
deleteItem( n->getData() );
|
|
delete n;
|
|
n = next;
|
|
}
|
|
}
|
|
break;
|
|
case IntKey:
|
|
{
|
|
QIntBucket *n=(QIntBucket *)vec[j];
|
|
while ( n ) {
|
|
QIntBucket *next = (QIntBucket*)n->getNext();
|
|
deleteItem( n->getData() );
|
|
delete n;
|
|
n = next;
|
|
}
|
|
}
|
|
break;
|
|
case PtrKey:
|
|
{
|
|
QPtrBucket *n=(QPtrBucket *)vec[j];
|
|
while ( n ) {
|
|
QPtrBucket *next = (QPtrBucket*)n->getNext();
|
|
deleteItem( n->getData() );
|
|
delete n;
|
|
n = next;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
vec[j] = 0; // detach list of buckets
|
|
}
|
|
}
|
|
if ( iterators && iterators->count() ) { // invalidate all iterators
|
|
QGDictIterator *i = iterators->first();
|
|
while ( i ) {
|
|
i->curNode = 0;
|
|
i = iterators->next();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Outputs debug statistics.
|
|
*/
|
|
void QGDict::statistics() const
|
|
{
|
|
#if defined(QT_DEBUG)
|
|
QString line;
|
|
line.fill( '-', 60 );
|
|
double real, ideal;
|
|
qDebug( "%s", line.ascii() );
|
|
qDebug( "DICTIONARY STATISTICS:" );
|
|
if ( count() == 0 ) {
|
|
qDebug( "Empty!" );
|
|
qDebug( "%s", line.ascii() );
|
|
return;
|
|
}
|
|
real = 0.0;
|
|
ideal = (float)count()/(2.0*size())*(count()+2.0*size()-1);
|
|
uint i = 0;
|
|
while ( i<size() ) {
|
|
QBaseBucket *n = vec[i];
|
|
int b = 0;
|
|
while ( n ) { // count number of buckets
|
|
b++;
|
|
n = n->getNext();
|
|
}
|
|
real = real + (double)b * ((double)b+1.0)/2.0;
|
|
char buf[80], *pbuf;
|
|
if ( b > 78 )
|
|
b = 78;
|
|
pbuf = buf;
|
|
while ( b-- )
|
|
*pbuf++ = '*';
|
|
*pbuf = '\0';
|
|
qDebug( "%s", buf );
|
|
i++;
|
|
}
|
|
qDebug( "Array size = %d", size() );
|
|
qDebug( "# items = %d", count() );
|
|
qDebug( "Real dist = %g", real );
|
|
qDebug( "Rand dist = %g", ideal );
|
|
qDebug( "Real/Rand = %g", real/ideal );
|
|
qDebug( "%s", line.ascii() );
|
|
#endif // QT_DEBUG
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
QGDict stream functions
|
|
*****************************************************************************/
|
|
#ifndef QT_NO_DATASTREAM
|
|
QDataStream &operator>>( QDataStream &s, QGDict &dict )
|
|
{
|
|
return dict.read( s );
|
|
}
|
|
|
|
QDataStream &operator<<( QDataStream &s, const QGDict &dict )
|
|
{
|
|
return dict.write( s );
|
|
}
|
|
|
|
#if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0 >= 50190001)
|
|
#pragma message disable narrowptr
|
|
#endif
|
|
|
|
/*!
|
|
Reads a dictionary from the stream \a s.
|
|
*/
|
|
|
|
QDataStream &QGDict::read( QDataStream &s )
|
|
{
|
|
uint num;
|
|
s >> num; // read number of items
|
|
clear(); // clear dict
|
|
while ( num-- ) { // read all items
|
|
Item d;
|
|
switch ( keytype ) {
|
|
case StringKey:
|
|
{
|
|
QString k;
|
|
s >> k;
|
|
read( s, d );
|
|
look_string( k, d, op_insert );
|
|
}
|
|
break;
|
|
case AsciiKey:
|
|
{
|
|
char *k;
|
|
s >> k;
|
|
read( s, d );
|
|
look_ascii( k, d, op_insert );
|
|
if ( copyk )
|
|
delete [] k;
|
|
}
|
|
break;
|
|
case IntKey:
|
|
{
|
|
Q_UINT32 k;
|
|
s >> k;
|
|
read( s, d );
|
|
look_int( k, d, op_insert );
|
|
}
|
|
break;
|
|
case PtrKey:
|
|
{
|
|
Q_UINT32 k;
|
|
s >> k;
|
|
read( s, d );
|
|
// ### cannot insert 0 - this renders the thing
|
|
// useless since all pointers are written as 0,
|
|
// but hey, serializing pointers? can it be done
|
|
// at all, ever?
|
|
if ( k )
|
|
look_ptr( (void *)k, d, op_insert );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/*!
|
|
Writes the dictionary to the stream \a s.
|
|
*/
|
|
|
|
QDataStream& QGDict::write( QDataStream &s ) const
|
|
{
|
|
s << count(); // write number of items
|
|
uint i = 0;
|
|
while ( i<size() ) {
|
|
QBaseBucket *n = vec[i];
|
|
while ( n ) { // write all buckets
|
|
switch ( keytype ) {
|
|
case StringKey:
|
|
s << ((QStringBucket*)n)->getKey();
|
|
break;
|
|
case AsciiKey:
|
|
s << ((QAsciiBucket*)n)->getKey();
|
|
break;
|
|
case IntKey:
|
|
s << (Q_UINT32)((QIntBucket*)n)->getKey();
|
|
break;
|
|
case PtrKey:
|
|
s << (Q_UINT32)0; // ### cannot serialize a pointer
|
|
break;
|
|
}
|
|
write( s, n->getData() ); // write data
|
|
n = n->getNext();
|
|
}
|
|
i++;
|
|
}
|
|
return s;
|
|
}
|
|
#endif //QT_NO_DATASTREAM
|
|
|
|
/*****************************************************************************
|
|
QGDictIterator member functions
|
|
*****************************************************************************/
|
|
|
|
/*!
|
|
\class QGDictIterator qgdict.h
|
|
\reentrant
|
|
\ingroup collection
|
|
\brief The QGDictIterator class is an internal class for implementing QDictIterator and QIntDictIterator.
|
|
|
|
\internal
|
|
|
|
QGDictIterator is a strictly internal class that does the heavy work for
|
|
QDictIterator and QIntDictIterator.
|
|
*/
|
|
|
|
/*!
|
|
Constructs an iterator that operates on the dictionary \a d.
|
|
*/
|
|
|
|
QGDictIterator::QGDictIterator( const QGDict &d )
|
|
{
|
|
dict = (QGDict *)&d; // get reference to dict
|
|
toFirst(); // set to first noe
|
|
if ( !dict->iterators ) {
|
|
dict->iterators = new QGDItList; // create iterator list
|
|
Q_CHECK_PTR( dict->iterators );
|
|
}
|
|
dict->iterators->append( this ); // attach iterator to dict
|
|
}
|
|
|
|
/*!
|
|
Constructs a copy of the iterator \a it.
|
|
*/
|
|
|
|
QGDictIterator::QGDictIterator( const QGDictIterator &it )
|
|
{
|
|
dict = it.dict;
|
|
curNode = it.curNode;
|
|
curIndex = it.curIndex;
|
|
if ( dict )
|
|
dict->iterators->append( this ); // attach iterator to dict
|
|
}
|
|
|
|
/*!
|
|
Assigns a copy of the iterator \a it and returns a reference to this
|
|
iterator.
|
|
*/
|
|
|
|
QGDictIterator &QGDictIterator::operator=( const QGDictIterator &it )
|
|
{
|
|
if ( dict ) // detach from old dict
|
|
dict->iterators->removeRef( this );
|
|
dict = it.dict;
|
|
curNode = it.curNode;
|
|
curIndex = it.curIndex;
|
|
if ( dict )
|
|
dict->iterators->append( this ); // attach to new list
|
|
return *this;
|
|
}
|
|
|
|
/*!
|
|
Destroys the iterator.
|
|
*/
|
|
|
|
QGDictIterator::~QGDictIterator()
|
|
{
|
|
if ( dict ) // detach iterator from dict
|
|
dict->iterators->removeRef( this );
|
|
}
|
|
|
|
|
|
/*!
|
|
Sets the iterator to point to the first item in the dictionary.
|
|
*/
|
|
|
|
QPtrCollection::Item QGDictIterator::toFirst()
|
|
{
|
|
if ( !dict ) {
|
|
#if defined(QT_CHECK_NULL)
|
|
qWarning( "QGDictIterator::toFirst: Dictionary has been deleted" );
|
|
#endif
|
|
return 0;
|
|
}
|
|
if ( dict->count() == 0 ) { // empty dictionary
|
|
curNode = 0;
|
|
return 0;
|
|
}
|
|
uint i = 0;
|
|
QBaseBucket **v = dict->vec;
|
|
while ( !(*v++) )
|
|
i++;
|
|
curNode = dict->vec[i];
|
|
curIndex = i;
|
|
return curNode->getData();
|
|
}
|
|
|
|
|
|
/*!
|
|
Moves to the next item (postfix).
|
|
*/
|
|
|
|
QPtrCollection::Item QGDictIterator::operator()()
|
|
{
|
|
if ( !dict ) {
|
|
#if defined(QT_CHECK_NULL)
|
|
qWarning( "QGDictIterator::operator(): Dictionary has been deleted" );
|
|
#endif
|
|
return 0;
|
|
}
|
|
if ( !curNode )
|
|
return 0;
|
|
QPtrCollection::Item d = curNode->getData();
|
|
this->operator++();
|
|
return d;
|
|
}
|
|
|
|
/*!
|
|
Moves to the next item (prefix).
|
|
*/
|
|
|
|
QPtrCollection::Item QGDictIterator::operator++()
|
|
{
|
|
if ( !dict ) {
|
|
#if defined(QT_CHECK_NULL)
|
|
qWarning( "QGDictIterator::operator++: Dictionary has been deleted" );
|
|
#endif
|
|
return 0;
|
|
}
|
|
if ( !curNode )
|
|
return 0;
|
|
curNode = curNode->getNext();
|
|
if ( !curNode ) { // no next bucket
|
|
uint i = curIndex + 1; // look from next vec element
|
|
QBaseBucket **v = &dict->vec[i];
|
|
while ( i < dict->size() && !(*v++) )
|
|
i++;
|
|
if ( i == dict->size() ) { // nothing found
|
|
curNode = 0;
|
|
return 0;
|
|
}
|
|
curNode = dict->vec[i];
|
|
curIndex = i;
|
|
}
|
|
return curNode->getData();
|
|
}
|
|
|
|
/*!
|
|
Moves \a jumps positions forward.
|
|
*/
|
|
|
|
QPtrCollection::Item QGDictIterator::operator+=( uint jumps )
|
|
{
|
|
while ( curNode && jumps-- )
|
|
operator++();
|
|
return curNode ? curNode->getData() : 0;
|
|
}
|