Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qpixmapcache.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qpixmapcache.h"
5#include "qobject.h"
6#include "qdebug.h"
7#include "qpixmapcache_p.h"
8#include "qthread.h"
9#include "qcoreapplication.h"
10
11using namespace std::chrono_literals;
12
14
59static const int cache_limit_default = 10240; // 10 MB cache limit
60
61static inline qsizetype cost(const QPixmap &pixmap)
62{
63 // make sure to do a 64bit calculation; qsizetype might be smaller
64 const qint64 costKb = static_cast<qint64>(pixmap.width())
65 * pixmap.height() * pixmap.depth() / (8 * 1024);
66 const qint64 costMax = std::numeric_limits<qsizetype>::max();
67 // a small pixmap should have at least a cost of 1(kb)
68 return static_cast<qsizetype>(qBound(1LL, costKb, costMax));
69}
70
71static inline bool qt_pixmapcache_thread_test()
72{
74 return true;
75
76 return false;
77}
78
97
103{
104 if (other.d)
105 ++(other.d->ref);
106 d = other.d;
107}
108
113{
114 if (d && --(d->ref) == 0)
115 delete d;
116}
117
125{
126 return (d == key.d);
127}
128
157bool QPixmapCache::Key::isValid() const noexcept
158{
159 return d && d->isValid;
160}
161
166{
167 if (d != other.d) {
168 if (other.d)
169 ++(other.d->ref);
170 if (d && --(d->ref) == 0)
171 delete d;
172 d = other.d;
173 }
174 return *this;
175}
176
177class QPMCache : public QObject, public QCache<QPixmapCache::Key, QPixmapCacheEntry>
178{
180public:
181 QPMCache();
182 ~QPMCache();
183
184 void timerEvent(QTimerEvent *) override;
185 bool insert(const QString& key, const QPixmap &pixmap, int cost);
187 bool remove(const QString &key);
188 bool remove(const QPixmapCache::Key &key);
189
190 void resizeKeyArray(int size);
191 QPixmapCache::Key createKey();
192 void releaseKey(const QPixmapCache::Key &key);
193 void clear();
194
195 QPixmap *object(const QString &key) const;
196 QPixmap *object(const QPixmapCache::Key &key) const;
197
199 {return key.d;}
200
201 static QPixmapCache::KeyData* getKeyData(QPixmapCache::Key *key);
202
203 bool flushDetachedPixmaps(bool nt);
204
205private:
206 static constexpr auto soon_time = 10s;
207 static constexpr auto flush_time = 30s;
208 int *keyArray;
209 int theid;
210 int ps;
211 int keyArraySize;
212 int freeKey;
213 QHash<QString, QPixmapCache::Key> cacheKeys;
214 bool t;
215};
216
218#include "qpixmapcache.moc"
220
227size_t QPixmapCache::Key::hash(size_t seed) const noexcept
228{
229 return qHash(this->d ? this->d->key : 0, seed);
230}
231
233 : QObject(nullptr),
235 keyArray(nullptr), theid(0), ps(0), keyArraySize(0), freeKey(0), t(false)
236{
237}
239{
240 clear();
241 free(keyArray);
242}
243
244/*
245 This is supposed to cut the cache size down by about 25% in a
246 minute once the application becomes idle, to let any inserted pixmap
247 remain in the cache for some time before it becomes a candidate for
248 cleaning-up, and to not cut down the size of the cache while the
249 cache is in active use.
250
251 When the last detached pixmap has been deleted from the cache, kill the
252 timer so Qt won't keep the CPU from going into sleep mode. Currently
253 the timer is not restarted when the pixmap becomes unused, but it does
254 restart once something else is added (i.e. the cache space is actually needed).
255
256 Returns \c true if any were removed.
257*/
259{
260 auto mc = maxCost();
261 const qsizetype currentTotal = totalCost();
262 const qsizetype oldSize = size();
263 if (currentTotal)
264 setMaxCost(nt ? currentTotal * 3 / 4 : currentTotal - 1);
265 setMaxCost(mc);
266 ps = totalCost();
267 return size() != oldSize;
268}
269
271{
272 bool nt = totalCost() == ps;
273 if (!flushDetachedPixmaps(nt)) {
274 killTimer(theid);
275 theid = 0;
276 } else if (nt != t) {
277 killTimer(theid);
278 theid = startTimer(nt ? soon_time : flush_time);
279 t = nt;
280 }
281}
282
283
285{
286 if (const auto it = cacheKeys.find(key); it != cacheKeys.cend())
287 return object(it.value());
288 return nullptr;
289}
290
292{
293 Q_ASSERT(key.isValid());
295 //We didn't find the pixmap in the cache, the key is not valid anymore
296 if (!ptr)
297 const_cast<QPMCache *>(this)->releaseKey(key);
298 return ptr;
299}
300
302{
303 //If for the same key we add already a pixmap we should delete it
304 remove(key);
305
306 // this will create a new key; the old one has been removed
307 auto k = insert(pixmap, cost);
308 if (k.isValid()) {
309 k.d->stringKey = key;
310 cacheKeys[key] = std::move(k);
311 return true;
312 }
313 return false;
314}
315
317{
318 QPixmapCache::Key cacheKey = createKey(); // invalidated by ~QPixmapCacheEntry on failed insert
320 Q_ASSERT(success || !cacheKey.isValid());
321 if (success) {
322 if (!theid) {
323 theid = startTimer(flush_time);
324 t = false;
325 }
326 }
327 return cacheKey;
328}
329
331{
332 const auto cacheKey = cacheKeys.take(key);
333 return cacheKey.isValid() && remove(cacheKey);
334}
335
340
342{
343 if (size <= keyArraySize || size == 0)
344 return;
345 keyArray = q_check_ptr(static_cast<int *>(realloc(keyArray,
346 size * sizeof(int))));
347 for (int i = keyArraySize; i != size; ++i)
348 keyArray[i] = i + 1;
349 keyArraySize = size;
350}
351
353{
354 if (freeKey == keyArraySize)
355 resizeKeyArray(keyArraySize ? keyArraySize << 1 : 2);
356 int id = freeKey;
357 freeKey = keyArray[id];
360 d->key = ++id;
361 return key;
362}
363
365{
366 QPixmapCache::KeyData *keyData = key.d;
367 if (!keyData)
368 return;
369 if (!keyData->stringKey.isNull())
370 cacheKeys.remove(keyData->stringKey);
371 if (keyData->key > keyArraySize || keyData->key <= 0)
372 return;
373 keyData->key--;
374 keyArray[keyData->key] = freeKey;
375 freeKey = keyData->key;
376 keyData->isValid = false;
377 keyData->key = 0;
378}
379
381{
382 free(keyArray);
383 keyArray = nullptr;
384 freeKey = 0;
385 keyArraySize = 0;
386 //Mark all keys as invalid
387 const QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QPixmapCacheEntry>::keys();
388 for (const auto &key : keys) {
389 if (key.d)
390 key.d->isValid = false;
391 }
393 // Nothing left to flush; stop the timer
394 if (theid) {
395 killTimer(theid);
396 theid = 0;
397 }
398}
399
406
407Q_GLOBAL_STATIC(QPMCache, pm_cache)
408
410{
411 return pm_cache()->size();
412}
413
415{
416 pm_cache()->releaseKey(key);
417}
418
431{
432 if (key.isEmpty() || !qt_pixmapcache_thread_test())
433 return false;
434 QPixmap *ptr = pm_cache()->object(key);
435 if (ptr && pixmap)
436 *pixmap = *ptr;
437 return ptr != nullptr;
438}
439
450{
452 return false;
453 //The key is not valid anymore, a flush happened before probably
454 if (!key.d || !key.d->isValid)
455 return false;
456 QPixmap *ptr = pm_cache()->object(key);
457 if (ptr && pixmap)
458 *pixmap = *ptr;
459 return ptr != nullptr;
460}
461
483{
484 if (key.isEmpty() || !qt_pixmapcache_thread_test())
485 return false;
486 return pm_cache()->insert(key, pixmap, cost(pixmap));
487}
488
505{
507 return QPixmapCache::Key();
508 return pm_cache()->insert(pixmap, cost(pixmap));
509}
510
511#if QT_DEPRECATED_SINCE(6, 6)
529#endif // QT_DEPRECATED_SINCE(6, 6)
530
540{
542 return 0;
543 return pm_cache()->maxCost();
544}
545
555{
557 return;
558 pm_cache()->setMaxCost(n);
559}
560
565{
566 if (key.isEmpty() || !qt_pixmapcache_thread_test())
567 return;
568 pm_cache()->remove(key);
569}
570
578{
580 return;
581 //The key is not valid anymore, a flush happened before probably
582 if (!key.d || !key.d->isValid)
583 return;
584 pm_cache()->remove(key);
585}
586
592{
594 return;
595 QT_TRY {
596 if (pm_cache.exists())
597 pm_cache->clear();
598 } QT_CATCH(const std::bad_alloc &) {
599 // if we ran out of memory during pm_cache(), it's no leak,
600 // so just ignore it.
601 }
602}
603
605{
607 return;
608 pm_cache()->flushDetachedPixmaps(true);
609}
610
612{
614 return 0;
615 return (pm_cache()->totalCost()+1023) / 1024;
616}
617
bool remove(const Key &key) noexcept(std::is_nothrow_destructible_v< Node >)
Definition qcache.h:222
void setMaxCost(qsizetype m) noexcept(std::is_nothrow_destructible_v< Node >)
Definition qcache.h:154
T * object(const Key &key) const noexcept
Definition qcache.h:209
qsizetype maxCost() const noexcept
Definition qcache.h:153
qsizetype totalCost() const noexcept
Definition qcache.h:159
void clear() noexcept(std::is_nothrow_destructible_v< Node >)
Definition qcache.h:176
bool insert(const Key &key, T *object, qsizetype cost=1)
Definition qcache.h:184
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
static bool closingDown()
Returns true if the application objects are being destroyed; otherwise returns false.
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:958
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1291
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:985
const_iterator cend() const noexcept
Definition qhash.h:1218
\inmodule QtCore
Definition qobject.h:103
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
This is an overloaded function that will start a timer of type timerType and a timeout of interval mi...
Definition qobject.cpp:1817
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition qobject.cpp:1912
bool remove(const QString &key)
bool insert(const QString &key, const QPixmap &pixmap, int cost)
void releaseKey(const QPixmapCache::Key &key)
static QPixmapCache::KeyData * getKeyData(QPixmapCache::Key *key)
bool flushDetachedPixmaps(bool nt)
QPixmap * object(const QString &key) const
static QPixmapCache::KeyData * get(const QPixmapCache::Key &key)
void resizeKeyArray(int size)
QPixmapCache::Key createKey()
void timerEvent(QTimerEvent *) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
The QPixmapCache::Key class can be used for efficient access to the QPixmapCache.
Key & operator=(Key &&other) noexcept
Key()
Constructs an empty Key object.
bool isValid() const noexcept
Returns true if there is a cached pixmap associated with this key.
~Key()
Destroys the key.
bool operator==(const Key &key) const
\inmodule QtGui
static bool find(const QString &key, QPixmap *pixmap)
Looks for a cached pixmap associated with the given key in the cache.
static void remove(const QString &key)
Removes the pixmap associated with key from the cache.
static int cacheLimit()
Returns the cache limit (in kilobytes).
static bool insert(const QString &key, const QPixmap &pixmap)
Inserts a copy of the pixmap pixmap associated with the key into the cache.
static void setCacheLimit(int)
Sets the cache limit to n kilobytes.
static void clear()
Removes all pixmaps from the cache.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QThread * currentThread()
Definition qthread.cpp:1039
\inmodule QtCore
Definition qcoreevent.h:366
b clear()
cache insert(employee->id(), employee)
QSet< QString >::iterator it
Combined button and popup list for selecting options.
#define Q_LIKELY(x)
#define QT_CATCH(A)
#define QT_TRY
size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed=0)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
static QByteArray cacheKey(Args &&...args)
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint id
[7]
GLuint object
[3]
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble t
Definition qopenglext.h:243
static bool qt_pixmapcache_thread_test()
static qsizetype cost(const QPixmap &pixmap)
int Q_AUTOTEST_EXPORT q_QPixmapCache_keyHashSize()
static const int cache_limit_default
Q_AUTOTEST_EXPORT int qt_qpixmapcache_qpixmapcache_total_used()
Q_AUTOTEST_EXPORT void qt_qpixmapcache_flush_detached_pixmaps()
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QT_BEGIN_INCLUDE_NAMESPACE
#define Q_AUTOTEST_EXPORT
#define QT_END_INCLUDE_NAMESPACE
#define Q_OBJECT
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
settings remove("monkey")
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
widget render & pixmap