| 1 | /****************************************************************************
|
|---|
| 2 | ** $Id: qgcache.cpp 2 2005-11-16 15:49:26Z dmik $
|
|---|
| 3 | **
|
|---|
| 4 | ** Implementation of QGCache and QGCacheIterator classes
|
|---|
| 5 | **
|
|---|
| 6 | ** Created : 950208
|
|---|
| 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 "qgcache.h"
|
|---|
| 39 | #include "qptrlist.h"
|
|---|
| 40 | #include "qdict.h"
|
|---|
| 41 | #include "qstring.h"
|
|---|
| 42 |
|
|---|
| 43 | /*!
|
|---|
| 44 | \class QGCache qgcache.h
|
|---|
| 45 | \reentrant
|
|---|
| 46 | \ingroup shared
|
|---|
| 47 | \ingroup collection
|
|---|
| 48 | \brief The QGCache class is an internal class for implementing QCache
|
|---|
| 49 | template classes.
|
|---|
| 50 |
|
|---|
| 51 | \internal
|
|---|
| 52 |
|
|---|
| 53 | QGCache is a strictly internal class that acts as a base class for the
|
|---|
| 54 | \link collection.html collection classes\endlink QCache and QIntCache.
|
|---|
| 55 | */
|
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 | /*****************************************************************************
|
|---|
| 59 | QGCacheItem class (internal cache item)
|
|---|
| 60 | *****************************************************************************/
|
|---|
| 61 |
|
|---|
| 62 | struct QCacheItem
|
|---|
| 63 | {
|
|---|
| 64 | QCacheItem( void *k, QPtrCollection::Item d, int c, short p )
|
|---|
| 65 | : priority(p), skipPriority(p), cost(c), key(k), data(d), node(0) {}
|
|---|
| 66 | short priority;
|
|---|
| 67 | short skipPriority;
|
|---|
| 68 | int cost;
|
|---|
| 69 | void *key;
|
|---|
| 70 | QPtrCollection::Item data;
|
|---|
| 71 | QLNode *node;
|
|---|
| 72 | };
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 | /*****************************************************************************
|
|---|
| 76 | QCList class (internal list of cache items)
|
|---|
| 77 | *****************************************************************************/
|
|---|
| 78 |
|
|---|
| 79 | class QCList : private QPtrList<QCacheItem>
|
|---|
| 80 | {
|
|---|
| 81 | friend class QGCacheIterator;
|
|---|
| 82 | friend class QCListIt;
|
|---|
| 83 | public:
|
|---|
| 84 | QCList() {}
|
|---|
| 85 | ~QCList();
|
|---|
| 86 |
|
|---|
| 87 | void insert( QCacheItem * ); // insert according to priority
|
|---|
| 88 | void insert( int, QCacheItem * );
|
|---|
| 89 | void take( QCacheItem * );
|
|---|
| 90 | void reference( QCacheItem * );
|
|---|
| 91 |
|
|---|
| 92 | void setAutoDelete( bool del ) { QPtrCollection::setAutoDelete(del); }
|
|---|
| 93 |
|
|---|
| 94 | bool removeFirst() { return QPtrList<QCacheItem>::removeFirst(); }
|
|---|
| 95 | bool removeLast() { return QPtrList<QCacheItem>::removeLast(); }
|
|---|
| 96 |
|
|---|
| 97 | QCacheItem *first() { return QPtrList<QCacheItem>::first(); }
|
|---|
| 98 | QCacheItem *last() { return QPtrList<QCacheItem>::last(); }
|
|---|
| 99 | QCacheItem *prev() { return QPtrList<QCacheItem>::prev(); }
|
|---|
| 100 | QCacheItem *next() { return QPtrList<QCacheItem>::next(); }
|
|---|
| 101 |
|
|---|
| 102 | #if defined(QT_DEBUG)
|
|---|
| 103 | int inserts; // variables for statistics
|
|---|
| 104 | int insertCosts;
|
|---|
| 105 | int insertMisses;
|
|---|
| 106 | int finds;
|
|---|
| 107 | int hits;
|
|---|
| 108 | int hitCosts;
|
|---|
| 109 | int dumps;
|
|---|
| 110 | int dumpCosts;
|
|---|
| 111 | #endif
|
|---|
| 112 | };
|
|---|
| 113 |
|
|---|
| 114 |
|
|---|
| 115 | QCList::~QCList()
|
|---|
| 116 | {
|
|---|
| 117 | #if defined(QT_DEBUG)
|
|---|
| 118 | Q_ASSERT( count() == 0 );
|
|---|
| 119 | #endif
|
|---|
| 120 | }
|
|---|
| 121 |
|
|---|
| 122 |
|
|---|
| 123 | void QCList::insert( QCacheItem *ci )
|
|---|
| 124 | {
|
|---|
| 125 | QCacheItem *item = first();
|
|---|
| 126 | while( item && item->skipPriority > ci->priority ) {
|
|---|
| 127 | item->skipPriority--;
|
|---|
| 128 | item = next();
|
|---|
| 129 | }
|
|---|
| 130 | if ( item )
|
|---|
| 131 | QPtrList<QCacheItem>::insert( at(), ci );
|
|---|
| 132 | else
|
|---|
| 133 | append( ci );
|
|---|
| 134 | #if defined(QT_DEBUG)
|
|---|
| 135 | Q_ASSERT( ci->node == 0 );
|
|---|
| 136 | #endif
|
|---|
| 137 | ci->node = currentNode();
|
|---|
| 138 | }
|
|---|
| 139 |
|
|---|
| 140 | inline void QCList::insert( int i, QCacheItem *ci )
|
|---|
| 141 | {
|
|---|
| 142 | QPtrList<QCacheItem>::insert( i, ci );
|
|---|
| 143 | #if defined(QT_DEBUG)
|
|---|
| 144 | Q_ASSERT( ci->node == 0 );
|
|---|
| 145 | #endif
|
|---|
| 146 | ci->node = currentNode();
|
|---|
| 147 | }
|
|---|
| 148 |
|
|---|
| 149 |
|
|---|
| 150 | void QCList::take( QCacheItem *ci )
|
|---|
| 151 | {
|
|---|
| 152 | if ( ci ) {
|
|---|
| 153 | #if defined(QT_DEBUG)
|
|---|
| 154 | Q_ASSERT( ci->node != 0 );
|
|---|
| 155 | #endif
|
|---|
| 156 | takeNode( ci->node );
|
|---|
| 157 | ci->node = 0;
|
|---|
| 158 | }
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 |
|
|---|
| 162 | inline void QCList::reference( QCacheItem *ci )
|
|---|
| 163 | {
|
|---|
| 164 | #if defined(QT_DEBUG)
|
|---|
| 165 | Q_ASSERT( ci != 0 && ci->node != 0 );
|
|---|
| 166 | #endif
|
|---|
| 167 | ci->skipPriority = ci->priority;
|
|---|
| 168 | relinkNode( ci->node ); // relink as first item
|
|---|
| 169 | }
|
|---|
| 170 |
|
|---|
| 171 |
|
|---|
| 172 | class QCListIt: public QPtrListIterator<QCacheItem>
|
|---|
| 173 | {
|
|---|
| 174 | public:
|
|---|
| 175 | QCListIt( const QCList *p ): QPtrListIterator<QCacheItem>( *p ) {}
|
|---|
| 176 | QCListIt( const QCListIt *p ): QPtrListIterator<QCacheItem>( *p ) {}
|
|---|
| 177 | };
|
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 | /*****************************************************************************
|
|---|
| 181 | QCDict class (internal dictionary of cache items)
|
|---|
| 182 | *****************************************************************************/
|
|---|
| 183 |
|
|---|
| 184 | //
|
|---|
| 185 | // Since we need to decide if the dictionary should use an int or const
|
|---|
| 186 | // char * key (the "bool trivial" argument in the constructor below)
|
|---|
| 187 | // we cannot use the macro/template dict, but inherit directly from QGDict.
|
|---|
| 188 | //
|
|---|
| 189 |
|
|---|
| 190 | class QCDict : public QGDict
|
|---|
| 191 | {
|
|---|
| 192 | public:
|
|---|
| 193 | QCDict( uint size, uint kt, bool caseSensitive, bool copyKeys )
|
|---|
| 194 | : QGDict( size, (KeyType)kt, caseSensitive, copyKeys ) {}
|
|---|
| 195 | ~QCDict();
|
|---|
| 196 |
|
|---|
| 197 | void clear() { QGDict::clear(); }
|
|---|
| 198 |
|
|---|
| 199 | QCacheItem *find_string(const QString &key) const
|
|---|
| 200 | { return (QCacheItem*)((QCDict*)this)->look_string(key, 0, 0); }
|
|---|
| 201 | QCacheItem *find_ascii(const char *key) const
|
|---|
| 202 | { return (QCacheItem*)((QCDict*)this)->look_ascii(key, 0, 0); }
|
|---|
| 203 | QCacheItem *find_int(long key) const
|
|---|
| 204 | { return (QCacheItem*)((QCDict*)this)->look_int(key, 0, 0); }
|
|---|
| 205 |
|
|---|
| 206 | QCacheItem *take_string(const QString &key)
|
|---|
| 207 | { return (QCacheItem*)QGDict::take_string(key); }
|
|---|
| 208 | QCacheItem *take_ascii(const char *key)
|
|---|
| 209 | { return (QCacheItem*)QGDict::take_ascii(key); }
|
|---|
| 210 | QCacheItem *take_int(long key)
|
|---|
| 211 | { return (QCacheItem*)QGDict::take_int(key); }
|
|---|
| 212 |
|
|---|
| 213 | bool insert_string( const QString &key, const QCacheItem *ci )
|
|---|
| 214 | { return QGDict::look_string(key,(Item)ci,1)!=0;}
|
|---|
| 215 | bool insert_ascii( const char *key, const QCacheItem *ci )
|
|---|
| 216 | { return QGDict::look_ascii(key,(Item)ci,1)!=0;}
|
|---|
| 217 | bool insert_int( long key, const QCacheItem *ci )
|
|---|
| 218 | { return QGDict::look_int(key,(Item)ci,1)!=0;}
|
|---|
| 219 |
|
|---|
| 220 | bool remove_string( QCacheItem *item )
|
|---|
| 221 | { return QGDict::remove_string(*((QString*)(item->key)),item); }
|
|---|
| 222 | bool remove_ascii( QCacheItem *item )
|
|---|
| 223 | { return QGDict::remove_ascii((const char *)item->key,item); }
|
|---|
| 224 | bool remove_int( QCacheItem *item )
|
|---|
| 225 | { return QGDict::remove_int((long)item->key,item);}
|
|---|
| 226 |
|
|---|
| 227 | void statistics() { QGDict::statistics(); }
|
|---|
| 228 |
|
|---|
| 229 | private:
|
|---|
| 230 | void deleteItem( void *item )
|
|---|
| 231 | { if ( del_item ) { QCacheItem *d = (QCacheItem*)item; delete d; } }
|
|---|
| 232 | };
|
|---|
| 233 |
|
|---|
| 234 | inline QCDict::~QCDict()
|
|---|
| 235 | {
|
|---|
| 236 | clear();
|
|---|
| 237 | }
|
|---|
| 238 |
|
|---|
| 239 | /*****************************************************************************
|
|---|
| 240 | QGDict member functions
|
|---|
| 241 | *****************************************************************************/
|
|---|
| 242 |
|
|---|
| 243 | /*!
|
|---|
| 244 | Constructs a cache.
|
|---|
| 245 | The maximum cost of the cache is given by \a maxCost and the size by \a
|
|---|
| 246 | size. The key type is \a kt which may be \c StringKey, \c AsciiKey,
|
|---|
| 247 | \c IntKey or \c PtrKey. The case-sensitivity of lookups is set with
|
|---|
| 248 | \a caseSensitive. Keys are copied if \a copyKeys is TRUE.
|
|---|
| 249 | */
|
|---|
| 250 |
|
|---|
| 251 | QGCache::QGCache( int maxCost, uint size, KeyType kt, bool caseSensitive,
|
|---|
| 252 | bool copyKeys )
|
|---|
| 253 | {
|
|---|
| 254 | keytype = kt;
|
|---|
| 255 | lruList = new QCList;
|
|---|
| 256 | Q_CHECK_PTR( lruList );
|
|---|
| 257 | lruList->setAutoDelete( TRUE );
|
|---|
| 258 | copyk = ((keytype == AsciiKey) && copyKeys);
|
|---|
| 259 | dict = new QCDict( size, kt, caseSensitive, FALSE );
|
|---|
| 260 | Q_CHECK_PTR( dict );
|
|---|
| 261 | mCost = maxCost;
|
|---|
| 262 | tCost = 0;
|
|---|
| 263 | #if defined(QT_DEBUG)
|
|---|
| 264 | lruList->inserts = 0;
|
|---|
| 265 | lruList->insertCosts = 0;
|
|---|
| 266 | lruList->insertMisses = 0;
|
|---|
| 267 | lruList->finds = 0;
|
|---|
| 268 | lruList->hits = 0;
|
|---|
| 269 | lruList->hitCosts = 0;
|
|---|
| 270 | lruList->dumps = 0;
|
|---|
| 271 | lruList->dumpCosts = 0;
|
|---|
| 272 | #endif
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|
| 275 | /*!
|
|---|
| 276 | Cannot copy a cache.
|
|---|
| 277 | */
|
|---|
| 278 |
|
|---|
| 279 | QGCache::QGCache( const QGCache & )
|
|---|
| 280 | : QPtrCollection()
|
|---|
| 281 | {
|
|---|
| 282 | #if defined(QT_CHECK_NULL)
|
|---|
| 283 | qFatal( "QGCache::QGCache(QGCache &): Cannot copy a cache" );
|
|---|
| 284 | #endif
|
|---|
| 285 | }
|
|---|
| 286 |
|
|---|
| 287 | /*!
|
|---|
| 288 | Removes all items from the cache and destroys it.
|
|---|
| 289 | */
|
|---|
| 290 |
|
|---|
| 291 | QGCache::~QGCache()
|
|---|
| 292 | {
|
|---|
| 293 | clear();
|
|---|
| 294 | delete dict;
|
|---|
| 295 | delete lruList;
|
|---|
| 296 | }
|
|---|
| 297 |
|
|---|
| 298 | /*!
|
|---|
| 299 | Cannot assign a cache.
|
|---|
| 300 | */
|
|---|
| 301 |
|
|---|
| 302 | QGCache &QGCache::operator=( const QGCache & )
|
|---|
| 303 | {
|
|---|
| 304 | #if defined(QT_CHECK_NULL)
|
|---|
| 305 | qFatal( "QGCache::operator=: Cannot copy a cache" );
|
|---|
| 306 | #endif
|
|---|
| 307 | return *this;
|
|---|
| 308 | }
|
|---|
| 309 |
|
|---|
| 310 |
|
|---|
| 311 | /*!
|
|---|
| 312 | Returns the number of items in the cache.
|
|---|
| 313 | */
|
|---|
| 314 |
|
|---|
| 315 | uint QGCache::count() const
|
|---|
| 316 | {
|
|---|
| 317 | return dict->count();
|
|---|
| 318 | }
|
|---|
| 319 |
|
|---|
| 320 | /*!
|
|---|
| 321 | Returns the size of the hash array.
|
|---|
| 322 | */
|
|---|
| 323 |
|
|---|
| 324 | uint QGCache::size() const
|
|---|
| 325 | {
|
|---|
| 326 | return dict->size();
|
|---|
| 327 | }
|
|---|
| 328 |
|
|---|
| 329 | /*!
|
|---|
| 330 | \fn int QGCache::maxCost() const
|
|---|
| 331 |
|
|---|
| 332 | Returns the maximum cache cost.
|
|---|
| 333 | */
|
|---|
| 334 |
|
|---|
| 335 | /*!
|
|---|
| 336 | \fn int QGCache::totalCost() const
|
|---|
| 337 |
|
|---|
| 338 | Returns the total cache cost.
|
|---|
| 339 | */
|
|---|
| 340 |
|
|---|
| 341 | /*!
|
|---|
| 342 | Sets the maximum cache cost to \a maxCost.
|
|---|
| 343 | */
|
|---|
| 344 |
|
|---|
| 345 | void QGCache::setMaxCost( int maxCost )
|
|---|
| 346 | {
|
|---|
| 347 | if ( maxCost < tCost ) {
|
|---|
| 348 | if ( !makeRoomFor(tCost - maxCost) ) // remove excess cost
|
|---|
| 349 | return;
|
|---|
| 350 | }
|
|---|
| 351 | mCost = maxCost;
|
|---|
| 352 | }
|
|---|
| 353 |
|
|---|
| 354 |
|
|---|
| 355 | /*!
|
|---|
| 356 | Inserts an item with data \a data into the cache using key \a key.
|
|---|
| 357 | The item has cost \a cost and priority \a priority.
|
|---|
| 358 |
|
|---|
| 359 | \warning If this function returns FALSE, you must delete \a data
|
|---|
| 360 | yourself. Additionally, be very careful about using \a data after
|
|---|
| 361 | calling this function, as any other insertions into the cache, from
|
|---|
| 362 | anywhere in the application, or within Qt itself, could cause the
|
|---|
| 363 | data to be discarded from the cache, and the pointer to become
|
|---|
| 364 | invalid.
|
|---|
| 365 | */
|
|---|
| 366 |
|
|---|
| 367 | bool QGCache::insert_string( const QString &key, QPtrCollection::Item data,
|
|---|
| 368 | int cost, int priority)
|
|---|
| 369 | {
|
|---|
| 370 | if ( tCost + cost > mCost ) {
|
|---|
| 371 | if ( !makeRoomFor(tCost + cost - mCost, priority) ) {
|
|---|
| 372 | #if defined(QT_DEBUG)
|
|---|
| 373 | lruList->insertMisses++;
|
|---|
| 374 | #endif
|
|---|
| 375 | return FALSE;
|
|---|
| 376 | }
|
|---|
| 377 | }
|
|---|
| 378 | #if defined(QT_DEBUG)
|
|---|
| 379 | Q_ASSERT( keytype == StringKey );
|
|---|
| 380 | lruList->inserts++;
|
|---|
| 381 | lruList->insertCosts += cost;
|
|---|
| 382 | #endif
|
|---|
| 383 | if ( priority < -32768 )
|
|---|
| 384 | priority = -32768;
|
|---|
| 385 | else if ( priority > 32767 )
|
|---|
| 386 | priority = 32677;
|
|---|
| 387 | QCacheItem *ci = new QCacheItem( new QString(key), newItem(data),
|
|---|
| 388 | cost, (short)priority );
|
|---|
| 389 | Q_CHECK_PTR( ci );
|
|---|
| 390 | lruList->insert( 0, ci );
|
|---|
| 391 | dict->insert_string( key, ci );
|
|---|
| 392 | tCost += cost;
|
|---|
| 393 | return TRUE;
|
|---|
| 394 | }
|
|---|
| 395 |
|
|---|
| 396 | bool QGCache::insert_other( const char *key, QPtrCollection::Item data,
|
|---|
| 397 | int cost, int priority)
|
|---|
| 398 | {
|
|---|
| 399 | if ( tCost + cost > mCost ) {
|
|---|
| 400 | if ( !makeRoomFor(tCost + cost - mCost, priority) ) {
|
|---|
| 401 | #if defined(QT_DEBUG)
|
|---|
| 402 | lruList->insertMisses++;
|
|---|
| 403 | #endif
|
|---|
| 404 | return FALSE;
|
|---|
| 405 | }
|
|---|
| 406 | }
|
|---|
| 407 | #if defined(QT_DEBUG)
|
|---|
| 408 | Q_ASSERT( keytype != StringKey );
|
|---|
| 409 | lruList->inserts++;
|
|---|
| 410 | lruList->insertCosts += cost;
|
|---|
| 411 | #endif
|
|---|
| 412 | if ( keytype == AsciiKey && copyk )
|
|---|
| 413 | key = qstrdup( key );
|
|---|
| 414 | if ( priority < -32768 )
|
|---|
| 415 | priority = -32768;
|
|---|
| 416 | else if ( priority > 32767 )
|
|---|
| 417 | priority = 32677;
|
|---|
| 418 | QCacheItem *ci = new QCacheItem( (void*)key, newItem(data), cost,
|
|---|
| 419 | (short)priority );
|
|---|
| 420 | Q_CHECK_PTR( ci );
|
|---|
| 421 | lruList->insert( 0, ci );
|
|---|
| 422 | if ( keytype == AsciiKey )
|
|---|
| 423 | dict->insert_ascii( key, ci );
|
|---|
| 424 | else
|
|---|
| 425 | dict->insert_int( (long)key, ci );
|
|---|
| 426 | tCost += cost;
|
|---|
| 427 | return TRUE;
|
|---|
| 428 | }
|
|---|
| 429 |
|
|---|
| 430 |
|
|---|
| 431 | /*!
|
|---|
| 432 | Removes the item with key \a key from the cache. Returns TRUE if the
|
|---|
| 433 | item was removed; otherwise returns FALSE.
|
|---|
| 434 | */
|
|---|
| 435 |
|
|---|
| 436 | bool QGCache::remove_string( const QString &key )
|
|---|
| 437 | {
|
|---|
| 438 | Item d = take_string( key );
|
|---|
| 439 | if ( d )
|
|---|
| 440 | deleteItem( d );
|
|---|
| 441 | return d != 0;
|
|---|
| 442 | }
|
|---|
| 443 |
|
|---|
| 444 | bool QGCache::remove_other( const char *key )
|
|---|
| 445 | {
|
|---|
| 446 | Item d = take_other( key );
|
|---|
| 447 | if ( d )
|
|---|
| 448 | deleteItem( d );
|
|---|
| 449 | return d != 0;
|
|---|
| 450 | }
|
|---|
| 451 |
|
|---|
| 452 |
|
|---|
| 453 | /*!
|
|---|
| 454 | Takes the item with key \a key out of the cache. The item is not
|
|---|
| 455 | deleted. If no item has this \a key 0 is returned.
|
|---|
| 456 | */
|
|---|
| 457 |
|
|---|
| 458 | QPtrCollection::Item QGCache::take_string( const QString &key )
|
|---|
| 459 | {
|
|---|
| 460 | QCacheItem *ci = dict->take_string( key ); // take from dict
|
|---|
| 461 | Item d;
|
|---|
| 462 | if ( ci ) {
|
|---|
| 463 | d = ci->data;
|
|---|
| 464 | tCost -= ci->cost;
|
|---|
| 465 | lruList->take( ci ); // take from list
|
|---|
| 466 | delete (QString*)ci->key;
|
|---|
| 467 | delete ci;
|
|---|
| 468 | } else {
|
|---|
| 469 | d = 0;
|
|---|
| 470 | }
|
|---|
| 471 | return d;
|
|---|
| 472 | }
|
|---|
| 473 |
|
|---|
| 474 | /*!
|
|---|
| 475 | Takes the item with key \a key out of the cache. The item is not
|
|---|
| 476 | deleted. If no item has this \a key 0 is returned.
|
|---|
| 477 | */
|
|---|
| 478 |
|
|---|
| 479 | QPtrCollection::Item QGCache::take_other( const char *key )
|
|---|
| 480 | {
|
|---|
| 481 | QCacheItem *ci;
|
|---|
| 482 | if ( keytype == AsciiKey )
|
|---|
| 483 | ci = dict->take_ascii( key );
|
|---|
| 484 | else
|
|---|
| 485 | ci = dict->take_int( (long)key );
|
|---|
| 486 | Item d;
|
|---|
| 487 | if ( ci ) {
|
|---|
| 488 | d = ci->data;
|
|---|
| 489 | tCost -= ci->cost;
|
|---|
| 490 | lruList->take( ci ); // take from list
|
|---|
| 491 | if ( copyk )
|
|---|
| 492 | delete [] (char *)ci->key;
|
|---|
| 493 | delete ci;
|
|---|
| 494 | } else {
|
|---|
| 495 | d = 0;
|
|---|
| 496 | }
|
|---|
| 497 | return d;
|
|---|
| 498 | }
|
|---|
| 499 |
|
|---|
| 500 |
|
|---|
| 501 | /*!
|
|---|
| 502 | Clears the cache.
|
|---|
| 503 | */
|
|---|
| 504 |
|
|---|
| 505 | void QGCache::clear()
|
|---|
| 506 | {
|
|---|
| 507 | QCacheItem *ci;
|
|---|
| 508 | while ( (ci = lruList->first()) ) {
|
|---|
| 509 | switch ( keytype ) {
|
|---|
| 510 | case StringKey:
|
|---|
| 511 | dict->remove_string( ci );
|
|---|
| 512 | delete (QString*)ci->key;
|
|---|
| 513 | break;
|
|---|
| 514 | case AsciiKey:
|
|---|
| 515 | dict->remove_ascii( ci );
|
|---|
| 516 | if ( copyk )
|
|---|
| 517 | delete [] (char*)ci->key;
|
|---|
| 518 | break;
|
|---|
| 519 | case IntKey:
|
|---|
| 520 | dict->remove_int( ci );
|
|---|
| 521 | break;
|
|---|
| 522 | case PtrKey: // unused
|
|---|
| 523 | break;
|
|---|
| 524 | }
|
|---|
| 525 | deleteItem( ci->data ); // delete data
|
|---|
| 526 | lruList->removeFirst(); // remove from list
|
|---|
| 527 | }
|
|---|
| 528 | tCost = 0;
|
|---|
| 529 | }
|
|---|
| 530 |
|
|---|
| 531 |
|
|---|
| 532 | /*!
|
|---|
| 533 | Finds an item for \a key in the cache and adds a reference if \a ref is TRUE.
|
|---|
| 534 | */
|
|---|
| 535 |
|
|---|
| 536 | QPtrCollection::Item QGCache::find_string( const QString &key, bool ref ) const
|
|---|
| 537 | {
|
|---|
| 538 | QCacheItem *ci = dict->find_string( key );
|
|---|
| 539 | #if defined(QT_DEBUG)
|
|---|
| 540 | lruList->finds++;
|
|---|
| 541 | #endif
|
|---|
| 542 | if ( ci ) {
|
|---|
| 543 | #if defined(QT_DEBUG)
|
|---|
| 544 | lruList->hits++;
|
|---|
| 545 | lruList->hitCosts += ci->cost;
|
|---|
| 546 | #endif
|
|---|
| 547 | if ( ref )
|
|---|
| 548 | lruList->reference( ci );
|
|---|
| 549 | return ci->data;
|
|---|
| 550 | }
|
|---|
| 551 | return 0;
|
|---|
| 552 | }
|
|---|
| 553 |
|
|---|
| 554 |
|
|---|
| 555 | /*!
|
|---|
| 556 | Finds an item for \a key in the cache and adds a reference if \a ref is TRUE.
|
|---|
| 557 | */
|
|---|
| 558 |
|
|---|
| 559 | QPtrCollection::Item QGCache::find_other( const char *key, bool ref ) const
|
|---|
| 560 | {
|
|---|
| 561 | QCacheItem *ci = keytype == AsciiKey ? dict->find_ascii(key)
|
|---|
| 562 | : dict->find_int((long)key);
|
|---|
| 563 | #if defined(QT_DEBUG)
|
|---|
| 564 | lruList->finds++;
|
|---|
| 565 | #endif
|
|---|
| 566 | if ( ci ) {
|
|---|
| 567 | #if defined(QT_DEBUG)
|
|---|
| 568 | lruList->hits++;
|
|---|
| 569 | lruList->hitCosts += ci->cost;
|
|---|
| 570 | #endif
|
|---|
| 571 | if ( ref )
|
|---|
| 572 | lruList->reference( ci );
|
|---|
| 573 | return ci->data;
|
|---|
| 574 | }
|
|---|
| 575 | return 0;
|
|---|
| 576 | }
|
|---|
| 577 |
|
|---|
| 578 |
|
|---|
| 579 | /*!
|
|---|
| 580 | Allocates cache space for one or more items.
|
|---|
| 581 | */
|
|---|
| 582 |
|
|---|
| 583 | bool QGCache::makeRoomFor( int cost, int priority )
|
|---|
| 584 | {
|
|---|
| 585 | if ( cost > mCost ) // cannot make room for more
|
|---|
| 586 | return FALSE; // than maximum cost
|
|---|
| 587 | if ( priority == -1 )
|
|---|
| 588 | priority = 32767;
|
|---|
| 589 | register QCacheItem *ci = lruList->last();
|
|---|
| 590 | int cntCost = 0;
|
|---|
| 591 | int dumps = 0; // number of items to dump
|
|---|
| 592 | while ( cntCost < cost && ci && ci->skipPriority <= priority ) {
|
|---|
| 593 | cntCost += ci->cost;
|
|---|
| 594 | ci = lruList->prev();
|
|---|
| 595 | dumps++;
|
|---|
| 596 | }
|
|---|
| 597 | if ( cntCost < cost ) // can enough cost be dumped?
|
|---|
| 598 | return FALSE; // no
|
|---|
| 599 | #if defined(QT_DEBUG)
|
|---|
| 600 | Q_ASSERT( dumps > 0 );
|
|---|
| 601 | #endif
|
|---|
| 602 | while ( dumps-- ) {
|
|---|
| 603 | ci = lruList->last();
|
|---|
| 604 | #if defined(QT_DEBUG)
|
|---|
| 605 | lruList->dumps++;
|
|---|
| 606 | lruList->dumpCosts += ci->cost;
|
|---|
| 607 | #endif
|
|---|
| 608 | switch ( keytype ) {
|
|---|
| 609 | case StringKey:
|
|---|
| 610 | dict->remove_string( ci );
|
|---|
| 611 | delete (QString*)ci->key;
|
|---|
| 612 | break;
|
|---|
| 613 | case AsciiKey:
|
|---|
| 614 | dict->remove_ascii( ci );
|
|---|
| 615 | if ( copyk )
|
|---|
| 616 | delete [] (char *)ci->key;
|
|---|
| 617 | break;
|
|---|
| 618 | case IntKey:
|
|---|
| 619 | dict->remove_int( ci );
|
|---|
| 620 | break;
|
|---|
| 621 | case PtrKey: // unused
|
|---|
| 622 | break;
|
|---|
| 623 | }
|
|---|
| 624 | deleteItem( ci->data ); // delete data
|
|---|
| 625 | lruList->removeLast(); // remove from list
|
|---|
| 626 | }
|
|---|
| 627 | tCost -= cntCost;
|
|---|
| 628 | return TRUE;
|
|---|
| 629 | }
|
|---|
| 630 |
|
|---|
| 631 |
|
|---|
| 632 | /*!
|
|---|
| 633 | Outputs debug statistics.
|
|---|
| 634 | */
|
|---|
| 635 |
|
|---|
| 636 | void QGCache::statistics() const
|
|---|
| 637 | {
|
|---|
| 638 | #if defined(QT_DEBUG)
|
|---|
| 639 | QString line;
|
|---|
| 640 | line.fill( '*', 80 );
|
|---|
| 641 | qDebug( line.ascii() );
|
|---|
| 642 | qDebug( "CACHE STATISTICS:" );
|
|---|
| 643 | qDebug( "cache contains %d item%s, with a total cost of %d",
|
|---|
| 644 | count(), count() != 1 ? "s" : "", tCost );
|
|---|
| 645 | qDebug( "maximum cost is %d, cache is %d%% full.",
|
|---|
| 646 | mCost, (200*tCost + mCost) / (mCost*2) );
|
|---|
| 647 | qDebug( "find() has been called %d time%s",
|
|---|
| 648 | lruList->finds, lruList->finds != 1 ? "s" : "" );
|
|---|
| 649 | qDebug( "%d of these were hits, items found had a total cost of %d.",
|
|---|
| 650 | lruList->hits,lruList->hitCosts );
|
|---|
| 651 | qDebug( "%d item%s %s been inserted with a total cost of %d.",
|
|---|
| 652 | lruList->inserts,lruList->inserts != 1 ? "s" : "",
|
|---|
| 653 | lruList->inserts != 1 ? "have" : "has", lruList->insertCosts );
|
|---|
| 654 | qDebug( "%d item%s %s too large or had too low priority to be inserted.",
|
|---|
| 655 | lruList->insertMisses, lruList->insertMisses != 1 ? "s" : "",
|
|---|
| 656 | lruList->insertMisses != 1 ? "were" : "was" );
|
|---|
| 657 | qDebug( "%d item%s %s been thrown away with a total cost of %d.",
|
|---|
| 658 | lruList->dumps, lruList->dumps != 1 ? "s" : "",
|
|---|
| 659 | lruList->dumps != 1 ? "have" : "has", lruList->dumpCosts );
|
|---|
| 660 | qDebug( "Statistics from internal dictionary class:" );
|
|---|
| 661 | dict->statistics();
|
|---|
| 662 | qDebug( line.ascii() );
|
|---|
| 663 | #endif
|
|---|
| 664 | }
|
|---|
| 665 |
|
|---|
| 666 |
|
|---|
| 667 | /*****************************************************************************
|
|---|
| 668 | QGCacheIterator member functions
|
|---|
| 669 | *****************************************************************************/
|
|---|
| 670 |
|
|---|
| 671 | /*!
|
|---|
| 672 | \class QGCacheIterator qgcache.h
|
|---|
| 673 | \reentrant
|
|---|
| 674 | \ingroup shared
|
|---|
| 675 | \ingroup collection
|
|---|
| 676 | \brief The QGCacheIterator class is an internal class for implementing QCacheIterator and
|
|---|
| 677 | QIntCacheIterator.
|
|---|
| 678 |
|
|---|
| 679 | \internal
|
|---|
| 680 |
|
|---|
| 681 | QGCacheIterator is a strictly internal class that does the heavy work for
|
|---|
| 682 | QCacheIterator and QIntCacheIterator.
|
|---|
| 683 | */
|
|---|
| 684 |
|
|---|
| 685 | /*!
|
|---|
| 686 | Constructs an iterator that operates on the cache \a c.
|
|---|
| 687 | */
|
|---|
| 688 |
|
|---|
| 689 | QGCacheIterator::QGCacheIterator( const QGCache &c )
|
|---|
| 690 | {
|
|---|
| 691 | it = new QCListIt( c.lruList );
|
|---|
| 692 | #if defined(QT_DEBUG)
|
|---|
| 693 | Q_ASSERT( it != 0 );
|
|---|
| 694 | #endif
|
|---|
| 695 | }
|
|---|
| 696 |
|
|---|
| 697 | /*!
|
|---|
| 698 | Constructs an iterator that operates on the same cache as \a ci.
|
|---|
| 699 | */
|
|---|
| 700 |
|
|---|
| 701 | QGCacheIterator::QGCacheIterator( const QGCacheIterator &ci )
|
|---|
| 702 | {
|
|---|
| 703 | it = new QCListIt( ci.it );
|
|---|
| 704 | #if defined(QT_DEBUG)
|
|---|
| 705 | Q_ASSERT( it != 0 );
|
|---|
| 706 | #endif
|
|---|
| 707 | }
|
|---|
| 708 |
|
|---|
| 709 | /*!
|
|---|
| 710 | Destroys the iterator.
|
|---|
| 711 | */
|
|---|
| 712 |
|
|---|
| 713 | QGCacheIterator::~QGCacheIterator()
|
|---|
| 714 | {
|
|---|
| 715 | delete it;
|
|---|
| 716 | }
|
|---|
| 717 |
|
|---|
| 718 | /*!
|
|---|
| 719 | Assigns the iterator \a ci to this cache iterator.
|
|---|
| 720 | */
|
|---|
| 721 |
|
|---|
| 722 | QGCacheIterator &QGCacheIterator::operator=( const QGCacheIterator &ci )
|
|---|
| 723 | {
|
|---|
| 724 | *it = *ci.it;
|
|---|
| 725 | return *this;
|
|---|
| 726 | }
|
|---|
| 727 |
|
|---|
| 728 | /*!
|
|---|
| 729 | Returns the number of items in the cache.
|
|---|
| 730 | */
|
|---|
| 731 |
|
|---|
| 732 | uint QGCacheIterator::count() const
|
|---|
| 733 | {
|
|---|
| 734 | return it->count();
|
|---|
| 735 | }
|
|---|
| 736 |
|
|---|
| 737 | /*!
|
|---|
| 738 | Returns TRUE if the iterator points to the first item.
|
|---|
| 739 | */
|
|---|
| 740 |
|
|---|
| 741 | bool QGCacheIterator::atFirst() const
|
|---|
| 742 | {
|
|---|
| 743 | return it->atFirst();
|
|---|
| 744 | }
|
|---|
| 745 |
|
|---|
| 746 | /*!
|
|---|
| 747 | Returns TRUE if the iterator points to the last item.
|
|---|
| 748 | */
|
|---|
| 749 |
|
|---|
| 750 | bool QGCacheIterator::atLast() const
|
|---|
| 751 | {
|
|---|
| 752 | return it->atLast();
|
|---|
| 753 | }
|
|---|
| 754 |
|
|---|
| 755 | /*!
|
|---|
| 756 | Sets the list iterator to point to the first item in the cache.
|
|---|
| 757 | */
|
|---|
| 758 |
|
|---|
| 759 | QPtrCollection::Item QGCacheIterator::toFirst()
|
|---|
| 760 | {
|
|---|
| 761 | QCacheItem *item = it->toFirst();
|
|---|
| 762 | return item ? item->data : 0;
|
|---|
| 763 | }
|
|---|
| 764 |
|
|---|
| 765 | /*!
|
|---|
| 766 | Sets the list iterator to point to the last item in the cache.
|
|---|
| 767 | */
|
|---|
| 768 |
|
|---|
| 769 | QPtrCollection::Item QGCacheIterator::toLast()
|
|---|
| 770 | {
|
|---|
| 771 | QCacheItem *item = it->toLast();
|
|---|
| 772 | return item ? item->data : 0;
|
|---|
| 773 | }
|
|---|
| 774 |
|
|---|
| 775 | /*!
|
|---|
| 776 | Returns the current item.
|
|---|
| 777 | */
|
|---|
| 778 |
|
|---|
| 779 | QPtrCollection::Item QGCacheIterator::get() const
|
|---|
| 780 | {
|
|---|
| 781 | QCacheItem *item = it->current();
|
|---|
| 782 | return item ? item->data : 0;
|
|---|
| 783 | }
|
|---|
| 784 |
|
|---|
| 785 | /*!
|
|---|
| 786 | Returns the key of the current item.
|
|---|
| 787 | */
|
|---|
| 788 |
|
|---|
| 789 | QString QGCacheIterator::getKeyString() const
|
|---|
| 790 | {
|
|---|
| 791 | QCacheItem *item = it->current();
|
|---|
| 792 | return item ? *((QString*)item->key) : QString::null;
|
|---|
| 793 | }
|
|---|
| 794 |
|
|---|
| 795 | /*!
|
|---|
| 796 | Returns the key of the current item, as a \0-terminated C string.
|
|---|
| 797 | */
|
|---|
| 798 |
|
|---|
| 799 | const char *QGCacheIterator::getKeyAscii() const
|
|---|
| 800 | {
|
|---|
| 801 | QCacheItem *item = it->current();
|
|---|
| 802 | return item ? (const char *)item->key : 0;
|
|---|
| 803 | }
|
|---|
| 804 |
|
|---|
| 805 | /*!
|
|---|
| 806 | Returns the key of the current item, as a long.
|
|---|
| 807 | */
|
|---|
| 808 |
|
|---|
| 809 | long QGCacheIterator::getKeyInt() const
|
|---|
| 810 | {
|
|---|
| 811 | QCacheItem *item = it->current();
|
|---|
| 812 | return item ? (long)item->key : 0;
|
|---|
| 813 | }
|
|---|
| 814 |
|
|---|
| 815 | /*!
|
|---|
| 816 | Moves to the next item (postfix).
|
|---|
| 817 | */
|
|---|
| 818 |
|
|---|
| 819 | QPtrCollection::Item QGCacheIterator::operator()()
|
|---|
| 820 | {
|
|---|
| 821 | QCacheItem *item = it->operator()();
|
|---|
| 822 | return item ? item->data : 0;
|
|---|
| 823 | }
|
|---|
| 824 |
|
|---|
| 825 | /*!
|
|---|
| 826 | Moves to the next item (prefix).
|
|---|
| 827 | */
|
|---|
| 828 |
|
|---|
| 829 | QPtrCollection::Item QGCacheIterator::operator++()
|
|---|
| 830 | {
|
|---|
| 831 | QCacheItem *item = it->operator++();
|
|---|
| 832 | return item ? item->data : 0;
|
|---|
| 833 | }
|
|---|
| 834 |
|
|---|
| 835 | /*!
|
|---|
| 836 | Moves \a jump positions forward.
|
|---|
| 837 | */
|
|---|
| 838 |
|
|---|
| 839 | QPtrCollection::Item QGCacheIterator::operator+=( uint jump )
|
|---|
| 840 | {
|
|---|
| 841 | QCacheItem *item = it->operator+=(jump);
|
|---|
| 842 | return item ? item->data : 0;
|
|---|
| 843 | }
|
|---|
| 844 |
|
|---|
| 845 | /*!
|
|---|
| 846 | Moves to the previous item (prefix).
|
|---|
| 847 | */
|
|---|
| 848 |
|
|---|
| 849 | QPtrCollection::Item QGCacheIterator::operator--()
|
|---|
| 850 | {
|
|---|
| 851 | QCacheItem *item = it->operator--();
|
|---|
| 852 | return item ? item->data : 0;
|
|---|
| 853 | }
|
|---|
| 854 |
|
|---|
| 855 | /*!
|
|---|
| 856 | Moves \a jump positions backward.
|
|---|
| 857 | */
|
|---|
| 858 |
|
|---|
| 859 | QPtrCollection::Item QGCacheIterator::operator-=( uint jump )
|
|---|
| 860 | {
|
|---|
| 861 | QCacheItem *item = it->operator-=(jump);
|
|---|
| 862 | return item ? item->data : 0;
|
|---|
| 863 | }
|
|---|