00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "qgcache.h"
00039 #include "qptrlist.h"
00040 #include "qdict.h"
00041 #include "qstring.h"
00042
00058
00059
00060
00061
00062 struct QCacheItem
00063 {
00064 QCacheItem( void *k, QPtrCollection::Item d, int c, short p )
00065 : priority(p), skipPriority(p), cost(c), key(k), data(d), node(0) {}
00066 short priority;
00067 short skipPriority;
00068 int cost;
00069 void *key;
00070 QPtrCollection::Item data;
00071 QLNode *node;
00072 };
00073
00074
00075
00076
00077
00078
00079 class QCList : private QPtrList<QCacheItem>
00080 {
00081 friend class QGCacheIterator;
00082 friend class QCListIt;
00083 public:
00084 QCList() {}
00085 ~QCList();
00086
00087 void insert( QCacheItem * );
00088 void insert( int, QCacheItem * );
00089 void take( QCacheItem * );
00090 void reference( QCacheItem * );
00091
00092 void setAutoDelete( bool del ) { QPtrCollection::setAutoDelete(del); }
00093
00094 bool removeFirst() { return QPtrList<QCacheItem>::removeFirst(); }
00095 bool removeLast() { return QPtrList<QCacheItem>::removeLast(); }
00096
00097 QCacheItem *first() { return QPtrList<QCacheItem>::first(); }
00098 QCacheItem *last() { return QPtrList<QCacheItem>::last(); }
00099 QCacheItem *prev() { return QPtrList<QCacheItem>::prev(); }
00100 QCacheItem *next() { return QPtrList<QCacheItem>::next(); }
00101
00102 #if defined(QT_DEBUG)
00103 int inserts;
00104 int insertCosts;
00105 int insertMisses;
00106 int finds;
00107 int hits;
00108 int hitCosts;
00109 int dumps;
00110 int dumpCosts;
00111 #endif
00112 };
00113
00114
00115 QCList::~QCList()
00116 {
00117 #if defined(QT_DEBUG)
00118 Q_ASSERT( count() == 0 );
00119 #endif
00120 }
00121
00122
00123 void QCList::insert( QCacheItem *ci )
00124 {
00125 QCacheItem *item = first();
00126 while( item && item->skipPriority > ci->priority ) {
00127 item->skipPriority--;
00128 item = next();
00129 }
00130 if ( item )
00131 QPtrList<QCacheItem>::insert( at(), ci );
00132 else
00133 append( ci );
00134 #if defined(QT_DEBUG)
00135 Q_ASSERT( ci->node == 0 );
00136 #endif
00137 ci->node = currentNode();
00138 }
00139
00140 inline void QCList::insert( int i, QCacheItem *ci )
00141 {
00142 QPtrList<QCacheItem>::insert( i, ci );
00143 #if defined(QT_DEBUG)
00144 Q_ASSERT( ci->node == 0 );
00145 #endif
00146 ci->node = currentNode();
00147 }
00148
00149
00150 void QCList::take( QCacheItem *ci )
00151 {
00152 if ( ci ) {
00153 #if defined(QT_DEBUG)
00154 Q_ASSERT( ci->node != 0 );
00155 #endif
00156 takeNode( ci->node );
00157 ci->node = 0;
00158 }
00159 }
00160
00161
00162 inline void QCList::reference( QCacheItem *ci )
00163 {
00164 #if defined(QT_DEBUG)
00165 Q_ASSERT( ci != 0 && ci->node != 0 );
00166 #endif
00167 ci->skipPriority = ci->priority;
00168 relinkNode( ci->node );
00169 }
00170
00171
00172 class QCListIt: public QPtrListIterator<QCacheItem>
00173 {
00174 public:
00175 QCListIt( const QCList *p ): QPtrListIterator<QCacheItem>( *p ) {}
00176 QCListIt( const QCListIt *p ): QPtrListIterator<QCacheItem>( *p ) {}
00177 };
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190 class QCDict : public QGDict
00191 {
00192 public:
00193 QCDict( uint size, uint kt, bool caseSensitive, bool copyKeys )
00194 : QGDict( size, (KeyType)kt, caseSensitive, copyKeys ) {}
00195 ~QCDict();
00196
00197 void clear() { QGDict::clear(); }
00198
00199 QCacheItem *find_string(const QString &key) const
00200 { return (QCacheItem*)((QCDict*)this)->look_string(key, 0, 0); }
00201 QCacheItem *find_ascii(const char *key) const
00202 { return (QCacheItem*)((QCDict*)this)->look_ascii(key, 0, 0); }
00203 QCacheItem *find_int(long key) const
00204 { return (QCacheItem*)((QCDict*)this)->look_int(key, 0, 0); }
00205
00206 QCacheItem *take_string(const QString &key)
00207 { return (QCacheItem*)QGDict::take_string(key); }
00208 QCacheItem *take_ascii(const char *key)
00209 { return (QCacheItem*)QGDict::take_ascii(key); }
00210 QCacheItem *take_int(long key)
00211 { return (QCacheItem*)QGDict::take_int(key); }
00212
00213 bool insert_string( const QString &key, const QCacheItem *ci )
00214 { return QGDict::look_string(key,(Item)ci,1)!=0;}
00215 bool insert_ascii( const char *key, const QCacheItem *ci )
00216 { return QGDict::look_ascii(key,(Item)ci,1)!=0;}
00217 bool insert_int( long key, const QCacheItem *ci )
00218 { return QGDict::look_int(key,(Item)ci,1)!=0;}
00219
00220 bool remove_string( QCacheItem *item )
00221 { return QGDict::remove_string(*((QString*)(item->key)),item); }
00222 bool remove_ascii( QCacheItem *item )
00223 { return QGDict::remove_ascii((const char *)item->key,item); }
00224 bool remove_int( QCacheItem *item )
00225 { return QGDict::remove_int((long)item->key,item);}
00226
00227 void statistics() { QGDict::statistics(); }
00228
00229 private:
00230 void deleteItem( void *item )
00231 { if ( del_item ) { QCacheItem *d = (QCacheItem*)item; delete d; } }
00232 };
00233
00234 inline QCDict::~QCDict()
00235 {
00236 clear();
00237 }
00238
00239
00240
00241
00242
00251 QGCache::QGCache( int maxCost, uint size, KeyType kt, bool caseSensitive,
00252 bool copyKeys )
00253 {
00254 keytype = kt;
00255 lruList = new QCList;
00256 Q_CHECK_PTR( lruList );
00257 lruList->setAutoDelete( TRUE );
00258 copyk = ((keytype == AsciiKey) && copyKeys);
00259 dict = new QCDict( size, kt, caseSensitive, FALSE );
00260 Q_CHECK_PTR( dict );
00261 mCost = maxCost;
00262 tCost = 0;
00263 #if defined(QT_DEBUG)
00264 lruList->inserts = 0;
00265 lruList->insertCosts = 0;
00266 lruList->insertMisses = 0;
00267 lruList->finds = 0;
00268 lruList->hits = 0;
00269 lruList->hitCosts = 0;
00270 lruList->dumps = 0;
00271 lruList->dumpCosts = 0;
00272 #endif
00273 }
00274
00279 QGCache::QGCache( const QGCache & )
00280 : QPtrCollection()
00281 {
00282 #if defined(QT_CHECK_NULL)
00283 qFatal( "QGCache::QGCache(QGCache &): Cannot copy a cache" );
00284 #endif
00285 }
00286
00291 QGCache::~QGCache()
00292 {
00293 clear();
00294 delete dict;
00295 delete lruList;
00296 }
00297
00302 QGCache &QGCache::operator=( const QGCache & )
00303 {
00304 #if defined(QT_CHECK_NULL)
00305 qFatal( "QGCache::operator=: Cannot copy a cache" );
00306 #endif
00307 return *this;
00308 }
00309
00310
00315 uint QGCache::count() const
00316 {
00317 return dict->count();
00318 }
00319
00324 uint QGCache::size() const
00325 {
00326 return dict->size();
00327 }
00328
00345 void QGCache::setMaxCost( int maxCost )
00346 {
00347 if ( maxCost < tCost ) {
00348 if ( !makeRoomFor(tCost - maxCost) )
00349 return;
00350 }
00351 mCost = maxCost;
00352 }
00353
00354
00367 bool QGCache::insert_string( const QString &key, QPtrCollection::Item data,
00368 int cost, int priority)
00369 {
00370 if ( tCost + cost > mCost ) {
00371 if ( !makeRoomFor(tCost + cost - mCost, priority) ) {
00372 #if defined(QT_DEBUG)
00373 lruList->insertMisses++;
00374 #endif
00375 return FALSE;
00376 }
00377 }
00378 #if defined(QT_DEBUG)
00379 Q_ASSERT( keytype == StringKey );
00380 lruList->inserts++;
00381 lruList->insertCosts += cost;
00382 #endif
00383 if ( priority < -32768 )
00384 priority = -32768;
00385 else if ( priority > 32767 )
00386 priority = 32677;
00387 QCacheItem *ci = new QCacheItem( new QString(key), newItem(data),
00388 cost, (short)priority );
00389 Q_CHECK_PTR( ci );
00390 lruList->insert( 0, ci );
00391 dict->insert_string( key, ci );
00392 tCost += cost;
00393 return TRUE;
00394 }
00395
00396 bool QGCache::insert_other( const char *key, QPtrCollection::Item data,
00397 int cost, int priority)
00398 {
00399 if ( tCost + cost > mCost ) {
00400 if ( !makeRoomFor(tCost + cost - mCost, priority) ) {
00401 #if defined(QT_DEBUG)
00402 lruList->insertMisses++;
00403 #endif
00404 return FALSE;
00405 }
00406 }
00407 #if defined(QT_DEBUG)
00408 Q_ASSERT( keytype != StringKey );
00409 lruList->inserts++;
00410 lruList->insertCosts += cost;
00411 #endif
00412 if ( keytype == AsciiKey && copyk )
00413 key = qstrdup( key );
00414 if ( priority < -32768 )
00415 priority = -32768;
00416 else if ( priority > 32767 )
00417 priority = 32677;
00418 QCacheItem *ci = new QCacheItem( (void*)key, newItem(data), cost,
00419 (short)priority );
00420 Q_CHECK_PTR( ci );
00421 lruList->insert( 0, ci );
00422 if ( keytype == AsciiKey )
00423 dict->insert_ascii( key, ci );
00424 else
00425 dict->insert_int( (long)key, ci );
00426 tCost += cost;
00427 return TRUE;
00428 }
00429
00430
00436 bool QGCache::remove_string( const QString &key )
00437 {
00438 Item d = take_string( key );
00439 if ( d )
00440 deleteItem( d );
00441 return d != 0;
00442 }
00443
00444 bool QGCache::remove_other( const char *key )
00445 {
00446 Item d = take_other( key );
00447 if ( d )
00448 deleteItem( d );
00449 return d != 0;
00450 }
00451
00452
00458 QPtrCollection::Item QGCache::take_string( const QString &key )
00459 {
00460 QCacheItem *ci = dict->take_string( key );
00461 Item d;
00462 if ( ci ) {
00463 d = ci->data;
00464 tCost -= ci->cost;
00465 lruList->take( ci );
00466 delete (QString*)ci->key;
00467 delete ci;
00468 } else {
00469 d = 0;
00470 }
00471 return d;
00472 }
00473
00479 QPtrCollection::Item QGCache::take_other( const char *key )
00480 {
00481 QCacheItem *ci;
00482 if ( keytype == AsciiKey )
00483 ci = dict->take_ascii( key );
00484 else
00485 ci = dict->take_int( (long)key );
00486 Item d;
00487 if ( ci ) {
00488 d = ci->data;
00489 tCost -= ci->cost;
00490 lruList->take( ci );
00491 if ( copyk )
00492 delete [] (char *)ci->key;
00493 delete ci;
00494 } else {
00495 d = 0;
00496 }
00497 return d;
00498 }
00499
00500
00505 void QGCache::clear()
00506 {
00507 QCacheItem *ci;
00508 while ( (ci = lruList->first()) ) {
00509 switch ( keytype ) {
00510 case StringKey:
00511 dict->remove_string( ci );
00512 delete (QString*)ci->key;
00513 break;
00514 case AsciiKey:
00515 dict->remove_ascii( ci );
00516 if ( copyk )
00517 delete [] (char*)ci->key;
00518 break;
00519 case IntKey:
00520 dict->remove_int( ci );
00521 break;
00522 case PtrKey:
00523 break;
00524 }
00525 deleteItem( ci->data );
00526 lruList->removeFirst();
00527 }
00528 tCost = 0;
00529 }
00530
00531
00536 QPtrCollection::Item QGCache::find_string( const QString &key, bool ref ) const
00537 {
00538 QCacheItem *ci = dict->find_string( key );
00539 #if defined(QT_DEBUG)
00540 lruList->finds++;
00541 #endif
00542 if ( ci ) {
00543 #if defined(QT_DEBUG)
00544 lruList->hits++;
00545 lruList->hitCosts += ci->cost;
00546 #endif
00547 if ( ref )
00548 lruList->reference( ci );
00549 return ci->data;
00550 }
00551 return 0;
00552 }
00553
00554
00559 QPtrCollection::Item QGCache::find_other( const char *key, bool ref ) const
00560 {
00561 QCacheItem *ci = keytype == AsciiKey ? dict->find_ascii(key)
00562 : dict->find_int((long)key);
00563 #if defined(QT_DEBUG)
00564 lruList->finds++;
00565 #endif
00566 if ( ci ) {
00567 #if defined(QT_DEBUG)
00568 lruList->hits++;
00569 lruList->hitCosts += ci->cost;
00570 #endif
00571 if ( ref )
00572 lruList->reference( ci );
00573 return ci->data;
00574 }
00575 return 0;
00576 }
00577
00578
00583 bool QGCache::makeRoomFor( int cost, int priority )
00584 {
00585 if ( cost > mCost )
00586 return FALSE;
00587 if ( priority == -1 )
00588 priority = 32767;
00589 register QCacheItem *ci = lruList->last();
00590 int cntCost = 0;
00591 int dumps = 0;
00592 while ( cntCost < cost && ci && ci->skipPriority <= priority ) {
00593 cntCost += ci->cost;
00594 ci = lruList->prev();
00595 dumps++;
00596 }
00597 if ( cntCost < cost )
00598 return FALSE;
00599 #if defined(QT_DEBUG)
00600 Q_ASSERT( dumps > 0 );
00601 #endif
00602 while ( dumps-- ) {
00603 ci = lruList->last();
00604 #if defined(QT_DEBUG)
00605 lruList->dumps++;
00606 lruList->dumpCosts += ci->cost;
00607 #endif
00608 switch ( keytype ) {
00609 case StringKey:
00610 dict->remove_string( ci );
00611 delete (QString*)ci->key;
00612 break;
00613 case AsciiKey:
00614 dict->remove_ascii( ci );
00615 if ( copyk )
00616 delete [] (char *)ci->key;
00617 break;
00618 case IntKey:
00619 dict->remove_int( ci );
00620 break;
00621 case PtrKey:
00622 break;
00623 }
00624 deleteItem( ci->data );
00625 lruList->removeLast();
00626 }
00627 tCost -= cntCost;
00628 return TRUE;
00629 }
00630
00631
00636 void QGCache::statistics() const
00637 {
00638 #if defined(QT_DEBUG)
00639 QString line;
00640 line.fill( '*', 80 );
00641 qDebug( line.ascii() );
00642 qDebug( "CACHE STATISTICS:" );
00643 qDebug( "cache contains %d item%s, with a total cost of %d",
00644 count(), count() != 1 ? "s" : "", tCost );
00645 qDebug( "maximum cost is %d, cache is %d%% full.",
00646 mCost, (200*tCost + mCost) / (mCost*2) );
00647 qDebug( "find() has been called %d time%s",
00648 lruList->finds, lruList->finds != 1 ? "s" : "" );
00649 qDebug( "%d of these were hits, items found had a total cost of %d.",
00650 lruList->hits,lruList->hitCosts );
00651 qDebug( "%d item%s %s been inserted with a total cost of %d.",
00652 lruList->inserts,lruList->inserts != 1 ? "s" : "",
00653 lruList->inserts != 1 ? "have" : "has", lruList->insertCosts );
00654 qDebug( "%d item%s %s too large or had too low priority to be inserted.",
00655 lruList->insertMisses, lruList->insertMisses != 1 ? "s" : "",
00656 lruList->insertMisses != 1 ? "were" : "was" );
00657 qDebug( "%d item%s %s been thrown away with a total cost of %d.",
00658 lruList->dumps, lruList->dumps != 1 ? "s" : "",
00659 lruList->dumps != 1 ? "have" : "has", lruList->dumpCosts );
00660 qDebug( "Statistics from internal dictionary class:" );
00661 dict->statistics();
00662 qDebug( line.ascii() );
00663 #endif
00664 }
00665
00666
00667
00668
00669
00670
00689 QGCacheIterator::QGCacheIterator( const QGCache &c )
00690 {
00691 it = new QCListIt( c.lruList );
00692 #if defined(QT_DEBUG)
00693 Q_ASSERT( it != 0 );
00694 #endif
00695 }
00696
00701 QGCacheIterator::QGCacheIterator( const QGCacheIterator &ci )
00702 {
00703 it = new QCListIt( ci.it );
00704 #if defined(QT_DEBUG)
00705 Q_ASSERT( it != 0 );
00706 #endif
00707 }
00708
00713 QGCacheIterator::~QGCacheIterator()
00714 {
00715 delete it;
00716 }
00717
00722 QGCacheIterator &QGCacheIterator::operator=( const QGCacheIterator &ci )
00723 {
00724 *it = *ci.it;
00725 return *this;
00726 }
00727
00732 uint QGCacheIterator::count() const
00733 {
00734 return it->count();
00735 }
00736
00741 bool QGCacheIterator::atFirst() const
00742 {
00743 return it->atFirst();
00744 }
00745
00750 bool QGCacheIterator::atLast() const
00751 {
00752 return it->atLast();
00753 }
00754
00759 QPtrCollection::Item QGCacheIterator::toFirst()
00760 {
00761 QCacheItem *item = it->toFirst();
00762 return item ? item->data : 0;
00763 }
00764
00769 QPtrCollection::Item QGCacheIterator::toLast()
00770 {
00771 QCacheItem *item = it->toLast();
00772 return item ? item->data : 0;
00773 }
00774
00779 QPtrCollection::Item QGCacheIterator::get() const
00780 {
00781 QCacheItem *item = it->current();
00782 return item ? item->data : 0;
00783 }
00784
00789 QString QGCacheIterator::getKeyString() const
00790 {
00791 QCacheItem *item = it->current();
00792 return item ? *((QString*)item->key) : QString::null;
00793 }
00794
00799 const char *QGCacheIterator::getKeyAscii() const
00800 {
00801 QCacheItem *item = it->current();
00802 return item ? (const char *)item->key : 0;
00803 }
00804
00809 long QGCacheIterator::getKeyInt() const
00810 {
00811 QCacheItem *item = it->current();
00812 return item ? (long)item->key : 0;
00813 }
00814
00819 QPtrCollection::Item QGCacheIterator::operator()()
00820 {
00821 QCacheItem *item = it->operator()();
00822 return item ? item->data : 0;
00823 }
00824
00829 QPtrCollection::Item QGCacheIterator::operator++()
00830 {
00831 QCacheItem *item = it->operator++();
00832 return item ? item->data : 0;
00833 }
00834
00839 QPtrCollection::Item QGCacheIterator::operator+=( uint jump )
00840 {
00841 QCacheItem *item = it->operator+=(jump);
00842 return item ? item->data : 0;
00843 }
00844
00849 QPtrCollection::Item QGCacheIterator::operator--()
00850 {
00851 QCacheItem *item = it->operator--();
00852 return item ? item->data : 0;
00853 }
00854
00859 QPtrCollection::Item QGCacheIterator::operator-=( uint jump )
00860 {
00861 QCacheItem *item = it->operator-=(jump);
00862 return item ? item->data : 0;
00863 }