QmlMaterial 0.1.0
Loading...
Searching...
No Matches
pool.hpp
1#pragma once
2
3#include <deque>
4#include <map>
5#include <memory>
6#include <optional>
7#include <set>
8
9#include <QtCore/QPointer>
10#include <QtCore/QVariant>
11#include <QtQml/QQmlComponent>
12#include <QtQml/QQmlEngine>
13#include <QtQml/QQmlIncubator>
14
15#include "qml_material/export.hpp"
16
17namespace qml_material
18{
19
20auto pool_object_count() -> std::size_t;
21
22class Pool;
23
24class QML_MATERIAL_API PoolRequest : public QObject {
25 Q_OBJECT
26 QML_NAMED_ELEMENT(PoolRequest)
27 QML_UNCREATABLE("PoolRequest objects are returned by Pool.request()")
28
29 Q_PROPERTY(qint64 id READ id CONSTANT FINAL)
30 Q_PROPERTY(QVariant key READ key CONSTANT FINAL)
31 Q_PROPERTY(Status status READ status NOTIFY statusChanged FINAL)
32 Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged FINAL)
33 Q_PROPERTY(QObject* object READ object NOTIFY objectChanged FINAL)
34 Q_PROPERTY(bool cached READ cached NOTIFY cachedChanged FINAL)
35 Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged FINAL)
36
37public:
38 enum Status
39 {
40 Null,
41 Loading,
42 Ready,
43 Error,
44 Cancelled,
45 Released,
46 };
47 Q_ENUM(Status)
48
49 auto id() const -> qint64;
50 auto key() const -> QVariant;
51 auto status() const -> Status;
52 auto progress() const -> qreal;
53 auto object() const -> QObject*;
54 auto cached() const -> bool;
55 auto errorString() const -> QString;
56
57 Q_INVOKABLE void cancel();
58 Q_INVOKABLE void forceCompletion();
59 Q_INVOKABLE void release();
60
61 Q_SIGNAL void statusChanged();
62 Q_SIGNAL void progressChanged();
63 Q_SIGNAL void objectChanged();
64 Q_SIGNAL void cachedChanged();
65 Q_SIGNAL void errorStringChanged();
66
67private:
68 friend class Pool;
69
70 PoolRequest(Pool* pool, qint64 id, QVariant key);
71
72 void setStatus(Status value);
73 void setProgress(qreal value);
74 void setObject(QObject* value);
75 void setCached(bool value);
76 void setErrorString(QString value);
77
78 QPointer<Pool> m_pool;
79 qint64 m_id;
80 QVariant m_key;
81 Status m_status { Null };
82 qreal m_progress { 0 };
83 QPointer<QObject> m_object;
84 bool m_cached { false };
85 QString m_errorString;
86};
87
88class PoolIncubator : public QQmlIncubator {
89public:
90 PoolIncubator(Pool* pool, qint64 id, IncubationMode mode);
91
92protected:
93 void statusChanged(Status status) override;
94 void setInitialState(QObject* object) override;
95
96private:
97 Pool* m_pool;
98 qint64 m_id;
99};
100
101class QML_MATERIAL_API Pool : public QObject {
102 Q_OBJECT
103 QML_ELEMENT
104
105 Q_PROPERTY(bool async READ async WRITE setAsync NOTIFY asyncChanged FINAL)
106
107 friend class PoolIncubator;
108 friend class PoolRequest;
109
110public:
111 enum IncubationMode
112 {
113 Asynchronous,
114 AsynchronousIfNested,
115 Synchronous,
116 };
117 Q_ENUM(IncubationMode)
118
119 explicit Pool(QObject* parent = nullptr);
120 ~Pool() override;
121
122 Q_INVOKABLE PoolRequest* request(const QVariant& source,
123 const QVariantMap& initialProperties = {},
124 const QVariant& key = {},
125 IncubationMode mode = AsynchronousIfNested);
126
127 Q_INVOKABLE bool contains(const QString& key) const;
128 Q_INVOKABLE QObject* get(const QString& key) const;
129 Q_INVOKABLE bool evict(const QVariant& key);
130 Q_INVOKABLE void clear();
131
132 Q_INVOKABLE void add(const QVariant& source, const QVariantMap& initialProperties,
133 bool autoKey = false);
134 Q_INVOKABLE void addWithKey(const QString& key, const QVariant& source,
135 const QVariantMap& initialProperties);
136 Q_SIGNAL void objectAdded(QObject* object, const QVariant& key);
137
138 auto async() const -> bool;
139 void setAsync(bool value);
140 Q_SIGNAL void asyncChanged(bool value);
141
142 Q_INVOKABLE bool removeObject(QObject* object);
143
144 void add(std::optional<QStringView> key, QQmlComponent* component,
145 const QVariantMap& initialProperties);
146
147private:
148 struct Task {
149 qint64 id;
150 QVariant source;
151 QVariantMap initialProperties;
152 QString key;
153 bool hasKey { false };
154 IncubationMode mode;
155 QPointer<PoolRequest> request;
156 QPointer<QQmlComponent> component;
157 std::unique_ptr<QQmlComponent> ownedComponent;
158 std::unique_ptr<PoolIncubator> incubator;
159 QString sourceError;
160 bool terminal { false };
161 };
162
163 struct CacheEntry {
164 QPointer<QObject> object;
165 QPointer<PoolRequest> lease;
166 qint64 generation;
167 bool evictOnRelease { false };
168 };
169
170 void incubatorStateChanged(qint64 id, QQmlIncubator::Status status);
171 void setInitialState(qint64 id, QObject* object);
172 void onComponentStatusChanged(qint64 id);
173 void onComponentProgressChanged(qint64 id, qreal progress);
174 void startIncubation(qint64 id);
175 void forceRequest(PoolRequest* request);
176 void cancelRequest(PoolRequest* request);
177 void releaseRequest(PoolRequest* request);
178
179 auto createComponent(Task& task, QQmlComponent::CompilationMode mode) -> bool;
180 auto taskError(const Task& task) const -> QString;
181 auto genSerial() -> qint64;
182 auto toQtMode(IncubationMode mode) const -> QQmlIncubator::IncubationMode;
183
184 void finishReady(qint64 id, QObject* object);
185 void finishError(qint64 id, QString error);
186 void finishCancelled(qint64 id);
187 void scheduleTaskCleanup(qint64 id);
188 void removeInflightKey(const Task& task);
189
190 void onCacheObjectDestroyed(const QString& key, qint64 generation);
191 void onUncachedObjectDestroyed(QObject* object);
192 void attachLegacy(PoolRequest* request);
193 void queueLegacyDrain();
194 void drainLegacy();
195
196 std::map<qint64, std::unique_ptr<Task>> m_tasks;
197 std::map<QString, CacheEntry, std::less<>> m_cache;
198 std::map<QString, QPointer<PoolRequest>, std::less<>> m_inflightKeys;
199 std::map<QObject*, QPointer<PoolRequest>> m_uncached;
200 std::deque<QPointer<PoolRequest>> m_legacyQueue;
201
202 qint64 m_serial { 0 };
203 bool m_async { true };
204 bool m_destroying { false };
205 bool m_legacyDrainPending { false };
206};
207
208} // namespace qml_material