@@ -0,0 +1,187 | |||||
|
1 | #ifndef VARIANTWITHBASE_H | |||
|
2 | #define VARIANTWITHBASE_H | |||
|
3 | // stolen without any shame from | |||
|
4 | // https://tower120.github.io/2018/05/18/variant_with_base.html (•_•) ( | |||
|
5 | // •_•)>⌐■-■ (⌐■_■) | |||
|
6 | #include <cassert> | |||
|
7 | #include <tuple> | |||
|
8 | #include <type_traits> | |||
|
9 | #include <variant> | |||
|
10 | ||||
|
11 | template<class Base, class Variant> class variant_w_base | |||
|
12 | { | |||
|
13 | using Self = variant_w_base<Base, Variant>; | |||
|
14 | ||||
|
15 | auto& self_mut() const { return *const_cast<Self*>(this); } | |||
|
16 | ||||
|
17 | Base* m_base; | |||
|
18 | Variant m_variant; | |||
|
19 | ||||
|
20 | void update_base() | |||
|
21 | { | |||
|
22 | m_base = std::visit( | |||
|
23 | [](auto&& arg) -> Base* { | |||
|
24 | using Arg = std::decay_t<decltype(arg)>; | |||
|
25 | if constexpr(std::is_same_v<Arg, std::monostate>) { return nullptr; } | |||
|
26 | else | |||
|
27 | { | |||
|
28 | return static_cast<Base*>(&arg); | |||
|
29 | } | |||
|
30 | }, | |||
|
31 | m_variant); | |||
|
32 | } | |||
|
33 | template<class T> void update_base() | |||
|
34 | { | |||
|
35 | using Arg = std::decay_t<T>; | |||
|
36 | if constexpr(std::is_same_v<Arg, std::monostate>) { m_base = nullptr; } | |||
|
37 | else | |||
|
38 | { | |||
|
39 | m_base = std::get_if<Arg>(&m_variant); | |||
|
40 | assert(m_base); | |||
|
41 | } | |||
|
42 | } | |||
|
43 | ||||
|
44 | template<class T> | |||
|
45 | using is_not_self = std::enable_if_t<!std::is_same_v<std::decay_t<T>, Self>>; | |||
|
46 | ||||
|
47 | public: | |||
|
48 | variant_w_base() { update_base(); } | |||
|
49 | variant_w_base(const variant_w_base& other) : m_variant(other.m_variant) | |||
|
50 | { | |||
|
51 | update_base(); | |||
|
52 | } | |||
|
53 | variant_w_base(variant_w_base&& other) : m_variant(std::move(other.m_variant)) | |||
|
54 | { | |||
|
55 | update_base(); | |||
|
56 | } | |||
|
57 | variant_w_base(const Variant& var) : m_variant(var) { update_base(); } | |||
|
58 | variant_w_base(Variant&& var) : m_variant(std::move(var)) { update_base(); } | |||
|
59 | template<class T, typename = is_not_self<T>> | |||
|
60 | variant_w_base(T&& value) : m_variant(std::forward<T>(value)) | |||
|
61 | { | |||
|
62 | update_base<T>(); | |||
|
63 | } | |||
|
64 | template<class T, class... Args> | |||
|
65 | explicit variant_w_base(std::in_place_type_t<T>, Args&&... args) | |||
|
66 | : m_variant(std::in_place_type_t<T>(), std::forward<Args>(args)...) | |||
|
67 | { | |||
|
68 | update_base<T>(); | |||
|
69 | } | |||
|
70 | ||||
|
71 | variant_w_base& operator=(const variant_w_base& other) | |||
|
72 | { | |||
|
73 | m_variant = other.m_variant; | |||
|
74 | update_base(); | |||
|
75 | return *this; | |||
|
76 | } | |||
|
77 | variant_w_base& operator=(variant_w_base&& other) | |||
|
78 | { | |||
|
79 | m_variant = std::move(other.m_variant); | |||
|
80 | update_base(); | |||
|
81 | return *this; | |||
|
82 | } | |||
|
83 | ||||
|
84 | template<class T, typename = is_not_self<T>> | |||
|
85 | variant_w_base& operator=(T&& value) | |||
|
86 | { | |||
|
87 | m_variant = std::forward<T>(value); | |||
|
88 | update_base<T>(); | |||
|
89 | return *this; | |||
|
90 | } | |||
|
91 | variant_w_base& operator=(const Variant& var) | |||
|
92 | { | |||
|
93 | m_variant = var; | |||
|
94 | update_base(); | |||
|
95 | return *this; | |||
|
96 | } | |||
|
97 | variant_w_base& operator=(Variant&& var) | |||
|
98 | { | |||
|
99 | m_variant = std::move(var); | |||
|
100 | update_base(); | |||
|
101 | return *this; | |||
|
102 | } | |||
|
103 | constexpr std::size_t index() const noexcept { return m_variant.index(); } | |||
|
104 | constexpr bool operator==(const variant_w_base& other) const | |||
|
105 | { | |||
|
106 | return m_variant == other.m_variant; | |||
|
107 | } | |||
|
108 | constexpr bool operator!=(const variant_w_base& other) const | |||
|
109 | { | |||
|
110 | return m_variant != other.m_variant; | |||
|
111 | } | |||
|
112 | ||||
|
113 | // free functions from std::variant | |||
|
114 | template<class T> constexpr T* get_if() | |||
|
115 | { | |||
|
116 | if constexpr(std::is_same_v<T, Base>) { return base(); } | |||
|
117 | else | |||
|
118 | { | |||
|
119 | return std::get_if<T>(variant()); | |||
|
120 | } | |||
|
121 | } | |||
|
122 | template<class T> constexpr const T* get_if() const | |||
|
123 | { | |||
|
124 | return self_mut().template get<T>(); | |||
|
125 | } | |||
|
126 | ||||
|
127 | template<std::size_t I> constexpr decltype(auto) get_if() | |||
|
128 | { | |||
|
129 | return std::get_if<I>(variant()); | |||
|
130 | } | |||
|
131 | template<std::size_t I> constexpr decltype(auto) get_if() const | |||
|
132 | { | |||
|
133 | return std::get_if<I>(variant()); | |||
|
134 | } | |||
|
135 | ||||
|
136 | template<class T> constexpr T& get() | |||
|
137 | { | |||
|
138 | if constexpr(std::is_same_v<T, Base>) | |||
|
139 | { | |||
|
140 | if(base() == nullptr) { throw std::bad_variant_access(); } | |||
|
141 | return *base(); | |||
|
142 | } | |||
|
143 | else | |||
|
144 | { | |||
|
145 | return std::get<T>(variant()); | |||
|
146 | } | |||
|
147 | } | |||
|
148 | template<class T> constexpr const T& get() const | |||
|
149 | { | |||
|
150 | return self_mut().template get<T>(); | |||
|
151 | } | |||
|
152 | ||||
|
153 | template<std::size_t I> constexpr decltype(auto) get() | |||
|
154 | { | |||
|
155 | return std::get<I>(variant()); | |||
|
156 | } | |||
|
157 | template<std::size_t I> constexpr decltype(auto) get() const | |||
|
158 | { | |||
|
159 | return std::get<I>(variant()); | |||
|
160 | } | |||
|
161 | ||||
|
162 | template<class Visitor> constexpr decltype(auto) visit(Visitor&& vis) | |||
|
163 | { | |||
|
164 | return std::visit(std::forward<Visitor>(vis), variant()); | |||
|
165 | } | |||
|
166 | template<class Visitor> constexpr decltype(auto) visit(Visitor&& vis) const | |||
|
167 | { | |||
|
168 | return std::visit(std::forward<Visitor>(vis), variant()); | |||
|
169 | } | |||
|
170 | ||||
|
171 | Base* base() noexcept { return m_base; } | |||
|
172 | const Base* base() const noexcept { return m_base; } | |||
|
173 | operator Base&() noexcept { return *m_base; } | |||
|
174 | operator const Base&() const noexcept { return *m_base; } | |||
|
175 | Base* operator->() noexcept { return m_base; } | |||
|
176 | const Base* operator->() const noexcept { return m_base; } | |||
|
177 | Base& operator*() noexcept { return m_base; } | |||
|
178 | const Base& operator*() const noexcept { return m_base; } | |||
|
179 | ||||
|
180 | constexpr const Variant& variant() const noexcept { return m_variant; } | |||
|
181 | ||||
|
182 | private: | |||
|
183 | // hide, to keep variant type change tracked. | |||
|
184 | constexpr Variant& variant() noexcept { return m_variant; } | |||
|
185 | }; | |||
|
186 | ||||
|
187 | #endif // VARIANTWITHBASE_H |
@@ -0,0 +1,97 | |||||
|
1 | #ifndef SCIQLOP_VARIABLE2_H | |||
|
2 | #define SCIQLOP_VARIABLE2_H | |||
|
3 | ||||
|
4 | #include "CoreGlobal.h" | |||
|
5 | ||||
|
6 | #include <Common/MetaTypes.h> | |||
|
7 | #include <Common/deprecate.h> | |||
|
8 | #include <Common/spimpl.h> | |||
|
9 | #include <Common/variant_with_base.h> | |||
|
10 | #include <Data/DataSeriesType.h> | |||
|
11 | #include <Data/DateTimeRange.h> | |||
|
12 | #include <Data/ScalarTimeSerie.h> | |||
|
13 | #include <Data/VectorTimeSerie.h> | |||
|
14 | #include <QDataStream> | |||
|
15 | #include <QObject> | |||
|
16 | #include <QReadWriteLock> | |||
|
17 | #include <QUuid> | |||
|
18 | #include <TimeSeries.h> | |||
|
19 | #include <optional> | |||
|
20 | ||||
|
21 | using AnyTimeSerie = variant_w_base< | |||
|
22 | TimeSeries::ITimeSerie, | |||
|
23 | std::variant<std::monostate, ScalarTimeSerie, VectorTimeSerie>>; | |||
|
24 | ||||
|
25 | class SCIQLOP_CORE_EXPORT Variable2 : public QObject | |||
|
26 | { | |||
|
27 | Q_OBJECT | |||
|
28 | ||||
|
29 | public: | |||
|
30 | explicit Variable2(const QString& name, const QVariantHash& metadata = {}); | |||
|
31 | ||||
|
32 | /// Copy ctor | |||
|
33 | explicit Variable2(const Variable2& other); | |||
|
34 | ||||
|
35 | std::shared_ptr<Variable2> clone() const; | |||
|
36 | ||||
|
37 | QString name() const noexcept; | |||
|
38 | void setName(const QString& name) noexcept; | |||
|
39 | DateTimeRange range() const noexcept; | |||
|
40 | std::optional<DateTimeRange> realRange() const noexcept; | |||
|
41 | ||||
|
42 | std::size_t nbPoints() const noexcept; | |||
|
43 | ||||
|
44 | /// @return the data of the variable, nullptr if there is no data | |||
|
45 | AnyTimeSerie* data() const noexcept; | |||
|
46 | ||||
|
47 | /// @return the type of data that the variable holds | |||
|
48 | DataSeriesType type() const noexcept; | |||
|
49 | ||||
|
50 | QVariantHash metadata() const noexcept; | |||
|
51 | ||||
|
52 | void setData(const std::vector<AnyTimeSerie*>& dataSeries, | |||
|
53 | const DateTimeRange& range, bool notify = true); | |||
|
54 | ||||
|
55 | static QByteArray | |||
|
56 | mimeData(const std::vector<std::shared_ptr<Variable2>>& variables) | |||
|
57 | { | |||
|
58 | auto encodedData = QByteArray{}; | |||
|
59 | QDataStream stream{&encodedData, QIODevice::WriteOnly}; | |||
|
60 | for(auto& var : variables) | |||
|
61 | { | |||
|
62 | stream << var->ID().toByteArray(); | |||
|
63 | } | |||
|
64 | return encodedData; | |||
|
65 | } | |||
|
66 | ||||
|
67 | static std::vector<QUuid> IDs(QByteArray mimeData) | |||
|
68 | { | |||
|
69 | std::vector<QUuid> variables; | |||
|
70 | QDataStream stream{mimeData}; | |||
|
71 | ||||
|
72 | QVariantList ids; | |||
|
73 | stream >> ids; | |||
|
74 | std::transform(std::cbegin(ids), std::cend(ids), | |||
|
75 | std::back_inserter(variables), | |||
|
76 | [](const auto& id) { return id.toByteArray(); }); | |||
|
77 | return variables; | |||
|
78 | } | |||
|
79 | ||||
|
80 | operator QUuid() { return _uuid; } | |||
|
81 | QUuid ID() { return _uuid; } | |||
|
82 | signals: | |||
|
83 | void updated(QUuid ID); | |||
|
84 | ||||
|
85 | private: | |||
|
86 | struct VariablePrivate; | |||
|
87 | spimpl::unique_impl_ptr<VariablePrivate> impl; | |||
|
88 | QUuid _uuid; | |||
|
89 | QReadWriteLock m_lock; | |||
|
90 | }; | |||
|
91 | ||||
|
92 | // Required for using shared_ptr in signals/slots | |||
|
93 | // SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable2>) | |||
|
94 | // SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, | |||
|
95 | // QVector<std::shared_ptr<Variable2>>) | |||
|
96 | ||||
|
97 | #endif // SCIQLOP_VARIABLE2_H |
@@ -0,0 +1,123 | |||||
|
1 | #include "Variable/Variable2.h" | |||
|
2 | ||||
|
3 | #define PROPERTY_(property, getter, setter, type) \ | |||
|
4 | type getter() noexcept \ | |||
|
5 | { \ | |||
|
6 | QReadLocker lock{&m_Lock}; \ | |||
|
7 | return property; \ | |||
|
8 | } \ | |||
|
9 | void setter(const type& getter) noexcept \ | |||
|
10 | { \ | |||
|
11 | QWriteLocker lock{&m_Lock}; \ | |||
|
12 | property = getter; \ | |||
|
13 | } \ | |||
|
14 | type property; | |||
|
15 | ||||
|
16 | #define V_FW_GETTER_SETTER(getter, setter, type) \ | |||
|
17 | type Variable2::getter() const noexcept { return impl->getter(); } \ | |||
|
18 | void Variable2::setter(const type& value) noexcept \ | |||
|
19 | { \ | |||
|
20 | impl->setter(value); \ | |||
|
21 | emit updated(this->ID()); \ | |||
|
22 | } | |||
|
23 | ||||
|
24 | struct Variable2::VariablePrivate | |||
|
25 | { | |||
|
26 | VariablePrivate(const QString& name, const QVariantHash& metadata) | |||
|
27 | : m_Name{name}, m_Range{INVALID_RANGE}, m_Metadata{metadata}, m_TimeSerie{ | |||
|
28 | nullptr} | |||
|
29 | {} | |||
|
30 | VariablePrivate(const VariablePrivate& other) {} | |||
|
31 | std::size_t nbPoints() | |||
|
32 | { | |||
|
33 | if(m_TimeSerie) return m_TimeSerie->base()->size(); | |||
|
34 | return 0; | |||
|
35 | } | |||
|
36 | DataSeriesType type() const | |||
|
37 | { | |||
|
38 | if(m_TimeSerie) return DataSeriesType(m_TimeSerie->index()); | |||
|
39 | return DataSeriesType::NONE; | |||
|
40 | } | |||
|
41 | ||||
|
42 | PROPERTY_(m_Name, name, setName, QString) | |||
|
43 | PROPERTY_(m_Range, range, setRange, DateTimeRange) | |||
|
44 | PROPERTY_(m_Metadata, metadata, setMetadata, QVariantHash) | |||
|
45 | AnyTimeSerie& dataSeries() { return *m_TimeSerie.get(); } | |||
|
46 | void setDataSeries(std::unique_ptr<AnyTimeSerie>&& timeSerie) | |||
|
47 | { | |||
|
48 | QWriteLocker lock{&m_Lock}; | |||
|
49 | m_TimeSerie = std::move(timeSerie); | |||
|
50 | } | |||
|
51 | std::unique_ptr<AnyTimeSerie> m_TimeSerie; | |||
|
52 | QReadWriteLock m_Lock; | |||
|
53 | }; | |||
|
54 | ||||
|
55 | Variable2::Variable2(const QString& name, const QVariantHash& metadata) | |||
|
56 | : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}, | |||
|
57 | _uuid{QUuid::createUuid()} | |||
|
58 | {} | |||
|
59 | ||||
|
60 | Variable2::Variable2(const Variable2& other) | |||
|
61 | : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}, | |||
|
62 | _uuid{QUuid::createUuid()} // is a clone but must have a != uuid | |||
|
63 | {} | |||
|
64 | ||||
|
65 | std::shared_ptr<Variable2> Variable2::clone() const | |||
|
66 | { | |||
|
67 | return std::make_shared<Variable2>(*this); | |||
|
68 | } | |||
|
69 | ||||
|
70 | V_FW_GETTER_SETTER(name, setName, QString) | |||
|
71 | ||||
|
72 | DateTimeRange Variable2::range() const noexcept { return impl->range(); } | |||
|
73 | ||||
|
74 | std::size_t Variable2::nbPoints() const noexcept { return impl->nbPoints(); } | |||
|
75 | ||||
|
76 | AnyTimeSerie* Variable2::data() const noexcept {} | |||
|
77 | ||||
|
78 | DataSeriesType Variable2::type() const noexcept { return impl->type(); } | |||
|
79 | ||||
|
80 | QVariantHash Variable2::metadata() const noexcept {} | |||
|
81 | ||||
|
82 | template<typename T> | |||
|
83 | void _merge(const std::vector<AnyTimeSerie*>& source, AnyTimeSerie* dest) | |||
|
84 | { | |||
|
85 | // std::for_each( | |||
|
86 | // std::cbegin(source) + 1, std::cend(source), [dest](AnyTimeSerie* | |||
|
87 | // serie) { | |||
|
88 | // std::copy(std::begin(serie->get<T>()), std::end(serie->get<T>()), | |||
|
89 | // std::back_inserter(dest->get<T>())); | |||
|
90 | // }); | |||
|
91 | } | |||
|
92 | ||||
|
93 | std::unique_ptr<AnyTimeSerie> | |||
|
94 | merge(const std::vector<AnyTimeSerie*>& dataSeries) | |||
|
95 | { | |||
|
96 | std::unique_ptr<AnyTimeSerie> ts; | |||
|
97 | *ts = *dataSeries.front(); | |||
|
98 | switch(DataSeriesType(ts->index())) | |||
|
99 | { | |||
|
100 | case DataSeriesType::NONE: break; | |||
|
101 | case DataSeriesType::SCALAR: | |||
|
102 | _merge<ScalarTimeSerie>(dataSeries, ts.get()); | |||
|
103 | break; | |||
|
104 | case DataSeriesType::VECTOR: | |||
|
105 | _merge<VectorTimeSerie>(dataSeries, ts.get()); | |||
|
106 | break; | |||
|
107 | case DataSeriesType::SPECTROGRAM: | |||
|
108 | // merge<Spe>(dataSeries, ts.get()); | |||
|
109 | break; | |||
|
110 | } | |||
|
111 | return ts; | |||
|
112 | } | |||
|
113 | ||||
|
114 | void Variable2::setData(const std::vector<AnyTimeSerie*>& dataSeries, | |||
|
115 | const DateTimeRange& range, bool notify) | |||
|
116 | { | |||
|
117 | if(dataSeries.size()) | |||
|
118 | { | |||
|
119 | impl->setDataSeries(merge(dataSeries)); | |||
|
120 | impl->setRange(range); | |||
|
121 | if(notify) emit this->updated(this->ID()); | |||
|
122 | } | |||
|
123 | } |
@@ -78,6 +78,7 FILE (GLOB_RECURSE core_SRCS | |||||
78 | ./include/Common/containers.h |
|
78 | ./include/Common/containers.h | |
79 | ./include/Common/debug.h |
|
79 | ./include/Common/debug.h | |
80 | ./include/Common/cpp_utils.h |
|
80 | ./include/Common/cpp_utils.h | |
|
81 | ./include/Common/variant_with_base.h | |||
81 | ./include/Plugin/IPlugin.h |
|
82 | ./include/Plugin/IPlugin.h | |
82 | ./include/Data/ArrayDataIterator.h |
|
83 | ./include/Data/ArrayDataIterator.h | |
83 | ./include/Data/VectorSeries.h |
|
84 | ./include/Data/VectorSeries.h | |
@@ -112,6 +113,7 FILE (GLOB_RECURSE core_SRCS | |||||
112 | ./include/Variable/SingleThresholdCacheStrategy.h |
|
113 | ./include/Variable/SingleThresholdCacheStrategy.h | |
113 | ./include/Variable/VariableCacheStrategyFactory.h |
|
114 | ./include/Variable/VariableCacheStrategyFactory.h | |
114 | ./include/Variable/Variable.h |
|
115 | ./include/Variable/Variable.h | |
|
116 | ./include/Variable/Variable2.h | |||
115 | ./include/Variable/VariableController2.h |
|
117 | ./include/Variable/VariableController2.h | |
116 | ./include/Variable/private/VCTransaction.h |
|
118 | ./include/Variable/private/VCTransaction.h | |
117 | ./include/Time/TimeController.h |
|
119 | ./include/Time/TimeController.h | |
@@ -143,6 +145,7 FILE (GLOB_RECURSE core_SRCS | |||||
143 | ./src/Variable/VariableModel2.cpp |
|
145 | ./src/Variable/VariableModel2.cpp | |
144 | ./src/Variable/VariableSynchronizationGroup2.cpp |
|
146 | ./src/Variable/VariableSynchronizationGroup2.cpp | |
145 | ./src/Variable/Variable.cpp |
|
147 | ./src/Variable/Variable.cpp | |
|
148 | ./src/Variable/Variable2.cpp | |||
146 | ./src/Version.cpp |
|
149 | ./src/Version.cpp | |
147 | ./src/Time/TimeController.cpp |
|
150 | ./src/Time/TimeController.cpp | |
148 | ./src/Settings/SqpSettingsDefs.cpp |
|
151 | ./src/Settings/SqpSettingsDefs.cpp |
@@ -1,1 +1,1 | |||||
1 | Subproject commit f76d1333ff1b2a9e1629a5a79226424a8fe84f00 |
|
1 | Subproject commit ce006cf8df2b0bb3d433f901b6e80ce69119a430 |
@@ -1,1 +1,1 | |||||
1 | Subproject commit 9e6d585db2d3bea47c864622ee9f67d496aa7251 |
|
1 | Subproject commit 9c518f27796798fda36a1495b329808177c4c150 |
@@ -5,10 +5,10 | |||||
5 |
|
5 | |||
6 | enum class DataSeriesType |
|
6 | enum class DataSeriesType | |
7 | { |
|
7 | { | |
|
8 | NONE, | |||
8 | SCALAR, |
|
9 | SCALAR, | |
9 | SPECTROGRAM, |
|
|||
10 | VECTOR, |
|
10 | VECTOR, | |
11 | UNKNOWN |
|
11 | SPECTROGRAM | |
12 | }; |
|
12 | }; | |
13 |
|
13 | |||
14 | struct DataSeriesTypeUtils |
|
14 | struct DataSeriesTypeUtils | |
@@ -27,7 +27,7 struct DataSeriesTypeUtils | |||||
27 | } |
|
27 | } | |
28 | else |
|
28 | else | |
29 | { |
|
29 | { | |
30 |
return DataSeriesType:: |
|
30 | return DataSeriesType::NONE; | |
31 | } |
|
31 | } | |
32 | } |
|
32 | } | |
33 | }; |
|
33 | }; |
@@ -1,23 +1,21 | |||||
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> |
|
|||
5 |
|
||||
6 | #include <QLoggingCategory> |
|
|||
7 | #include <QObject> |
|
|||
8 | #include <QUuid> |
|
|||
9 | #include <QReadWriteLock> |
|
|||
10 | #include <QDataStream> |
|
|||
11 |
|
||||
12 | #include "CoreGlobal.h" |
|
4 | #include "CoreGlobal.h" | |
13 | #include <Data/DataSeriesIterator.h> |
|
|||
14 | #include <Data/DataSeriesType.h> |
|
|||
15 | #include <Data/DateTimeRange.h> |
|
|||
16 |
|
||||
17 |
|
5 | |||
18 | #include <Common/deprecate.h> |
|
|||
19 | #include <Common/MetaTypes.h> |
|
6 | #include <Common/MetaTypes.h> | |
|
7 | #include <Common/deprecate.h> | |||
20 | #include <Common/spimpl.h> |
|
8 | #include <Common/spimpl.h> | |
|
9 | #include <Data/DataSeriesIterator.h> | |||
|
10 | #include <Data/DataSeriesType.h> | |||
|
11 | #include <Data/DateTimeRange.h> | |||
|
12 | #include <QDataStream> | |||
|
13 | #include <QLoggingCategory> | |||
|
14 | #include <QObject> | |||
|
15 | #include <QReadWriteLock> | |||
|
16 | #include <QUuid> | |||
|
17 | #include <TimeSeries.h> | |||
|
18 | #include <optional> | |||
21 |
|
19 | |||
22 | Q_DECLARE_LOGGING_CATEGORY(LOG_Variable) |
|
20 | Q_DECLARE_LOGGING_CATEGORY(LOG_Variable) | |
23 |
|
21 | |||
@@ -27,91 +25,95 class QString; | |||||
27 | /** |
|
25 | /** | |
28 | * @brief The Variable class represents a variable in SciQlop. |
|
26 | * @brief The Variable class represents a variable in SciQlop. | |
29 | */ |
|
27 | */ | |
30 |
class SCIQLOP_CORE_EXPORT Variable : public QObject |
|
28 | class SCIQLOP_CORE_EXPORT Variable : public QObject | |
31 |
|
29 | { | ||
32 |
|
|
30 | Q_OBJECT | |
33 |
|
31 | |||
34 | public: |
|
32 | public: | |
35 |
|
|
33 | explicit Variable(const QString& name, const QVariantHash& metadata = {}); | |
36 |
|
34 | |||
37 |
|
|
35 | /// Copy ctor | |
38 |
|
|
36 | explicit Variable(const Variable& other); | |
39 |
|
37 | |||
40 |
|
|
38 | std::shared_ptr<Variable> clone() const; | |
41 |
|
39 | |||
42 |
|
|
40 | QString name() const noexcept; | |
43 |
|
|
41 | void setName(const QString& name) noexcept; | |
44 |
|
|
42 | DateTimeRange range() const noexcept; | |
45 |
|
|
43 | void setRange(const DateTimeRange& range, bool notify = false) noexcept; | |
46 |
|
|
44 | DateTimeRange cacheRange() const noexcept; | |
47 |
|
|
45 | void setCacheRange(const DateTimeRange& cacheRange) noexcept; | |
48 |
|
46 | |||
49 |
|
|
47 | /// @return the number of points hold by the variable. The number of points is | |
50 |
|
|
48 | /// updated each time the data series changes | |
51 |
|
|
49 | unsigned int nbPoints() const noexcept; | |
52 |
|
50 | |||
53 |
|
|
51 | /// Returns the real range of the variable, i.e. the min and max x-axis values | |
54 |
|
|
52 | /// of the data series between the range of the variable. The real range is | |
55 |
|
|
53 | /// updated each time the variable range or the data series changed | |
56 |
|
|
54 | /// @return the real range, invalid range if the data series is null or empty | |
57 |
|
|
55 | /// @sa setDataSeries() | |
58 |
|
|
56 | /// @sa setRange() | |
59 |
|
|
57 | std::optional<DateTimeRange> realRange() const noexcept; | |
60 |
|
58 | |||
61 |
|
|
59 | /// @return the data of the variable, nullptr if there is no data | |
62 |
|
|
60 | std::shared_ptr<IDataSeries> dataSeries() const noexcept; | |
63 |
|
61 | |||
64 |
|
|
62 | /// @return the type of data that the variable holds | |
65 |
|
|
63 | DataSeriesType type() const noexcept; | |
66 |
|
64 | |||
67 |
|
|
65 | QVariantHash metadata() const noexcept; | |
68 |
|
66 | |||
69 |
|
|
67 | void updateData(const std::vector<IDataSeries*>& dataSeries, | |
70 |
|
|
68 | const DateTimeRange& newRange, | |
71 | bool notify=true); |
|
69 | const DateTimeRange& newCacheRange, bool notify = true); | |
72 |
|
70 | |||
73 |
|
|
71 | void setData(const std::vector<IDataSeries*>& dataSeries, | |
74 |
|
|
72 | const DateTimeRange& newRange, | |
75 |
|
|
73 | const DateTimeRange& newCacheRange, bool notify = true); | |
76 |
|
74 | |||
77 | static QByteArray mimeData(const std::vector<std::shared_ptr<Variable> > &variables) |
|
75 | static QByteArray | |
|
76 | mimeData(const std::vector<std::shared_ptr<Variable>>& variables) | |||
|
77 | { | |||
|
78 | auto encodedData = QByteArray{}; | |||
|
79 | QDataStream stream{&encodedData, QIODevice::WriteOnly}; | |||
|
80 | for(auto& var : variables) | |||
78 | { |
|
81 | { | |
79 | auto encodedData = QByteArray{}; |
|
82 | stream << var->ID().toByteArray(); | |
80 | QDataStream stream{&encodedData, QIODevice::WriteOnly}; |
|
|||
81 | for (auto &var : variables) { |
|
|||
82 | stream << var->ID().toByteArray(); |
|
|||
83 | } |
|
|||
84 | return encodedData; |
|
|||
85 | } |
|
83 | } | |
|
84 | return encodedData; | |||
|
85 | } | |||
86 |
|
86 | |||
87 |
|
|
87 | static std::vector<QUuid> variablesIDs(QByteArray mimeData) | |
88 |
|
|
88 | { | |
89 |
|
|
89 | std::vector<QUuid> variables; | |
90 |
|
|
90 | QDataStream stream{mimeData}; | |
91 |
|
91 | |||
92 |
|
|
92 | QVariantList ids; | |
93 |
|
|
93 | stream >> ids; | |
94 |
|
94 | |||
95 |
|
|
95 | for(const auto& id : ids) | |
96 | variables.emplace_back (id.toByteArray()); |
|
96 | { | |
97 | } |
|
97 | variables.emplace_back(id.toByteArray()); | |
98 | return variables; |
|
|||
99 | } |
|
98 | } | |
|
99 | return variables; | |||
|
100 | } | |||
100 |
|
101 | |||
101 |
|
|
102 | operator QUuid() { return _uuid; } | |
102 |
|
|
103 | QUuid ID() { return _uuid; } | |
103 | signals: |
|
104 | signals: | |
104 |
|
|
105 | void updated(QUuid ID); | |
105 |
|
106 | |||
106 | private: |
|
107 | private: | |
107 |
|
|
108 | class VariablePrivate; | |
108 |
|
|
109 | spimpl::unique_impl_ptr<VariablePrivate> impl; | |
109 |
|
|
110 | QUuid _uuid; | |
110 |
|
|
111 | QReadWriteLock m_lock; | |
111 | }; |
|
112 | }; | |
112 |
|
113 | |||
113 | // Required for using shared_ptr in signals/slots |
|
114 | // Required for using shared_ptr in signals/slots | |
114 | SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>) |
|
115 | SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>) | |
115 |
SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, |
|
116 | SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, | |
|
117 | QVector<std::shared_ptr<Variable>>) | |||
116 |
|
118 | |||
117 | #endif // SCIQLOP_VARIABLE_H |
|
119 | #endif // SCIQLOP_VARIABLE_H |
@@ -1,13 +1,18 | |||||
1 | #include "Common/DateUtils.h" |
|
1 | #include "Common/DateUtils.h" | |
2 |
|
2 | |||
|
3 | #include <cmath> | |||
|
4 | ||||
3 | QDateTime DateUtils::dateTime(double secs, Qt::TimeSpec timeSpec) noexcept |
|
5 | QDateTime DateUtils::dateTime(double secs, Qt::TimeSpec timeSpec) noexcept | |
4 | { |
|
6 | { | |
5 |
|
|
7 | // Uses msecs to be Qt 4 compatible | |
6 | return QDateTime::fromMSecsSinceEpoch(secs * 1000., timeSpec); |
|
8 | if(!std::isnan(secs)) | |
|
9 | return QDateTime::fromMSecsSinceEpoch(static_cast<qint64>(secs * 1000.), | |||
|
10 | timeSpec); | |||
|
11 | return QDateTime(); | |||
7 | } |
|
12 | } | |
8 |
|
13 | |||
9 |
double DateUtils::secondsSinceEpoch(const QDateTime |
|
14 | double DateUtils::secondsSinceEpoch(const QDateTime& dateTime) noexcept | |
10 | { |
|
15 | { | |
11 |
|
|
16 | // Uses msecs to be Qt 4 compatible | |
12 |
|
|
17 | return dateTime.toMSecsSinceEpoch() / 1000.; | |
13 | } |
|
18 | } |
@@ -1,225 +1,211 | |||||
1 | #include <optional> |
|
|||
2 | #include <QMutex> |
|
|||
3 | #include <QReadWriteLock> |
|
|||
4 | #include <QThread> |
|
|||
5 |
|
||||
6 |
|
|
1 | #include "Variable/Variable.h" | |
7 |
|
2 | |||
8 | #include <Data/IDataSeries.h> |
|
|||
9 | #include <Data/DateTimeRange.h> |
|
|||
10 |
|
||||
11 | #include <Common/debug.h> |
|
3 | #include <Common/debug.h> | |
|
4 | #include <Data/DateTimeRange.h> | |||
|
5 | #include <Data/IDataSeries.h> | |||
|
6 | #include <QMutex> | |||
|
7 | #include <QReadWriteLock> | |||
|
8 | #include <QThread> | |||
|
9 | #include <optional> | |||
12 |
|
10 | |||
13 | Q_LOGGING_CATEGORY(LOG_Variable, "Variable") |
|
11 | Q_LOGGING_CATEGORY(LOG_Variable, "Variable") | |
14 |
|
12 | |||
15 |
|
||||
16 | /** |
|
13 | /** | |
17 | * Searches in metadata for a value that can be converted to DataSeriesType |
|
14 | * Searches in metadata for a value that can be converted to DataSeriesType | |
18 | * @param metadata the metadata where to search |
|
15 | * @param metadata the metadata where to search | |
19 |
* @return the value converted to a DataSeriesType if it was found, UNKNOWN type |
|
16 | * @return the value converted to a DataSeriesType if it was found, UNKNOWN type | |
|
17 | * otherwise | |||
20 | * @sa DataSeriesType |
|
18 | * @sa DataSeriesType | |
21 | */ |
|
19 | */ | |
22 |
static DataSeriesType findDataSeriesType(const QVariantHash |
|
20 | static DataSeriesType findDataSeriesType(const QVariantHash& metadata) | |
23 | { |
|
21 | { | |
24 |
|
|
22 | auto dataSeriesType = DataSeriesType::NONE; | |
25 |
|
23 | |||
26 |
|
|
24 | // Go through the metadata and stop at the first value that could be converted | |
27 | for (auto it = metadata.cbegin(), end = metadata.cend(); |
|
25 | // to DataSeriesType | |
28 | it != end && dataSeriesType == DataSeriesType::UNKNOWN; ++it) { |
|
26 | for(auto it = metadata.cbegin(), end = metadata.cend(); | |
29 |
dataSeriesType = DataSeriesType |
|
27 | it != end && dataSeriesType == DataSeriesType::NONE; ++it) | |
30 | } |
|
28 | { | |
|
29 | dataSeriesType = DataSeriesTypeUtils::fromString(it.value().toString()); | |||
|
30 | } | |||
31 |
|
31 | |||
32 |
|
|
32 | return dataSeriesType; | |
33 | } |
|
33 | } | |
34 |
|
34 | |||
35 |
|
35 | #define VP_PROPERTY(property, getter, setter, type) \ | ||
36 | #define VP_PROPERTY(property,getter,setter,type) \ |
|
36 | type getter() noexcept \ | |
37 | type getter() noexcept\ |
|
37 | { \ | |
38 | {\ |
|
38 | QReadLocker lock{&m_Lock}; \ | |
39 | QReadLocker lock{&m_Lock};\ |
|
39 | return property; \ | |
40 | return property;\ |
|
40 | } \ | |
41 | }\ |
|
41 | void setter(const type& getter) noexcept \ | |
42 | void setter(const type& getter) noexcept\ |
|
42 | { \ | |
43 | {\ |
|
43 | QWriteLocker lock{&m_Lock}; \ | |
44 | QWriteLocker lock{&m_Lock};\ |
|
44 | property = getter; \ | |
45 | property = getter;\ |
|
45 | } \ | |
46 | }\ |
|
46 | type property; | |
47 | type property;\ |
|
47 | ||
48 |
|
48 | #define V_FW_GETTER_SETTER(getter, setter, type) \ | ||
49 | #define V_FW_GETTER_SETTER(getter,setter, type)\ |
|
49 | type Variable::getter() const noexcept { return impl->getter(); } \ | |
50 | type Variable::getter() const noexcept \ |
|
50 | void Variable::setter(const type& getter) noexcept \ | |
51 | {\ |
|
51 | { \ | |
52 | return impl->getter();\ |
|
52 | impl->setter(getter); \ | |
53 | }\ |
|
53 | emit updated(this->ID()); \ | |
54 | void Variable::setter(const type& getter) noexcept \ |
|
54 | } | |
55 | {\ |
|
55 | ||
56 | impl->setter(getter);\ |
|
56 | struct Variable::VariablePrivate | |
57 | emit updated(this->ID());\ |
|
57 | { | |
58 | }\ |
|
58 | explicit VariablePrivate(const QString& name, const QVariantHash& metadata) | |
59 |
|
59 | : m_Name{name}, m_Range{INVALID_RANGE}, m_CacheRange{INVALID_RANGE}, | ||
60 | struct Variable::VariablePrivate { |
|
60 | m_Metadata{metadata}, m_DataSeries{nullptr}, m_RealRange{INVALID_RANGE}, | |
61 | explicit VariablePrivate(const QString &name, const QVariantHash &metadata) |
|
61 | m_NbPoints{0}, m_Type{findDataSeriesType(m_Metadata)} | |
62 | : m_Name{name}, |
|
62 | {} | |
63 | m_Range{INVALID_RANGE}, |
|
63 | ||
64 | m_CacheRange{INVALID_RANGE}, |
|
64 | VariablePrivate(const VariablePrivate& other) | |
65 | m_Metadata{metadata}, |
|
65 | : m_Name{other.m_Name}, m_Range{other.m_Range}, | |
66 | m_DataSeries{nullptr}, |
|
66 | m_CacheRange{other.m_CacheRange}, m_Metadata{other.m_Metadata}, | |
67 | m_RealRange{INVALID_RANGE}, |
|
67 | m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() | |
68 | m_NbPoints{0}, |
|
68 | : nullptr}, | |
69 | m_Type{findDataSeriesType(m_Metadata)} |
|
69 | m_RealRange{other.m_RealRange}, | |
70 | { |
|
70 | m_NbPoints{other.m_NbPoints}, m_Type{findDataSeriesType(m_Metadata)} | |
71 |
|
|
71 | {} | |
72 |
|
72 | |||
73 | VariablePrivate(const VariablePrivate &other) |
|
73 | void lockRead() { m_Lock.lockForRead(); } | |
74 | : m_Name{other.m_Name}, |
|
74 | void lockWrite() { m_Lock.lockForWrite(); } | |
75 | m_Range{other.m_Range}, |
|
75 | void unlock() { m_Lock.unlock(); } | |
76 | m_CacheRange{other.m_CacheRange}, |
|
76 | ||
77 | m_Metadata{other.m_Metadata}, |
|
77 | void purgeDataSeries() | |
78 | m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr}, |
|
78 | { | |
79 | m_RealRange{other.m_RealRange}, |
|
79 | if(m_DataSeries) | |
80 | m_NbPoints{other.m_NbPoints}, |
|
80 | { m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd); } | |
81 | m_Type{findDataSeriesType(m_Metadata)} |
|
81 | updateRealRange(); | |
82 | { |
|
82 | updateNbPoints(); | |
83 |
|
|
83 | } | |
84 |
|
84 | void mergeDataSeries(const std::vector<IDataSeries*>& dataseries, | ||
85 | void lockRead() { m_Lock.lockForRead(); } |
|
85 | bool overwrite = false) | |
86 | void lockWrite() { m_Lock.lockForWrite(); } |
|
86 | { | |
87 | void unlock() { m_Lock.unlock(); } |
|
87 | QWriteLocker lock{&m_Lock}; | |
88 |
|
88 | for(auto ds : dataseries) | ||
89 | void purgeDataSeries() |
|
|||
90 | { |
|
89 | { | |
91 |
|
|
90 | if(!overwrite & bool(m_DataSeries)) | |
92 | m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd); |
|
91 | m_DataSeries->merge(ds); | |
93 |
|
|
92 | else | |
94 | updateRealRange(); |
|
93 | m_DataSeries = ds->clone(); | |
95 | updateNbPoints(); |
|
|||
96 | } |
|
94 | } | |
97 | void mergeDataSeries(const std::vector<IDataSeries*>& dataseries, bool overwrite=false) |
|
95 | } | |
|
96 | void updateNbPoints() | |||
|
97 | { | |||
|
98 | m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; | |||
|
99 | } | |||
|
100 | ||||
|
101 | /// Updates real range according to current variable range and data series | |||
|
102 | void updateRealRange() | |||
|
103 | { | |||
|
104 | if(m_DataSeries) | |||
98 | { |
|
105 | { | |
99 | QWriteLocker lock{&m_Lock}; |
|
106 | auto lock = m_DataSeries->getReadLock(); | |
100 | for(auto ds:dataseries) |
|
107 | auto end = m_DataSeries->cend(); | |
101 | { |
|
108 | auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart); | |
102 | if(!overwrite & bool(m_DataSeries)) |
|
109 | auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd); | |
103 | m_DataSeries->merge(ds); |
|
110 | if(minXAxisIt != end && maxXAxisIt != end && | |
104 | else |
|
111 | minXAxisIt->x() <= maxXAxisIt->x()) | |
105 | m_DataSeries = ds->clone(); |
|
112 | m_RealRange = DateTimeRange{minXAxisIt->x(), maxXAxisIt->x()}; | |
106 |
|
|
113 | else | |
|
114 | m_RealRange = std::nullopt; | |||
107 | } |
|
115 | } | |
108 | void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; } |
|
116 | else | |
109 |
|
||||
110 | /// Updates real range according to current variable range and data series |
|
|||
111 | void updateRealRange() |
|
|||
112 | { |
|
117 | { | |
113 | if (m_DataSeries) { |
|
118 | m_RealRange = std::nullopt; | |
114 | auto lock = m_DataSeries->getReadLock(); |
|
|||
115 | auto end = m_DataSeries->cend(); |
|
|||
116 | auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart); |
|
|||
117 | auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd); |
|
|||
118 | if(minXAxisIt != end && maxXAxisIt != end && minXAxisIt->x() <= maxXAxisIt->x()) |
|
|||
119 | m_RealRange = DateTimeRange{minXAxisIt->x(), maxXAxisIt->x()}; |
|
|||
120 | else |
|
|||
121 | m_RealRange = std::nullopt; |
|
|||
122 | } |
|
|||
123 | else { |
|
|||
124 | m_RealRange = std::nullopt; |
|
|||
125 | } |
|
|||
126 | } |
|
119 | } | |
127 |
|
120 | } | ||
128 | VP_PROPERTY(m_Name, name, setName, QString) |
|
121 | ||
129 |
|
|
122 | VP_PROPERTY(m_Name, name, setName, QString) | |
130 |
|
|
123 | VP_PROPERTY(m_Range, range, setRange, DateTimeRange) | |
131 | VP_PROPERTY(m_Metadata, metadata, setMetadata, QVariantHash) |
|
124 | VP_PROPERTY(m_CacheRange, cacheRange, setCacheRange, DateTimeRange) | |
132 | VP_PROPERTY(m_DataSeries, dataSeries, setDataSeries, std::shared_ptr<IDataSeries>) |
|
125 | VP_PROPERTY(m_Metadata, metadata, setMetadata, QVariantHash) | |
133 | VP_PROPERTY(m_RealRange, realRange, setRealRange, std::optional<DateTimeRange>) |
|
126 | VP_PROPERTY(m_DataSeries, dataSeries, setDataSeries, | |
134 | unsigned int m_NbPoints; |
|
127 | std::shared_ptr<IDataSeries>) | |
135 | VP_PROPERTY(m_Type, type, setType, DataSeriesType) |
|
128 | VP_PROPERTY(m_RealRange, realRange, setRealRange, | |
136 | QReadWriteLock m_Lock; |
|
129 | std::optional<DateTimeRange>) | |
|
130 | unsigned int m_NbPoints; | |||
|
131 | VP_PROPERTY(m_Type, type, setType, DataSeriesType) | |||
|
132 | QReadWriteLock m_Lock; | |||
137 | }; |
|
133 | }; | |
138 |
|
134 | |||
139 |
Variable::Variable(const QString |
|
135 | Variable::Variable(const QString& name, const QVariantHash& metadata) | |
140 |
|
|
136 | : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}, | |
141 |
|
|
137 | _uuid{QUuid::createUuid()} | |
142 | { |
|
138 | {} | |
143 | } |
|
|||
144 |
|
139 | |||
145 |
Variable::Variable(const Variable |
|
140 | Variable::Variable(const Variable& other) | |
146 |
|
|
141 | : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}, | |
147 |
|
|
142 | _uuid{QUuid::createUuid()} // is a clone but must have a != uuid | |
148 | { |
|
143 | {} | |
149 | } |
|
|||
150 |
|
144 | |||
151 | std::shared_ptr<Variable> Variable::clone() const |
|
145 | std::shared_ptr<Variable> Variable::clone() const | |
152 | { |
|
146 | { | |
153 |
|
|
147 | return std::make_shared<Variable>(*this); | |
154 | } |
|
148 | } | |
155 |
|
149 | |||
156 | V_FW_GETTER_SETTER(name,setName,QString) |
|
150 | V_FW_GETTER_SETTER(name, setName, QString) | |
157 |
|
151 | |||
158 | DateTimeRange Variable::range() const noexcept |
|
152 | DateTimeRange Variable::range() const noexcept { return impl->range(); } | |
159 | { |
|
|||
160 | return impl->range(); |
|
|||
161 | } |
|
|||
162 |
|
153 | |||
163 |
void Variable::setRange(const DateTimeRange |
|
154 | void Variable::setRange(const DateTimeRange& range, bool notify) noexcept | |
164 | { |
|
155 | { | |
165 |
|
|
156 | impl->setRange(range); | |
166 |
|
|
157 | impl->updateRealRange(); | |
167 | if(notify) |
|
158 | if(notify) emit this->updated(this->ID()); | |
168 | emit this->updated(this->ID()); |
|
|||
169 | } |
|
159 | } | |
170 |
|
160 | |||
171 | V_FW_GETTER_SETTER(cacheRange, setCacheRange, DateTimeRange) |
|
161 | V_FW_GETTER_SETTER(cacheRange, setCacheRange, DateTimeRange) | |
172 |
|
162 | |||
173 | unsigned int Variable::nbPoints() const noexcept |
|
163 | unsigned int Variable::nbPoints() const noexcept { return impl->m_NbPoints; } | |
174 | { |
|
|||
175 | return impl->m_NbPoints; |
|
|||
176 | } |
|
|||
177 |
|
164 | |||
178 | std::optional<DateTimeRange> Variable::realRange() const noexcept |
|
165 | std::optional<DateTimeRange> Variable::realRange() const noexcept | |
179 | { |
|
166 | { | |
180 |
|
|
167 | return impl->realRange(); | |
181 | } |
|
168 | } | |
182 |
|
169 | |||
183 |
void Variable::updateData(const std::vector<IDataSeries |
|
170 | void Variable::updateData(const std::vector<IDataSeries*>& dataSeries, | |
|
171 | const DateTimeRange& newRange, | |||
|
172 | const DateTimeRange& newCacheRange, bool notify) | |||
184 | { |
|
173 | { | |
185 |
|
|
174 | { | |
186 |
|
|
175 | QWriteLocker lock{&m_lock}; | |
187 |
|
|
176 | impl->mergeDataSeries(dataSeries); | |
188 |
|
|
177 | impl->setRange(newRange); | |
189 |
|
|
178 | impl->setCacheRange(newCacheRange); | |
190 |
|
|
179 | impl->purgeDataSeries(); | |
191 |
|
|
180 | } | |
192 | if(notify) |
|
181 | if(notify) emit updated(this->ID()); | |
193 | emit updated(this->ID()); |
|
|||
194 | } |
|
182 | } | |
195 |
|
183 | |||
196 |
void Variable::setData(const std::vector<IDataSeries |
|
184 | void Variable::setData(const std::vector<IDataSeries*>& dataSeries, | |
|
185 | const DateTimeRange& newRange, | |||
|
186 | const DateTimeRange& newCacheRange, bool notify) | |||
197 | { |
|
187 | { | |
198 |
|
|
188 | { | |
199 |
|
|
189 | QWriteLocker lock{&m_lock}; | |
200 |
|
|
190 | impl->mergeDataSeries(dataSeries, true); | |
201 |
|
|
191 | impl->setRange(newRange); | |
202 |
|
|
192 | impl->setCacheRange(newCacheRange); | |
203 |
|
|
193 | impl->purgeDataSeries(); | |
204 |
|
|
194 | } | |
205 | if(notify) |
|
195 | if(notify) emit updated(this->ID()); | |
206 | emit updated(this->ID()); |
|
|||
207 | } |
|
196 | } | |
208 |
|
197 | |||
209 | std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept |
|
198 | std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept | |
210 | { |
|
199 | { | |
211 |
|
|
200 | return impl->dataSeries(); | |
212 | } |
|
201 | } | |
213 |
|
202 | |||
214 | DataSeriesType Variable::type() const noexcept |
|
203 | DataSeriesType Variable::type() const noexcept { return impl->type(); } | |
215 | { |
|
|||
216 | return impl->type(); |
|
|||
217 | } |
|
|||
218 |
|
204 | |||
219 | QVariantHash Variable::metadata() const noexcept |
|
205 | QVariantHash Variable::metadata() const noexcept | |
220 | { |
|
206 | { | |
221 |
|
|
207 | impl->lockRead(); | |
222 |
|
|
208 | auto metadata = impl->m_Metadata; | |
223 |
|
|
209 | impl->unlock(); | |
224 |
|
|
210 | return metadata; | |
225 | } |
|
211 | } |
@@ -62,7 +62,10 class VariableController2::VariableController2Private | |||||
62 | { |
|
62 | { | |
63 | QReadLocker lock{&_lock}; |
|
63 | QReadLocker lock{&_lock}; | |
64 | auto it = _variables.find(variable); |
|
64 | auto it = _variables.find(variable); | |
65 | [[unlikely]] if(it == _variables.end()) |
|
65 | #if __cplusplus > 201703L | |
|
66 | [[unlikely]] | |||
|
67 | #endif | |||
|
68 | if(it == _variables.end()) | |||
66 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); |
|
69 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); | |
67 | return (*it).second; |
|
70 | return (*it).second; | |
68 | } |
|
71 | } | |
@@ -70,7 +73,10 class VariableController2::VariableController2Private | |||||
70 | inline std::shared_ptr<Variable> variable(int index) |
|
73 | inline std::shared_ptr<Variable> variable(int index) | |
71 | { |
|
74 | { | |
72 | QReadLocker lock{&_lock}; |
|
75 | QReadLocker lock{&_lock}; | |
73 | [[unlikely]] if(!_variables.size() > index) |
|
76 | #if __cplusplus > 201703L | |
|
77 | [[unlikely]] | |||
|
78 | #endif | |||
|
79 | if(!_variables.size() > index) | |||
74 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Index is out of bounds"); |
|
80 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Index is out of bounds"); | |
75 | auto it = _variables.cbegin(); |
|
81 | auto it = _variables.cbegin(); | |
76 | while(index != 0) |
|
82 | while(index != 0) | |
@@ -95,7 +101,10 class VariableController2::VariableController2Private | |||||
95 | inline std::shared_ptr<IDataProvider> provider(QUuid variable) |
|
101 | inline std::shared_ptr<IDataProvider> provider(QUuid variable) | |
96 | { |
|
102 | { | |
97 | QReadLocker lock{&_lock}; |
|
103 | QReadLocker lock{&_lock}; | |
98 | [[unlikely]] if(!_providers.contains(variable)) |
|
104 | #if __cplusplus > 201703L | |
|
105 | [[unlikely]] | |||
|
106 | #endif | |||
|
107 | if(!_providers.contains(variable)) | |||
99 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); |
|
108 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); | |
100 | return _providers[variable]; |
|
109 | return _providers[variable]; | |
101 | } |
|
110 | } | |
@@ -103,7 +112,10 class VariableController2::VariableController2Private | |||||
103 | inline std::shared_ptr<VariableSynchronizationGroup2> group(QUuid variable) |
|
112 | inline std::shared_ptr<VariableSynchronizationGroup2> group(QUuid variable) | |
104 | { |
|
113 | { | |
105 | QReadLocker lock{&_lock}; |
|
114 | QReadLocker lock{&_lock}; | |
106 | [[unlikely]] if(!_synchronizationGroups.contains(variable)) |
|
115 | #if __cplusplus > 201703L | |
|
116 | [[unlikely]] | |||
|
117 | #endif | |||
|
118 | if(!_synchronizationGroups.contains(variable)) | |||
107 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); |
|
119 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); | |
108 | return _synchronizationGroups[variable]; |
|
120 | return _synchronizationGroups[variable]; | |
109 | } |
|
121 | } |
@@ -11,6 +11,7 | |||||
11 | #include <Data/VectorSeries.h> |
|
11 | #include <Data/VectorSeries.h> | |
12 | #include <Network/Downloader.h> |
|
12 | #include <Network/Downloader.h> | |
13 | #include <Time/TimeController.h> |
|
13 | #include <Time/TimeController.h> | |
|
14 | #include <Variable/Variable2.h> | |||
14 | #include <Variable/VariableController2.h> |
|
15 | #include <Variable/VariableController2.h> | |
15 | #include <pybind11/chrono.h> |
|
16 | #include <pybind11/chrono.h> | |
16 | #include <pybind11/embed.h> |
|
17 | #include <pybind11/embed.h> | |
@@ -19,6 +20,7 | |||||
19 | #include <pybind11/operators.h> |
|
20 | #include <pybind11/operators.h> | |
20 | #include <pybind11/pybind11.h> |
|
21 | #include <pybind11/pybind11.h> | |
21 | #include <pybind11/stl.h> |
|
22 | #include <pybind11/stl.h> | |
|
23 | #include <pybind11/stl_bind.h> | |||
22 | #include <sstream> |
|
24 | #include <sstream> | |
23 | #include <string> |
|
25 | #include <string> | |
24 |
|
26 | |||
@@ -27,11 +29,13 using namespace std::chrono; | |||||
27 |
|
29 | |||
28 | PYBIND11_MODULE(pysciqlopcore, m) |
|
30 | PYBIND11_MODULE(pysciqlopcore, m) | |
29 | { |
|
31 | { | |
|
32 | pybind11::bind_vector<std::vector<double>>(m, "VectorDouble"); | |||
|
33 | ||||
30 | py::enum_<DataSeriesType>(m, "DataSeriesType") |
|
34 | py::enum_<DataSeriesType>(m, "DataSeriesType") | |
31 | .value("SCALAR", DataSeriesType::SCALAR) |
|
35 | .value("SCALAR", DataSeriesType::SCALAR) | |
32 | .value("SPECTROGRAM", DataSeriesType::SPECTROGRAM) |
|
36 | .value("SPECTROGRAM", DataSeriesType::SPECTROGRAM) | |
33 | .value("VECTOR", DataSeriesType::VECTOR) |
|
37 | .value("VECTOR", DataSeriesType::VECTOR) | |
34 |
.value(" |
|
38 | .value("NONE", DataSeriesType::NONE) | |
35 | .export_values(); |
|
39 | .export_values(); | |
36 |
|
40 | |||
37 | py::class_<Unit>(m, "Unit") |
|
41 | py::class_<Unit>(m, "Unit") | |
@@ -149,9 +153,58 PYBIND11_MODULE(pysciqlopcore, m) | |||||
149 | }) |
|
153 | }) | |
150 | .def("__repr__", __repr__<Variable>); |
|
154 | .def("__repr__", __repr__<Variable>); | |
151 |
|
155 | |||
|
156 | py::class_<TimeSeries::ITimeSerie>(m, "ITimeSerie") | |||
|
157 | .def_property_readonly( | |||
|
158 | "size", [](const TimeSeries::ITimeSerie& ts) { return ts.size(); }) | |||
|
159 | .def_property_readonly( | |||
|
160 | "t", | |||
|
161 | [](TimeSeries::ITimeSerie& ts) -> decltype(ts.axis(0))& { | |||
|
162 | return ts.axis(0); | |||
|
163 | }, | |||
|
164 | py::return_value_policy::reference); | |||
|
165 | ||||
|
166 | py::class_<ScalarTimeSerie, TimeSeries::ITimeSerie>(m, "ScalarTimeSerie") | |||
|
167 | .def(py::init<>()) | |||
|
168 | .def(py::init<std::size_t>()) | |||
|
169 | .def("__getitem__", | |||
|
170 | [](ScalarTimeSerie& ts, std::size_t key) { return ts[key]; }) | |||
|
171 | .def("__setitem__", [](ScalarTimeSerie& ts, std::size_t key, | |||
|
172 | double value) { *(ts.begin() + key) = value; }); | |||
|
173 | ||||
|
174 | py::class_<VectorTimeSerie::raw_value_type>(m, "vector") | |||
|
175 | .def(py::init<>()) | |||
|
176 | .def(py::init<double, double, double>()) | |||
|
177 | .def("__repr__", __repr__<VectorTimeSerie::raw_value_type>) | |||
|
178 | .def_readwrite("x", &VectorTimeSerie::raw_value_type::x) | |||
|
179 | .def_readwrite("y", &VectorTimeSerie::raw_value_type::y) | |||
|
180 | .def_readwrite("z", &VectorTimeSerie::raw_value_type::z); | |||
|
181 | ||||
|
182 | py::class_<VectorTimeSerie, TimeSeries::ITimeSerie>(m, "VectorTimeSerie") | |||
|
183 | .def(py::init<>()) | |||
|
184 | .def(py::init<std::size_t>()) | |||
|
185 | .def("__getitem__", | |||
|
186 | [](VectorTimeSerie& ts, std::size_t key) | |||
|
187 | -> VectorTimeSerie::raw_value_type& { return ts[key]; }, | |||
|
188 | py::return_value_policy::reference) | |||
|
189 | .def("__setitem__", [](VectorTimeSerie& ts, std::size_t key, | |||
|
190 | VectorTimeSerie::raw_value_type value) { | |||
|
191 | *(ts.begin() + key) = value; | |||
|
192 | }); | |||
|
193 | ||||
|
194 | py::class_<Variable2, std::shared_ptr<Variable2>>(m, "Variable2") | |||
|
195 | .def(py::init<const QString&>()) | |||
|
196 | .def_property("name", &Variable2::name, &Variable2::setName) | |||
|
197 | .def_property_readonly("range", &Variable2::range) | |||
|
198 | .def_property_readonly("nbPoints", &Variable2::nbPoints) | |||
|
199 | .def_property_readonly( | |||
|
200 | "dataSeries", [](const Variable2& var) { return var.data()->base(); }) | |||
|
201 | .def("set_data", &Variable2::setData) | |||
|
202 | .def("__len__", &Variable2::nbPoints) | |||
|
203 | .def("__repr__", __repr__<Variable2>); | |||
|
204 | ||||
152 | py::class_<DateTimeRange>(m, "SqpRange") |
|
205 | py::class_<DateTimeRange>(m, "SqpRange") | |
153 | //.def("fromDateTime", &DateTimeRange::fromDateTime, |
|
206 | //.def("fromDateTime", &DateTimeRange::fromDateTime, | |
154 | //py::return_value_policy::move) |
|
207 | // py::return_value_policy::move) | |
155 | .def(py::init([](double start, double stop) { |
|
208 | .def(py::init([](double start, double stop) { | |
156 | return DateTimeRange{start, stop}; |
|
209 | return DateTimeRange{start, stop}; | |
157 | })) |
|
210 | })) |
@@ -1,54 +1,79 | |||||
1 | #pragma once |
|
1 | #pragma once | |
2 | #include <pybind11/pybind11.h> |
|
|||
3 | #include <pybind11/operators.h> |
|
|||
4 |
|
||||
5 | #include <string> |
|
|||
6 | #include <sstream> |
|
|||
7 | #include "pywrappers_common.h" |
|
|||
8 | #include "QtWrappers.h" |
|
2 | #include "QtWrappers.h" | |
|
3 | #include "pywrappers_common.h" | |||
|
4 | ||||
9 | #include <Data/DataSeriesType.h> |
|
5 | #include <Data/DataSeriesType.h> | |
10 |
#include <Data/ |
|
6 | #include <Data/DateTimeRange.h> | |
11 | #include <Data/IDataSeries.h> |
|
7 | #include <Data/IDataSeries.h> | |
|
8 | #include <Data/Unit.h> | |||
12 | #include <Variable/Variable.h> |
|
9 | #include <Variable/Variable.h> | |
13 | #include <Data/DateTimeRange.h> |
|
10 | #include <Variable/Variable2.h> | |
|
11 | #include <pybind11/pybind11.h> | |||
|
12 | #include <sstream> | |||
|
13 | #include <string> | |||
14 |
|
14 | |||
|
15 | PYBIND11_MAKE_OPAQUE(std::vector<double>); | |||
15 |
|
16 | |||
16 |
std::ostream |
|
17 | std::ostream& operator<<(std::ostream& os, const Unit& u) | |
17 | { |
|
18 | { | |
18 |
|
|
19 | os << "=========================" << std::endl | |
19 |
|
|
20 | << "Unit:" << std::endl | |
20 |
|
|
21 | << " Name: " << u.m_Name << std::endl | |
21 |
|
|
22 | << " Is_TimeUnit: " << u.m_TimeUnit << std::endl; | |
22 |
|
|
23 | return os; | |
23 | } |
|
24 | } | |
24 |
|
25 | |||
|
26 | std::ostream& operator<<(std::ostream& os, const IDataSeries& ds) | |||
|
27 | { | |||
|
28 | os << "=========================" << std::endl | |||
|
29 | << "DataSerie:" << std::endl | |||
|
30 | << " Number of points:" << ds.nbPoints() << std::endl | |||
|
31 | << " X Axis Unit:" << std::endl | |||
|
32 | << ds.xAxisUnit() << std::endl | |||
|
33 | << " Y Axis Unit:" << std::endl | |||
|
34 | << ds.yAxisUnit() << std::endl | |||
|
35 | << " Values Axis Unit:" << std::endl | |||
|
36 | << ds.valuesUnit() << std::endl; | |||
|
37 | return os; | |||
|
38 | } | |||
|
39 | ||||
|
40 | std::ostream& operator<<(std::ostream& os, const DateTimeRange& range) | |||
|
41 | { | |||
|
42 | os << "=========================" << std::endl | |||
|
43 | << "SqpRange:" << std::endl | |||
|
44 | << " Start date: " << DateUtils::dateTime(range.m_TStart).toString() | |||
|
45 | << std::endl | |||
|
46 | << " Stop date: " << DateUtils::dateTime(range.m_TEnd).toString() | |||
|
47 | << std::endl; | |||
|
48 | return os; | |||
|
49 | } | |||
25 |
|
50 | |||
26 |
std::ostream |
|
51 | std::ostream& operator<<(std::ostream& os, const Variable& variable) | |
27 | { |
|
52 | { | |
28 |
|
|
53 | os << "=========================" << std::endl | |
29 |
|
|
54 | << "Variable:" << std::endl | |
30 |
|
|
55 | << " Name: " << variable.name() << std::endl | |
31 | << " X Axis Unit:" << std::endl << ds.xAxisUnit() << std::endl |
|
56 | << " range: " << std::endl | |
32 | << " Y Axis Unit:" << std::endl << ds.yAxisUnit()<< std::endl |
|
57 | << variable.range() << std::endl | |
33 | << " Values Axis Unit:" << std::endl << ds.valuesUnit()<< std::endl; |
|
58 | << " cache range: " << std::endl | |
34 | return os; |
|
59 | << variable.cacheRange() << std::endl; | |
|
60 | return os; | |||
35 | } |
|
61 | } | |
36 |
|
62 | |||
37 |
std::ostream |
|
63 | std::ostream& operator<<(std::ostream& os, const Variable2& variable) | |
38 | { |
|
64 | { | |
39 |
|
|
65 | os << "=========================" << std::endl | |
40 |
|
|
66 | << "Variable:" << std::endl | |
41 | << " Start date: " << DateUtils::dateTime(range.m_TStart).toString() << std::endl |
|
67 | << " Name: " << variable.name() << std::endl | |
42 | << " Stop date: " << DateUtils::dateTime(range.m_TEnd).toString() << std::endl; |
|
68 | << " range: " << std::endl | |
43 | return os; |
|
69 | << variable.range() << std::endl; | |
|
70 | return os; | |||
44 | } |
|
71 | } | |
45 |
|
72 | |||
46 |
std::ostream |
|
73 | std::ostream& operator<<(std::ostream& os, | |
|
74 | const VectorTimeSerie::raw_value_type& value) | |||
47 | { |
|
75 | { | |
48 | os << "=========================" << std::endl |
|
76 | os << "[" << value.x << ", " << value.y << ", " << value.z << "]" | |
49 |
|
|
77 | << std::endl; | |
50 | << " Name: " << variable.name() << std::endl |
|
78 | return os; | |
51 | << " range: " << std::endl << variable.range() << std::endl |
|
|||
52 | << " cache range: " << std::endl << variable.cacheRange() << std::endl; |
|
|||
53 | return os; |
|
|||
54 | } |
|
79 | } |
@@ -1,23 +1,20 | |||||
1 | #include <Variable/Variable.h> |
|
|||
2 |
|
||||
3 | #include <Data/ScalarSeries.h> |
|
|||
4 |
|
||||
5 |
|
|
1 | #include <QObject> | |
6 | #include <QtTest> |
|
2 | #include <QtTest> | |
7 |
|
3 | #include <Variable/Variable2.h> | ||
8 | #include <memory> |
|
4 | #include <memory> | |
9 |
|
5 | |||
10 |
|
6 | class TestVariable : public QObject | ||
11 |
|
7 | { | ||
12 | class TestVariable : public QObject { |
|
8 | Q_OBJECT | |
13 | Q_OBJECT |
|
|||
14 |
|
9 | |||
15 | private slots: |
|
10 | private slots: | |
16 | void initTestCase() { QSKIP("Please Write me! .·´¯`(>▂<)´¯`·. "); } |
|
11 | void initTestCase() {} | |
|
12 | void type_matches_TS_type() | |||
|
13 | { | |||
|
14 | Variable2 v("none", {}); | |||
|
15 | QVERIFY(v.type() == DataSeriesType::NONE); | |||
|
16 | } | |||
17 | }; |
|
17 | }; | |
18 |
|
18 | |||
19 |
|
||||
20 |
|
||||
21 |
|
||||
22 | QTEST_MAIN(TestVariable) |
|
19 | QTEST_MAIN(TestVariable) | |
23 | #include "TestVariable.moc" |
|
20 | #include "TestVariable.moc" |
General Comments 0
You need to be logged in to leave comments.
Login now