Variable.cpp
211 lines
| 7.0 KiB
| text/x-c
|
CppLexer
r0 | #include "Variable/Variable.h" | |||
r2 | #include <Common/debug.h> | |||
r62 | #include <Data/DateTimeRange.h> | |||
#include <Data/IDataSeries.h> | ||||
#include <QMutex> | ||||
#include <QReadWriteLock> | ||||
#include <QThread> | ||||
#include <optional> | ||||
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 | ||||
r62 | * @return the value converted to a DataSeriesType if it was found, UNKNOWN type | |||
* otherwise | ||||
r0 | * @sa DataSeriesType | |||
*/ | ||||
r62 | static DataSeriesType findDataSeriesType(const QVariantHash& metadata) | |||
r0 | { | |||
r62 | auto dataSeriesType = DataSeriesType::NONE; | |||
r0 | ||||
r62 | // 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::NONE; ++it) | ||||
{ | ||||
dataSeriesType = DataSeriesTypeUtils::fromString(it.value().toString()); | ||||
} | ||||
r0 | ||||
r62 | return dataSeriesType; | |||
r0 | } | |||
r62 | #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(this->ID()); \ | ||||
} | ||||
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<IDataSeries*>& dataseries, | ||||
bool overwrite = false) | ||||
{ | ||||
QWriteLocker lock{&m_Lock}; | ||||
for(auto ds : dataseries) | ||||
r0 | { | |||
r62 | if(!overwrite & bool(m_DataSeries)) | |||
m_DataSeries->merge(ds); | ||||
else | ||||
m_DataSeries = ds->clone(); | ||||
r0 | } | |||
r62 | } | |||
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 | { | |||
r62 | 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; | ||||
r16 | } | |||
r62 | else | |||
r0 | { | |||
r62 | m_RealRange = std::nullopt; | |||
r0 | } | |||
r62 | } | |||
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>) | ||||
unsigned int m_NbPoints; | ||||
VP_PROPERTY(m_Type, type, setType, DataSeriesType) | ||||
QReadWriteLock m_Lock; | ||||
r0 | }; | |||
r62 | Variable::Variable(const QString& name, const QVariantHash& metadata) | |||
: impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}, | ||||
_uuid{QUuid::createUuid()} | ||||
{} | ||||
r0 | ||||
r62 | Variable::Variable(const Variable& other) | |||
: 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 | ||||
{ | ||||
r62 | return std::make_shared<Variable>(*this); | |||
r0 | } | |||
r62 | V_FW_GETTER_SETTER(name, setName, QString) | |||
r0 | ||||
r62 | DateTimeRange Variable::range() const noexcept { return impl->range(); } | |||
r0 | ||||
r62 | void Variable::setRange(const DateTimeRange& range, bool notify) noexcept | |||
r0 | { | |||
r62 | impl->setRange(range); | |||
impl->updateRealRange(); | ||||
if(notify) emit this->updated(this->ID()); | ||||
r0 | } | |||
r15 | V_FW_GETTER_SETTER(cacheRange, setCacheRange, DateTimeRange) | |||
r0 | ||||
r62 | unsigned int Variable::nbPoints() const noexcept { return impl->m_NbPoints; } | |||
r0 | ||||
r15 | std::optional<DateTimeRange> Variable::realRange() const noexcept | |||
r0 | { | |||
r62 | return impl->realRange(); | |||
r0 | } | |||
r62 | void Variable::updateData(const std::vector<IDataSeries*>& dataSeries, | |||
const DateTimeRange& newRange, | ||||
const DateTimeRange& newCacheRange, bool notify) | ||||
r2 | { | |||
r62 | { | |||
QWriteLocker lock{&m_lock}; | ||||
impl->mergeDataSeries(dataSeries); | ||||
impl->setRange(newRange); | ||||
impl->setCacheRange(newCacheRange); | ||||
impl->purgeDataSeries(); | ||||
} | ||||
if(notify) emit updated(this->ID()); | ||||
r2 | } | |||
r62 | void Variable::setData(const std::vector<IDataSeries*>& dataSeries, | |||
const DateTimeRange& newRange, | ||||
const DateTimeRange& newCacheRange, bool notify) | ||||
r44 | { | |||
r62 | { | |||
QWriteLocker lock{&m_lock}; | ||||
impl->mergeDataSeries(dataSeries, true); | ||||
impl->setRange(newRange); | ||||
impl->setCacheRange(newCacheRange); | ||||
impl->purgeDataSeries(); | ||||
} | ||||
if(notify) emit updated(this->ID()); | ||||
r44 | } | |||
r0 | std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept | |||
{ | ||||
r62 | return impl->dataSeries(); | |||
r0 | } | |||
r62 | DataSeriesType Variable::type() const noexcept { return impl->type(); } | |||
r0 | ||||
QVariantHash Variable::metadata() const noexcept | ||||
{ | ||||
r62 | impl->lockRead(); | |||
auto metadata = impl->m_Metadata; | ||||
impl->unlock(); | ||||
return metadata; | ||||
r0 | } | |||