Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/QtCore/qcache.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // Copyright (C) 2016 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QCACHE_H
0005 #define QCACHE_H
0006 
0007 #include <QtCore/qhash.h>
0008 
0009 QT_BEGIN_NAMESPACE
0010 
0011 
0012 template <class Key, class T>
0013 class QCache
0014 {
0015     struct Value
0016     {
0017         T *t = nullptr;
0018         qsizetype cost = 0;
0019         Value() noexcept = default;
0020         Value(T *tt, qsizetype c) noexcept
0021             : t(tt), cost(c)
0022         {}
0023         Value(Value &&other) noexcept
0024             : t(other.t),
0025               cost(other.cost)
0026         {
0027             other.t = nullptr;
0028         }
0029         Value &operator=(Value &&other) noexcept
0030         {
0031             qt_ptr_swap(t, other.t);
0032             std::swap(cost, other.cost);
0033             return *this;
0034         }
0035         ~Value() { delete t; }
0036 
0037     private:
0038         Q_DISABLE_COPY(Value)
0039     };
0040 
0041     struct Chain
0042     {
0043         Chain() noexcept : prev(this), next(this) { }
0044         Chain *prev;
0045         Chain *next;
0046     };
0047 
0048     struct Node : public Chain
0049     {
0050         using KeyType = Key;
0051         using ValueType = Value;
0052 
0053         Key key;
0054         Value value;
0055 
0056         Node(const Key &k, Value &&t) noexcept(std::is_nothrow_move_assignable_v<Key>)
0057             : Chain(),
0058               key(k),
0059               value(std::move(t))
0060         {
0061         }
0062         Node(Key &&k, Value &&t) noexcept(std::is_nothrow_move_assignable_v<Key>)
0063             : Chain(),
0064               key(std::move(k)),
0065               value(std::move(t))
0066         {
0067         }
0068         static void createInPlace(Node *n, const Key &k, T *o, qsizetype cost)
0069         {
0070             new (n) Node{ Key(k), Value(o, cost) };
0071         }
0072         void emplace(T *o, qsizetype cost)
0073         {
0074             value = Value(o, cost);
0075         }
0076 
0077         Node(Node &&other)
0078             : Chain(other),
0079               key(std::move(other.key)),
0080               value(std::move(other.value))
0081         {
0082             Q_ASSERT(this->prev);
0083             Q_ASSERT(this->next);
0084             this->prev->next = this;
0085             this->next->prev = this;
0086         }
0087     private:
0088         Q_DISABLE_COPY(Node)
0089     };
0090 
0091     using Data = QHashPrivate::Data<Node>;
0092 
0093     mutable Chain chain;
0094     Data d;
0095     qsizetype mx = 0;
0096     qsizetype total = 0;
0097 
0098     void unlink(Node *n) noexcept(std::is_nothrow_destructible_v<Node>)
0099     {
0100         Q_ASSERT(n->prev);
0101         Q_ASSERT(n->next);
0102         n->prev->next = n->next;
0103         n->next->prev = n->prev;
0104         total -= n->value.cost;
0105         auto it = d.findBucket(n->key);
0106         d.erase(it);
0107     }
0108     T *relink(const Key &key) const noexcept
0109     {
0110         if (isEmpty())
0111             return nullptr;
0112         Node *n = d.findNode(key);
0113         if (!n)
0114             return nullptr;
0115 
0116         if (chain.next != n) {
0117             Q_ASSERT(n->prev);
0118             Q_ASSERT(n->next);
0119             n->prev->next = n->next;
0120             n->next->prev = n->prev;
0121             n->next = chain.next;
0122             chain.next->prev = n;
0123             n->prev = &chain;
0124             chain.next = n;
0125         }
0126         return n->value.t;
0127     }
0128 
0129     void trim(qsizetype m) noexcept(std::is_nothrow_destructible_v<Node>)
0130     {
0131         while (chain.prev != &chain && total > m) {
0132             Node *n = static_cast<Node *>(chain.prev);
0133             unlink(n);
0134         }
0135     }
0136 
0137 
0138     Q_DISABLE_COPY(QCache)
0139 
0140 public:
0141     inline explicit QCache(qsizetype maxCost = 100) noexcept
0142         : mx(maxCost)
0143     {
0144     }
0145     inline ~QCache()
0146     {
0147         static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
0148         static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
0149 
0150         clear();
0151     }
0152 
0153     inline qsizetype maxCost() const noexcept { return mx; }
0154     void setMaxCost(qsizetype m) noexcept(std::is_nothrow_destructible_v<Node>)
0155     {
0156         mx = m;
0157         trim(mx);
0158     }
0159     inline qsizetype totalCost() const noexcept { return total; }
0160 
0161     inline qsizetype size() const noexcept { return qsizetype(d.size); }
0162     inline qsizetype count() const noexcept { return qsizetype(d.size); }
0163     inline bool isEmpty() const noexcept { return !d.size; }
0164     inline QList<Key> keys() const
0165     {
0166         QList<Key> k;
0167         if (size()) {
0168             k.reserve(size());
0169             for (auto it = d.begin(); it != d.end(); ++it)
0170                 k << it.node()->key;
0171         }
0172         Q_ASSERT(k.size() == size());
0173         return k;
0174     }
0175 
0176     void clear() noexcept(std::is_nothrow_destructible_v<Node>)
0177     {
0178         d.clear();
0179         total = 0;
0180         chain.next = &chain;
0181         chain.prev = &chain;
0182     }
0183 
0184     bool insert(const Key &key, T *object, qsizetype cost = 1)
0185     {
0186         if (cost > mx) {
0187             remove(key);
0188             delete object;
0189             return false;
0190         }
0191         trim(mx - cost);
0192         auto result = d.findOrInsert(key);
0193         Node *n = result.it.node();
0194         if (result.initialized) {
0195             auto prevCost = n->value.cost;
0196             result.it.node()->emplace(object, cost);
0197             cost -= prevCost;
0198             relink(key);
0199         } else {
0200             Node::createInPlace(n, key, object, cost);
0201             n->prev = &chain;
0202             n->next = chain.next;
0203             chain.next->prev = n;
0204             chain.next = n;
0205         }
0206         total += cost;
0207         return true;
0208     }
0209     T *object(const Key &key) const noexcept
0210     {
0211         return relink(key);
0212     }
0213     T *operator[](const Key &key) const noexcept
0214     {
0215         return relink(key);
0216     }
0217     inline bool contains(const Key &key) const noexcept
0218     {
0219         return !isEmpty() && d.findNode(key) != nullptr;
0220     }
0221 
0222     bool remove(const Key &key) noexcept(std::is_nothrow_destructible_v<Node>)
0223     {
0224         if (isEmpty())
0225             return false;
0226         Node *n = d.findNode(key);
0227         if (!n) {
0228             return false;
0229         } else {
0230             unlink(n);
0231             return true;
0232         }
0233     }
0234 
0235     T *take(const Key &key) noexcept(std::is_nothrow_destructible_v<Key>)
0236     {
0237         if (isEmpty())
0238             return nullptr;
0239         Node *n = d.findNode(key);
0240         if (!n)
0241             return nullptr;
0242 
0243         T *t = n->value.t;
0244         n->value.t = nullptr;
0245         unlink(n);
0246         return t;
0247     }
0248 
0249 };
0250 
0251 QT_END_NAMESPACE
0252 
0253 #endif // QCACHE_H