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