Variable.cpp
214 lines
| 6.0 KiB
| text/x-c
|
CppLexer
r15 | #include <optional> | |||
#include <QMutex> | ||||
#include <QReadWriteLock> | ||||
#include <QThread> | ||||
r0 | #include "Variable/Variable.h" | |||
#include <Data/IDataSeries.h> | ||||
#include <Data/DateTimeRange.h> | ||||
r2 | #include <Common/debug.h> | |||
r0 | ||||
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 | ||||
*/ | ||||
r16 | static DataSeriesType findDataSeriesType(const QVariantHash &metadata) | |||
r0 | { | |||
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; | ||||
} | ||||
r15 | #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);\ | ||||
r29 | emit updated();\ | |||
r15 | }\ | |||
r0 | 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(); | ||||
} | ||||
r16 | void mergeDataSeries(const std::vector<IDataSeries*>& dataseries) | |||
{ | ||||
QWriteLocker lock{&m_Lock}; | ||||
for(auto ds:dataseries) | ||||
{ | ||||
if(m_DataSeries) | ||||
m_DataSeries->merge(ds); | ||||
else | ||||
m_DataSeries = ds->clone(); | ||||
} | ||||
} | ||||
r0 | 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) { | ||||
r16 | auto lock = m_DataSeries->getReadLock(); | |||
r0 | auto end = m_DataSeries->cend(); | |||
auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart); | ||||
auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd); | ||||
r16 | if(minXAxisIt != end && maxXAxisIt != end && minXAxisIt->x() <= maxXAxisIt->x()) | |||
m_RealRange = DateTimeRange{minXAxisIt->x(), maxXAxisIt->x()}; | ||||
else | ||||
m_RealRange = std::nullopt; | ||||
r0 | } | |||
else { | ||||
r15 | m_RealRange = std::nullopt; | |||
r0 | } | |||
} | ||||
r15 | 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<IDataSeries>) | ||||
VP_PROPERTY(m_RealRange, realRange, setRealRange, std::optional<DateTimeRange>) | ||||
r3 | unsigned int m_NbPoints; | |||
r15 | VP_PROPERTY(m_Type, type, setType, DataSeriesType) | |||
r0 | QReadWriteLock m_Lock; | |||
}; | ||||
Variable::Variable(const QString &name, const QVariantHash &metadata) | ||||
r2 | : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}, | |||
_uuid{QUuid::createUuid()} | ||||
r0 | { | |||
} | ||||
Variable::Variable(const Variable &other) | ||||
r2 | : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}, | |||
_uuid{QUuid::createUuid()} //is a clone but must have a != uuid | ||||
r0 | { | |||
} | ||||
std::shared_ptr<Variable> Variable::clone() const | ||||
{ | ||||
return std::make_shared<Variable>(*this); | ||||
} | ||||
r15 | V_FW_GETTER_SETTER(name,setName,QString) | |||
r0 | ||||
DateTimeRange Variable::range() const noexcept | ||||
{ | ||||
r15 | return impl->range(); | |||
r0 | } | |||
r9 | void Variable::setRange(const DateTimeRange &range, bool notify) noexcept | |||
r0 | { | |||
r15 | impl->setRange(range); | |||
r0 | impl->updateRealRange(); | |||
r9 | if(notify) | |||
emit this->updated(); | ||||
r0 | } | |||
r15 | V_FW_GETTER_SETTER(cacheRange, setCacheRange, DateTimeRange) | |||
r0 | ||||
r3 | unsigned int Variable::nbPoints() const noexcept | |||
r0 | { | |||
return impl->m_NbPoints; | ||||
} | ||||
r15 | std::optional<DateTimeRange> Variable::realRange() const noexcept | |||
r0 | { | |||
r15 | return impl->realRange(); | |||
r0 | } | |||
r16 | void Variable::updateData(const std::vector<IDataSeries *> &dataSeries, const DateTimeRange &newRange, const DateTimeRange &newCacheRange, bool notify) | |||
r2 | { | |||
r16 | { | |||
QWriteLocker lock{&m_lock}; | ||||
impl->mergeDataSeries(dataSeries); | ||||
impl->setRange(newRange); | ||||
impl->setCacheRange(newCacheRange); | ||||
impl->purgeDataSeries(); | ||||
r2 | } | |||
r9 | if(notify) | |||
r16 | emit updated(); | |||
r2 | } | |||
r0 | ||||
std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept | ||||
{ | ||||
r15 | return impl->dataSeries(); | |||
r0 | } | |||
DataSeriesType Variable::type() const noexcept | ||||
{ | ||||
r15 | return impl->type(); | |||
r0 | } | |||
QVariantHash Variable::metadata() const noexcept | ||||
{ | ||||
impl->lockRead(); | ||||
auto metadata = impl->m_Metadata; | ||||
impl->unlock(); | ||||
return metadata; | ||||
} | ||||