6 #ifndef SWIFT_MISC_VALUECACHE_H
7 #define SWIFT_MISC_VALUECACHE_H
16 #include <QDBusArgument>
19 #include <QJsonObject>
25 #include <QSharedPointer>
27 #include <QStringList>
49 class CLogCategoryList;
62 public CDictionary<QString, std::pair<CVariant, qint64>, QMap>,
77 : m_saved(saved), m_valuesChanged(valuesChanged)
89 void setSaved(
bool saved =
true) { m_saved = saved; }
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; }
141 bool m_saved =
false;
142 bool m_valuesChanged =
true;
164 explicit CValueCache(
int fileSplitDepth, QObject *parent =
nullptr);
202 const QString &prefix);
239 void setHumanReadableName(
const QString &key,
const QString &name);
274 return makeRange(m_elements.lowerBound(keyPrefix),
275 m_elements.lowerBound(keyPrefix + QChar(QChar::LastValidCodePoint)));
279 return makeRange(m_elements.lowerBound(keyPrefix),
280 m_elements.lowerBound(keyPrefix + QChar(QChar::LastValidCodePoint)));
287 const QString &keysMessage = {})
const;
293 bool keysOnly =
false)
const;
315 static const QString &getCacheRootDirectory();
318 friend class private_ns::CValuePage;
321 using ElementPtr = QSharedPointer<Element>;
325 const int m_fileSplitDepth = 1;
327 Element &getElement(
const QString &key);
329 std::tuple<CVariant, qint64, bool> getValue(
const QString &key);
330 void backupFile(QFile &file)
const;
332 virtual void connectPage(private_ns::CValuePage *page);
335 QSet<QString> m_warnedKeys;
336 QMutex m_warnedKeysMutex;
351 template <
typename T>
360 template <
typename U>
362 :
CCached(cache, key, name, nullptr, T {}, owner)
372 template <
typename U,
typename F>
373 CCached(
CValueCache *cache,
const QString &key,
const QString &name, F validator,
const T &defaultValue,
375 : m_page(&private_ns::CValuePage::getPageFor(owner, cache)),
377 &m_page->createElement(key, name, qMetaTypeId<T>(), wrap(validator),
CVariant::from(defaultValue)))
383 template <
typename F>
391 using U =
typename private_ns::TClassOfPointerToMember<F>::type;
392 Q_ASSERT_X(m_page->parent()->metaObject()->inherits(&U::staticMetaObject), Q_FUNC_INFO,
393 "Slot is member function of wrong class");
394 m_page->setNotifySlot(
396 { [slot](QObject *obj) { private_ns::invokeSlot(slot,
static_cast<U *
>(obj)); }, makeId(slot) });
402 static const T empty {};
403 return *(isValid() ?
static_cast<const T *
>(getVariant().data()) : &empty);
408 T
get()
const {
return isValid() ? getVariantCopy().template value<T>() : T {}; }
413 return m_page->setValue(*m_element,
CVariant::from(value), timestamp);
419 return m_page->setValue(*m_element,
CVariant::from(value), timestamp,
true);
429 v.setPropertyByIndex(index, value);
430 return set(v, timestamp);
437 v.setPropertyByIndex(index, value);
442 bool isOwnerThread()
const {
return QThread::currentThread() == m_page->thread(); }
445 const QString &
getKey()
const {
return m_page->getKey(*m_element); }
449 QDateTime
getTimestamp()
const {
return QDateTime::fromMSecsSinceEpoch(m_page->getTimestamp(*m_element)); }
459 bool isSaved()
const {
return m_page->isSaved(*m_element); }
462 bool isSaving()
const {
return m_page->isSaving(*m_element); }
474 template <
typename F>
475 static private_ns::CValuePage::Validator wrap(F func)
477 return [func](
const CVariant &value, QString &reason) ->
bool {
return func(value.
to<T>(), reason); };
479 static private_ns::CValuePage::Validator wrap(std::nullptr_t) {
return {}; }
481 template <
typename F>
482 static auto makeId(F &&)
486 template <
typename U,
typename M>
487 static auto makeId(M U::*slot)
489 return static_cast<std::tuple_element_t<1, private_ns::CValuePage::NotifySlot>
>(slot);
492 const QVariant &getVariant()
const {
return m_page->getValue(*m_element).getQVariant(); }
493 QVariant getVariantCopy()
const {
return m_page->getValueCopy(*m_element).getQVariant(); }
494 bool isValid()
const {
return m_page->isValid(*m_element, qMetaTypeId<T>()); }
498 void onOwnerNameChanged(
const std::function<
void()> &
function)
500 connectOnce(m_page->parent(), &QObject::objectNameChanged, [
function](
const QString &) { function(); });
503 private_ns::CValuePage *m_page = (
throw std::logic_error(
"Uninitialized member"),
nullptr);
504 private_ns::CValuePage::Element *m_element =
505 (
throw std::logic_error(
"Uninitialized member"),
nullptr);
524 BatchGuard(BatchGuard &&other) noexcept : m_page(other.m_page) { other.m_page =
nullptr; }
535 BatchGuard(private_ns::CValuePage &page) : m_page(&page) {}
536 private_ns::CValuePage *m_page;
Provides access to one of the values stored in a CValueCache.
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.
bool isSaving() const
Return true if this value is currently saving.
bool isInitialized() const
Can be false if key contains OwnerName% and owner's objectName was empty.
CStatusMessage save()
Save using the currently set value. Must be called from the thread in which the owner lives.
CCached(const CCached &)=delete
Deleted copy constructor.
qint64 getTimestampMsSinceEpoch() const
Return the time when this value was updated.
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.
CCached(CValueCache *cache, const QString &key, const QString &name, F validator, const T &defaultValue, U *owner)
Constructor.
CStatusMessage set(const T &value, qint64 timestamp=0)
Write a new value. Must be called from the thread in which the owner lives.
CCached(CValueCache *cache, const QString &key, const QString &name, U *owner)
Constructor.
CCached & operator=(const CCached &)=delete
Deleted copy assignment operator.
const QString & getKey() const
Get the key string of this value.
void setNotifySlot(F slot)
Set a callback to be called when the value is changed by another source.
bool isOwnerThread() const
Is current thread the owner thread, so CCached::set is safe.
qint64 lastUpdatedAge() const
How old is that cache (ms)?
QDateTime getTimestamp() const
Return the time when this value was updated.
bool isSaved() const
Return true if this value was already saved.
const T & getThreadLocal() const
Read the current value.
T get() const
Get a copy of the current value.
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.
Associative container with value semantics, chooses a sensible default implementation container type.
std::pair< CVariant, qint64 > value_type
STL compatibility.
const_iterator cbegin() const
Returns const iterator at the beginning of the dictionary.
iterator insert(const Key &key, const Value &value)
Insert new item with key and value.
std::pair< CVariant, qint64 > & reference
STL compatibility.
const_iterator cend() const
Returns const iterator at the end of the dictionary.
Impl< Key, Value >::const_iterator const_iterator
STL compatibility.
Value object encapsulating information identifying a component of a modular distributed swift process...
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.
Manages a map of { QString, CVariant } pairs, which can be distributed among multiple processes.
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.
static const QStringList & getLogCategories()
Log categories.
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...
BatchGuard & operator=(const BatchGuard &)=delete
Deleted copy assignment operator. Class is move-only.
QString getHumanReadableName(const QString &key) const
Return the human readable name of the given key, or the raw key string if there is none.
BatchGuard(BatchGuard &&other) noexcept
Move constructor.
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...
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 ¤t, 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.
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.
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.
BatchGuard(const BatchGuard &)=delete
Deleted copy constructor. Class is move-only.
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...
BatchGuard & operator=(BatchGuard &&other) noexcept
Move assignment operator.
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 ...
~BatchGuard()
Destructor. Applies deferred changes.
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.
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.
Value class used for signalling changed values in the cache.
const_iterator begin() const
Iterators.
QMap< QString, qint64 > toTimestampMap() const
Discard values and return as map of timestamps.
void setTimestamps(const QMap< QString, qint64 > &)
Change the timestamps of values.
void setSaved(bool saved=true)
Values are to be saved.
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.
void insert(const CValueCachePacket &other)
Insert values from another packet.
CValueCachePacket takeByKey(const QString &key)
Remove value matching the given key, and return it in a separate packet.
const_iterator cend() const
Iterators.
const_iterator end() const
Iterators.
static void registerMetadata()
Register metadata.
bool valuesChanged() const
Values have been changed.
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.
CVariantMap toVariantMap() const
Discard timestamps and return as variant map.
const_iterator cbegin() const
Iterators.
Wrapper around QVariant which provides transparent access to CValueObject methods of the contained ob...
T to() const
Synonym for value().
static CVariant from(T &&value)
Synonym for fromValue().
Map of { QString, CVariant } pairs.
#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...
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.
auto makeRange(I begin, I2 end) -> CRange< I >
Returns a CRange constructed from begin and end iterators of deduced types.
SWIFT_MISC_EXPORT void setMockCacheRootDirectory(const QString &path)
Overwrite the default root directory for cache and settings, for testing purposes.
void swap(Optional< T > &a, Optional< T > &b) noexcept(std::is_nothrow_swappable_v< T >)
Efficient swap for two Optional objects.
#define SWIFT_MISC_EXPORT
Export a class or function from the library.