#include #include #include #include #include "Variable/Variable.h" #include #include #include Q_LOGGING_CATEGORY(LOG_Variable, "Variable") /** * Searches in metadata for a value that can be converted to DataSeriesType * @param metadata the metadata where to search * @return the value converted to a DataSeriesType if it was found, UNKNOWN type otherwise * @sa DataSeriesType */ static DataSeriesType findDataSeriesType(const QVariantHash &metadata) { auto dataSeriesType = DataSeriesType::UNKNOWN; // Go through the metadata and stop at the first value that could be converted to DataSeriesType for (auto it = metadata.cbegin(), end = metadata.cend(); it != end && dataSeriesType == DataSeriesType::UNKNOWN; ++it) { dataSeriesType = DataSeriesTypeUtils::fromString(it.value().toString()); } return dataSeriesType; } #define VP_PROPERTY(property,getter,setter,type) \ type getter() noexcept\ {\ QReadLocker lock{&m_Lock};\ return property;\ }\ void setter(const type& getter) noexcept\ {\ QWriteLocker lock{&m_Lock};\ property = getter;\ }\ type property;\ #define V_FW_GETTER_SETTER(getter,setter, type)\ type Variable::getter() const noexcept \ {\ return impl->getter();\ }\ void Variable::setter(const type& getter) noexcept \ {\ impl->setter(getter);\ emit updated();\ }\ struct Variable::VariablePrivate { explicit VariablePrivate(const QString &name, const QVariantHash &metadata) : m_Name{name}, m_Range{INVALID_RANGE}, m_CacheRange{INVALID_RANGE}, m_Metadata{metadata}, m_DataSeries{nullptr}, m_RealRange{INVALID_RANGE}, m_NbPoints{0}, m_Type{findDataSeriesType(m_Metadata)} { } VariablePrivate(const VariablePrivate &other) : m_Name{other.m_Name}, m_Range{other.m_Range}, m_CacheRange{other.m_CacheRange}, m_Metadata{other.m_Metadata}, m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr}, m_RealRange{other.m_RealRange}, m_NbPoints{other.m_NbPoints}, m_Type{findDataSeriesType(m_Metadata)} { } void lockRead() { m_Lock.lockForRead(); } void lockWrite() { m_Lock.lockForWrite(); } void unlock() { m_Lock.unlock(); } void purgeDataSeries() { if (m_DataSeries) { m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd); } updateRealRange(); updateNbPoints(); } void mergeDataSeries(const std::vector& dataseries) { QWriteLocker lock{&m_Lock}; for(auto ds:dataseries) { if(m_DataSeries) m_DataSeries->merge(ds); else m_DataSeries = ds->clone(); } } void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; } /// Updates real range according to current variable range and data series void updateRealRange() { if (m_DataSeries) { auto lock = m_DataSeries->getReadLock(); auto end = m_DataSeries->cend(); auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart); auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd); if(minXAxisIt != end && maxXAxisIt != end && minXAxisIt->x() <= maxXAxisIt->x()) m_RealRange = DateTimeRange{minXAxisIt->x(), maxXAxisIt->x()}; else m_RealRange = std::nullopt; } else { m_RealRange = std::nullopt; } } VP_PROPERTY(m_Name, name, setName, QString) VP_PROPERTY(m_Range, range, setRange, DateTimeRange) VP_PROPERTY(m_CacheRange, cacheRange, setCacheRange, DateTimeRange) VP_PROPERTY(m_Metadata, metadata, setMetadata, QVariantHash) VP_PROPERTY(m_DataSeries, dataSeries, setDataSeries, std::shared_ptr) VP_PROPERTY(m_RealRange, realRange, setRealRange, std::optional) unsigned int m_NbPoints; VP_PROPERTY(m_Type, type, setType, DataSeriesType) QReadWriteLock m_Lock; }; Variable::Variable(const QString &name, const QVariantHash &metadata) : impl{spimpl::make_unique_impl(name, metadata)}, _uuid{QUuid::createUuid()} { } Variable::Variable(const Variable &other) : impl{spimpl::make_unique_impl(*other.impl)}, _uuid{QUuid::createUuid()} //is a clone but must have a != uuid { } std::shared_ptr Variable::clone() const { return std::make_shared(*this); } V_FW_GETTER_SETTER(name,setName,QString) DateTimeRange Variable::range() const noexcept { return impl->range(); } void Variable::setRange(const DateTimeRange &range, bool notify) noexcept { impl->setRange(range); impl->updateRealRange(); if(notify) emit this->updated(); } V_FW_GETTER_SETTER(cacheRange, setCacheRange, DateTimeRange) unsigned int Variable::nbPoints() const noexcept { return impl->m_NbPoints; } std::optional Variable::realRange() const noexcept { return impl->realRange(); } void Variable::updateData(const std::vector &dataSeries, const DateTimeRange &newRange, const DateTimeRange &newCacheRange, bool notify) { { QWriteLocker lock{&m_lock}; impl->mergeDataSeries(dataSeries); impl->setRange(newRange); impl->setCacheRange(newCacheRange); impl->purgeDataSeries(); } if(notify) emit updated(); } std::shared_ptr Variable::dataSeries() const noexcept { return impl->dataSeries(); } DataSeriesType Variable::type() const noexcept { return impl->type(); } QVariantHash Variable::metadata() const noexcept { impl->lockRead(); auto metadata = impl->m_Metadata; impl->unlock(); return metadata; }