From 7315812f38391ae65688cfd4309ded15ec96d7e6 2019-03-14 19:12:12 From: Alexis Jeandet Date: 2019-03-14 19:12:12 Subject: [PATCH] New TimeSeries integration WIP Signed-off-by: Alexis Jeandet --- diff --git a/CMakeLists.txt b/CMakeLists.txt index a913623..91d278d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ FILE (GLOB_RECURSE core_SRCS ./include/Common/containers.h ./include/Common/debug.h ./include/Common/cpp_utils.h + ./include/Common/variant_with_base.h ./include/Plugin/IPlugin.h ./include/Data/ArrayDataIterator.h ./include/Data/VectorSeries.h @@ -112,6 +113,7 @@ FILE (GLOB_RECURSE core_SRCS ./include/Variable/SingleThresholdCacheStrategy.h ./include/Variable/VariableCacheStrategyFactory.h ./include/Variable/Variable.h + ./include/Variable/Variable2.h ./include/Variable/VariableController2.h ./include/Variable/private/VCTransaction.h ./include/Time/TimeController.h @@ -143,6 +145,7 @@ FILE (GLOB_RECURSE core_SRCS ./src/Variable/VariableModel2.cpp ./src/Variable/VariableSynchronizationGroup2.cpp ./src/Variable/Variable.cpp + ./src/Variable/Variable2.cpp ./src/Version.cpp ./src/Time/TimeController.cpp ./src/Settings/SqpSettingsDefs.cpp diff --git a/external/TimeSeries b/external/TimeSeries index f76d133..ce006cf 160000 --- a/external/TimeSeries +++ b/external/TimeSeries @@ -1 +1 @@ -Subproject commit f76d1333ff1b2a9e1629a5a79226424a8fe84f00 +Subproject commit ce006cf8df2b0bb3d433f901b6e80ce69119a430 diff --git a/external/catalogicpp b/external/catalogicpp index 9e6d585..9c518f2 160000 --- a/external/catalogicpp +++ b/external/catalogicpp @@ -1 +1 @@ -Subproject commit 9e6d585db2d3bea47c864622ee9f67d496aa7251 +Subproject commit 9c518f27796798fda36a1495b329808177c4c150 diff --git a/include/Common/variant_with_base.h b/include/Common/variant_with_base.h new file mode 100644 index 0000000..6db1523 --- /dev/null +++ b/include/Common/variant_with_base.h @@ -0,0 +1,187 @@ +#ifndef VARIANTWITHBASE_H +#define VARIANTWITHBASE_H +// stolen without any shame from +// https://tower120.github.io/2018/05/18/variant_with_base.html (•_•) ( +// •_•)>⌐■-■ (⌐■_■) +#include +#include +#include +#include + +template class variant_w_base +{ + using Self = variant_w_base; + + auto& self_mut() const { return *const_cast(this); } + + Base* m_base; + Variant m_variant; + + void update_base() + { + m_base = std::visit( + [](auto&& arg) -> Base* { + using Arg = std::decay_t; + if constexpr(std::is_same_v) { return nullptr; } + else + { + return static_cast(&arg); + } + }, + m_variant); + } + template void update_base() + { + using Arg = std::decay_t; + if constexpr(std::is_same_v) { m_base = nullptr; } + else + { + m_base = std::get_if(&m_variant); + assert(m_base); + } + } + + template + using is_not_self = std::enable_if_t, Self>>; + +public: + variant_w_base() { update_base(); } + variant_w_base(const variant_w_base& other) : m_variant(other.m_variant) + { + update_base(); + } + variant_w_base(variant_w_base&& other) : m_variant(std::move(other.m_variant)) + { + update_base(); + } + variant_w_base(const Variant& var) : m_variant(var) { update_base(); } + variant_w_base(Variant&& var) : m_variant(std::move(var)) { update_base(); } + template> + variant_w_base(T&& value) : m_variant(std::forward(value)) + { + update_base(); + } + template + explicit variant_w_base(std::in_place_type_t, Args&&... args) + : m_variant(std::in_place_type_t(), std::forward(args)...) + { + update_base(); + } + + variant_w_base& operator=(const variant_w_base& other) + { + m_variant = other.m_variant; + update_base(); + return *this; + } + variant_w_base& operator=(variant_w_base&& other) + { + m_variant = std::move(other.m_variant); + update_base(); + return *this; + } + + template> + variant_w_base& operator=(T&& value) + { + m_variant = std::forward(value); + update_base(); + return *this; + } + variant_w_base& operator=(const Variant& var) + { + m_variant = var; + update_base(); + return *this; + } + variant_w_base& operator=(Variant&& var) + { + m_variant = std::move(var); + update_base(); + return *this; + } + constexpr std::size_t index() const noexcept { return m_variant.index(); } + constexpr bool operator==(const variant_w_base& other) const + { + return m_variant == other.m_variant; + } + constexpr bool operator!=(const variant_w_base& other) const + { + return m_variant != other.m_variant; + } + + // free functions from std::variant + template constexpr T* get_if() + { + if constexpr(std::is_same_v) { return base(); } + else + { + return std::get_if(variant()); + } + } + template constexpr const T* get_if() const + { + return self_mut().template get(); + } + + template constexpr decltype(auto) get_if() + { + return std::get_if(variant()); + } + template constexpr decltype(auto) get_if() const + { + return std::get_if(variant()); + } + + template constexpr T& get() + { + if constexpr(std::is_same_v) + { + if(base() == nullptr) { throw std::bad_variant_access(); } + return *base(); + } + else + { + return std::get(variant()); + } + } + template constexpr const T& get() const + { + return self_mut().template get(); + } + + template constexpr decltype(auto) get() + { + return std::get(variant()); + } + template constexpr decltype(auto) get() const + { + return std::get(variant()); + } + + template constexpr decltype(auto) visit(Visitor&& vis) + { + return std::visit(std::forward(vis), variant()); + } + template constexpr decltype(auto) visit(Visitor&& vis) const + { + return std::visit(std::forward(vis), variant()); + } + + Base* base() noexcept { return m_base; } + const Base* base() const noexcept { return m_base; } + operator Base&() noexcept { return *m_base; } + operator const Base&() const noexcept { return *m_base; } + Base* operator->() noexcept { return m_base; } + const Base* operator->() const noexcept { return m_base; } + Base& operator*() noexcept { return m_base; } + const Base& operator*() const noexcept { return m_base; } + + constexpr const Variant& variant() const noexcept { return m_variant; } + +private: + // hide, to keep variant type change tracked. + constexpr Variant& variant() noexcept { return m_variant; } +}; + +#endif // VARIANTWITHBASE_H diff --git a/include/Data/DataSeriesType.h b/include/Data/DataSeriesType.h index ba31397..b255c52 100644 --- a/include/Data/DataSeriesType.h +++ b/include/Data/DataSeriesType.h @@ -5,10 +5,10 @@ enum class DataSeriesType { + NONE, SCALAR, - SPECTROGRAM, VECTOR, - UNKNOWN + SPECTROGRAM }; struct DataSeriesTypeUtils @@ -27,7 +27,7 @@ struct DataSeriesTypeUtils } else { - return DataSeriesType::UNKNOWN; + return DataSeriesType::NONE; } } }; diff --git a/include/Variable/Variable.h b/include/Variable/Variable.h index 84c4aba..f7284a1 100644 --- a/include/Variable/Variable.h +++ b/include/Variable/Variable.h @@ -1,23 +1,21 @@ #ifndef SCIQLOP_VARIABLE_H #define SCIQLOP_VARIABLE_H -#include - -#include -#include -#include -#include -#include - #include "CoreGlobal.h" -#include -#include -#include - -#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include Q_DECLARE_LOGGING_CATEGORY(LOG_Variable) @@ -27,91 +25,95 @@ class QString; /** * @brief The Variable class represents a variable in SciQlop. */ -class SCIQLOP_CORE_EXPORT Variable : public QObject { - - Q_OBJECT +class SCIQLOP_CORE_EXPORT Variable : public QObject +{ + Q_OBJECT public: - explicit Variable(const QString &name, const QVariantHash &metadata = {}); - - /// Copy ctor - explicit Variable(const Variable &other); - - std::shared_ptr clone() const; - - QString name() const noexcept; - void setName(const QString &name) noexcept; - DateTimeRange range() const noexcept; - void setRange(const DateTimeRange &range, bool notify=false) noexcept; - DateTimeRange cacheRange() const noexcept; - void setCacheRange(const DateTimeRange &cacheRange) noexcept; - - /// @return the number of points hold by the variable. The number of points is updated each time - /// the data series changes - unsigned int nbPoints() const noexcept; - - /// Returns the real range of the variable, i.e. the min and max x-axis values of the data - /// series between the range of the variable. The real range is updated each time the variable - /// range or the data series changed - /// @return the real range, invalid range if the data series is null or empty - /// @sa setDataSeries() - /// @sa setRange() - std::optional realRange() const noexcept; - - /// @return the data of the variable, nullptr if there is no data - std::shared_ptr dataSeries() const noexcept; - - /// @return the type of data that the variable holds - DataSeriesType type() const noexcept; - - QVariantHash metadata() const noexcept; - - void updateData(const std::vector& dataSeries, - const DateTimeRange& newRange, const DateTimeRange& newCacheRange, - bool notify=true); - - void setData(const std::vector& dataSeries, - const DateTimeRange& newRange, const DateTimeRange& newCacheRange, - bool notify=true); - - static QByteArray mimeData(const std::vector > &variables) + explicit Variable(const QString& name, const QVariantHash& metadata = {}); + + /// Copy ctor + explicit Variable(const Variable& other); + + std::shared_ptr clone() const; + + QString name() const noexcept; + void setName(const QString& name) noexcept; + DateTimeRange range() const noexcept; + void setRange(const DateTimeRange& range, bool notify = false) noexcept; + DateTimeRange cacheRange() const noexcept; + void setCacheRange(const DateTimeRange& cacheRange) noexcept; + + /// @return the number of points hold by the variable. The number of points is + /// updated each time the data series changes + unsigned int nbPoints() const noexcept; + + /// Returns the real range of the variable, i.e. the min and max x-axis values + /// of the data series between the range of the variable. The real range is + /// updated each time the variable range or the data series changed + /// @return the real range, invalid range if the data series is null or empty + /// @sa setDataSeries() + /// @sa setRange() + std::optional realRange() const noexcept; + + /// @return the data of the variable, nullptr if there is no data + std::shared_ptr dataSeries() const noexcept; + + /// @return the type of data that the variable holds + DataSeriesType type() const noexcept; + + QVariantHash metadata() const noexcept; + + void updateData(const std::vector& dataSeries, + const DateTimeRange& newRange, + const DateTimeRange& newCacheRange, bool notify = true); + + void setData(const std::vector& dataSeries, + const DateTimeRange& newRange, + const DateTimeRange& newCacheRange, bool notify = true); + + static QByteArray + mimeData(const std::vector>& variables) + { + auto encodedData = QByteArray{}; + QDataStream stream{&encodedData, QIODevice::WriteOnly}; + for(auto& var : variables) { - auto encodedData = QByteArray{}; - QDataStream stream{&encodedData, QIODevice::WriteOnly}; - for (auto &var : variables) { - stream << var->ID().toByteArray(); - } - return encodedData; + stream << var->ID().toByteArray(); } + return encodedData; + } - static std::vector variablesIDs(QByteArray mimeData) - { - std::vector variables; - QDataStream stream{mimeData}; + static std::vector variablesIDs(QByteArray mimeData) + { + std::vector variables; + QDataStream stream{mimeData}; - QVariantList ids; - stream >> ids; + QVariantList ids; + stream >> ids; - for (const auto& id : ids) { - variables.emplace_back (id.toByteArray()); - } - return variables; + for(const auto& id : ids) + { + variables.emplace_back(id.toByteArray()); } + return variables; + } - operator QUuid() {return _uuid;} - QUuid ID(){return _uuid;} + operator QUuid() { return _uuid; } + QUuid ID() { return _uuid; } signals: - void updated(QUuid ID); + void updated(QUuid ID); private: - class VariablePrivate; - spimpl::unique_impl_ptr impl; - QUuid _uuid; - QReadWriteLock m_lock; + class VariablePrivate; + spimpl::unique_impl_ptr impl; + QUuid _uuid; + QReadWriteLock m_lock; }; // Required for using shared_ptr in signals/slots SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr) -SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector >) +SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, + QVector>) #endif // SCIQLOP_VARIABLE_H diff --git a/include/Variable/Variable2.h b/include/Variable/Variable2.h new file mode 100644 index 0000000..08a4bea --- /dev/null +++ b/include/Variable/Variable2.h @@ -0,0 +1,97 @@ +#ifndef SCIQLOP_VARIABLE2_H +#define SCIQLOP_VARIABLE2_H + +#include "CoreGlobal.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using AnyTimeSerie = variant_w_base< + TimeSeries::ITimeSerie, + std::variant>; + +class SCIQLOP_CORE_EXPORT Variable2 : public QObject +{ + Q_OBJECT + +public: + explicit Variable2(const QString& name, const QVariantHash& metadata = {}); + + /// Copy ctor + explicit Variable2(const Variable2& other); + + std::shared_ptr clone() const; + + QString name() const noexcept; + void setName(const QString& name) noexcept; + DateTimeRange range() const noexcept; + std::optional realRange() const noexcept; + + std::size_t nbPoints() const noexcept; + + /// @return the data of the variable, nullptr if there is no data + AnyTimeSerie* data() const noexcept; + + /// @return the type of data that the variable holds + DataSeriesType type() const noexcept; + + QVariantHash metadata() const noexcept; + + void setData(const std::vector& dataSeries, + const DateTimeRange& range, bool notify = true); + + static QByteArray + mimeData(const std::vector>& variables) + { + auto encodedData = QByteArray{}; + QDataStream stream{&encodedData, QIODevice::WriteOnly}; + for(auto& var : variables) + { + stream << var->ID().toByteArray(); + } + return encodedData; + } + + static std::vector IDs(QByteArray mimeData) + { + std::vector variables; + QDataStream stream{mimeData}; + + QVariantList ids; + stream >> ids; + std::transform(std::cbegin(ids), std::cend(ids), + std::back_inserter(variables), + [](const auto& id) { return id.toByteArray(); }); + return variables; + } + + operator QUuid() { return _uuid; } + QUuid ID() { return _uuid; } +signals: + void updated(QUuid ID); + +private: + struct VariablePrivate; + spimpl::unique_impl_ptr impl; + QUuid _uuid; + QReadWriteLock m_lock; +}; + +// Required for using shared_ptr in signals/slots +// SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr) +// SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, +// QVector>) + +#endif // SCIQLOP_VARIABLE2_H diff --git a/src/Common/DateUtils.cpp b/src/Common/DateUtils.cpp index 635bbf2..2041c69 100644 --- a/src/Common/DateUtils.cpp +++ b/src/Common/DateUtils.cpp @@ -1,13 +1,18 @@ #include "Common/DateUtils.h" +#include + QDateTime DateUtils::dateTime(double secs, Qt::TimeSpec timeSpec) noexcept { - // Uses msecs to be Qt 4 compatible - return QDateTime::fromMSecsSinceEpoch(secs * 1000., timeSpec); + // Uses msecs to be Qt 4 compatible + if(!std::isnan(secs)) + return QDateTime::fromMSecsSinceEpoch(static_cast(secs * 1000.), + timeSpec); + return QDateTime(); } -double DateUtils::secondsSinceEpoch(const QDateTime &dateTime) noexcept +double DateUtils::secondsSinceEpoch(const QDateTime& dateTime) noexcept { - // Uses msecs to be Qt 4 compatible - return dateTime.toMSecsSinceEpoch() / 1000.; + // Uses msecs to be Qt 4 compatible + return dateTime.toMSecsSinceEpoch() / 1000.; } diff --git a/src/Variable/Variable.cpp b/src/Variable/Variable.cpp index c7bcb21..b5c3406 100644 --- a/src/Variable/Variable.cpp +++ b/src/Variable/Variable.cpp @@ -1,225 +1,211 @@ -#include -#include -#include -#include - #include "Variable/Variable.h" -#include -#include - #include +#include +#include +#include +#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 + * @return the value converted to a DataSeriesType if it was found, UNKNOWN type + * otherwise * @sa DataSeriesType */ -static DataSeriesType findDataSeriesType(const QVariantHash &metadata) +static DataSeriesType findDataSeriesType(const QVariantHash& metadata) { - auto dataSeriesType = DataSeriesType::UNKNOWN; + auto dataSeriesType = DataSeriesType::NONE; - // 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()); - } + // 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()); + } - return dataSeriesType; + 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(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() +#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& dataseries, + bool overwrite = false) + { + QWriteLocker lock{&m_Lock}; + for(auto ds : dataseries) { - if (m_DataSeries) { - m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd); - } - updateRealRange(); - updateNbPoints(); + if(!overwrite & bool(m_DataSeries)) + m_DataSeries->merge(ds); + else + m_DataSeries = ds->clone(); } - void mergeDataSeries(const std::vector& dataseries, bool overwrite=false) + } + 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) { - QWriteLocker lock{&m_Lock}; - for(auto ds:dataseries) - { - if(!overwrite & bool(m_DataSeries)) - m_DataSeries->merge(ds); - else - m_DataSeries = ds->clone(); - } + 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; } - void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; } - - /// Updates real range according to current variable range and data series - void updateRealRange() + else { - 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; - } + 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; + } + + 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 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 -{ -} +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); + return std::make_shared(*this); } -V_FW_GETTER_SETTER(name,setName,QString) +V_FW_GETTER_SETTER(name, setName, QString) -DateTimeRange Variable::range() const noexcept -{ - return impl->range(); -} +DateTimeRange Variable::range() const noexcept { return impl->range(); } -void Variable::setRange(const DateTimeRange &range, bool notify) noexcept +void Variable::setRange(const DateTimeRange& range, bool notify) noexcept { - impl->setRange(range); - impl->updateRealRange(); - if(notify) - emit this->updated(this->ID()); + impl->setRange(range); + impl->updateRealRange(); + if(notify) emit this->updated(this->ID()); } V_FW_GETTER_SETTER(cacheRange, setCacheRange, DateTimeRange) -unsigned int Variable::nbPoints() const noexcept -{ - return impl->m_NbPoints; -} +unsigned int Variable::nbPoints() const noexcept { return impl->m_NbPoints; } std::optional Variable::realRange() const noexcept { - return impl->realRange(); + return impl->realRange(); } -void Variable::updateData(const std::vector &dataSeries, const DateTimeRange &newRange, const DateTimeRange &newCacheRange, bool notify) +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(this->ID()); + { + QWriteLocker lock{&m_lock}; + impl->mergeDataSeries(dataSeries); + impl->setRange(newRange); + impl->setCacheRange(newCacheRange); + impl->purgeDataSeries(); + } + if(notify) emit updated(this->ID()); } -void Variable::setData(const std::vector &dataSeries, const DateTimeRange &newRange, const DateTimeRange &newCacheRange, bool notify) +void Variable::setData(const std::vector& dataSeries, + const DateTimeRange& newRange, + const DateTimeRange& newCacheRange, bool notify) { - { - QWriteLocker lock{&m_lock}; - impl->mergeDataSeries(dataSeries, true); - impl->setRange(newRange); - impl->setCacheRange(newCacheRange); - impl->purgeDataSeries(); - } - if(notify) - emit updated(this->ID()); + { + QWriteLocker lock{&m_lock}; + impl->mergeDataSeries(dataSeries, true); + impl->setRange(newRange); + impl->setCacheRange(newCacheRange); + impl->purgeDataSeries(); + } + if(notify) emit updated(this->ID()); } std::shared_ptr Variable::dataSeries() const noexcept { - return impl->dataSeries(); + return impl->dataSeries(); } -DataSeriesType Variable::type() const noexcept -{ - return impl->type(); -} +DataSeriesType Variable::type() const noexcept { return impl->type(); } QVariantHash Variable::metadata() const noexcept { - impl->lockRead(); - auto metadata = impl->m_Metadata; - impl->unlock(); - return metadata; + impl->lockRead(); + auto metadata = impl->m_Metadata; + impl->unlock(); + return metadata; } diff --git a/src/Variable/Variable2.cpp b/src/Variable/Variable2.cpp new file mode 100644 index 0000000..4718043 --- /dev/null +++ b/src/Variable/Variable2.cpp @@ -0,0 +1,123 @@ +#include "Variable/Variable2.h" + +#define 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 Variable2::getter() const noexcept { return impl->getter(); } \ + void Variable2::setter(const type& value) noexcept \ + { \ + impl->setter(value); \ + emit updated(this->ID()); \ + } + +struct Variable2::VariablePrivate +{ + VariablePrivate(const QString& name, const QVariantHash& metadata) + : m_Name{name}, m_Range{INVALID_RANGE}, m_Metadata{metadata}, m_TimeSerie{ + nullptr} + {} + VariablePrivate(const VariablePrivate& other) {} + std::size_t nbPoints() + { + if(m_TimeSerie) return m_TimeSerie->base()->size(); + return 0; + } + DataSeriesType type() const + { + if(m_TimeSerie) return DataSeriesType(m_TimeSerie->index()); + return DataSeriesType::NONE; + } + + PROPERTY_(m_Name, name, setName, QString) + PROPERTY_(m_Range, range, setRange, DateTimeRange) + PROPERTY_(m_Metadata, metadata, setMetadata, QVariantHash) + AnyTimeSerie& dataSeries() { return *m_TimeSerie.get(); } + void setDataSeries(std::unique_ptr&& timeSerie) + { + QWriteLocker lock{&m_Lock}; + m_TimeSerie = std::move(timeSerie); + } + std::unique_ptr m_TimeSerie; + QReadWriteLock m_Lock; +}; + +Variable2::Variable2(const QString& name, const QVariantHash& metadata) + : impl{spimpl::make_unique_impl(name, metadata)}, + _uuid{QUuid::createUuid()} +{} + +Variable2::Variable2(const Variable2& other) + : impl{spimpl::make_unique_impl(*other.impl)}, + _uuid{QUuid::createUuid()} // is a clone but must have a != uuid +{} + +std::shared_ptr Variable2::clone() const +{ + return std::make_shared(*this); +} + +V_FW_GETTER_SETTER(name, setName, QString) + +DateTimeRange Variable2::range() const noexcept { return impl->range(); } + +std::size_t Variable2::nbPoints() const noexcept { return impl->nbPoints(); } + +AnyTimeSerie* Variable2::data() const noexcept {} + +DataSeriesType Variable2::type() const noexcept { return impl->type(); } + +QVariantHash Variable2::metadata() const noexcept {} + +template +void _merge(const std::vector& source, AnyTimeSerie* dest) +{ + // std::for_each( + // std::cbegin(source) + 1, std::cend(source), [dest](AnyTimeSerie* + // serie) { + // std::copy(std::begin(serie->get()), std::end(serie->get()), + // std::back_inserter(dest->get())); + // }); +} + +std::unique_ptr +merge(const std::vector& dataSeries) +{ + std::unique_ptr ts; + *ts = *dataSeries.front(); + switch(DataSeriesType(ts->index())) + { + case DataSeriesType::NONE: break; + case DataSeriesType::SCALAR: + _merge(dataSeries, ts.get()); + break; + case DataSeriesType::VECTOR: + _merge(dataSeries, ts.get()); + break; + case DataSeriesType::SPECTROGRAM: + // merge(dataSeries, ts.get()); + break; + } + return ts; +} + +void Variable2::setData(const std::vector& dataSeries, + const DateTimeRange& range, bool notify) +{ + if(dataSeries.size()) + { + impl->setDataSeries(merge(dataSeries)); + impl->setRange(range); + if(notify) emit this->updated(this->ID()); + } +} diff --git a/src/Variable/VariableController2.cpp b/src/Variable/VariableController2.cpp index 92a8ab9..0242603 100644 --- a/src/Variable/VariableController2.cpp +++ b/src/Variable/VariableController2.cpp @@ -62,7 +62,10 @@ class VariableController2::VariableController2Private { QReadLocker lock{&_lock}; auto it = _variables.find(variable); - [[unlikely]] if(it == _variables.end()) +#if __cplusplus > 201703L + [[unlikely]] +#endif + if(it == _variables.end()) SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); return (*it).second; } @@ -70,7 +73,10 @@ class VariableController2::VariableController2Private inline std::shared_ptr variable(int index) { QReadLocker lock{&_lock}; - [[unlikely]] if(!_variables.size() > index) +#if __cplusplus > 201703L + [[unlikely]] +#endif + if(!_variables.size() > index) SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Index is out of bounds"); auto it = _variables.cbegin(); while(index != 0) @@ -95,7 +101,10 @@ class VariableController2::VariableController2Private inline std::shared_ptr provider(QUuid variable) { QReadLocker lock{&_lock}; - [[unlikely]] if(!_providers.contains(variable)) +#if __cplusplus > 201703L + [[unlikely]] +#endif + if(!_providers.contains(variable)) SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); return _providers[variable]; } @@ -103,7 +112,10 @@ class VariableController2::VariableController2Private inline std::shared_ptr group(QUuid variable) { QReadLocker lock{&_lock}; - [[unlikely]] if(!_synchronizationGroups.contains(variable)) +#if __cplusplus > 201703L + [[unlikely]] +#endif + if(!_synchronizationGroups.contains(variable)) SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); return _synchronizationGroups[variable]; } diff --git a/src/pybind11_wrappers/CoreWrappers.cpp b/src/pybind11_wrappers/CoreWrappers.cpp index 6064161..2acff7c 100644 --- a/src/pybind11_wrappers/CoreWrappers.cpp +++ b/src/pybind11_wrappers/CoreWrappers.cpp @@ -11,6 +11,7 @@ #include #include #include