swift
Loading...
Searching...
No Matches
valuecache.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (C) 2015 swift Project Community / Contributors
2// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3
5
6#ifndef SWIFT_MISC_VALUECACHE_H
7#define SWIFT_MISC_VALUECACHE_H
8
9#include <cstddef>
10#include <memory>
11#include <stdexcept>
12#include <tuple>
13#include <utility>
14
15#include <QChar>
16#include <QDBusArgument>
17#include <QDateTime>
18#include <QFile>
19#include <QJsonObject>
20#include <QMap>
21#include <QMetaType>
22#include <QMutex>
23#include <QObject>
24#include <QSet>
25#include <QSharedPointer>
26#include <QString>
27#include <QStringList>
28#include <QThread>
29#include <QVariant>
30#include <QtGlobal>
31
32#include "misc/dictionary.h"
33#include "misc/identifier.h"
34#include "misc/metaclass.h"
40#include "misc/range.h"
41#include "misc/slot.h"
45#include "misc/variantmap.h"
46
47namespace swift::misc
48{
49 class CLogCategoryList;
50
57
62 public CDictionary<QString, std::pair<CVariant, qint64>, QMap>,
63 public mixin::MetaType<CValueCachePacket>,
64 public mixin::DBusByMetaClass<CValueCachePacket>,
65 public mixin::DataStreamByMetaClass<CValueCachePacket>,
66 public mixin::EqualsByMetaClass<CValueCachePacket>
67 {
68 public:
71
72
74
76 CValueCachePacket(bool saved = false, bool valuesChanged = true)
77 : m_saved(saved), m_valuesChanged(valuesChanged)
78 {}
79
81 CValueCachePacket(const CVariantMap &values, qint64 timestamp, bool saved = false, bool valuesChanged = true);
82
84 bool valuesChanged() const { return m_valuesChanged; }
85
88 bool isSaved() const { return m_saved; }
89 void setSaved(bool saved = true) { m_saved = saved; }
91
93 void insert(const QString &key, const CVariant &value, qint64 timestamp);
94
96 void insert(const CVariantMap &values, qint64 timestamp);
97
99 void insert(const CValueCachePacket &other) { CDictionary::insert(other); }
100
103
106
109
112
115
117 static void registerMetadata();
118
120 struct const_iterator : public CDictionary::const_iterator
121 {
122 using value_type = CVariant;
123 using pointer = const value_type *;
124 using reference = const value_type &;
125 const_iterator(CDictionary::const_iterator base) : CDictionary::const_iterator(base) {}
126 reference value() const { return CDictionary::const_iterator::value().first; }
127 reference operator*() const { return value(); }
128 pointer operator->() const { return &value(); }
129 qint64 timestamp() const { return CDictionary::const_iterator::value().second; }
130 };
131
134 const_iterator cbegin() const { return CDictionary::cbegin(); }
135 const_iterator cend() const { return CDictionary::cend(); }
136 const_iterator begin() const { return CDictionary::cbegin(); }
137 const_iterator end() const { return CDictionary::cend(); }
139
140 private:
141 bool m_saved = false;
142 bool m_valuesChanged = true;
143
146 SWIFT_METAMEMBER(saved),
147 SWIFT_METAMEMBER(valuesChanged));
148 };
149
154 {
156
157 public:
158 class BatchGuard;
159
162
164 explicit CValueCache(int fileSplitDepth, QObject *parent = nullptr);
165
169 swift::misc::CVariantMap getAllValues(const QString &keyPrefix = {}) const;
170
174
178
181 QStringList getAllUnsavedKeys(const QString &keyPrefix = {}) const;
182
187
191 QJsonObject saveToJson(const QString &keyPrefix = {}) const;
192
197 void loadFromJson(const QJsonObject &json);
198
202 const QString &prefix);
203
207 CStatusMessage saveToFiles(const QString &directory, const QString &keyPrefix = {});
208
211 CStatusMessage saveToFiles(const QString &directory, const QStringList &keys);
212
217
221 QString filenameForKey(const QString &key) const;
222
226 QStringList enumerateFiles(const QString &directory) const;
227
230 void clearAllValues(const QString &keyPrefix = {});
231
234
237
239 void setHumanReadableName(const QString &key, const QString &name);
240
249
250 public slots:
256 const swift::misc::CIdentifier &originator);
257
258 signals:
264
268
269 protected:
272 auto elementsStartingWith(const QString &keyPrefix)
273 {
274 return makeRange(m_elements.lowerBound(keyPrefix),
275 m_elements.lowerBound(keyPrefix + QChar(QChar::LastValidCodePoint)));
276 }
277 auto elementsStartingWith(const QString &keyPrefix) const
278 {
279 return makeRange(m_elements.lowerBound(keyPrefix),
280 m_elements.lowerBound(keyPrefix + QChar(QChar::LastValidCodePoint)));
281 }
282
283
286 CStatusMessage saveToFiles(const QString &directory, const CVariantMap &values,
287 const QString &keysMessage = {}) const;
288
291 CStatusMessage loadFromFiles(const QString &directory, const QSet<QString> &keys, const CVariantMap &current,
292 CValueCachePacket &o_values, const QString &keysMessage = {},
293 bool keysOnly = false) const;
294
297 void markAllAsSaved(const QString &keyPrefix);
298
301 void markAllAsSaved(const QStringList &keys);
302
305
308 CVariant getValueSync(const QString &key) { return std::get<0>(getValue(key)); }
309
312 qint64 getTimestampSync(const QString &key) { return std::get<1>(getValue(key)); }
313
315 static const QString &getCacheRootDirectory();
316
317 private:
318 friend class private_ns::CValuePage;
319 struct Element;
320
321 using ElementPtr = QSharedPointer<Element>; // QMap doesn't support move-only types
322
323 QMap<QString, ElementPtr> m_elements;
324 QMap<QString, QString> m_humanReadable;
325 const int m_fileSplitDepth = 1;
326
327 Element &getElement(const QString &key);
328 Element &getElement(const QString &key, QMap<QString, ElementPtr>::const_iterator pos);
329 std::tuple<CVariant, qint64, bool> getValue(const QString &key);
330 void backupFile(QFile &file) const;
331
332 virtual void connectPage(private_ns::CValuePage *page);
333
334 // only used by CValuePage::createElement
335 QSet<QString> m_warnedKeys;
336 QMutex m_warnedKeysMutex;
337
338 signals:
340 void valuesChanged(const swift::misc::CValueCachePacket &values, QObject *changedBy);
341
342 protected slots:
344 void changeValues(const swift::misc::CValueCachePacket &values);
345 };
346
351 template <typename T>
353 {
354 public:
360 template <typename U>
361 CCached(CValueCache *cache, const QString &key, const QString &name, U *owner)
362 : CCached(cache, key, name, nullptr, T {}, owner)
363 {}
364
372 template <typename U, typename F>
373 CCached(CValueCache *cache, const QString &key, const QString &name, F validator, const T &defaultValue,
374 U *owner)
375 : m_page(&private_ns::CValuePage::getPageFor(owner, cache)),
376 m_element(&m_page->createElement(key, name, qMetaTypeId<T>(), wrap(validator),
377 CVariant::fromValue(defaultValue)))
378 {
379 if (isInitialized())
380 {
381 cache->setHumanReadableName(getKey(), name);
382 }
383 }
384
386 template <typename F>
387 void setNotifySlot(F slot)
388 {
389 if (!isInitialized())
390 {
391 onOwnerNameChanged([this, slot] { setNotifySlot(slot); });
392 return;
393 }
394 using U = typename private_ns::TClassOfPointerToMember<F>::type;
395 Q_ASSERT_X(m_page->parent()->metaObject()->inherits(&U::staticMetaObject), Q_FUNC_INFO,
396 "Slot is member function of wrong class");
397 m_page->setNotifySlot(
398 *m_element,
399 { [slot](QObject *obj) { private_ns::invokeSlot(slot, static_cast<U *>(obj)); }, makeId(slot) });
400 }
401
403 const T &getThreadLocal() const
404 {
405 static const T empty {};
406 return *(isValid() ? static_cast<const T *>(getVariant().data()) : &empty);
407 }
408
411 T get() const { return isValid() ? getVariantCopy().template value<T>() : T {}; }
412
414 CStatusMessage set(const T &value, qint64 timestamp = 0)
415 {
416 return m_page->setValue(*m_element, CVariant::fromValue(value), timestamp);
417 }
418
420 CStatusMessage setAndSave(const T &value, qint64 timestamp = 0)
421 {
422 return m_page->setValue(*m_element, CVariant::fromValue(value), timestamp, true);
423 }
424
426 CStatusMessage save() { return m_page->setValue(*m_element, {}, 0, true); }
427
429 CStatusMessage setProperty(CPropertyIndexRef index, const CVariant &value, qint64 timestamp = 0)
430 {
431 auto v = get();
432 v.setPropertyByIndex(index, value);
433 return set(v, timestamp);
434 }
435
437 CStatusMessage setAndSaveProperty(CPropertyIndexRef index, const CVariant &value, qint64 timestamp = 0)
438 {
439 auto v = get();
440 v.setPropertyByIndex(index, value);
441 return setAndSave(v, timestamp);
442 }
443
445 bool isOwnerThread() const { return QThread::currentThread() == m_page->thread(); }
446
448 const QString &getKey() const { return m_page->getKey(*m_element); }
449
452 QDateTime getTimestamp() const { return QDateTime::fromMSecsSinceEpoch(m_page->getTimestamp(*m_element)); }
453
456 qint64 getTimestampMsSinceEpoch() const { return this->getTimestamp().toMSecsSinceEpoch(); }
457
460
462 bool isSaved() const { return m_page->isSaved(*m_element); }
463
465 bool isSaving() const { return m_page->isSaving(*m_element); }
466
468 bool isInitialized() const { return m_page->isInitialized(*m_element); }
469
471 CCached(const CCached &) = delete;
472
474 CCached &operator=(const CCached &) = delete;
475
476 private:
477 template <typename F>
478 static private_ns::CValuePage::Validator wrap(F func)
479 {
480 return [func](const CVariant &value, QString &reason) -> bool { return func(value.value<T>(), reason); };
481 }
482 static private_ns::CValuePage::Validator wrap(std::nullptr_t) { return {}; }
483
484 template <typename F>
485 static auto makeId(F &&)
486 {
487 return nullptr;
488 }
489 template <typename U, typename M>
490 static auto makeId(M U::*slot)
491 {
492 return static_cast<std::tuple_element_t<1, private_ns::CValuePage::NotifySlot>>(slot);
493 }
494
495 const QVariant &getVariant() const { return m_page->getValue(*m_element).getQVariant(); }
496 QVariant getVariantCopy() const { return m_page->getValueCopy(*m_element).getQVariant(); }
497 bool isValid() const { return m_page->isValid(*m_element, qMetaTypeId<T>()); }
498
499 protected:
501 void onOwnerNameChanged(const std::function<void()> &function)
502 {
503 connectOnce(m_page->parent(), &QObject::objectNameChanged, [function](const QString &) { function(); });
504 }
505
506 private_ns::CValuePage *m_page = (throw std::logic_error("Uninitialized member"), nullptr);
507 private_ns::CValuePage::Element *m_element =
508 (throw std::logic_error("Uninitialized member"), nullptr);
509 };
510
514 class SWIFT_MISC_EXPORT CValueCache::BatchGuard
515 {
516 public:
519
521 BatchGuard(const BatchGuard &) = delete;
522
524 BatchGuard &operator=(const BatchGuard &) = delete;
525
527 BatchGuard(BatchGuard &&other) noexcept : m_page(other.m_page) { other.m_page = nullptr; }
528
530 BatchGuard &operator=(BatchGuard &&other) noexcept
531 {
532 std::swap(m_page, other.m_page);
533 return *this;
534 }
535
536 private:
537 friend class CValueCache;
538 BatchGuard(private_ns::CValuePage &page) : m_page(&page) {}
539 private_ns::CValuePage *m_page;
540 };
541
542} // namespace swift::misc
543
544Q_DECLARE_METATYPE(swift::misc::CValueCachePacket)
545
546#endif // SWIFT_MISC_VALUECACHE_H
CStatusMessage setProperty(CPropertyIndexRef index, const CVariant &value, qint64 timestamp=0)
Write a property of the value. Must be called from the thread in which the owner lives.
Definition valuecache.h:429
bool isSaving() const
Return true if this value is currently saving.
Definition valuecache.h:465
bool isInitialized() const
Can be false if key contains OwnerName% and owner's objectName was empty.
Definition valuecache.h:468
CStatusMessage save()
Save using the currently set value. Must be called from the thread in which the owner lives.
Definition valuecache.h:426
const QString & getKey() const
Get the key string of this value.
Definition valuecache.h:448
CCached(const CCached &)=delete
Deleted copy constructor.
qint64 getTimestampMsSinceEpoch() const
Return the time when this value was updated.
Definition valuecache.h:456
CStatusMessage setAndSave(const T &value, qint64 timestamp=0)
Write and save in the same step. Must be called from the thread in which the owner lives.
Definition valuecache.h:420
CCached(CValueCache *cache, const QString &key, const QString &name, F validator, const T &defaultValue, U *owner)
Constructor.
Definition valuecache.h:373
CStatusMessage set(const T &value, qint64 timestamp=0)
Write a new value. Must be called from the thread in which the owner lives.
Definition valuecache.h:414
CCached(CValueCache *cache, const QString &key, const QString &name, U *owner)
Constructor.
Definition valuecache.h:361
CCached & operator=(const CCached &)=delete
Deleted copy assignment operator.
void setNotifySlot(F slot)
Set a callback to be called when the value is changed by another source.
Definition valuecache.h:387
const T & getThreadLocal() const
Read the current value.
Definition valuecache.h:403
bool isOwnerThread() const
Is current thread the owner thread, so CCached::set is safe.
Definition valuecache.h:445
qint64 lastUpdatedAge() const
How old is that cache (ms)?
Definition valuecache.h:459
QDateTime getTimestamp() const
Return the time when this value was updated.
Definition valuecache.h:452
bool isSaved() const
Return true if this value was already saved.
Definition valuecache.h:462
T get() const
Get a copy of the current value.
Definition valuecache.h:411
CStatusMessage setAndSaveProperty(CPropertyIndexRef index, const CVariant &value, qint64 timestamp=0)
Write a property and save in the same step. Must be called from the thread in which the owner lives.
Definition valuecache.h:437
const std::pair< CVariant, qint64 > value(const QString &key) const
Definition dictionary.h:447
const_iterator cbegin() const
Returns const iterator at the beginning of the dictionary.
Definition dictionary.h:342
iterator insert(const Key &key, const Value &value)
Insert new item with key and value.
Definition dictionary.h:414
typename Impl< Key, Value >::const_iterator const_iterator
STL compatibility.
Definition dictionary.h:119
const QString key(const std::pair< CVariant, qint64 > &value) const
Definition dictionary.h:429
const_iterator cend() const
Returns const iterator at the end of the dictionary.
Definition dictionary.h:351
Value object encapsulating information identifying a component of a modular distributed swift process...
Definition identifier.h:29
A sequence of log categories.
Non-owning reference to a CPropertyIndex with a subset of its features.
Streamable status message, e.g.
Status messages, e.g. from Core -> GUI.
RAII object returned by CValueCache::batchChanges.
Definition valuecache.h:515
BatchGuard & operator=(BatchGuard &&other) noexcept
Move assignment operator.
Definition valuecache.h:530
BatchGuard(const BatchGuard &)=delete
Deleted copy constructor. Class is move-only.
BatchGuard & operator=(const BatchGuard &)=delete
Deleted copy assignment operator. Class is move-only.
BatchGuard(BatchGuard &&other) noexcept
Move constructor.
Definition valuecache.h:527
~BatchGuard()
Destructor. Applies deferred changes.
Manages a map of { QString, CVariant } pairs, which can be distributed among multiple processes.
Definition valuecache.h:154
void changeValuesFromRemote(const swift::misc::CValueCachePacket &values, const swift::misc::CIdentifier &originator)
Notify this cache that values have been changed by one of the duplicate caches in the multi-process e...
auto elementsStartingWith(const QString &keyPrefix) const
Returns a range referring to all elements which start with the given prefix.
Definition valuecache.h:277
swift::misc::CVariantMap getAllValues(const QString &keyPrefix={}) const
Return map containing all values in the cache. If prefix is provided then only those values whose key...
QString getHumanReadableName(const QString &key) const
Return the human readable name of the given key, or the raw key string if there is none.
QStringList enumerateFiles(const QString &directory) const
List the Json files which are (or would be) used to save the current values. The files may or may not...
static const QStringList & getLogCategories()
Log categories.
QString filenameForKey(const QString &key) const
Return the (relative) filename that may is (or would be) used to save the value with the given key....
CStatusMessage loadFromFiles(const QString &directory, const QSet< QString > &keys, const CVariantMap &current, CValueCachePacket &o_values, const QString &keysMessage={}, bool keysOnly=false) const
Load from Json files in a given directory any values which differ from the current ones,...
void markAllAsSaved(const QStringList &keys)
Mark all values with given keys as having been saved.
BatchGuard batchChanges(QObject *owner)
Begins a batch of changes to be made through CCached instances owned by owner.
CVariant getValueSync(const QString &key)
Synchronously return a current value.
Definition valuecache.h:308
CStatusMessage saveToFiles(const QString &directory, const QStringList &keys)
Save values to Json files in a given directory.
CValueCache(int fileSplitDepth, QObject *parent=nullptr)
Constructor.
QRecursiveMutex m_mutex
Mutex protecting operations which are critical on m_elements.
Definition valuecache.h:304
void clearAllValues(const QString &keyPrefix={})
Clear all values from the cache.
CStatusMessage saveToFiles(const QString &directory, const CVariantMap &values, const QString &keysMessage={}) const
Save specific values to Json files in a given directory.
swift::misc::CValueCachePacket getAllValuesWithTimestamps(const QString &keyPrefix={}) const
Return map containing all values in the cache, and timestamps when they were modified.
QJsonObject saveToJson(const QString &keyPrefix={}) const
Save values in Json format. If prefix is provided then only those values whose keys start with that p...
void markAllAsSaved(const QString &keyPrefix)
Mark all values with keys that start with the given prefix as having been saved.
void insertValues(const swift::misc::CValueCachePacket &values)
Add some values to the cache. Values already in the cache will remain in the cache unless they are ov...
QString getHumanReadableWithKey(const QString &key) const
Return the human readable name of the given key, with the raw key string appended.
void valuesSaveRequested(const swift::misc::CValueCachePacket &values)
Emitted when this cache has ratified a change which included a request to save (i....
CStatusMessage loadFromFiles(const QString &directory)
Load all values from Json files in a given directory. Values already in the cache will remain in the ...
void valuesChangedByLocal(const swift::misc::CValueCachePacket &values)
Emitted when values in the cache are changed by an object in this very process. The interprocess comm...
swift::misc::CVariantMap getAllValues(const QStringList &keys) const
Return map containing all given values in the cache.
void loadFromJson(const QJsonObject &json)
Load all values in Json format. Values already in the cache will remain in the cache unless they are ...
QStringList getAllUnsavedKeys(const QString &keyPrefix={}) const
Return keys of all values which have been changed but not saved.
CStatusMessageList loadFromJsonNoThrow(const QJsonObject &json, const CLogCategoryList &categories, const QString &prefix)
Call loadFromJson, catch any CJsonException that are thrown and return them as CStatusMessage.
qint64 getTimestampSync(const QString &key)
Synchronously return a current timestamp.
Definition valuecache.h:312
CStatusMessage saveToFiles(const QString &directory, const QString &keyPrefix={})
Save values to Json files in a given directory. If prefix is provided then only those values whose ke...
auto elementsStartingWith(const QString &keyPrefix)
Returns a range referring to all elements which start with the given prefix.
Definition valuecache.h:272
Value class used for signalling changed values in the cache.
Definition valuecache.h:67
const_iterator begin() const
Iterators.
Definition valuecache.h:136
CValueCachePacket(bool saved=false, bool valuesChanged=true)
Constructor.
Definition valuecache.h:76
void setTimestamps(const QMap< QString, qint64 > &)
Change the timestamps of values.
void setSaved(bool saved=true)
Values are to be saved.
Definition valuecache.h:89
void insert(const CVariantMap &values, qint64 timestamp)
Insert a CVariantMap with a timestamp.
QString toTimestampMapString(const QStringList &keys) const
Return map of timestamps converted to string.
void insert(const QString &key, const CVariant &value, qint64 timestamp)
Insert a key/value pair with a timestamp.
CDictionary base_type
Base class.
Definition valuecache.h:73
void insert(const CValueCachePacket &other)
Insert values from another packet.
Definition valuecache.h:99
CValueCachePacket takeByKey(const QString &key)
Remove value matching the given key, and return it in a separate packet.
const_iterator cend() const
Iterators.
Definition valuecache.h:135
QMap< QString, qint64 > toTimestampMap() const
Discard values and return as map of timestamps.
const_iterator end() const
Iterators.
Definition valuecache.h:137
static void registerMetadata()
Register metadata.
bool valuesChanged() const
Values have been changed.
Definition valuecache.h:84
CValueCachePacket(const CVariantMap &values, qint64 timestamp, bool saved=false, bool valuesChanged=true)
Construct from CVariantMap and a timestamp.
bool isSaved() const
Values are to be saved.
Definition valuecache.h:88
CVariantMap toVariantMap() const
Discard timestamps and return as variant map.
const_iterator cbegin() const
Iterators.
Definition valuecache.h:134
Wrapper around QVariant which provides transparent access to CValueObject methods of the contained ob...
Definition variant.h:69
static CVariant fromValue(T &&value)
Construct a variant from a value.
Definition variant.h:139
T value() const
Return the value converted to the type T.
Definition variant.h:154
Map of { QString, CVariant } pairs.
Definition variantmap.h:35
CRTP class template from which a derived class can inherit common methods dealing with marshalling in...
Definition mixindbus.h:71
CRTP class template to generate QDataStream marshalling methods using CMetaClass.
CRTP class template from which a derived class can inherit operator== implemented by metaclass.
CRTP class template from which a derived class can inherit common methods dealing with the metatype o...
#define SWIFT_METAMEMBER(MEMBER,...)
Macro to define an element within a metaclass.
Definition metaclass.h:72
#define SWIFT_METACLASS(CLASS,...)
Macro to define a nested metaclass that describes the attributes of its enclosing class.
Definition metaclass.h:52
#define SWIFT_MISC_DECLARE_USING_MIXIN_DATASTREAM(DERIVED)
When a derived class and a base class both inherit from mixin::DataStreamByMetaClass,...
#define SWIFT_MISC_DECLARE_USING_MIXIN_DBUS(DERIVED,...)
When a derived class and a base class both inherit from mixin::DBusByTuple, the derived class uses th...
Definition mixindbus.h:193
Free functions in swift::misc.
QMetaObject::Connection connectOnce(T *sender, F signal, U *receiver, G &&slot, Qt::ConnectionType type=Qt::AutoConnection)
Wrapper around QObject::connect which disconnects after the signal has been emitted once.
Definition slot.h:27
auto makeRange(I begin, I2 end) -> CRange< I >
Returns a CRange constructed from begin and end iterators of deduced types.
Definition range.h:328
SWIFT_MISC_EXPORT void setMockCacheRootDirectory(const QString &path)
Overwrite the default root directory for cache and settings, for testing purposes.
LastValidCodePoint
qint64 currentMSecsSinceEpoch()
QDateTime fromMSecsSinceEpoch(qint64 msecs)
qint64 toMSecsSinceEpoch() const const
QObject(QObject *parent)
Q_OBJECTQ_OBJECT
void objectNameChanged(const QString &objectName)
QObject * parent() const const
QThread * thread() const const
QThread * currentThread()
#define SWIFT_MISC_EXPORT
Export a class or function from the library.