1 /****************************************************************************
4 ** Implementation of QGCache and QGCacheIterator classes
8 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
10 ** This file is part of the tools module of the Qt GUI Toolkit.
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.
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.
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.
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.
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.
33 ** Contact info@trolltech.com if any conditions of this licensing are
36 **********************************************************************/
46 \class QGCache qgcache.h
48 \brief The QGCache class is an internal class for implementing QCache template classes.
50 QGCache is a strictly internal class that acts as a base class for the
51 \link collection.html collection classes\endlink QCache and QIntCache.
55 /*****************************************************************************
56 QGCacheItem class (internal cache item)
57 *****************************************************************************/
61 QCacheItem( void *k, QCollection::Item d, int c, short p )
62 : priority(p), skipPriority(p), cost(c), key(k), data(d), node(0) {}
67 QCollection::Item data;
72 /*****************************************************************************
73 QCList class (internal list of cache items)
74 *****************************************************************************/
76 class QCList : private QList<QCacheItem>
78 friend class QGCacheIterator;
79 friend class QCListIt;
84 void insert( QCacheItem * ); // insert according to priority
85 void insert( int, QCacheItem * );
86 void take( QCacheItem * );
87 void reference( QCacheItem * );
89 void setAutoDelete( bool del ) { QCollection::setAutoDelete(del); }
91 bool removeFirst() { return QList<QCacheItem>::removeFirst(); }
92 bool removeLast() { return QList<QCacheItem>::removeLast(); }
94 QCacheItem *first() { return QList<QCacheItem>::first(); }
95 QCacheItem *last() { return QList<QCacheItem>::last(); }
96 QCacheItem *prev() { return QList<QCacheItem>::prev(); }
97 QCacheItem *next() { return QList<QCacheItem>::next(); }
100 int inserts; // variables for statistics
115 ASSERT( count() == 0 );
120 void QCList::insert( QCacheItem *ci )
122 QCacheItem *item = first();
123 while( item && item->skipPriority > ci->priority ) {
124 item->skipPriority--;
128 QList<QCacheItem>::insert( at(), ci );
132 ASSERT( ci->node == 0 );
134 ci->node = currentNode();
137 inline void QCList::insert( int i, QCacheItem *ci )
139 QList<QCacheItem>::insert( i, ci );
141 ASSERT( ci->node == 0 );
143 ci->node = currentNode();
147 void QCList::take( QCacheItem *ci )
151 ASSERT( ci->node != 0 );
153 takeNode( ci->node );
159 inline void QCList::reference( QCacheItem *ci )
162 ASSERT( ci != 0 && ci->node != 0 );
164 ci->skipPriority = ci->priority;
165 relinkNode( ci->node ); // relink as first item
169 class QCListIt: public QListIterator<QCacheItem>
172 QCListIt( const QCList *p ): QListIterator<QCacheItem>( *p ) {}
173 QCListIt( const QCListIt *p ): QListIterator<QCacheItem>( *p ) {}
177 /*****************************************************************************
178 QCDict class (internal dictionary of cache items)
179 *****************************************************************************/
182 // Since we need to decide if the dictionary should use an int or const
183 // char * key (the "bool trivial" argument in the constructor below)
184 // we cannot use the macro/template dict, but inherit directly from QGDict.
187 class QCDict : public QGDict
190 QCDict( uint size, uint kt, bool caseSensitive, bool copyKeys )
191 : QGDict( size, (KeyType)kt, caseSensitive, copyKeys ) {}
193 QCacheItem *find_string(const QString &key) const
194 { return (QCacheItem*)((QCDict*)this)->look_string(key, 0, 0); }
195 QCacheItem *find_ascii(const char *key) const
196 { return (QCacheItem*)((QCDict*)this)->look_ascii(key, 0, 0); }
197 QCacheItem *find_int(long key) const
198 { return (QCacheItem*)((QCDict*)this)->look_int(key, 0, 0); }
200 QCacheItem *take_string(const QString &key)
201 { return (QCacheItem*)QGDict::take_string(key); }
202 QCacheItem *take_ascii(const char *key)
203 { return (QCacheItem*)QGDict::take_ascii(key); }
204 QCacheItem *take_int(long key)
205 { return (QCacheItem*)QGDict::take_int(key); }
207 bool insert_string( const QString &key, const QCacheItem *ci )
208 { return QGDict::look_string(key,(Item)ci,1)!=0;}
209 bool insert_ascii( const char *key, const QCacheItem *ci )
210 { return QGDict::look_ascii(key,(Item)ci,1)!=0;}
211 bool insert_int( long key, const QCacheItem *ci )
212 { return QGDict::look_int(key,(Item)ci,1)!=0;}
214 bool remove_string( QCacheItem *item )
215 { return QGDict::remove_string(*((QString*)(item->key)),item); }
216 bool remove_ascii( QCacheItem *item )
217 { return QGDict::remove_ascii((const char *)item->key,item); }
218 bool remove_int( QCacheItem *item )
219 { return QGDict::remove_int((long)item->key,item);}
221 void statistics() { QGDict::statistics(); }
225 /*****************************************************************************
226 QGDict member functions
227 *****************************************************************************/
234 QGCache::QGCache( int maxCost, uint size, KeyType kt, bool caseSensitive,
238 lruList = new QCList;
239 CHECK_PTR( lruList );
240 lruList->setAutoDelete( TRUE );
241 copyk = ((keytype == AsciiKey) && copyKeys);
242 dict = new QCDict( size, kt, caseSensitive, FALSE );
247 lruList->inserts = 0;
248 lruList->insertCosts = 0;
249 lruList->insertMisses = 0;
252 lruList->hitCosts = 0;
254 lruList->dumpCosts = 0;
263 QGCache::QGCache( const QGCache & )
266 #if defined(CHECK_NULL)
267 qFatal( "QGCache::QGCache(QGCache &): Cannot copy a cache" );
273 Removes all items from the cache and destroys it.
278 clear(); // delete everything first
285 Cannot assign a cache.
288 QGCache &QGCache::operator=( const QGCache & )
290 #if defined(CHECK_NULL)
291 qFatal( "QGCache::operator=: Cannot copy a cache" );
293 return *this; // satisfy the compiler
298 \fn uint QGCache::count() const
300 Returns the number of items in the cache.
304 \fn uint QGCache::size() const
306 Returns the size of the hash array.
310 \fn int QGCache::maxCost() const
312 Returns the maximum cache cost.
316 \fn int QGCache::totalCost() const
318 Returns the total cache cost.
323 Sets the maximum cache cost.
326 void QGCache::setMaxCost( int maxCost )
328 if ( maxCost < tCost ) {
329 if ( !makeRoomFor(tCost - maxCost) ) // remove excess cost
338 Inserts an item into the cache.
340 \warning If this function returns FALSE, you must delete \a data
341 yourself. Additionally, be very careful about using \a data after
342 calling this function, as any other insertions into the cache, from
343 anywhere in the application, or within Qt itself, could cause the
344 data to be discarded from the cache, and the pointer to become
348 bool QGCache::insert_string( const QString &key, QCollection::Item data,
349 int cost, int priority)
351 if ( tCost + cost > mCost ) {
352 if ( !makeRoomFor(tCost + cost - mCost, priority) ) {
354 lruList->insertMisses++;
360 ASSERT( keytype == StringKey );
362 lruList->insertCosts += cost;
364 if ( priority < -32768 )
366 else if ( priority > 32767 )
368 QCacheItem *ci = new QCacheItem( new QString(key), newItem(data),
369 cost, (short)priority );
371 lruList->insert( 0, ci );
372 dict->insert_string( key, ci );
380 bool QGCache::insert_other( const char *key, QCollection::Item data,
381 int cost, int priority)
383 if ( tCost + cost > mCost ) {
384 if ( !makeRoomFor(tCost + cost - mCost, priority) ) {
386 lruList->insertMisses++;
392 ASSERT( keytype != StringKey );
394 lruList->insertCosts += cost;
396 if ( keytype == AsciiKey && copyk )
397 key = qstrdup( key );
398 if ( priority < -32768 )
400 else if ( priority > 32767 )
402 QCacheItem *ci = new QCacheItem( (void*)key, newItem(data), cost,
405 lruList->insert( 0, ci );
406 if ( keytype == AsciiKey )
407 dict->insert_ascii( key, ci );
409 dict->insert_int( (long)key, ci );
417 Removes an item from the cache.
420 bool QGCache::remove_string( const QString &key )
422 Item d = take_string( key );
431 bool QGCache::remove_other( const char *key )
433 Item d = take_other( key );
442 Takes an item out of the cache (no delete).
445 QCollection::Item QGCache::take_string( const QString &key )
447 QCacheItem *ci = dict->take_string( key ); // take from dict
452 lruList->take( ci ); // take from list
453 delete (QString*)ci->key;
463 Takes an item out of the cache (no delete).
466 QCollection::Item QGCache::take_other( const char *key )
469 if ( keytype == AsciiKey )
470 ci = dict->take_ascii( key );
472 ci = dict->take_int( (long)key );
477 lruList->take( ci ); // take from list
479 delete [] (char *)ci->key;
493 void QGCache::clear()
496 while ( (ci = lruList->first()) ) {
499 dict->remove_string( ci );
500 delete (QString*)ci->key;
503 dict->remove_ascii( ci );
505 delete [] (char*)ci->key;
508 dict->remove_int( ci );
510 case PtrKey: // unused
513 deleteItem( ci->data ); // delete data
514 lruList->removeFirst(); // remove from list
522 Finds an item in the cache.
525 QCollection::Item QGCache::find_string( const QString &key, bool ref ) const
527 QCacheItem *ci = dict->find_string( key );
534 lruList->hitCosts += ci->cost;
537 lruList->reference( ci );
546 Finds an item in the cache.
549 QCollection::Item QGCache::find_other( const char *key, bool ref ) const
551 QCacheItem *ci = keytype == AsciiKey ? dict->find_ascii(key)
552 : dict->find_int((long)key);
559 lruList->hitCosts += ci->cost;
562 lruList->reference( ci );
571 Allocates cache space for one or more items.
574 bool QGCache::makeRoomFor( int cost, int priority )
576 if ( cost > mCost ) // cannot make room for more
577 return FALSE; // than maximum cost
578 if ( priority == -1 )
580 register QCacheItem *ci = lruList->last();
582 int dumps = 0; // number of items to dump
583 while ( cntCost < cost && ci && ci->skipPriority <= priority ) {
585 ci = lruList->prev();
588 if ( cntCost < cost ) // can enough cost be dumped?
594 ci = lruList->last();
597 lruList->dumpCosts += ci->cost;
601 dict->remove_string( ci );
602 delete (QString*)ci->key;
605 dict->remove_ascii( ci );
607 delete [] (char *)ci->key;
610 dict->remove_int( ci );
612 case PtrKey: // unused
615 deleteItem( ci->data ); // delete data
616 lruList->removeLast(); // remove from list
625 Outputs debug statistics.
628 void QGCache::statistics() const
632 line.fill( '*', 80 );
633 qDebug( "%s",line.ascii() );
634 qDebug( "CACHE STATISTICS:" );
635 qDebug( "cache contains %d item%s, with a total cost of %d",
636 count(), count() != 1 ? "s" : "", tCost );
637 qDebug( "maximum cost is %d, cache is %d%% full.",
638 mCost, (200*tCost + mCost) / (mCost*2) );
639 qDebug( "find() has been called %d time%s",
640 lruList->finds, lruList->finds != 1 ? "s" : "" );
641 qDebug( "%d of these were hits, items found had a total cost of %d.",
642 lruList->hits,lruList->hitCosts );
643 qDebug( "%d item%s %s been inserted with a total cost of %d.",
644 lruList->inserts,lruList->inserts != 1 ? "s" : "",
645 lruList->inserts != 1 ? "have" : "has", lruList->insertCosts );
646 qDebug( "%d item%s %s too large or had too low priority to be inserted.",
647 lruList->insertMisses, lruList->insertMisses != 1 ? "s" : "",
648 lruList->insertMisses != 1 ? "were" : "was" );
649 qDebug( "%d item%s %s been thrown away with a total cost of %d.",
650 lruList->dumps, lruList->dumps != 1 ? "s" : "",
651 lruList->dumps != 1 ? "have" : "has", lruList->dumpCosts );
652 qDebug( "Statistics from internal dictionary class:" );
654 qDebug( "%s",line.ascii() );
658 int QGCache::hits() const
660 return lruList->hits;
663 int QGCache::misses() const
665 return lruList->finds - lruList->hits;
669 /*****************************************************************************
670 QGCacheIterator member functions
671 *****************************************************************************/
674 \class QGCacheIterator qgcache.h
676 \brief An internal class for implementing QCacheIterator and QIntCacheIterator.
678 QGCacheIterator is a strictly internal class that does the heavy work for
679 QCacheIterator and QIntCacheIterator.
684 Constructs an iterator that operates on the cache \e c.
687 QGCacheIterator::QGCacheIterator( const QGCache &c )
689 it = new QCListIt( c.lruList );
697 Constructs an iterator that operates on the same cache as \e ci.
700 QGCacheIterator::QGCacheIterator( const QGCacheIterator &ci )
702 it = new QCListIt( ci.it );
710 Destroys the iterator.
713 QGCacheIterator::~QGCacheIterator()
720 Assigns the iterator \e ci to this cache iterator.
723 QGCacheIterator &QGCacheIterator::operator=( const QGCacheIterator &ci )
731 Returns the number of items in the cache.
734 uint QGCacheIterator::count() const
741 Returns TRUE if the iterator points to the first item.
744 bool QGCacheIterator::atFirst() const
746 return it->atFirst();
751 Returns TRUE if the iterator points to the last item.
754 bool QGCacheIterator::atLast() const
761 Sets the list iterator to point to the first item in the cache.
764 QCollection::Item QGCacheIterator::toFirst()
766 QCacheItem *item = it->toFirst();
767 return item ? item->data : 0;
772 Sets the list iterator to point to the last item in the cache.
775 QCollection::Item QGCacheIterator::toLast()
777 QCacheItem *item = it->toLast();
778 return item ? item->data : 0;
783 Returns the current item.
786 QCollection::Item QGCacheIterator::get() const
788 QCacheItem *item = it->current();
789 return item ? item->data : 0;
794 Returns the key of the current item.
797 QString QGCacheIterator::getKeyString() const
799 QCacheItem *item = it->current();
800 return item ? *((QString*)item->key) : QString::null;
805 Returns the key of the current item, as a \0-terminated C string.
808 const char *QGCacheIterator::getKeyAscii() const
810 QCacheItem *item = it->current();
811 return item ? (const char *)item->key : 0;
816 Returns the key of the current item, as a long.
819 long QGCacheIterator::getKeyInt() const
821 QCacheItem *item = it->current();
822 return item ? (long)item->key : 0;
827 Moves to the next item (postfix).
830 QCollection::Item QGCacheIterator::operator()()
832 QCacheItem *item = it->operator()();
833 return item ? item->data : 0;
838 Moves to the next item (prefix).
841 QCollection::Item QGCacheIterator::operator++()
843 QCacheItem *item = it->operator++();
844 return item ? item->data : 0;
849 Moves \e jumps positions forward.
852 QCollection::Item QGCacheIterator::operator+=( uint jump )
854 QCacheItem *item = it->operator+=(jump);
855 return item ? item->data : 0;
860 Moves to the previous item (prefix).
863 QCollection::Item QGCacheIterator::operator--()
865 QCacheItem *item = it->operator--();
866 return item ? item->data : 0;
871 Moves \e jumps positions backward.
874 QCollection::Item QGCacheIterator::operator-=( uint jump )
876 QCacheItem *item = it->operator-=(jump);
877 return item ? item->data : 0;