File indexing completed on 2025-01-05 04:46:55
0001 /* 0002 SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include "akthread.h" 0010 #include "entities.h" 0011 0012 #include "private/tristate_p.h" 0013 0014 #include <QHash> 0015 #include <QList> 0016 #include <QReadWriteLock> 0017 0018 namespace Akonadi 0019 { 0020 class Scope; 0021 0022 namespace Server 0023 { 0024 class CommandContext; 0025 0026 class CollectionTreeCache : public AkThread 0027 { 0028 Q_OBJECT 0029 0030 protected: 0031 class Node 0032 { 0033 public: 0034 explicit Node(); 0035 explicit Node(const Collection &query); 0036 0037 ~Node(); 0038 0039 void appendChild(Node *child); 0040 void removeChild(Node *child); 0041 0042 Node *parent = nullptr; 0043 QList<Node *> children; 0044 QAtomicInt lruCounter; 0045 qint64 id; 0046 0047 Collection collection; 0048 }; 0049 0050 public: 0051 explicit CollectionTreeCache(); 0052 ~CollectionTreeCache() override; 0053 0054 QList<Collection> 0055 retrieveCollections(const Scope &scope, int depth, int ancestorDepth, const QString &resource = QString(), CommandContext *context = nullptr) const; 0056 0057 public Q_SLOTS: 0058 void collectionAdded(const Collection &col); 0059 void collectionChanged(const Collection &col); 0060 void collectionMoved(const Collection &col); 0061 void collectionRemoved(const Collection &col); 0062 0063 protected: 0064 void init() override; 0065 void quit() override; 0066 0067 Node *findNode(const QString &rid, const QString &resource) const; 0068 0069 template<typename Predicate> 0070 Node *findNode(Node *root, Predicate pred) const; 0071 0072 QList<Collection> retrieveCollections(Node *root, int depth, int ancestorDepth) const; 0073 0074 protected: 0075 mutable QReadWriteLock mLock; 0076 0077 Node *mRoot = nullptr; 0078 0079 QHash<qint64 /* col ID */, Node *> mNodeLookup; 0080 }; 0081 0082 // Non-recursive depth-first tree traversal, looking for first Node matching the predicate 0083 template<typename Predicate> 0084 CollectionTreeCache::Node *CollectionTreeCache::findNode(Node *root, Predicate pred) const 0085 { 0086 QList<Node *> toVisit = {root}; 0087 // We expect a single subtree to not contain more than 1/4 of all collections, 0088 // which is an arbitrary guess, but should be good enough for most cases. 0089 toVisit.reserve(mNodeLookup.size() / 4); 0090 while (!toVisit.isEmpty()) { 0091 auto node = toVisit.takeFirst(); 0092 if (pred(node)) { 0093 return node; 0094 } 0095 0096 for (auto child : std::as_const(node->children)) { 0097 toVisit.prepend(child); 0098 } 0099 } 0100 0101 return nullptr; 0102 } 0103 0104 } // namespace Server 0105 } // namespace Akonadi