@@ -1,135 +1,112 | |||||
1 | #ifndef SCIQLOP_VARIABLE_H |
|
1 | #ifndef SCIQLOP_VARIABLE_H | |
2 | #define SCIQLOP_VARIABLE_H |
|
2 | #define SCIQLOP_VARIABLE_H | |
3 |
|
3 | |||
4 | #include <optional> |
|
4 | #include <optional> | |
5 |
|
5 | |||
6 | #include <QLoggingCategory> |
|
6 | #include <QLoggingCategory> | |
7 | #include <QObject> |
|
7 | #include <QObject> | |
8 | #include <QUuid> |
|
8 | #include <QUuid> | |
9 | #include <QReadWriteLock> |
|
9 | #include <QReadWriteLock> | |
10 | #include <QDataStream> |
|
10 | #include <QDataStream> | |
11 |
|
11 | |||
12 | #include "CoreGlobal.h" |
|
12 | #include "CoreGlobal.h" | |
13 | #include <Data/DataSeriesIterator.h> |
|
13 | #include <Data/DataSeriesIterator.h> | |
14 | #include <Data/DataSeriesType.h> |
|
14 | #include <Data/DataSeriesType.h> | |
15 | #include <Data/DateTimeRange.h> |
|
15 | #include <Data/DateTimeRange.h> | |
16 |
|
16 | |||
17 |
|
17 | |||
18 | #include <Common/deprecate.h> |
|
18 | #include <Common/deprecate.h> | |
19 | #include <Common/MetaTypes.h> |
|
19 | #include <Common/MetaTypes.h> | |
20 | #include <Common/spimpl.h> |
|
20 | #include <Common/spimpl.h> | |
21 |
|
21 | |||
22 | Q_DECLARE_LOGGING_CATEGORY(LOG_Variable) |
|
22 | Q_DECLARE_LOGGING_CATEGORY(LOG_Variable) | |
23 |
|
23 | |||
24 | class IDataSeries; |
|
24 | class IDataSeries; | |
25 | class QString; |
|
25 | class QString; | |
26 |
|
26 | |||
27 | /** |
|
27 | /** | |
28 | * @brief The Variable class represents a variable in SciQlop. |
|
28 | * @brief The Variable class represents a variable in SciQlop. | |
29 | */ |
|
29 | */ | |
30 | class SCIQLOP_CORE_EXPORT Variable : public QObject { |
|
30 | class SCIQLOP_CORE_EXPORT Variable : public QObject { | |
31 |
|
31 | |||
32 | Q_OBJECT |
|
32 | Q_OBJECT | |
33 |
|
33 | |||
34 | public: |
|
34 | public: | |
35 | explicit Variable(const QString &name, const QVariantHash &metadata = {}); |
|
35 | explicit Variable(const QString &name, const QVariantHash &metadata = {}); | |
36 |
|
36 | |||
37 | /// Copy ctor |
|
37 | /// Copy ctor | |
38 | explicit Variable(const Variable &other); |
|
38 | explicit Variable(const Variable &other); | |
39 |
|
39 | |||
40 | std::shared_ptr<Variable> clone() const; |
|
40 | std::shared_ptr<Variable> clone() const; | |
41 |
|
41 | |||
42 | QString name() const noexcept; |
|
42 | QString name() const noexcept; | |
43 | void setName(const QString &name) noexcept; |
|
43 | void setName(const QString &name) noexcept; | |
44 | DateTimeRange range() const noexcept; |
|
44 | DateTimeRange range() const noexcept; | |
45 | void setRange(const DateTimeRange &range, bool notify=false) noexcept; |
|
45 | void setRange(const DateTimeRange &range, bool notify=false) noexcept; | |
46 | DateTimeRange cacheRange() const noexcept; |
|
46 | DateTimeRange cacheRange() const noexcept; | |
47 | void setCacheRange(const DateTimeRange &cacheRange) noexcept; |
|
47 | void setCacheRange(const DateTimeRange &cacheRange) noexcept; | |
48 |
|
48 | |||
49 | /// @return the number of points hold by the variable. The number of points is updated each time |
|
49 | /// @return the number of points hold by the variable. The number of points is updated each time | |
50 | /// the data series changes |
|
50 | /// the data series changes | |
51 | unsigned int nbPoints() const noexcept; |
|
51 | unsigned int nbPoints() const noexcept; | |
52 |
|
52 | |||
53 | /// Returns the real range of the variable, i.e. the min and max x-axis values of the data |
|
53 | /// Returns the real range of the variable, i.e. the min and max x-axis values of the data | |
54 | /// series between the range of the variable. The real range is updated each time the variable |
|
54 | /// series between the range of the variable. The real range is updated each time the variable | |
55 | /// range or the data series changed |
|
55 | /// range or the data series changed | |
56 | /// @return the real range, invalid range if the data series is null or empty |
|
56 | /// @return the real range, invalid range if the data series is null or empty | |
57 | /// @sa setDataSeries() |
|
57 | /// @sa setDataSeries() | |
58 | /// @sa setRange() |
|
58 | /// @sa setRange() | |
59 | std::optional<DateTimeRange> realRange() const noexcept; |
|
59 | std::optional<DateTimeRange> realRange() const noexcept; | |
60 |
|
60 | |||
61 | /// @return the data of the variable, nullptr if there is no data |
|
61 | /// @return the data of the variable, nullptr if there is no data | |
62 | std::shared_ptr<IDataSeries> dataSeries() const noexcept; |
|
62 | std::shared_ptr<IDataSeries> dataSeries() const noexcept; | |
63 |
|
63 | |||
64 | /// @return the type of data that the variable holds |
|
64 | /// @return the type of data that the variable holds | |
65 | DataSeriesType type() const noexcept; |
|
65 | DataSeriesType type() const noexcept; | |
66 |
|
66 | |||
67 | QVariantHash metadata() const noexcept; |
|
67 | QVariantHash metadata() const noexcept; | |
68 |
|
68 | |||
69 | void updateData(const std::vector<IDataSeries*>& dataSeries, |
|
69 | void updateData(const std::vector<IDataSeries*>& dataSeries, | |
70 | const DateTimeRange& newRange, const DateTimeRange& newCacheRange, |
|
70 | const DateTimeRange& newRange, const DateTimeRange& newCacheRange, | |
71 | bool notify=true); |
|
71 | bool notify=true); | |
72 |
|
72 | |||
73 | static QByteArray mimeData(const std::vector<std::shared_ptr<Variable> > &variables) |
|
73 | static QByteArray mimeData(const std::vector<std::shared_ptr<Variable> > &variables) | |
74 | { |
|
74 | { | |
75 | auto encodedData = QByteArray{}; |
|
75 | auto encodedData = QByteArray{}; | |
76 | QDataStream stream{&encodedData, QIODevice::WriteOnly}; |
|
76 | QDataStream stream{&encodedData, QIODevice::WriteOnly}; | |
77 | for (auto &var : variables) { |
|
77 | for (auto &var : variables) { | |
78 | stream << var->ID().toByteArray(); |
|
78 | stream << var->ID().toByteArray(); | |
79 | } |
|
79 | } | |
80 | return encodedData; |
|
80 | return encodedData; | |
81 | } |
|
81 | } | |
82 |
|
82 | |||
83 | static std::vector<QUuid> variablesIDs(QByteArray mimeData) |
|
83 | static std::vector<QUuid> variablesIDs(QByteArray mimeData) | |
84 | { |
|
84 | { | |
85 | std::vector<QUuid> variables; |
|
85 | std::vector<QUuid> variables; | |
86 | QDataStream stream{mimeData}; |
|
86 | QDataStream stream{mimeData}; | |
87 |
|
87 | |||
88 | QVariantList ids; |
|
88 | QVariantList ids; | |
89 | stream >> ids; |
|
89 | stream >> ids; | |
90 |
|
90 | |||
91 | for (const auto& id : ids) { |
|
91 | for (const auto& id : ids) { | |
92 | variables.emplace_back (id.toByteArray()); |
|
92 | variables.emplace_back (id.toByteArray()); | |
93 | } |
|
93 | } | |
94 | return variables; |
|
94 | return variables; | |
95 | } |
|
95 | } | |
96 |
|
96 | |||
97 | DEPRECATE( |
|
|||
98 |
|
||||
99 | bool contains(const DateTimeRange &range) const noexcept; |
|
|||
100 | bool intersect(const DateTimeRange &range) const noexcept; |
|
|||
101 | bool isInside(const DateTimeRange &range) const noexcept; |
|
|||
102 |
|
||||
103 | bool cacheContains(const DateTimeRange &range) const noexcept; |
|
|||
104 | bool cacheIntersect(const DateTimeRange &range) const noexcept; |
|
|||
105 | bool cacheIsInside(const DateTimeRange &range) const noexcept; |
|
|||
106 | QVector<DateTimeRange> provideNotInCacheRangeList(const DateTimeRange &range) const noexcept; |
|
|||
107 | QVector<DateTimeRange> provideInCacheRangeList(const DateTimeRange &range) const noexcept; |
|
|||
108 | void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept; |
|
|||
109 | static QVector<DateTimeRange> provideNotInCacheRangeList(const DateTimeRange &oldRange, |
|
|||
110 | const DateTimeRange &nextRange); |
|
|||
111 |
|
||||
112 | static QVector<DateTimeRange> provideInCacheRangeList(const DateTimeRange &oldRange, |
|
|||
113 | const DateTimeRange &nextRange); |
|
|||
114 | ) |
|
|||
115 |
|
||||
116 | operator QUuid() {return _uuid;} |
|
97 | operator QUuid() {return _uuid;} | |
117 | QUuid ID(){return _uuid;} |
|
98 | QUuid ID(){return _uuid;} | |
118 | signals: |
|
99 | signals: | |
119 | void updated(); |
|
100 | void updated(); | |
120 | DEPRECATE( |
|
|||
121 | /// Signal emitted when when the data series of the variable is loaded for the first time |
|
|||
122 | void dataInitialized(); |
|
|||
123 | ) |
|
|||
124 | private: |
|
101 | private: | |
125 | class VariablePrivate; |
|
102 | class VariablePrivate; | |
126 | spimpl::unique_impl_ptr<VariablePrivate> impl; |
|
103 | spimpl::unique_impl_ptr<VariablePrivate> impl; | |
127 | QUuid _uuid; |
|
104 | QUuid _uuid; | |
128 | QReadWriteLock m_lock; |
|
105 | QReadWriteLock m_lock; | |
129 | }; |
|
106 | }; | |
130 |
|
107 | |||
131 | // Required for using shared_ptr in signals/slots |
|
108 | // Required for using shared_ptr in signals/slots | |
132 | SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>) |
|
109 | SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>) | |
133 | SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >) |
|
110 | SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >) | |
134 |
|
111 | |||
135 | #endif // SCIQLOP_VARIABLE_H |
|
112 | #endif // SCIQLOP_VARIABLE_H |
@@ -1,436 +1,214 | |||||
1 | #include <optional> |
|
1 | #include <optional> | |
2 | #include <QMutex> |
|
2 | #include <QMutex> | |
3 | #include <QReadWriteLock> |
|
3 | #include <QReadWriteLock> | |
4 | #include <QThread> |
|
4 | #include <QThread> | |
5 |
|
5 | |||
6 | #include "Variable/Variable.h" |
|
6 | #include "Variable/Variable.h" | |
7 |
|
7 | |||
8 | #include <Data/IDataSeries.h> |
|
8 | #include <Data/IDataSeries.h> | |
9 | #include <Data/DateTimeRange.h> |
|
9 | #include <Data/DateTimeRange.h> | |
10 |
|
10 | |||
11 | #include <Common/debug.h> |
|
11 | #include <Common/debug.h> | |
12 |
|
12 | |||
13 | Q_LOGGING_CATEGORY(LOG_Variable, "Variable") |
|
13 | Q_LOGGING_CATEGORY(LOG_Variable, "Variable") | |
14 |
|
14 | |||
15 |
|
15 | |||
16 | /** |
|
16 | /** | |
17 | * Searches in metadata for a value that can be converted to DataSeriesType |
|
17 | * Searches in metadata for a value that can be converted to DataSeriesType | |
18 | * @param metadata the metadata where to search |
|
18 | * @param metadata the metadata where to search | |
19 | * @return the value converted to a DataSeriesType if it was found, UNKNOWN type otherwise |
|
19 | * @return the value converted to a DataSeriesType if it was found, UNKNOWN type otherwise | |
20 | * @sa DataSeriesType |
|
20 | * @sa DataSeriesType | |
21 | */ |
|
21 | */ | |
22 | static DataSeriesType findDataSeriesType(const QVariantHash &metadata) |
|
22 | static DataSeriesType findDataSeriesType(const QVariantHash &metadata) | |
23 | { |
|
23 | { | |
24 | auto dataSeriesType = DataSeriesType::UNKNOWN; |
|
24 | auto dataSeriesType = DataSeriesType::UNKNOWN; | |
25 |
|
25 | |||
26 | // Go through the metadata and stop at the first value that could be converted to DataSeriesType |
|
26 | // Go through the metadata and stop at the first value that could be converted to DataSeriesType | |
27 | for (auto it = metadata.cbegin(), end = metadata.cend(); |
|
27 | for (auto it = metadata.cbegin(), end = metadata.cend(); | |
28 | it != end && dataSeriesType == DataSeriesType::UNKNOWN; ++it) { |
|
28 | it != end && dataSeriesType == DataSeriesType::UNKNOWN; ++it) { | |
29 | dataSeriesType = DataSeriesTypeUtils::fromString(it.value().toString()); |
|
29 | dataSeriesType = DataSeriesTypeUtils::fromString(it.value().toString()); | |
30 | } |
|
30 | } | |
31 |
|
31 | |||
32 | return dataSeriesType; |
|
32 | return dataSeriesType; | |
33 | } |
|
33 | } | |
34 |
|
34 | |||
35 |
|
35 | |||
36 | #define VP_PROPERTY(property,getter,setter,type) \ |
|
36 | #define VP_PROPERTY(property,getter,setter,type) \ | |
37 | type getter() noexcept\ |
|
37 | type getter() noexcept\ | |
38 | {\ |
|
38 | {\ | |
39 | QReadLocker lock{&m_Lock};\ |
|
39 | QReadLocker lock{&m_Lock};\ | |
40 | return property;\ |
|
40 | return property;\ | |
41 | }\ |
|
41 | }\ | |
42 | void setter(const type& getter) noexcept\ |
|
42 | void setter(const type& getter) noexcept\ | |
43 | {\ |
|
43 | {\ | |
44 | QWriteLocker lock{&m_Lock};\ |
|
44 | QWriteLocker lock{&m_Lock};\ | |
45 | property = getter;\ |
|
45 | property = getter;\ | |
46 | }\ |
|
46 | }\ | |
47 | type property;\ |
|
47 | type property;\ | |
48 |
|
48 | |||
49 | #define V_FW_GETTER_SETTER(getter,setter, type)\ |
|
49 | #define V_FW_GETTER_SETTER(getter,setter, type)\ | |
50 | type Variable::getter() const noexcept \ |
|
50 | type Variable::getter() const noexcept \ | |
51 | {\ |
|
51 | {\ | |
52 | return impl->getter();\ |
|
52 | return impl->getter();\ | |
53 | }\ |
|
53 | }\ | |
54 | void Variable::setter(const type& getter) noexcept \ |
|
54 | void Variable::setter(const type& getter) noexcept \ | |
55 | {\ |
|
55 | {\ | |
56 | impl->setter(getter);\ |
|
56 | impl->setter(getter);\ | |
|
57 | emit updated();\ | |||
57 | }\ |
|
58 | }\ | |
58 |
|
59 | |||
59 | struct Variable::VariablePrivate { |
|
60 | struct Variable::VariablePrivate { | |
60 | explicit VariablePrivate(const QString &name, const QVariantHash &metadata) |
|
61 | explicit VariablePrivate(const QString &name, const QVariantHash &metadata) | |
61 | : m_Name{name}, |
|
62 | : m_Name{name}, | |
62 | m_Range{INVALID_RANGE}, |
|
63 | m_Range{INVALID_RANGE}, | |
63 | m_CacheRange{INVALID_RANGE}, |
|
64 | m_CacheRange{INVALID_RANGE}, | |
64 | m_Metadata{metadata}, |
|
65 | m_Metadata{metadata}, | |
65 | m_DataSeries{nullptr}, |
|
66 | m_DataSeries{nullptr}, | |
66 | m_RealRange{INVALID_RANGE}, |
|
67 | m_RealRange{INVALID_RANGE}, | |
67 | m_NbPoints{0}, |
|
68 | m_NbPoints{0}, | |
68 | m_Type{findDataSeriesType(m_Metadata)} |
|
69 | m_Type{findDataSeriesType(m_Metadata)} | |
69 | { |
|
70 | { | |
70 | } |
|
71 | } | |
71 |
|
72 | |||
72 | VariablePrivate(const VariablePrivate &other) |
|
73 | VariablePrivate(const VariablePrivate &other) | |
73 | : m_Name{other.m_Name}, |
|
74 | : m_Name{other.m_Name}, | |
74 | m_Range{other.m_Range}, |
|
75 | m_Range{other.m_Range}, | |
75 | m_CacheRange{other.m_CacheRange}, |
|
76 | m_CacheRange{other.m_CacheRange}, | |
76 | m_Metadata{other.m_Metadata}, |
|
77 | m_Metadata{other.m_Metadata}, | |
77 | m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr}, |
|
78 | m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr}, | |
78 | m_RealRange{other.m_RealRange}, |
|
79 | m_RealRange{other.m_RealRange}, | |
79 | m_NbPoints{other.m_NbPoints}, |
|
80 | m_NbPoints{other.m_NbPoints}, | |
80 | m_Type{findDataSeriesType(m_Metadata)} |
|
81 | m_Type{findDataSeriesType(m_Metadata)} | |
81 | { |
|
82 | { | |
82 | } |
|
83 | } | |
83 |
|
84 | |||
84 | void lockRead() { m_Lock.lockForRead(); } |
|
85 | void lockRead() { m_Lock.lockForRead(); } | |
85 | void lockWrite() { m_Lock.lockForWrite(); } |
|
86 | void lockWrite() { m_Lock.lockForWrite(); } | |
86 | void unlock() { m_Lock.unlock(); } |
|
87 | void unlock() { m_Lock.unlock(); } | |
87 |
|
88 | |||
88 | void purgeDataSeries() |
|
89 | void purgeDataSeries() | |
89 | { |
|
90 | { | |
90 | if (m_DataSeries) { |
|
91 | if (m_DataSeries) { | |
91 | m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd); |
|
92 | m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd); | |
92 | } |
|
93 | } | |
93 | updateRealRange(); |
|
94 | updateRealRange(); | |
94 | updateNbPoints(); |
|
95 | updateNbPoints(); | |
95 | } |
|
96 | } | |
96 | void mergeDataSeries(const std::vector<IDataSeries*>& dataseries) |
|
97 | void mergeDataSeries(const std::vector<IDataSeries*>& dataseries) | |
97 | { |
|
98 | { | |
98 | QWriteLocker lock{&m_Lock}; |
|
99 | QWriteLocker lock{&m_Lock}; | |
99 | for(auto ds:dataseries) |
|
100 | for(auto ds:dataseries) | |
100 | { |
|
101 | { | |
101 | if(m_DataSeries) |
|
102 | if(m_DataSeries) | |
102 | m_DataSeries->merge(ds); |
|
103 | m_DataSeries->merge(ds); | |
103 | else |
|
104 | else | |
104 | m_DataSeries = ds->clone(); |
|
105 | m_DataSeries = ds->clone(); | |
105 | } |
|
106 | } | |
106 | } |
|
107 | } | |
107 | void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; } |
|
108 | void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; } | |
108 |
|
109 | |||
109 | /// Updates real range according to current variable range and data series |
|
110 | /// Updates real range according to current variable range and data series | |
110 | void updateRealRange() |
|
111 | void updateRealRange() | |
111 | { |
|
112 | { | |
112 | if (m_DataSeries) { |
|
113 | if (m_DataSeries) { | |
113 | auto lock = m_DataSeries->getReadLock(); |
|
114 | auto lock = m_DataSeries->getReadLock(); | |
114 | auto end = m_DataSeries->cend(); |
|
115 | auto end = m_DataSeries->cend(); | |
115 | auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart); |
|
116 | auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart); | |
116 | auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd); |
|
117 | auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd); | |
117 | if(minXAxisIt != end && maxXAxisIt != end && minXAxisIt->x() <= maxXAxisIt->x()) |
|
118 | if(minXAxisIt != end && maxXAxisIt != end && minXAxisIt->x() <= maxXAxisIt->x()) | |
118 | m_RealRange = DateTimeRange{minXAxisIt->x(), maxXAxisIt->x()}; |
|
119 | m_RealRange = DateTimeRange{minXAxisIt->x(), maxXAxisIt->x()}; | |
119 | else |
|
120 | else | |
120 | m_RealRange = std::nullopt; |
|
121 | m_RealRange = std::nullopt; | |
121 | } |
|
122 | } | |
122 | else { |
|
123 | else { | |
123 | m_RealRange = std::nullopt; |
|
124 | m_RealRange = std::nullopt; | |
124 | } |
|
125 | } | |
125 | } |
|
126 | } | |
126 |
|
127 | |||
127 | VP_PROPERTY(m_Name, name, setName, QString) |
|
128 | VP_PROPERTY(m_Name, name, setName, QString) | |
128 | VP_PROPERTY(m_Range, range, setRange, DateTimeRange) |
|
129 | VP_PROPERTY(m_Range, range, setRange, DateTimeRange) | |
129 | VP_PROPERTY(m_CacheRange, cacheRange, setCacheRange, DateTimeRange) |
|
130 | VP_PROPERTY(m_CacheRange, cacheRange, setCacheRange, DateTimeRange) | |
130 | VP_PROPERTY(m_Metadata, metadata, setMetadata, QVariantHash) |
|
131 | VP_PROPERTY(m_Metadata, metadata, setMetadata, QVariantHash) | |
131 | VP_PROPERTY(m_DataSeries, dataSeries, setDataSeries, std::shared_ptr<IDataSeries>) |
|
132 | VP_PROPERTY(m_DataSeries, dataSeries, setDataSeries, std::shared_ptr<IDataSeries>) | |
132 | VP_PROPERTY(m_RealRange, realRange, setRealRange, std::optional<DateTimeRange>) |
|
133 | VP_PROPERTY(m_RealRange, realRange, setRealRange, std::optional<DateTimeRange>) | |
133 | unsigned int m_NbPoints; |
|
134 | unsigned int m_NbPoints; | |
134 | VP_PROPERTY(m_Type, type, setType, DataSeriesType) |
|
135 | VP_PROPERTY(m_Type, type, setType, DataSeriesType) | |
135 | QReadWriteLock m_Lock; |
|
136 | QReadWriteLock m_Lock; | |
136 | }; |
|
137 | }; | |
137 |
|
138 | |||
138 | Variable::Variable(const QString &name, const QVariantHash &metadata) |
|
139 | Variable::Variable(const QString &name, const QVariantHash &metadata) | |
139 | : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}, |
|
140 | : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}, | |
140 | _uuid{QUuid::createUuid()} |
|
141 | _uuid{QUuid::createUuid()} | |
141 | { |
|
142 | { | |
142 | } |
|
143 | } | |
143 |
|
144 | |||
144 | Variable::Variable(const Variable &other) |
|
145 | Variable::Variable(const Variable &other) | |
145 | : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}, |
|
146 | : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}, | |
146 | _uuid{QUuid::createUuid()} //is a clone but must have a != uuid |
|
147 | _uuid{QUuid::createUuid()} //is a clone but must have a != uuid | |
147 | { |
|
148 | { | |
148 | } |
|
149 | } | |
149 |
|
150 | |||
150 | std::shared_ptr<Variable> Variable::clone() const |
|
151 | std::shared_ptr<Variable> Variable::clone() const | |
151 | { |
|
152 | { | |
152 | return std::make_shared<Variable>(*this); |
|
153 | return std::make_shared<Variable>(*this); | |
153 | } |
|
154 | } | |
154 |
|
155 | |||
155 | V_FW_GETTER_SETTER(name,setName,QString) |
|
156 | V_FW_GETTER_SETTER(name,setName,QString) | |
156 |
|
157 | |||
157 | DateTimeRange Variable::range() const noexcept |
|
158 | DateTimeRange Variable::range() const noexcept | |
158 | { |
|
159 | { | |
159 | return impl->range(); |
|
160 | return impl->range(); | |
160 | } |
|
161 | } | |
161 |
|
162 | |||
162 | void Variable::setRange(const DateTimeRange &range, bool notify) noexcept |
|
163 | void Variable::setRange(const DateTimeRange &range, bool notify) noexcept | |
163 | { |
|
164 | { | |
164 | impl->setRange(range); |
|
165 | impl->setRange(range); | |
165 | impl->updateRealRange(); |
|
166 | impl->updateRealRange(); | |
166 | if(notify) |
|
167 | if(notify) | |
167 | emit this->updated(); |
|
168 | emit this->updated(); | |
168 | } |
|
169 | } | |
169 |
|
170 | |||
170 | V_FW_GETTER_SETTER(cacheRange, setCacheRange, DateTimeRange) |
|
171 | V_FW_GETTER_SETTER(cacheRange, setCacheRange, DateTimeRange) | |
171 |
|
172 | |||
172 | unsigned int Variable::nbPoints() const noexcept |
|
173 | unsigned int Variable::nbPoints() const noexcept | |
173 | { |
|
174 | { | |
174 | return impl->m_NbPoints; |
|
175 | return impl->m_NbPoints; | |
175 | } |
|
176 | } | |
176 |
|
177 | |||
177 | std::optional<DateTimeRange> Variable::realRange() const noexcept |
|
178 | std::optional<DateTimeRange> Variable::realRange() const noexcept | |
178 | { |
|
179 | { | |
179 | return impl->realRange(); |
|
180 | return impl->realRange(); | |
180 | } |
|
181 | } | |
181 |
|
182 | |||
182 | void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept |
|
|||
183 | { |
|
|||
184 | qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries" |
|
|||
185 | << QThread::currentThread()->objectName(); |
|
|||
186 | if (!dataSeries) { |
|
|||
187 | /// @todo ALX : log |
|
|||
188 | return; |
|
|||
189 | } |
|
|||
190 |
|
||||
191 | auto dataInit = false; |
|
|||
192 |
|
||||
193 | // Add or merge the data |
|
|||
194 | impl->lockWrite(); |
|
|||
195 | if (!impl->m_DataSeries) { |
|
|||
196 | impl->m_DataSeries = dataSeries->clone(); |
|
|||
197 | dataInit = true; |
|
|||
198 | } |
|
|||
199 | else { |
|
|||
200 | impl->m_DataSeries->merge(dataSeries.get()); |
|
|||
201 | } |
|
|||
202 | impl->purgeDataSeries(); |
|
|||
203 | impl->unlock(); |
|
|||
204 |
|
||||
205 | if (dataInit) { |
|
|||
206 | emit dataInitialized(); |
|
|||
207 | } |
|
|||
208 | } |
|
|||
209 |
|
||||
210 | void Variable::updateData(const std::vector<IDataSeries *> &dataSeries, const DateTimeRange &newRange, const DateTimeRange &newCacheRange, bool notify) |
|
183 | void Variable::updateData(const std::vector<IDataSeries *> &dataSeries, const DateTimeRange &newRange, const DateTimeRange &newCacheRange, bool notify) | |
211 | { |
|
184 | { | |
212 | { |
|
185 | { | |
213 | QWriteLocker lock{&m_lock}; |
|
186 | QWriteLocker lock{&m_lock}; | |
214 | impl->mergeDataSeries(dataSeries); |
|
187 | impl->mergeDataSeries(dataSeries); | |
215 | impl->setRange(newRange); |
|
188 | impl->setRange(newRange); | |
216 | impl->setCacheRange(newCacheRange); |
|
189 | impl->setCacheRange(newCacheRange); | |
217 | impl->purgeDataSeries(); |
|
190 | impl->purgeDataSeries(); | |
218 | } |
|
191 | } | |
219 | if(notify) |
|
192 | if(notify) | |
220 | emit updated(); |
|
193 | emit updated(); | |
221 | } |
|
194 | } | |
222 |
|
195 | |||
223 |
|
196 | |||
224 | std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept |
|
197 | std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept | |
225 | { |
|
198 | { | |
226 | return impl->dataSeries(); |
|
199 | return impl->dataSeries(); | |
227 | } |
|
200 | } | |
228 |
|
201 | |||
229 | DataSeriesType Variable::type() const noexcept |
|
202 | DataSeriesType Variable::type() const noexcept | |
230 | { |
|
203 | { | |
231 | return impl->type(); |
|
204 | return impl->type(); | |
232 | } |
|
205 | } | |
233 |
|
206 | |||
234 | QVariantHash Variable::metadata() const noexcept |
|
207 | QVariantHash Variable::metadata() const noexcept | |
235 | { |
|
208 | { | |
236 | impl->lockRead(); |
|
209 | impl->lockRead(); | |
237 | auto metadata = impl->m_Metadata; |
|
210 | auto metadata = impl->m_Metadata; | |
238 | impl->unlock(); |
|
211 | impl->unlock(); | |
239 | return metadata; |
|
212 | return metadata; | |
240 | } |
|
213 | } | |
241 |
|
214 | |||
242 | bool Variable::contains(const DateTimeRange &range) const noexcept |
|
|||
243 | { |
|
|||
244 | impl->lockRead(); |
|
|||
245 | auto res = impl->m_Range.contains(range); |
|
|||
246 | impl->unlock(); |
|
|||
247 | return res; |
|
|||
248 | } |
|
|||
249 |
|
||||
250 | bool Variable::intersect(const DateTimeRange &range) const noexcept |
|
|||
251 | { |
|
|||
252 |
|
||||
253 | impl->lockRead(); |
|
|||
254 | auto res = impl->m_Range.intersect(range); |
|
|||
255 | impl->unlock(); |
|
|||
256 | return res; |
|
|||
257 | } |
|
|||
258 |
|
||||
259 | bool Variable::isInside(const DateTimeRange &range) const noexcept |
|
|||
260 | { |
|
|||
261 | impl->lockRead(); |
|
|||
262 | auto res = range.contains(DateTimeRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd}); |
|
|||
263 | impl->unlock(); |
|
|||
264 | return res; |
|
|||
265 | } |
|
|||
266 |
|
||||
267 | bool Variable::cacheContains(const DateTimeRange &range) const noexcept |
|
|||
268 | { |
|
|||
269 | impl->lockRead(); |
|
|||
270 | auto res = impl->m_CacheRange.contains(range); |
|
|||
271 | impl->unlock(); |
|
|||
272 | return res; |
|
|||
273 | } |
|
|||
274 |
|
||||
275 | bool Variable::cacheIntersect(const DateTimeRange &range) const noexcept |
|
|||
276 | { |
|
|||
277 | impl->lockRead(); |
|
|||
278 | auto res = impl->m_CacheRange.intersect(range); |
|
|||
279 | impl->unlock(); |
|
|||
280 | return res; |
|
|||
281 | } |
|
|||
282 |
|
||||
283 | bool Variable::cacheIsInside(const DateTimeRange &range) const noexcept |
|
|||
284 | { |
|
|||
285 | impl->lockRead(); |
|
|||
286 | auto res = range.contains(DateTimeRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd}); |
|
|||
287 | impl->unlock(); |
|
|||
288 | return res; |
|
|||
289 | } |
|
|||
290 |
|
||||
291 |
|
||||
292 | QVector<DateTimeRange> Variable::provideNotInCacheRangeList(const DateTimeRange &range) const noexcept |
|
|||
293 | { |
|
|||
294 | // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange |
|
|||
295 | auto notInCache = QVector<DateTimeRange>{}; |
|
|||
296 | if (impl->m_CacheRange != INVALID_RANGE) { |
|
|||
297 |
|
||||
298 | if (!this->cacheContains(range)) { |
|
|||
299 | if (range.m_TEnd <= impl->m_CacheRange.m_TStart |
|
|||
300 | || range.m_TStart >= impl->m_CacheRange.m_TEnd) { |
|
|||
301 | notInCache << range; |
|
|||
302 | } |
|
|||
303 | else if (range.m_TStart < impl->m_CacheRange.m_TStart |
|
|||
304 | && range.m_TEnd <= impl->m_CacheRange.m_TEnd) { |
|
|||
305 | notInCache << DateTimeRange{range.m_TStart, impl->m_CacheRange.m_TStart}; |
|
|||
306 | } |
|
|||
307 | else if (range.m_TStart < impl->m_CacheRange.m_TStart |
|
|||
308 | && range.m_TEnd > impl->m_CacheRange.m_TEnd) { |
|
|||
309 | notInCache << DateTimeRange{range.m_TStart, impl->m_CacheRange.m_TStart} |
|
|||
310 | << DateTimeRange{impl->m_CacheRange.m_TEnd, range.m_TEnd}; |
|
|||
311 | } |
|
|||
312 | else if (range.m_TStart < impl->m_CacheRange.m_TEnd) { |
|
|||
313 | notInCache << DateTimeRange{impl->m_CacheRange.m_TEnd, range.m_TEnd}; |
|
|||
314 | } |
|
|||
315 | else { |
|
|||
316 | qCCritical(LOG_Variable()) << tr("Detection of unknown case.") |
|
|||
317 | << QThread::currentThread(); |
|
|||
318 | } |
|
|||
319 | } |
|
|||
320 | } |
|
|||
321 | else { |
|
|||
322 | notInCache << range; |
|
|||
323 | } |
|
|||
324 |
|
||||
325 | return notInCache; |
|
|||
326 | } |
|
|||
327 |
|
||||
328 | QVector<DateTimeRange> Variable::provideInCacheRangeList(const DateTimeRange &range) const noexcept |
|
|||
329 | { |
|
|||
330 | // This code assume that cach in contigue. Can return 0 or 1 SqpRange |
|
|||
331 |
|
||||
332 | auto inCache = QVector<DateTimeRange>{}; |
|
|||
333 |
|
||||
334 | if (impl->m_CacheRange != INVALID_RANGE) { |
|
|||
335 |
|
||||
336 | if (this->cacheIntersect(range)) { |
|
|||
337 | if (range.m_TStart <= impl->m_CacheRange.m_TStart |
|
|||
338 | && range.m_TEnd >= impl->m_CacheRange.m_TStart |
|
|||
339 | && range.m_TEnd < impl->m_CacheRange.m_TEnd) { |
|
|||
340 | inCache << DateTimeRange{impl->m_CacheRange.m_TStart, range.m_TEnd}; |
|
|||
341 | } |
|
|||
342 |
|
||||
343 | else if (range.m_TStart >= impl->m_CacheRange.m_TStart |
|
|||
344 | && range.m_TEnd <= impl->m_CacheRange.m_TEnd) { |
|
|||
345 | inCache << range; |
|
|||
346 | } |
|
|||
347 | else if (range.m_TStart > impl->m_CacheRange.m_TStart |
|
|||
348 | && range.m_TEnd > impl->m_CacheRange.m_TEnd) { |
|
|||
349 | inCache << DateTimeRange{range.m_TStart, impl->m_CacheRange.m_TEnd}; |
|
|||
350 | } |
|
|||
351 | else if (range.m_TStart <= impl->m_CacheRange.m_TStart |
|
|||
352 | && range.m_TEnd >= impl->m_CacheRange.m_TEnd) { |
|
|||
353 | inCache << impl->m_CacheRange; |
|
|||
354 | } |
|
|||
355 | else { |
|
|||
356 | qCCritical(LOG_Variable()) << tr("Detection of unknown case.") |
|
|||
357 | << QThread::currentThread(); |
|
|||
358 | } |
|
|||
359 | } |
|
|||
360 | } |
|
|||
361 |
|
||||
362 | return inCache; |
|
|||
363 | } |
|
|||
364 |
|
||||
365 |
|
||||
366 | QVector<DateTimeRange> Variable::provideNotInCacheRangeList(const DateTimeRange &oldRange, |
|
|||
367 | const DateTimeRange &nextRange) |
|
|||
368 | { |
|
|||
369 |
|
||||
370 | // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange |
|
|||
371 | auto notInCache = QVector<DateTimeRange>{}; |
|
|||
372 | if (oldRange != INVALID_RANGE) { |
|
|||
373 |
|
||||
374 | if (!oldRange.contains(nextRange)) { |
|
|||
375 | if (nextRange.m_TEnd <= oldRange.m_TStart || nextRange.m_TStart >= oldRange.m_TEnd) { |
|
|||
376 | notInCache << nextRange; |
|
|||
377 | } |
|
|||
378 | else if (nextRange.m_TStart < oldRange.m_TStart |
|
|||
379 | && nextRange.m_TEnd <= oldRange.m_TEnd) { |
|
|||
380 | notInCache << DateTimeRange{nextRange.m_TStart, oldRange.m_TStart}; |
|
|||
381 | } |
|
|||
382 | else if (nextRange.m_TStart < oldRange.m_TStart && nextRange.m_TEnd > oldRange.m_TEnd) { |
|
|||
383 | notInCache << DateTimeRange{nextRange.m_TStart, oldRange.m_TStart} |
|
|||
384 | << DateTimeRange{oldRange.m_TEnd, nextRange.m_TEnd}; |
|
|||
385 | } |
|
|||
386 | else if (nextRange.m_TStart < oldRange.m_TEnd) { |
|
|||
387 | notInCache << DateTimeRange{oldRange.m_TEnd, nextRange.m_TEnd}; |
|
|||
388 | } |
|
|||
389 | else { |
|
|||
390 | qCCritical(LOG_Variable()) << tr("Detection of unknown case.") |
|
|||
391 | << QThread::currentThread(); |
|
|||
392 | } |
|
|||
393 | } |
|
|||
394 | } |
|
|||
395 | else { |
|
|||
396 | notInCache << nextRange; |
|
|||
397 | } |
|
|||
398 |
|
||||
399 | return notInCache; |
|
|||
400 | } |
|
|||
401 |
|
||||
402 | QVector<DateTimeRange> Variable::provideInCacheRangeList(const DateTimeRange &oldRange, |
|
|||
403 | const DateTimeRange &nextRange) |
|
|||
404 | { |
|
|||
405 | // This code assume that cach is contigue. Can return 0 or 1 SqpRange |
|
|||
406 |
|
||||
407 | auto inCache = QVector<DateTimeRange>{}; |
|
|||
408 |
|
||||
409 | if (oldRange != INVALID_RANGE) { |
|
|||
410 |
|
||||
411 | if (oldRange.intersect(nextRange)) { |
|
|||
412 | if (nextRange.m_TStart <= oldRange.m_TStart && nextRange.m_TEnd >= oldRange.m_TStart |
|
|||
413 | && nextRange.m_TEnd < oldRange.m_TEnd) { |
|
|||
414 | inCache << DateTimeRange{oldRange.m_TStart, nextRange.m_TEnd}; |
|
|||
415 | } |
|
|||
416 |
|
||||
417 | else if (nextRange.m_TStart >= oldRange.m_TStart |
|
|||
418 | && nextRange.m_TEnd <= oldRange.m_TEnd) { |
|
|||
419 | inCache << nextRange; |
|
|||
420 | } |
|
|||
421 | else if (nextRange.m_TStart > oldRange.m_TStart && nextRange.m_TEnd > oldRange.m_TEnd) { |
|
|||
422 | inCache << DateTimeRange{nextRange.m_TStart, oldRange.m_TEnd}; |
|
|||
423 | } |
|
|||
424 | else if (nextRange.m_TStart <= oldRange.m_TStart |
|
|||
425 | && nextRange.m_TEnd >= oldRange.m_TEnd) { |
|
|||
426 | inCache << oldRange; |
|
|||
427 | } |
|
|||
428 | else { |
|
|||
429 | qCCritical(LOG_Variable()) << tr("Detection of unknown case.") |
|
|||
430 | << QThread::currentThread(); |
|
|||
431 | } |
|
|||
432 | } |
|
|||
433 | } |
|
|||
434 |
|
||||
435 | return inCache; |
|
|||
436 | } |
|
@@ -1,410 +1,23 | |||||
1 | #include <Variable/Variable.h> |
|
1 | #include <Variable/Variable.h> | |
2 |
|
2 | |||
3 | #include <Data/ScalarSeries.h> |
|
3 | #include <Data/ScalarSeries.h> | |
4 |
|
4 | |||
5 | #include <QObject> |
|
5 | #include <QObject> | |
6 | #include <QtTest> |
|
6 | #include <QtTest> | |
7 |
|
7 | |||
8 | #include <memory> |
|
8 | #include <memory> | |
9 |
|
9 | |||
10 | namespace { |
|
|||
11 |
|
10 | |||
12 | /// Generates a date in double |
|
|||
13 | auto date = [](int year, int month, int day, int hours, int minutes, int seconds) { |
|
|||
14 | return DateUtils::secondsSinceEpoch( |
|
|||
15 | QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC}); |
|
|||
16 | }; |
|
|||
17 |
|
||||
18 | /// Generates a series of test data for a range |
|
|||
19 | std::shared_ptr<ScalarSeries> dataSeries(const DateTimeRange &range) |
|
|||
20 | { |
|
|||
21 | auto xAxisData = std::vector<double>{}; |
|
|||
22 | auto valuesData = std::vector<double>{}; |
|
|||
23 |
|
||||
24 | auto value = 0; |
|
|||
25 | for (auto x = range.m_TStart; x <= range.m_TEnd; ++x, ++value) { |
|
|||
26 | xAxisData.push_back(x); |
|
|||
27 | valuesData.push_back(value); |
|
|||
28 | } |
|
|||
29 |
|
||||
30 | return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{}, |
|
|||
31 | Unit{}); |
|
|||
32 | } |
|
|||
33 |
|
||||
34 | } // namespace |
|
|||
35 |
|
||||
36 | Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>) |
|
|||
37 |
|
11 | |||
38 | class TestVariable : public QObject { |
|
12 | class TestVariable : public QObject { | |
39 | Q_OBJECT |
|
13 | Q_OBJECT | |
40 |
|
14 | |||
41 | private slots: |
|
15 | private slots: | |
42 |
void initTestCase() { QSKIP(" |
|
16 | void initTestCase() { QSKIP("Please Write me! .·´¯`(>β<)´¯`Β·. "); } | |
43 | void testClone_data(); |
|
|||
44 | void testClone(); |
|
|||
45 |
|
||||
46 | void testNotInCacheRangeList(); |
|
|||
47 | void testInCacheRangeList(); |
|
|||
48 |
|
||||
49 | void testNbPoints_data(); |
|
|||
50 | void testNbPoints(); |
|
|||
51 |
|
||||
52 | void testRealRange_data(); |
|
|||
53 | void testRealRange(); |
|
|||
54 | }; |
|
17 | }; | |
55 |
|
18 | |||
56 | void TestVariable::testClone_data() |
|
|||
57 | { |
|
|||
58 | // ////////////// // |
|
|||
59 | // Test structure // |
|
|||
60 | // ////////////// // |
|
|||
61 |
|
||||
62 | QTest::addColumn<QString>("name"); |
|
|||
63 | QTest::addColumn<QVariantHash>("metadata"); |
|
|||
64 | QTest::addColumn<DateTimeRange>("range"); |
|
|||
65 | QTest::addColumn<DateTimeRange>("cacheRange"); |
|
|||
66 | QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries"); |
|
|||
67 |
|
||||
68 | // ////////// // |
|
|||
69 | // Test cases // |
|
|||
70 | // ////////// // |
|
|||
71 |
|
||||
72 | auto cacheRange = DateTimeRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 13, 0, 0)}; |
|
|||
73 | QTest::newRow("clone1") << QStringLiteral("var1") |
|
|||
74 | << QVariantHash{{"data1", 1}, {"data2", "abc"}} |
|
|||
75 | << DateTimeRange{date(2017, 1, 1, 12, 30, 0), (date(2017, 1, 1, 12, 45, 0))} |
|
|||
76 | << cacheRange << dataSeries(cacheRange); |
|
|||
77 | } |
|
|||
78 |
|
||||
79 | void TestVariable::testClone() |
|
|||
80 | { |
|
|||
81 | // Creates variable |
|
|||
82 | QFETCH(QString, name); |
|
|||
83 | QFETCH(QVariantHash, metadata); |
|
|||
84 | QFETCH(DateTimeRange, range); |
|
|||
85 | QFETCH(DateTimeRange, cacheRange); |
|
|||
86 | QFETCH(std::shared_ptr<ScalarSeries>, dataSeries); |
|
|||
87 |
|
||||
88 | Variable variable{name, metadata}; |
|
|||
89 | variable.setRange(range); |
|
|||
90 | variable.setCacheRange(cacheRange); |
|
|||
91 | variable.mergeDataSeries(dataSeries); |
|
|||
92 |
|
||||
93 | // Clones variable |
|
|||
94 | auto clone = variable.clone(); |
|
|||
95 |
|
||||
96 | // Checks cloned variable's state |
|
|||
97 | QCOMPARE(clone->name(), name); |
|
|||
98 | QCOMPARE(clone->metadata(), metadata); |
|
|||
99 | QCOMPARE(clone->range(), range); |
|
|||
100 | QCOMPARE(clone->cacheRange(), cacheRange); |
|
|||
101 |
|
||||
102 | // Compares data series |
|
|||
103 | if (dataSeries != nullptr) { |
|
|||
104 | QVERIFY(clone->dataSeries() != nullptr); |
|
|||
105 | QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), clone->dataSeries()->cbegin(), |
|
|||
106 | clone->dataSeries()->cend(), [](const auto &it1, const auto &it2) { |
|
|||
107 | return it1.x() == it2.x() && it1.value() == it2.value(); |
|
|||
108 | })); |
|
|||
109 | } |
|
|||
110 | else { |
|
|||
111 | QVERIFY(clone->dataSeries() == nullptr); |
|
|||
112 | } |
|
|||
113 | } |
|
|||
114 |
|
||||
115 | void TestVariable::testNotInCacheRangeList() |
|
|||
116 | { |
|
|||
117 | auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}}; |
|
|||
118 | auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}}; |
|
|||
119 |
|
||||
120 | auto sqpR = DateTimeRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)}; |
|
|||
121 |
|
||||
122 | auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}}; |
|
|||
123 | auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}}; |
|
|||
124 |
|
||||
125 | auto sqpCR |
|
|||
126 | = DateTimeRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)}; |
|
|||
127 |
|
||||
128 | Variable var{"Var test"}; |
|
|||
129 | var.setRange(sqpR); |
|
|||
130 | var.setCacheRange(sqpCR); |
|
|||
131 |
|
||||
132 | // 1: [ts,te] < varTS |
|
|||
133 | auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}}; |
|
|||
134 | auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}}; |
|
|||
135 | auto sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
136 |
|
||||
137 | auto notInCach = var.provideNotInCacheRangeList(sqp); |
|
|||
138 |
|
||||
139 | QCOMPARE(notInCach.size(), 1); |
|
|||
140 |
|
||||
141 | auto notInCachRange = notInCach.first(); |
|
|||
142 |
|
||||
143 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts)); |
|
|||
144 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te)); |
|
|||
145 |
|
||||
146 | // 2: ts < varTS < te < varTE |
|
|||
147 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}}; |
|
|||
148 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}}; |
|
|||
149 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
150 | notInCach = var.provideNotInCacheRangeList(sqp); |
|
|||
151 | QCOMPARE(notInCach.size(), 1); |
|
|||
152 | notInCachRange = notInCach.first(); |
|
|||
153 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts)); |
|
|||
154 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS)); |
|
|||
155 |
|
||||
156 | // 3: varTS < ts < te < varTE |
|
|||
157 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}}; |
|
|||
158 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}}; |
|
|||
159 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
160 | notInCach = var.provideNotInCacheRangeList(sqp); |
|
|||
161 | QCOMPARE(notInCach.size(), 0); |
|
|||
162 |
|
||||
163 |
|
||||
164 | // 4: varTS < ts < varTE < te |
|
|||
165 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}}; |
|
|||
166 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}}; |
|
|||
167 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
168 | notInCach = var.provideNotInCacheRangeList(sqp); |
|
|||
169 | QCOMPARE(notInCach.size(), 1); |
|
|||
170 | notInCachRange = notInCach.first(); |
|
|||
171 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE)); |
|
|||
172 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te)); |
|
|||
173 |
|
||||
174 | // 5: varTS < varTE < ts < te |
|
|||
175 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}}; |
|
|||
176 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}}; |
|
|||
177 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
178 | notInCach = var.provideNotInCacheRangeList(sqp); |
|
|||
179 | QCOMPARE(notInCach.size(), 1); |
|
|||
180 | notInCachRange = notInCach.first(); |
|
|||
181 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts)); |
|
|||
182 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te)); |
|
|||
183 |
|
||||
184 | // 6: ts <varTS < varTE < te |
|
|||
185 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}}; |
|
|||
186 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}}; |
|
|||
187 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
188 | notInCach = var.provideNotInCacheRangeList(sqp); |
|
|||
189 | QCOMPARE(notInCach.size(), 2); |
|
|||
190 | notInCachRange = notInCach.first(); |
|
|||
191 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts)); |
|
|||
192 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS)); |
|
|||
193 | notInCachRange = notInCach[1]; |
|
|||
194 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE)); |
|
|||
195 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te)); |
|
|||
196 | } |
|
|||
197 |
|
||||
198 |
|
||||
199 | void TestVariable::testInCacheRangeList() |
|
|||
200 | { |
|
|||
201 | auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}}; |
|
|||
202 | auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}}; |
|
|||
203 |
|
||||
204 | auto sqpR = DateTimeRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)}; |
|
|||
205 |
|
||||
206 | auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}}; |
|
|||
207 | auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}}; |
|
|||
208 | auto sqpCR |
|
|||
209 | = DateTimeRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)}; |
|
|||
210 |
|
||||
211 | Variable var{"Var test"}; |
|
|||
212 | var.setRange(sqpR); |
|
|||
213 | var.setCacheRange(sqpCR); |
|
|||
214 |
|
||||
215 | // 1: [ts,te] < varTS |
|
|||
216 | auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}}; |
|
|||
217 | auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}}; |
|
|||
218 | auto sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
219 |
|
||||
220 | auto notInCach = var.provideInCacheRangeList(sqp); |
|
|||
221 |
|
||||
222 | QCOMPARE(notInCach.size(), 0); |
|
|||
223 |
|
||||
224 | // 2: ts < varTS < te < varTE |
|
|||
225 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}}; |
|
|||
226 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}}; |
|
|||
227 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
228 | notInCach = var.provideInCacheRangeList(sqp); |
|
|||
229 | QCOMPARE(notInCach.size(), 1); |
|
|||
230 | auto notInCachRange = notInCach.first(); |
|
|||
231 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS)); |
|
|||
232 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te)); |
|
|||
233 |
|
||||
234 | // 3: varTS < ts < te < varTE |
|
|||
235 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}}; |
|
|||
236 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}}; |
|
|||
237 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
238 | notInCach = var.provideInCacheRangeList(sqp); |
|
|||
239 | QCOMPARE(notInCach.size(), 1); |
|
|||
240 | notInCachRange = notInCach.first(); |
|
|||
241 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts)); |
|
|||
242 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te)); |
|
|||
243 |
|
||||
244 | // 4: varTS < ts < varTE < te |
|
|||
245 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}}; |
|
|||
246 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}}; |
|
|||
247 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
248 | notInCach = var.provideInCacheRangeList(sqp); |
|
|||
249 | QCOMPARE(notInCach.size(), 1); |
|
|||
250 | notInCachRange = notInCach.first(); |
|
|||
251 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts)); |
|
|||
252 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE)); |
|
|||
253 |
|
||||
254 | // 5: varTS < varTE < ts < te |
|
|||
255 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}}; |
|
|||
256 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}}; |
|
|||
257 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
258 | notInCach = var.provideInCacheRangeList(sqp); |
|
|||
259 | QCOMPARE(notInCach.size(), 0); |
|
|||
260 |
|
||||
261 | // 6: ts <varTS < varTE < te |
|
|||
262 | ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}}; |
|
|||
263 | te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}}; |
|
|||
264 | sqp = DateTimeRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)}; |
|
|||
265 | notInCach = var.provideInCacheRangeList(sqp); |
|
|||
266 | QCOMPARE(notInCach.size(), 1); |
|
|||
267 | notInCachRange = notInCach.first(); |
|
|||
268 | QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS)); |
|
|||
269 | QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE)); |
|
|||
270 | } |
|
|||
271 |
|
||||
272 | namespace { |
|
|||
273 |
|
||||
274 | /// Struct used to represent an operation for @sa TestVariable::testNbPoints() |
|
|||
275 | struct NbPointsOperation { |
|
|||
276 | DateTimeRange m_CacheRange; /// Range to set for the variable |
|
|||
277 | std::shared_ptr<ScalarSeries> m_DataSeries; /// Series to merge in the variable |
|
|||
278 | int m_ExpectedNbPoints; /// Number of points in the variable expected after operation |
|
|||
279 | }; |
|
|||
280 |
|
||||
281 | using NbPointsOperations = std::vector<NbPointsOperation>; |
|
|||
282 |
|
||||
283 | } // namespace |
|
|||
284 |
|
||||
285 | Q_DECLARE_METATYPE(NbPointsOperations) |
|
|||
286 |
|
||||
287 | void TestVariable::testNbPoints_data() |
|
|||
288 | { |
|
|||
289 | // ////////////// // |
|
|||
290 | // Test structure // |
|
|||
291 | // ////////////// // |
|
|||
292 |
|
||||
293 | QTest::addColumn<NbPointsOperations>("operations"); |
|
|||
294 |
|
||||
295 | // ////////// // |
|
|||
296 | // Test cases // |
|
|||
297 | // ////////// // |
|
|||
298 | NbPointsOperations operations{}; |
|
|||
299 |
|
||||
300 | // Sets cache range (expected nb points = values data) |
|
|||
301 | auto cacheRange = DateTimeRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 9)}; |
|
|||
302 | operations.push_back({cacheRange, dataSeries(cacheRange), 10}); |
|
|||
303 |
|
||||
304 | // Doubles cache but don't add data series (expected nb points don't change) |
|
|||
305 | cacheRange = DateTimeRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)}; |
|
|||
306 | operations.push_back({cacheRange, dataSeries(INVALID_RANGE), 10}); |
|
|||
307 |
|
||||
308 | // Doubles cache and data series (expected nb points change) |
|
|||
309 | cacheRange = DateTimeRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)}; |
|
|||
310 | operations.push_back({cacheRange, dataSeries(cacheRange), 20}); |
|
|||
311 |
|
||||
312 | // Decreases cache (expected nb points decreases as the series is purged) |
|
|||
313 | cacheRange = DateTimeRange{date(2017, 1, 1, 12, 0, 5), date(2017, 1, 1, 12, 0, 9)}; |
|
|||
314 | operations.push_back({cacheRange, dataSeries(INVALID_RANGE), 5}); |
|
|||
315 |
|
||||
316 | QTest::newRow("nbPoints1") << operations; |
|
|||
317 | } |
|
|||
318 |
|
||||
319 | void TestVariable::testNbPoints() |
|
|||
320 | { |
|
|||
321 | // Creates variable |
|
|||
322 | Variable variable{"var"}; |
|
|||
323 | QCOMPARE(variable.nbPoints(), 0); |
|
|||
324 |
|
||||
325 | QFETCH(NbPointsOperations, operations); |
|
|||
326 | for (const auto &operation : operations) { |
|
|||
327 | // Sets cache range and merge data series |
|
|||
328 | variable.setCacheRange(operation.m_CacheRange); |
|
|||
329 | if (operation.m_DataSeries != nullptr) { |
|
|||
330 | variable.mergeDataSeries(operation.m_DataSeries); |
|
|||
331 | } |
|
|||
332 |
|
||||
333 | // Checks nb points |
|
|||
334 | QCOMPARE(variable.nbPoints(), operation.m_ExpectedNbPoints); |
|
|||
335 | } |
|
|||
336 | } |
|
|||
337 |
|
||||
338 | namespace { |
|
|||
339 |
|
||||
340 | /// Struct used to represent a range operation on a variable |
|
|||
341 | /// @sa TestVariable::testRealRange() |
|
|||
342 | struct RangeOperation { |
|
|||
343 | DateTimeRange m_CacheRange; /// Range to set for the variable |
|
|||
344 | std::shared_ptr<ScalarSeries> m_DataSeries; /// Series to merge in the variable |
|
|||
345 | DateTimeRange m_ExpectedRealRange; /// Real Range expected after operation on the variable |
|
|||
346 | }; |
|
|||
347 |
|
||||
348 | using RangeOperations = std::vector<RangeOperation>; |
|
|||
349 |
|
||||
350 | } // namespace |
|
|||
351 |
|
||||
352 | Q_DECLARE_METATYPE(RangeOperations) |
|
|||
353 |
|
||||
354 | void TestVariable::testRealRange_data() |
|
|||
355 | { |
|
|||
356 | // ////////////// // |
|
|||
357 | // Test structure // |
|
|||
358 | // ////////////// // |
|
|||
359 |
|
||||
360 | QTest::addColumn<RangeOperations>("operations"); |
|
|||
361 |
|
||||
362 | // ////////// // |
|
|||
363 | // Test cases // |
|
|||
364 | // ////////// // |
|
|||
365 | RangeOperations operations{}; |
|
|||
366 |
|
||||
367 | // Inits cache range and data series (expected real range = cache range) |
|
|||
368 | auto cacheRange = DateTimeRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 13, 0, 0)}; |
|
|||
369 | operations.push_back({cacheRange, dataSeries(cacheRange), cacheRange}); |
|
|||
370 |
|
||||
371 | // Changes cache range and updates data series (expected real range = cache range) |
|
|||
372 | cacheRange = DateTimeRange{date(2017, 1, 1, 14, 0, 0), date(2017, 1, 1, 15, 0, 0)}; |
|
|||
373 | operations.push_back({cacheRange, dataSeries(cacheRange), cacheRange}); |
|
|||
374 |
|
||||
375 | // Changes cache range and update data series but with a lower range (expected real range = |
|
|||
376 | // data series range) |
|
|||
377 | cacheRange = DateTimeRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 16, 0, 0)}; |
|
|||
378 | auto dataSeriesRange = DateTimeRange{date(2017, 1, 1, 14, 0, 0), date(2017, 1, 1, 15, 0, 0)}; |
|
|||
379 | operations.push_back({cacheRange, dataSeries(dataSeriesRange), dataSeriesRange}); |
|
|||
380 |
|
||||
381 | // Changes cache range but DON'T update data series (expected real range = cache range |
|
|||
382 | // before operation) |
|
|||
383 | cacheRange = DateTimeRange{date(2017, 1, 1, 10, 0, 0), date(2017, 1, 1, 17, 0, 0)}; |
|
|||
384 | operations.push_back({cacheRange, nullptr, dataSeriesRange}); |
|
|||
385 |
|
||||
386 | QTest::newRow("realRange1") << operations; |
|
|||
387 | } |
|
|||
388 |
|
||||
389 | void TestVariable::testRealRange() |
|
|||
390 | { |
|
|||
391 | // Creates variable (real range is invalid) |
|
|||
392 | Variable variable{"var"}; |
|
|||
393 | QCOMPARE(variable.realRange(), INVALID_RANGE); |
|
|||
394 |
|
||||
395 | QFETCH(RangeOperations, operations); |
|
|||
396 | for (const auto &operation : operations) { |
|
|||
397 | // Sets cache range and merge data series |
|
|||
398 | variable.setCacheRange(operation.m_CacheRange); |
|
|||
399 | if (operation.m_DataSeries != nullptr) { |
|
|||
400 | variable.mergeDataSeries(operation.m_DataSeries); |
|
|||
401 | } |
|
|||
402 |
|
19 | |||
403 | // Checks real range |
|
|||
404 | QCOMPARE(variable.realRange(), operation.m_ExpectedRealRange); |
|
|||
405 | } |
|
|||
406 | } |
|
|||
407 |
|
20 | |||
408 |
|
21 | |||
409 | QTEST_MAIN(TestVariable) |
|
22 | QTEST_MAIN(TestVariable) | |
410 | #include "TestVariable.moc" |
|
23 | #include "TestVariable.moc" |
General Comments 0
You need to be logged in to leave comments.
Login now