OSDN Git Service

reimplement QCache purely based on QHash
authorIvailo Monev <xakepa10@laimg.moc>
Mon, 29 Jul 2019 17:42:30 +0000 (17:42 +0000)
committerIvailo Monev <xakepa10@laimg.moc>
Mon, 29 Jul 2019 17:42:30 +0000 (17:42 +0000)
Signed-off-by: Ivailo Monev <xakepa10@laimg.moc>
src/core/tools/qcache.h
src/core/tools/qcache.qdoc

index 7e2a8f4..771557d 100644 (file)
@@ -43,43 +43,8 @@ QT_BEGIN_NAMESPACE
 template <class Key, class T>
 class QCache
 {
-    struct Node {
-        inline Node() : keyPtr(Q_NULLPTR) {}
-        inline Node(T *data, int cost)
-            : keyPtr(Q_NULLPTR), t(data), c(cost), p(Q_NULLPTR), n(Q_NULLPTR) {}
-        const Key *keyPtr; T *t; int c; Node *p,*n;
-    };
-    Node *f, *l;
-    QHash<Key, Node> hash;
-    int mx, total;
-
-    inline void unlink(Node &n) {
-        if (n.p) n.p->n = n.n;
-        if (n.n) n.n->p = n.p;
-        if (l == &n) l = n.p;
-        if (f == &n) f = n.n;
-        total -= n.c;
-        T *obj = n.t;
-        hash.remove(*n.keyPtr);
-        delete obj;
-    }
-    inline T *relink(const Key &key) {
-        typename QHash<Key, Node>::iterator i = hash.find(key);
-        if (typename QHash<Key, Node>::const_iterator(i) == hash.constEnd())
-            return Q_NULLPTR;
-
-        Node &n = *i;
-        if (f != &n) {
-            if (n.p) n.p->n = n.n;
-            if (n.n) n.n->p = n.p;
-            if (l == &n) l = n.p;
-            n.p = 0;
-            n.n = f;
-            f->p = &n;
-            f = &n;
-        }
-        return n.t;
-    }
+    QHash<Key, T*> hash;
+    int mx;
 
     Q_DISABLE_COPY(QCache)
 
@@ -88,46 +53,35 @@ public:
     inline ~QCache() { clear(); }
 
     inline int maxCost() const { return mx; }
-    void setMaxCost(int m);
-    inline int totalCost() const { return total; }
+    inline void setMaxCost(int m);
 
     inline int size() const { return hash.size(); }
     inline int count() const { return hash.size(); }
     inline bool isEmpty() const { return hash.isEmpty(); }
     inline QList<Key> keys() const { return hash.keys(); }
+    inline void clear() { hash.clear(); }
 
-    void clear();
-
-    bool insert(const Key &key, T *object, int cost = 1);
-    T *object(const Key &key) const;
+    inline bool insert(const Key &key, T *object, int cost = 1);
+    inline T *object(const Key &key) const { return hash.value(key, Q_NULLPTR); }
     inline bool contains(const Key &key) const { return hash.contains(key); }
-    T *operator[](const Key &key) const;
-
-    bool remove(const Key &key);
-    T *take(const Key &key);
-
-private:
-    void trim(int m);
-
+    inline T *operator[](const Key &key) const;
 
+    inline bool remove(const Key &key);
+    inline T *take(const Key &key);
 };
 
 template <class Key, class T>
 inline QCache<Key, T>::QCache(int amaxCost)
-    : f(Q_NULLPTR), l(Q_NULLPTR), mx(amaxCost), total(0) {}
-
-template <class Key, class T>
-inline void QCache<Key,T>::clear()
-{ while (f) { delete f->t; f = f->n; }
- hash.clear(); l = Q_NULLPTR; total = 0; }
+    : mx(amaxCost)
+{ hash.reserve(amaxCost); }
 
 template <class Key, class T>
 inline void QCache<Key,T>::setMaxCost(int m)
-{ mx = m; trim(mx); }
-
-template <class Key, class T>
-inline T *QCache<Key,T>::object(const Key &key) const
-{ return const_cast<QCache<Key,T>*>(this)->relink(key); }
+{
+    mx = m;
+    hash.clear();
+    hash.reserve(m);
+}
 
 template <class Key, class T>
 inline T *QCache<Key,T>::operator[](const Key &key) const
@@ -135,62 +89,29 @@ inline T *QCache<Key,T>::operator[](const Key &key) const
 
 template <class Key, class T>
 inline bool QCache<Key,T>::remove(const Key &key)
-{
-    typename QHash<Key, Node>::iterator i = hash.find(key);
-    if (typename QHash<Key, Node>::const_iterator(i) == hash.constEnd()) {
-        return false;
-    } else {
-        unlink(*i);
-        return true;
-    }
-}
+{ return hash.remove(key) != 0; }
 
 template <class Key, class T>
 inline T *QCache<Key,T>::take(const Key &key)
 {
-    typename QHash<Key, Node>::iterator i = hash.find(key);
-    if (i == hash.end())
+    if (!hash.contains(key))
         return Q_NULLPTR;
-
-    Node &n = *i;
-    T *t = n.t;
-    n.t = Q_NULLPTR;
-    unlink(n);
-    return t;
+    return hash.take(key);
 }
 
 template <class Key, class T>
-bool QCache<Key,T>::insert(const Key &akey, T *aobject, int acost)
+inline bool QCache<Key,T>::insert(const Key &akey, T *aobject, int acost)
 {
-    remove(akey);
     if (acost > mx) {
         delete aobject;
         return false;
+    } else if (hash.size() >= mx) {
+        hash.erase(hash.begin());
     }
-    trim(mx - acost);
-    Node sn(aobject, acost);
-    typename QHash<Key, Node>::iterator i = hash.insert(akey, sn);
-    total += acost;
-    Node *n = &i.value();
-    n->keyPtr = &i.key();
-    if (f) f->p = n;
-    n->n = f;
-    f = n;
-    if (!l) l = f;
+    hash.insert(akey, aobject);
     return true;
 }
 
-template <class Key, class T>
-void QCache<Key,T>::trim(int m)
-{
-    Node *n = l;
-    while (n && total > m) {
-        Node *u = n;
-        n = n->p;
-        unlink(*u);
-    }
-}
-
 QT_END_NAMESPACE
 
 QT_END_HEADER
index 81495c2..c14311a 100644 (file)
     deletes them to make room for new objects, if necessary. When
     inserting an object into the cache, you can specify a \e{cost},
     which should bear some approximate relationship to the amount of
-    memory taken by the object. When the sum of all objects' costs
-    (totalCost()) exceeds the cache's limit (maxCost()), QCache starts
-    deleting objects in the cache to keep under the limit, starting with
-    less recently accessed objects.
+    memory taken by the object. When the number of all objects' costs
+    exceeds the cache's limit (maxCost()), QCache starts deleting
+    objects in the cache to keep under the limit, starting with the
+    first object.
 
     By default, QCache's maxCost() is 100. You can specify a
     different value in the QCache constructor: