Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

qgcache.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** $Id: qgcache.cpp,v 1.2 2003/07/10 02:40:11 llornkcor Exp $
00003 **
00004 ** Implementation of QGCache and QGCacheIterator classes
00005 **
00006 ** Created : 950208
00007 **
00008 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
00009 **
00010 ** This file is part of the tools module of the Qt GUI Toolkit.
00011 **
00012 ** This file may be distributed under the terms of the Q Public License
00013 ** as defined by Trolltech AS of Norway and appearing in the file
00014 ** LICENSE.QPL included in the packaging of this file.
00015 **
00016 ** This file may be distributed and/or modified under the terms of the
00017 ** GNU General Public License version 2 as published by the Free Software
00018 ** Foundation and appearing in the file LICENSE.GPL included in the
00019 ** packaging of this file.
00020 **
00021 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
00022 ** licenses may use this file in accordance with the Qt Commercial License
00023 ** Agreement provided with the Software.
00024 **
00025 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00026 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00027 **
00028 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
00029 **   information about Qt Commercial License Agreements.
00030 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
00031 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00032 **
00033 ** Contact info@trolltech.com if any conditions of this licensing are
00034 ** not clear to you.
00035 **
00036 **********************************************************************/
00037 
00038 #include "qgcache.h"
00039 #include "qptrlist.h"
00040 #include "qdict.h"
00041 #include "qstring.h"
00042 
00058 /*****************************************************************************
00059   QGCacheItem class (internal cache item)
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   QCList class (internal list of cache items)
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 * );         // insert according to priority
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;                        // variables for statistics
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 );                     // relink as first item
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   QCDict class (internal dictionary of cache items)
00182  *****************************************************************************/
00183 
00184 //
00185 // Since we need to decide if the dictionary should use an int or const
00186 // char * key (the "bool trivial" argument in the constructor below)
00187 // we cannot use the macro/template dict, but inherit directly from QGDict.
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   QGDict member functions
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) )    // remove excess cost
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 );  // take from dict
00461     Item d;
00462     if ( ci ) {
00463         d = ci->data;
00464         tCost -= ci->cost;
00465         lruList->take( ci );                    // take from list
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 );                    // take from list
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:                        // unused
00523                 break;
00524         }
00525         deleteItem( ci->data );                 // delete data
00526         lruList->removeFirst();                 // remove from list
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 )                         // cannot make room for more
00586         return FALSE;                           //   than maximum cost
00587     if ( priority == -1 )
00588         priority = 32767;
00589     register QCacheItem *ci = lruList->last();
00590     int cntCost = 0;
00591     int dumps   = 0;                            // number of items to dump
00592     while ( cntCost < cost && ci && ci->skipPriority <= priority ) {
00593         cntCost += ci->cost;
00594         ci       = lruList->prev();
00595         dumps++;
00596     }
00597     if ( cntCost < cost )                       // can enough cost be dumped?
00598         return FALSE;                           // no
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:                        // unused
00622                 break;
00623         }
00624         deleteItem( ci->data );                 // delete data
00625         lruList->removeLast();                  // remove from list
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   QGCacheIterator member functions
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 }

Generated on Sat Nov 5 16:18:30 2005 for OPIE by  doxygen 1.4.2