@@ -0,0 +1,17 | |||||
|
1 | #ifndef SCIQLOP_SCALARTIMESERIE_H | |||
|
2 | #define SCIQLOP_SCALARTIMESERIE_H | |||
|
3 | ||||
|
4 | #include "CoreGlobal.h" | |||
|
5 | ||||
|
6 | #include <TimeSeries.h> | |||
|
7 | ||||
|
8 | class SCIQLOP_CORE_EXPORT ScalarTimeSerie | |||
|
9 | : public TimeSeries::TimeSerie<double, ScalarTimeSerie> | |||
|
10 | { | |||
|
11 | public: | |||
|
12 | ScalarTimeSerie() {} | |||
|
13 | ~ScalarTimeSerie() = default; | |||
|
14 | using TimeSerie::TimeSerie; | |||
|
15 | }; | |||
|
16 | ||||
|
17 | #endif // SCIQLOP_SCALARSERIES_H |
@@ -0,0 +1,22 | |||||
|
1 | #ifndef SCIQLOP_VECTORTIMESERIE_H | |||
|
2 | #define SCIQLOP_VECTORTIMESERIE_H | |||
|
3 | ||||
|
4 | #include "CoreGlobal.h" | |||
|
5 | ||||
|
6 | #include <TimeSeries.h> | |||
|
7 | ||||
|
8 | struct Vector | |||
|
9 | { | |||
|
10 | double x, y, z; | |||
|
11 | }; | |||
|
12 | ||||
|
13 | class SCIQLOP_CORE_EXPORT VectorTimeSerie | |||
|
14 | : public TimeSeries::TimeSerie<Vector, VectorTimeSerie> | |||
|
15 | { | |||
|
16 | public: | |||
|
17 | VectorTimeSerie() {} | |||
|
18 | ~VectorTimeSerie() = default; | |||
|
19 | using TimeSerie::TimeSerie; | |||
|
20 | }; | |||
|
21 | ||||
|
22 | #endif // SCIQLOP_VECTORTIMESERIE_H |
@@ -0,0 +1,1 | |||||
|
1 | #include <Data/ScalarTimeSerie.h> |
@@ -0,0 +1,1 | |||||
|
1 | #include <Data/VectorTimeSerie.h> |
@@ -81,9 +81,11 FILE (GLOB_RECURSE core_SRCS | |||||
81 | ./include/Plugin/IPlugin.h |
|
81 | ./include/Plugin/IPlugin.h | |
82 | ./include/Data/ArrayDataIterator.h |
|
82 | ./include/Data/ArrayDataIterator.h | |
83 | ./include/Data/VectorSeries.h |
|
83 | ./include/Data/VectorSeries.h | |
|
84 | ./include/Data/VectorTimeSerie.h | |||
84 | ./include/Data/DateTimeRange.h |
|
85 | ./include/Data/DateTimeRange.h | |
85 | ./include/Data/DateTimeRangeHelper.h |
|
86 | ./include/Data/DateTimeRangeHelper.h | |
86 | ./include/Data/ScalarSeries.h |
|
87 | ./include/Data/ScalarSeries.h | |
|
88 | ./include/Data/ScalarTimeSerie.h | |||
87 | ./include/Data/DataSeriesMergeHelper.h |
|
89 | ./include/Data/DataSeriesMergeHelper.h | |
88 | ./include/Data/DataSeries.h |
|
90 | ./include/Data/DataSeries.h | |
89 | ./include/Data/DataSeriesType.h |
|
91 | ./include/Data/DataSeriesType.h | |
@@ -125,12 +127,14 FILE (GLOB_RECURSE core_SRCS | |||||
125 | ./src/Common/StringUtils.cpp |
|
127 | ./src/Common/StringUtils.cpp | |
126 | ./src/Common/SignalWaiter.cpp |
|
128 | ./src/Common/SignalWaiter.cpp | |
127 | ./src/Data/ScalarSeries.cpp |
|
129 | ./src/Data/ScalarSeries.cpp | |
|
130 | ./src/Data/ScalarTimeSerie.cpp | |||
128 | ./src/Data/DataSeriesIterator.cpp |
|
131 | ./src/Data/DataSeriesIterator.cpp | |
129 | ./src/Data/OptionalAxis.cpp |
|
132 | ./src/Data/OptionalAxis.cpp | |
130 | ./src/Data/ArrayDataIterator.cpp |
|
133 | ./src/Data/ArrayDataIterator.cpp | |
131 | ./src/Data/SpectrogramSeries.cpp |
|
134 | ./src/Data/SpectrogramSeries.cpp | |
132 | ./src/Data/DataSeriesUtils.cpp |
|
135 | ./src/Data/DataSeriesUtils.cpp | |
133 | ./src/Data/VectorSeries.cpp |
|
136 | ./src/Data/VectorSeries.cpp | |
|
137 | ./src/Data/VectorTimeSerie.cpp | |||
134 | ./src/Network/NetworkController.cpp |
|
138 | ./src/Network/NetworkController.cpp | |
135 | ./src/Network/Downloader.cpp |
|
139 | ./src/Network/Downloader.cpp | |
136 | ./src/Visualization/VisualizationController.cpp |
|
140 | ./src/Visualization/VisualizationController.cpp | |
@@ -172,6 +176,7 target_include_directories(sciqlopcore PUBLIC | |||||
172 | target_link_libraries(sciqlopcore PUBLIC |
|
176 | target_link_libraries(sciqlopcore PUBLIC | |
173 | Qt5::Core |
|
177 | Qt5::Core | |
174 | Qt5::Network |
|
178 | Qt5::Network | |
|
179 | TimeSeries | |||
175 | ) |
|
180 | ) | |
176 |
|
181 | |||
177 | if(Catalog) |
|
182 | if(Catalog) |
@@ -3,24 +3,33 | |||||
3 |
|
3 | |||
4 | #include <QString> |
|
4 | #include <QString> | |
5 |
|
5 | |||
6 | enum class DataSeriesType { SCALAR, SPECTROGRAM, VECTOR, UNKNOWN }; |
|
6 | enum class DataSeriesType | |
|
7 | { | |||
|
8 | SCALAR, | |||
|
9 | SPECTROGRAM, | |||
|
10 | VECTOR, | |||
|
11 | UNKNOWN | |||
|
12 | }; | |||
7 |
|
13 | |||
8 |
struct DataSeriesTypeUtils |
|
14 | struct DataSeriesTypeUtils | |
9 | static DataSeriesType fromString(const QString &type) |
|
15 | { | |
|
16 | static DataSeriesType fromString(const QString& type) | |||
|
17 | { | |||
|
18 | if(type.toLower() == QStringLiteral("scalar")) | |||
|
19 | { return DataSeriesType::SCALAR; } | |||
|
20 | else if(type.toLower() == QStringLiteral("spectrogram")) | |||
|
21 | { | |||
|
22 | return DataSeriesType::SPECTROGRAM; | |||
|
23 | } | |||
|
24 | else if(type.toLower() == QStringLiteral("vector")) | |||
|
25 | { | |||
|
26 | return DataSeriesType::VECTOR; | |||
|
27 | } | |||
|
28 | else | |||
10 | { |
|
29 | { | |
11 | if (type == QStringLiteral("scalar")) { |
|
30 | return DataSeriesType::UNKNOWN; | |
12 | return DataSeriesType::SCALAR; |
|
|||
13 | } |
|
|||
14 | else if (type == QStringLiteral("spectrogram")) { |
|
|||
15 | return DataSeriesType::SPECTROGRAM; |
|
|||
16 | } |
|
|||
17 | else if (type == QStringLiteral("vector")) { |
|
|||
18 | return DataSeriesType::VECTOR; |
|
|||
19 | } |
|
|||
20 | else { |
|
|||
21 | return DataSeriesType::UNKNOWN; |
|
|||
22 | } |
|
|||
23 | } |
|
31 | } | |
|
32 | } | |||
24 | }; |
|
33 | }; | |
25 |
|
34 | |||
26 | #endif // SCIQLOP_DATASERIESTYPE_H |
|
35 | #endif // SCIQLOP_DATASERIESTYPE_H |
@@ -2,54 +2,48 | |||||
2 | #define SCIQLOP_IDATAPROVIDER_H |
|
2 | #define SCIQLOP_IDATAPROVIDER_H | |
3 |
|
3 | |||
4 | #include "CoreGlobal.h" |
|
4 | #include "CoreGlobal.h" | |
5 | #include <Common/deprecate.h> |
|
|||
6 |
|
||||
7 | #include <memory> |
|
|||
8 |
|
||||
9 | #include <QObject> |
|
|||
10 | #include <QUuid> |
|
|||
11 |
|
5 | |||
12 | #include <Common/MetaTypes.h> |
|
6 | #include <Common/MetaTypes.h> | |
13 |
|
7 | #include <Common/deprecate.h> | ||
14 | #include <Data/DateTimeRange.h> |
|
8 | #include <Data/DateTimeRange.h> | |
15 |
|
9 | #include <QObject> | ||
|
10 | #include <QUuid> | |||
16 | #include <functional> |
|
11 | #include <functional> | |
|
12 | #include <memory> | |||
17 |
|
13 | |||
18 | class DataProviderParameters; |
|
14 | class DataProviderParameters; | |
19 | class IDataSeries; |
|
15 | class IDataSeries; | |
20 | DEPRECATE( |
|
16 | DEPRECATE(class QNetworkReply; class QNetworkRequest;) | |
21 | class QNetworkReply; |
|
|||
22 | class QNetworkRequest; |
|
|||
23 | ) |
|
|||
24 |
|
17 | |||
25 | /** |
|
18 | /** | |
26 | * @brief The IDataProvider interface aims to declare a data provider. |
|
19 | * @brief The IDataProvider interface aims to declare a data provider. | |
27 | * |
|
20 | * | |
28 |
* A data provider is an entity that generates data and returns it according to |
|
21 | * A data provider is an entity that generates data and returns it according to | |
29 | * (time interval, product to retrieve the data, etc.) |
|
22 | * various parameters (time interval, product to retrieve the data, etc.) Since | |
30 |
* |
|
23 | * its client mihgt use it from different threads it has to be either stateless | |
|
24 | * and/or thread safe | |||
31 | * |
|
25 | * | |
32 | * @sa IDataSeries |
|
26 | * @sa IDataSeries | |
33 | */ |
|
27 | */ | |
34 |
class SCIQLOP_CORE_EXPORT IDataProvider : public QObject |
|
28 | class SCIQLOP_CORE_EXPORT IDataProvider : public QObject | |
35 |
|
29 | { | ||
36 |
|
|
30 | Q_OBJECT | |
37 | public: |
|
31 | public: | |
38 |
|
|
32 | virtual ~IDataProvider() noexcept = default; | |
39 |
|
|
33 | virtual std::shared_ptr<IDataProvider> clone() const = 0; | |
40 |
|
34 | |||
41 |
|
|
35 | // Synchronous call -> asyncGetData may be written for asynchronous get | |
42 |
|
|
36 | virtual IDataSeries* getData(const DataProviderParameters& parameters) = 0; | |
43 |
|
37 | |||
44 | signals: |
|
38 | signals: | |
45 |
|
39 | |||
46 |
|
|
40 | void progress(QUuid requestID, double progress); | |
47 |
|
||||
48 | }; |
|
41 | }; | |
49 |
|
42 | |||
50 | // Required for using shared_ptr in signals/slots |
|
43 | // Required for using shared_ptr in signals/slots | |
51 |
SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY, |
|
44 | SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY, | |
|
45 | std::shared_ptr<IDataProvider>) | |||
52 | SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_FUNCTION_REGISTRY, |
|
46 | SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_FUNCTION_REGISTRY, | |
53 |
std::function<void(QNetworkReply |
|
47 | std::function<void(QNetworkReply*, QUuid)>) | |
54 |
|
48 | |||
55 | #endif // SCIQLOP_IDATAPROVIDER_H |
|
49 | #endif // SCIQLOP_IDATAPROVIDER_H |
@@ -3,30 +3,15 | |||||
3 |
|
3 | |||
4 | #include "CoreGlobal.h" |
|
4 | #include "CoreGlobal.h" | |
5 |
|
5 | |||
6 | #include <QLoggingCategory> |
|
|||
7 | #include <QObject> |
|
|||
8 |
|
||||
9 | #include <Data/DateTimeRange.h> |
|
6 | #include <Data/DateTimeRange.h> | |
10 |
|
7 | |||
11 | #include <QLoggingCategory> |
|
|||
12 |
|
||||
13 | #include <Common/spimpl.h> |
|
|||
14 | #include <utility> |
|
|||
15 |
|
||||
16 |
|
||||
17 | Q_DECLARE_LOGGING_CATEGORY(LOG_VariableCacheStrategy) |
|
|||
18 |
|
||||
19 | class Variable; |
|
|||
20 |
|
||||
21 | /// This class aims to hande the cache strategy. |
|
8 | /// This class aims to hande the cache strategy. | |
22 |
class SCIQLOP_CORE_EXPORT VariableCacheStrategy |
|
9 | class SCIQLOP_CORE_EXPORT VariableCacheStrategy | |
23 |
|
10 | { | ||
24 | public: |
|
11 | public: | |
25 |
|
|
12 | virtual ~VariableCacheStrategy() noexcept = default; | |
26 |
|
|
13 | virtual DateTimeRange computeRange(const DateTimeRange& currentCacheRange, | |
27 |
|
|
14 | const DateTimeRange& rangeRequested) = 0; | |
28 | = 0; |
|
|||
29 | }; |
|
15 | }; | |
30 |
|
16 | |||
31 |
|
||||
32 | #endif // SCIQLOP_VARIABLECACHESTRATEGY_H |
|
17 | #endif // SCIQLOP_VARIABLECACHESTRATEGY_H |
This diff has been collapsed as it changes many lines, (696 lines changed) Show them Hide them | |||||
@@ -1,432 +1,452 | |||||
1 | #include <QQueue> |
|
|||
2 | #include <QThreadPool> |
|
|||
3 | #include <QRunnable> |
|
|||
4 | #include <QObject> |
|
|||
5 | #include <QDataStream> |
|
|||
6 |
|
||||
7 |
|
|
1 | #include "Variable/VariableController2.h" | |
|
2 | ||||
8 | #include "Variable/VariableSynchronizationGroup2.h" |
|
3 | #include "Variable/VariableSynchronizationGroup2.h" | |
|
4 | ||||
9 | #include <Common/containers.h> |
|
5 | #include <Common/containers.h> | |
10 | #include <Common/debug.h> |
|
6 | #include <Common/debug.h> | |
11 | #include <Data/DataProviderParameters.h> |
|
7 | #include <Data/DataProviderParameters.h> | |
12 | #include <Data/DateTimeRangeHelper.h> |
|
|||
13 | #include <Data/DateTimeRange.h> |
|
8 | #include <Data/DateTimeRange.h> | |
|
9 | #include <Data/DateTimeRangeHelper.h> | |||
|
10 | #include <QCoreApplication> | |||
|
11 | #include <QDataStream> | |||
|
12 | #include <QObject> | |||
|
13 | #include <QQueue> | |||
|
14 | #include <QRunnable> | |||
|
15 | #include <QThreadPool> | |||
14 | #include <Variable/VariableCacheStrategyFactory.h> |
|
16 | #include <Variable/VariableCacheStrategyFactory.h> | |
15 | #include <Variable/private/VCTransaction.h> |
|
17 | #include <Variable/private/VCTransaction.h> | |
16 | #include <QCoreApplication> |
|
|||
17 |
|
||||
18 |
|
18 | |||
19 | class VariableController2::VariableController2Private |
|
19 | class VariableController2::VariableController2Private | |
20 | { |
|
20 | { | |
21 |
|
|
21 | struct threadSafeVaraiblesMaps | |
|
22 | { | |||
|
23 | inline void | |||
|
24 | addVariable(const std::shared_ptr<Variable>& variable, | |||
|
25 | const std::shared_ptr<IDataProvider>& provider, | |||
|
26 | const std::shared_ptr<VariableSynchronizationGroup2>& | |||
|
27 | synchronizationGroup) | |||
22 | { |
|
28 | { | |
23 | inline void addVariable(const std::shared_ptr<Variable>& variable, const std::shared_ptr<IDataProvider>& provider, const std::shared_ptr<VariableSynchronizationGroup2>& synchronizationGroup) |
|
29 | QWriteLocker lock{&_lock}; | |
24 | { |
|
30 | _variables[*variable] = variable; | |
25 | QWriteLocker lock{&_lock}; |
|
31 | _providers[*variable] = provider; | |
26 | _variables[*variable] = variable; |
|
32 | _synchronizationGroups[*variable] = synchronizationGroup; | |
27 | _providers[*variable] = provider; |
|
|||
28 | _synchronizationGroups[*variable] = synchronizationGroup; |
|
|||
29 | } |
|
|||
30 |
|
||||
31 | inline void removeVariable(const std::shared_ptr<Variable>& variable) |
|
|||
32 | { |
|
|||
33 | QWriteLocker lock{&_lock}; |
|
|||
34 | _variables.erase(*variable); |
|
|||
35 | _providers.remove(*variable); |
|
|||
36 | _synchronizationGroups.remove(*variable); |
|
|||
37 | } |
|
|||
38 |
|
||||
39 | inline void synchronize(const std::shared_ptr<Variable>& variable, const std::optional<std::shared_ptr<Variable>>& with) |
|
|||
40 | { |
|
|||
41 | QWriteLocker lock{&_lock}; |
|
|||
42 | if(with.has_value()) |
|
|||
43 | { |
|
|||
44 | auto newGroup = _synchronizationGroups[*with.value()]; |
|
|||
45 | newGroup->addVariable(*variable); |
|
|||
46 | _synchronizationGroups[*variable] = newGroup; |
|
|||
47 | } |
|
|||
48 | else |
|
|||
49 | { |
|
|||
50 | _synchronizationGroups[*variable] = std::make_shared<VariableSynchronizationGroup2>(*variable); |
|
|||
51 | } |
|
|||
52 | } |
|
|||
53 |
|
||||
54 | inline std::shared_ptr<Variable> variable(QUuid variable) |
|
|||
55 | { |
|
|||
56 | QReadLocker lock{&_lock}; |
|
|||
57 | auto it = _variables.find(variable); |
|
|||
58 | [[unlikely]] |
|
|||
59 | if(it==_variables.end()) |
|
|||
60 | SCIQLOP_ERROR(threadSafeVaraiblesMaps,"Unknown Variable"); |
|
|||
61 | return (*it).second; |
|
|||
62 | } |
|
|||
63 |
|
||||
64 | inline std::shared_ptr<Variable> variable(int index) |
|
|||
65 | { |
|
|||
66 | QReadLocker lock{&_lock}; |
|
|||
67 | [[unlikely]] |
|
|||
68 | if(!_variables.size() > index) |
|
|||
69 | SCIQLOP_ERROR(threadSafeVaraiblesMaps,"Index is out of bounds"); |
|
|||
70 | auto it = _variables.cbegin(); |
|
|||
71 | while (index!=0) { |
|
|||
72 | index-=1; |
|
|||
73 | it++; |
|
|||
74 | } |
|
|||
75 | return (*it).second; |
|
|||
76 | } |
|
|||
77 |
|
||||
78 | inline const std::vector<std::shared_ptr<Variable>> variables() |
|
|||
79 | { |
|
|||
80 | std::vector<std::shared_ptr<Variable>> vars; |
|
|||
81 | QReadLocker lock{&_lock}; |
|
|||
82 | for(const auto&[id, var]:_variables) |
|
|||
83 | { |
|
|||
84 | vars.push_back(var); |
|
|||
85 | } |
|
|||
86 | return vars; |
|
|||
87 | } |
|
|||
88 |
|
||||
89 | inline std::shared_ptr<IDataProvider> provider(QUuid variable) |
|
|||
90 | { |
|
|||
91 | QReadLocker lock{&_lock}; |
|
|||
92 | [[unlikely]] |
|
|||
93 | if(!_providers.contains(variable)) |
|
|||
94 | SCIQLOP_ERROR(threadSafeVaraiblesMaps,"Unknown Variable"); |
|
|||
95 | return _providers[variable]; |
|
|||
96 | } |
|
|||
97 |
|
||||
98 | inline std::shared_ptr<VariableSynchronizationGroup2> group(QUuid variable) |
|
|||
99 | { |
|
|||
100 | QReadLocker lock{&_lock}; |
|
|||
101 | [[unlikely]] |
|
|||
102 | if(!_synchronizationGroups.contains(variable)) |
|
|||
103 | SCIQLOP_ERROR(threadSafeVaraiblesMaps,"Unknown Variable"); |
|
|||
104 | return _synchronizationGroups[variable]; |
|
|||
105 | } |
|
|||
106 |
|
||||
107 | inline bool has(const std::shared_ptr<Variable>& variable) |
|
|||
108 | { |
|
|||
109 | QReadLocker lock{&_lock}; |
|
|||
110 | return _variables.find(*variable)==_variables.end(); |
|
|||
111 | } |
|
|||
112 |
|
||||
113 | private: |
|
|||
114 | std::map<QUuid,std::shared_ptr<Variable>> _variables; |
|
|||
115 | QMap<QUuid,std::shared_ptr<IDataProvider>> _providers; |
|
|||
116 | QMap<QUuid,std::shared_ptr<VariableSynchronizationGroup2>> _synchronizationGroups; |
|
|||
117 | QReadWriteLock _lock{QReadWriteLock::Recursive}; |
|
|||
118 | }_maps; |
|
|||
119 | std::vector<QUuid> _variablesToRemove; |
|
|||
120 | QThreadPool* _ThreadPool; |
|
|||
121 | VCTransactionsQueues _transactions; |
|
|||
122 | std::unique_ptr<VariableCacheStrategy> _cacheStrategy; |
|
|||
123 |
|
||||
124 | void _transactionComplete(QUuid group, std::shared_ptr<VCTransaction> transaction) |
|
|||
125 | { |
|
|||
126 | if(transaction->done()) |
|
|||
127 | { |
|
|||
128 | _transactions.complete(group); |
|
|||
129 | } |
|
|||
130 | this->_processTransactions(); |
|
|||
131 | } |
|
33 | } | |
132 |
|
34 | |||
133 | void _cleanupVariables() |
|
35 | inline void removeVariable(const std::shared_ptr<Variable>& variable) | |
134 | { |
|
36 | { | |
135 | for(auto id:_variablesToRemove) |
|
37 | QWriteLocker lock{&_lock}; | |
136 | { |
|
38 | _variables.erase(*variable); | |
137 | auto v = this->variable(id); |
|
39 | _providers.remove(*variable); | |
138 | if(!hasPendingTransactions(v)) |
|
40 | _synchronizationGroups.remove(*variable); | |
139 | { |
|
|||
140 | _variablesToRemove.erase(std::remove(_variablesToRemove.begin(), _variablesToRemove.end(), id), _variablesToRemove.end()); |
|
|||
141 | this->deleteVariable(v); |
|
|||
142 | } |
|
|||
143 | } |
|
|||
144 | } |
|
41 | } | |
145 |
|
42 | |||
146 | void _processTransactions(bool fragmented=false) |
|
43 | inline void | |
|
44 | synchronize(const std::shared_ptr<Variable>& variable, | |||
|
45 | const std::optional<std::shared_ptr<Variable>>& with) | |||
147 | { |
|
46 | { | |
148 | auto nextTransactions = _transactions.nextTransactions(); |
|
47 | QWriteLocker lock{&_lock}; | |
149 | auto pendingTransactions = _transactions.pendingTransactions(); |
|
48 | if(with.has_value()) | |
150 | for( auto [groupID, newTransaction] : nextTransactions) |
|
49 | { | |
151 | { |
|
50 | auto newGroup = _synchronizationGroups[*with.value()]; | |
152 | if(newTransaction.has_value() && !pendingTransactions[groupID].has_value()) |
|
51 | newGroup->addVariable(*variable); | |
153 | { |
|
52 | _synchronizationGroups[*variable] = newGroup; | |
154 | _transactions.start(groupID); |
|
53 | } | |
155 | auto refVar = _maps.variable(newTransaction.value()->refVar); |
|
54 | else | |
156 | auto ranges = _computeAllRangesInGroup(refVar,newTransaction.value()->range); |
|
55 | { | |
157 | for( auto const& [ID, range] : ranges) |
|
56 | _synchronizationGroups[*variable] = | |
158 | { |
|
57 | std::make_shared<VariableSynchronizationGroup2>(*variable); | |
159 | auto provider = _maps.provider(ID); |
|
58 | } | |
160 | auto variable = _maps.variable(ID); |
|
|||
161 | if(fragmented) |
|
|||
162 | { |
|
|||
163 | auto [missingRanges, newCacheRange] = _computeMissingRanges(variable,range); |
|
|||
164 |
|
||||
165 | auto exe = new TransactionExe(variable, provider, missingRanges, range, newCacheRange); |
|
|||
166 | QObject::connect(exe, |
|
|||
167 | &TransactionExe::transactionComplete, |
|
|||
168 | [groupID=groupID,transaction=newTransaction.value(),this]() |
|
|||
169 | { |
|
|||
170 | this->_transactionComplete(groupID, transaction); |
|
|||
171 | } |
|
|||
172 | ); |
|
|||
173 | _ThreadPool->start(exe); |
|
|||
174 | } |
|
|||
175 | else |
|
|||
176 | { |
|
|||
177 | auto exe = new TransactionExe(variable, provider, {range}, range, range); |
|
|||
178 | QObject::connect(exe, |
|
|||
179 | &TransactionExe::transactionComplete, |
|
|||
180 | [groupID=groupID,transaction=newTransaction.value(),this]() |
|
|||
181 | { |
|
|||
182 | this->_transactionComplete(groupID, transaction); |
|
|||
183 | } |
|
|||
184 | ); |
|
|||
185 | _ThreadPool->start(exe); |
|
|||
186 | } |
|
|||
187 | } |
|
|||
188 | } |
|
|||
189 | } |
|
|||
190 | //after each transaction update we get a new distribution of idle and working variables |
|
|||
191 | //so we can delete variables which are waiting to be deleted if they are now idle |
|
|||
192 | _cleanupVariables(); |
|
|||
193 | } |
|
59 | } | |
194 |
|
60 | |||
195 | std::map<QUuid,DateTimeRange> _computeAllRangesInGroup(const std::shared_ptr<Variable>& refVar, DateTimeRange r) |
|
61 | inline std::shared_ptr<Variable> variable(QUuid variable) | |
196 | { |
|
62 | { | |
197 | std::map<QUuid,DateTimeRange> ranges; |
|
63 | QReadLocker lock{&_lock}; | |
198 | if(!DateTimeRangeHelper::hasnan(r)) |
|
64 | auto it = _variables.find(variable); | |
199 | { |
|
65 | [[unlikely]] if(it == _variables.end()) | |
200 | auto group = _maps.group(*refVar); |
|
66 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); | |
201 | if(auto transformation = DateTimeRangeHelper::computeTransformation(refVar->range(),r); |
|
67 | return (*it).second; | |
202 | transformation.has_value()) |
|
|||
203 | { |
|
|||
204 | for(auto varId:group->variables()) |
|
|||
205 | { |
|
|||
206 | auto var = _maps.variable(varId); |
|
|||
207 | auto newRange = var->range().transform(transformation.value()); |
|
|||
208 | ranges[varId] = newRange; |
|
|||
209 | } |
|
|||
210 | } |
|
|||
211 | else // force new range to all variables -> may be weird if more than one var in the group |
|
|||
212 | // @TODO ensure that there is no side effects |
|
|||
213 | { |
|
|||
214 | for(auto varId:group->variables()) |
|
|||
215 | { |
|
|||
216 | auto var = _maps.variable(varId); |
|
|||
217 | ranges[varId] = r; |
|
|||
218 | } |
|
|||
219 | } |
|
|||
220 | } |
|
|||
221 | else |
|
|||
222 | { |
|
|||
223 | SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN"); |
|
|||
224 | } |
|
|||
225 | return ranges; |
|
|||
226 | } |
|
68 | } | |
227 |
|
69 | |||
228 | std::pair<std::vector<DateTimeRange>,DateTimeRange> _computeMissingRanges(const std::shared_ptr<Variable>& var, DateTimeRange r) |
|
70 | inline std::shared_ptr<Variable> variable(int index) | |
229 | { |
|
71 | { | |
230 | DateTimeRange newCacheRange; |
|
72 | QReadLocker lock{&_lock}; | |
231 | std::vector<DateTimeRange> missingRanges; |
|
73 | [[unlikely]] if(!_variables.size() > index) | |
232 | if(DateTimeRangeHelper::hasnan(var->cacheRange())) |
|
74 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Index is out of bounds"); | |
233 | { |
|
75 | auto it = _variables.cbegin(); | |
234 | newCacheRange = _cacheStrategy->computeRange(r,r); |
|
76 | while(index != 0) | |
235 | missingRanges = {newCacheRange}; |
|
77 | { | |
236 | } |
|
78 | index -= 1; | |
237 |
|
|
79 | it++; | |
238 |
|
|
80 | } | |
239 | newCacheRange = _cacheStrategy->computeRange(var->cacheRange(),r); |
|
81 | return (*(it)).second; | |
240 | missingRanges = newCacheRange - var->cacheRange(); |
|
|||
241 | } |
|
|||
242 | return {missingRanges,newCacheRange}; |
|
|||
243 | } |
|
82 | } | |
244 |
|
83 | |||
245 | void _changeRange(QUuid id, DateTimeRange r) |
|
84 | inline const std::vector<std::shared_ptr<Variable>> variables() | |
246 | { |
|
85 | { | |
247 | _changeRange(_maps.variable(id) ,r); |
|
86 | std::vector<std::shared_ptr<Variable>> vars; | |
|
87 | QReadLocker lock{&_lock}; | |||
|
88 | for(const auto& [id, var] : _variables) | |||
|
89 | { | |||
|
90 | vars.push_back(var); | |||
|
91 | } | |||
|
92 | return vars; | |||
248 | } |
|
93 | } | |
249 | void _changeRange(const std::shared_ptr<Variable>& var, DateTimeRange r) |
|
94 | ||
|
95 | inline std::shared_ptr<IDataProvider> provider(QUuid variable) | |||
250 | { |
|
96 | { | |
251 | auto provider = _maps.provider(*var); |
|
97 | QReadLocker lock{&_lock}; | |
252 | auto [missingRanges, newCacheRange] = _computeMissingRanges(var,r); |
|
98 | [[unlikely]] if(!_providers.contains(variable)) | |
253 | std::vector<IDataSeries*> data; |
|
99 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); | |
254 | for(auto range:missingRanges) |
|
100 | return _providers[variable]; | |
255 | { |
|
|||
256 | data.push_back(provider->getData(DataProviderParameters{{range}, var->metadata()})); |
|
|||
257 | } |
|
|||
258 | var->updateData(data, r, newCacheRange, true); |
|
|||
259 | } |
|
101 | } | |
260 | public: |
|
102 | ||
261 | VariableController2Private(QObject* parent=Q_NULLPTR) |
|
103 | inline std::shared_ptr<VariableSynchronizationGroup2> group(QUuid variable) | |
262 | :_cacheStrategy(VariableCacheStrategyFactory::createCacheStrategy(CacheStrategy::SingleThreshold)) |
|
|||
263 | { |
|
104 | { | |
264 | Q_UNUSED(parent); |
|
105 | QReadLocker lock{&_lock}; | |
265 | this->_ThreadPool = new QThreadPool(); |
|
106 | [[unlikely]] if(!_synchronizationGroups.contains(variable)) | |
266 | this->_ThreadPool->setMaxThreadCount(32); |
|
107 | SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable"); | |
|
108 | return _synchronizationGroups[variable]; | |||
267 | } |
|
109 | } | |
268 |
|
110 | |||
269 | /* |
|
111 | inline bool has(const std::shared_ptr<Variable>& variable) | |
270 | * This dtor has to like this even if this is ugly, because default dtor would rely on |
|
|||
271 | * declaration order to destruct members and that would always lead to regressions when |
|
|||
272 | * modifying class members |
|
|||
273 | */ |
|
|||
274 | ~VariableController2Private() |
|
|||
275 | { |
|
112 | { | |
276 | delete this->_ThreadPool; |
|
113 | QReadLocker lock{&_lock}; | |
|
114 | return _variables.find(*variable) == _variables.end(); | |||
277 | } |
|
115 | } | |
278 |
|
116 | |||
279 | std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata, std::shared_ptr<IDataProvider> provider) |
|
117 | private: | |
|
118 | std::map<QUuid, std::shared_ptr<Variable>> _variables; | |||
|
119 | QMap<QUuid, std::shared_ptr<IDataProvider>> _providers; | |||
|
120 | QMap<QUuid, std::shared_ptr<VariableSynchronizationGroup2>> | |||
|
121 | _synchronizationGroups; | |||
|
122 | QReadWriteLock _lock{QReadWriteLock::Recursive}; | |||
|
123 | } _maps; | |||
|
124 | std::vector<QUuid> _variablesToRemove; | |||
|
125 | QThreadPool* _ThreadPool; | |||
|
126 | VCTransactionsQueues _transactions; | |||
|
127 | std::unique_ptr<VariableCacheStrategy> _cacheStrategy; | |||
|
128 | ||||
|
129 | void _transactionComplete(QUuid group, | |||
|
130 | std::shared_ptr<VCTransaction> transaction) | |||
|
131 | { | |||
|
132 | if(transaction->done()) { _transactions.complete(group); } | |||
|
133 | this->_processTransactions(); | |||
|
134 | } | |||
|
135 | ||||
|
136 | void _cleanupVariables() | |||
|
137 | { | |||
|
138 | for(auto id : _variablesToRemove) | |||
280 | { |
|
139 | { | |
281 | auto newVar = std::make_shared<Variable>(name,metadata); |
|
140 | auto v = this->variable(id); | |
282 | auto group = std::make_shared<VariableSynchronizationGroup2>(newVar->ID()); |
|
141 | if(!hasPendingTransactions(v)) | |
283 | _maps.addVariable(newVar,std::move(provider),group); |
|
142 | { | |
284 | this->_transactions.addEntry(*group); |
|
143 | _variablesToRemove.erase(std::remove(_variablesToRemove.begin(), | |
285 | return newVar; |
|
144 | _variablesToRemove.end(), id), | |
|
145 | _variablesToRemove.end()); | |||
|
146 | this->deleteVariable(v); | |||
|
147 | } | |||
286 | } |
|
148 | } | |
|
149 | } | |||
287 |
|
150 | |||
288 | std::shared_ptr<Variable> variable(QUuid ID) |
|
151 | void _processTransactions(bool fragmented = false) | |
|
152 | { | |||
|
153 | auto nextTransactions = _transactions.nextTransactions(); | |||
|
154 | auto pendingTransactions = _transactions.pendingTransactions(); | |||
|
155 | for(auto [groupID, newTransaction] : nextTransactions) | |||
289 | { |
|
156 | { | |
290 | return _maps.variable(ID); |
|
157 | if(newTransaction.has_value() && | |
|
158 | !pendingTransactions[groupID].has_value()) | |||
|
159 | { | |||
|
160 | _transactions.start(groupID); | |||
|
161 | auto refVar = _maps.variable(newTransaction.value()->refVar); | |||
|
162 | auto ranges = | |||
|
163 | _computeAllRangesInGroup(refVar, newTransaction.value()->range); | |||
|
164 | for(auto const& [ID, range] : ranges) | |||
|
165 | { | |||
|
166 | auto provider = _maps.provider(ID); | |||
|
167 | auto variable = _maps.variable(ID); | |||
|
168 | if(fragmented) | |||
|
169 | { | |||
|
170 | auto [missingRanges, newCacheRange] = | |||
|
171 | _computeMissingRanges(variable, range); | |||
|
172 | ||||
|
173 | auto exe = new TransactionExe(variable, provider, missingRanges, | |||
|
174 | range, newCacheRange); | |||
|
175 | QObject::connect( | |||
|
176 | exe, &TransactionExe::transactionComplete, | |||
|
177 | [groupID = groupID, transaction = newTransaction.value(), | |||
|
178 | this]() { this->_transactionComplete(groupID, transaction); }); | |||
|
179 | _ThreadPool->start(exe); | |||
|
180 | } | |||
|
181 | else | |||
|
182 | { | |||
|
183 | auto exe = | |||
|
184 | new TransactionExe(variable, provider, {range}, range, range); | |||
|
185 | QObject::connect( | |||
|
186 | exe, &TransactionExe::transactionComplete, | |||
|
187 | [groupID = groupID, transaction = newTransaction.value(), | |||
|
188 | this]() { this->_transactionComplete(groupID, transaction); }); | |||
|
189 | _ThreadPool->start(exe); | |||
|
190 | } | |||
|
191 | } | |||
|
192 | } | |||
291 | } |
|
193 | } | |
292 |
|
194 | // after each transaction update we get a new distribution of idle and | ||
293 | std::shared_ptr<Variable> variable(int index) |
|
195 | // working variables so we can delete variables which are waiting to be | |
|
196 | // deleted if they are now idle | |||
|
197 | _cleanupVariables(); | |||
|
198 | } | |||
|
199 | ||||
|
200 | std::map<QUuid, DateTimeRange> | |||
|
201 | _computeAllRangesInGroup(const std::shared_ptr<Variable>& refVar, | |||
|
202 | DateTimeRange r) | |||
|
203 | { | |||
|
204 | std::map<QUuid, DateTimeRange> ranges; | |||
|
205 | if(!DateTimeRangeHelper::hasnan(r)) | |||
294 | { |
|
206 | { | |
295 | return _maps.variable(index); |
|
207 | auto group = _maps.group(*refVar); | |
|
208 | if(auto transformation = | |||
|
209 | DateTimeRangeHelper::computeTransformation(refVar->range(), r); | |||
|
210 | transformation.has_value()) | |||
|
211 | { | |||
|
212 | for(auto varId : group->variables()) | |||
|
213 | { | |||
|
214 | auto var = _maps.variable(varId); | |||
|
215 | auto newRange = var->range().transform(transformation.value()); | |||
|
216 | ranges[varId] = newRange; | |||
|
217 | } | |||
|
218 | } | |||
|
219 | else // force new range to all variables -> may be weird if more than one | |||
|
220 | // var in the group | |||
|
221 | // @TODO ensure that there is no side effects | |||
|
222 | { | |||
|
223 | for(auto varId : group->variables()) | |||
|
224 | { | |||
|
225 | auto var = _maps.variable(varId); | |||
|
226 | ranges[varId] = r; | |||
|
227 | } | |||
|
228 | } | |||
296 | } |
|
229 | } | |
297 |
|
230 | else | ||
298 | std::shared_ptr<Variable> cloneVariable(const std::shared_ptr<Variable>& variable) |
|
|||
299 | { |
|
231 | { | |
300 | auto newVar = variable->clone(); |
|
232 | SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN"); | |
301 | _maps.synchronize(newVar,std::nullopt); |
|
|||
302 | _maps.addVariable(newVar,_maps.provider(*variable),_maps.group(*newVar)); |
|
|||
303 | this->_transactions.addEntry(*_maps.group(*newVar)); |
|
|||
304 | return newVar; |
|
|||
305 | } |
|
233 | } | |
306 |
|
234 | return ranges; | ||
307 | bool hasPendingTransactions(const std::shared_ptr<Variable>& variable) |
|
235 | } | |
|
236 | ||||
|
237 | std::pair<std::vector<DateTimeRange>, DateTimeRange> | |||
|
238 | _computeMissingRanges(const std::shared_ptr<Variable>& var, DateTimeRange r) | |||
|
239 | { | |||
|
240 | DateTimeRange newCacheRange; | |||
|
241 | std::vector<DateTimeRange> missingRanges; | |||
|
242 | if(DateTimeRangeHelper::hasnan(var->cacheRange())) | |||
308 | { |
|
243 | { | |
309 | return _transactions.active(*_maps.group(*variable)); |
|
244 | newCacheRange = _cacheStrategy->computeRange(r, r); | |
|
245 | missingRanges = {newCacheRange}; | |||
310 | } |
|
246 | } | |
311 |
|
247 | else | ||
312 | bool hasPendingTransactions() |
|
|||
313 | { |
|
248 | { | |
314 | bool has = false; |
|
249 | newCacheRange = _cacheStrategy->computeRange(var->cacheRange(), r); | |
315 | for(const auto& var:_maps.variables()) |
|
250 | missingRanges = newCacheRange - var->cacheRange(); | |
316 | { |
|
|||
317 | has |= _transactions.active(*_maps.group(*var)); |
|
|||
318 | } |
|
|||
319 | return has; |
|
|||
320 | } |
|
251 | } | |
321 |
|
252 | return {missingRanges, newCacheRange}; | ||
322 | void deleteVariable(const std::shared_ptr<Variable>& variable) |
|
253 | } | |
|
254 | ||||
|
255 | void _changeRange(QUuid id, DateTimeRange r) | |||
|
256 | { | |||
|
257 | _changeRange(_maps.variable(id), r); | |||
|
258 | } | |||
|
259 | void _changeRange(const std::shared_ptr<Variable>& var, DateTimeRange r) | |||
|
260 | { | |||
|
261 | auto provider = _maps.provider(*var); | |||
|
262 | auto [missingRanges, newCacheRange] = _computeMissingRanges(var, r); | |||
|
263 | std::vector<IDataSeries*> data; | |||
|
264 | for(auto range : missingRanges) | |||
323 | { |
|
265 | { | |
324 | if(!hasPendingTransactions(variable)) |
|
266 | data.push_back( | |
325 | _maps.removeVariable(variable); |
|
267 | provider->getData(DataProviderParameters{{range}, var->metadata()})); | |
326 | else |
|
|||
327 | _variablesToRemove.push_back(variable->ID()); |
|
|||
328 | } |
|
268 | } | |
|
269 | var->updateData(data, r, newCacheRange, true); | |||
|
270 | } | |||
329 |
|
271 | |||
330 | void asyncChangeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r) |
|
272 | public: | |
|
273 | VariableController2Private(QObject* parent = Q_NULLPTR) | |||
|
274 | : _cacheStrategy(VariableCacheStrategyFactory::createCacheStrategy( | |||
|
275 | CacheStrategy::SingleThreshold)) | |||
|
276 | { | |||
|
277 | Q_UNUSED(parent); | |||
|
278 | this->_ThreadPool = new QThreadPool(); | |||
|
279 | this->_ThreadPool->setMaxThreadCount(32); | |||
|
280 | } | |||
|
281 | ||||
|
282 | /* | |||
|
283 | * This dtor has to like this even if this is ugly, because default dtor would | |||
|
284 | * rely on declaration order to destruct members and that would always lead to | |||
|
285 | * regressions when modifying class members | |||
|
286 | */ | |||
|
287 | ~VariableController2Private() { delete this->_ThreadPool; } | |||
|
288 | ||||
|
289 | std::shared_ptr<Variable> | |||
|
290 | createVariable(const QString& name, const QVariantHash& metadata, | |||
|
291 | std::shared_ptr<IDataProvider> provider) | |||
|
292 | { | |||
|
293 | auto newVar = std::make_shared<Variable>(name, metadata); | |||
|
294 | auto group = std::make_shared<VariableSynchronizationGroup2>(newVar->ID()); | |||
|
295 | _maps.addVariable(newVar, std::move(provider), group); | |||
|
296 | this->_transactions.addEntry(*group); | |||
|
297 | return newVar; | |||
|
298 | } | |||
|
299 | ||||
|
300 | std::shared_ptr<Variable> variable(QUuid ID) { return _maps.variable(ID); } | |||
|
301 | ||||
|
302 | std::shared_ptr<Variable> variable(int index) | |||
|
303 | { | |||
|
304 | return _maps.variable(index); | |||
|
305 | } | |||
|
306 | ||||
|
307 | std::shared_ptr<Variable> | |||
|
308 | cloneVariable(const std::shared_ptr<Variable>& variable) | |||
|
309 | { | |||
|
310 | auto newVar = variable->clone(); | |||
|
311 | _maps.synchronize(newVar, std::nullopt); | |||
|
312 | _maps.addVariable(newVar, _maps.provider(*variable), _maps.group(*newVar)); | |||
|
313 | this->_transactions.addEntry(*_maps.group(*newVar)); | |||
|
314 | return newVar; | |||
|
315 | } | |||
|
316 | ||||
|
317 | bool hasPendingTransactions(const std::shared_ptr<Variable>& variable) | |||
|
318 | { | |||
|
319 | return _transactions.active(*_maps.group(*variable)); | |||
|
320 | } | |||
|
321 | ||||
|
322 | bool hasPendingTransactions() | |||
|
323 | { | |||
|
324 | bool has = false; | |||
|
325 | for(const auto& var : _maps.variables()) | |||
331 | { |
|
326 | { | |
332 | if(!DateTimeRangeHelper::hasnan(r)) |
|
327 | has |= _transactions.active(*_maps.group(*var)); | |
333 | { |
|
|||
334 | auto group = _maps.group(*variable); |
|
|||
335 | // Just overwrite next transaction |
|
|||
336 | { |
|
|||
337 | _transactions.enqueue(*group,std::make_shared<VCTransaction>(variable->ID(), r, static_cast<int>(group->variables().size()))); |
|
|||
338 | } |
|
|||
339 | _processTransactions(); |
|
|||
340 | } |
|
|||
341 | else |
|
|||
342 | { |
|
|||
343 | SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN"); |
|
|||
344 | } |
|
|||
345 | } |
|
328 | } | |
|
329 | return has; | |||
|
330 | } | |||
346 |
|
331 | |||
347 |
|
|
332 | void deleteVariable(const std::shared_ptr<Variable>& variable) | |
|
333 | { | |||
|
334 | if(!hasPendingTransactions(variable)) | |||
|
335 | _maps.removeVariable(variable); | |||
|
336 | else | |||
|
337 | _variablesToRemove.push_back(variable->ID()); | |||
|
338 | } | |||
|
339 | ||||
|
340 | void asyncChangeRange(const std::shared_ptr<Variable>& variable, | |||
|
341 | const DateTimeRange& r) | |||
|
342 | { | |||
|
343 | if(!DateTimeRangeHelper::hasnan(r)) | |||
348 | { |
|
344 | { | |
349 | asyncChangeRange(variable,r); |
|
345 | auto group = _maps.group(*variable); | |
350 | while (hasPendingTransactions(variable)) |
|
346 | // Just overwrite next transaction | |
351 |
|
|
347 | { | |
352 | QCoreApplication::processEvents(); |
|
348 | _transactions.enqueue(*group, | |
353 | } |
|
349 | std::make_shared<VCTransaction>( | |
|
350 | variable->ID(), r, | |||
|
351 | static_cast<int>(group->variables().size()))); | |||
|
352 | } | |||
|
353 | _processTransactions(); | |||
354 | } |
|
354 | } | |
355 |
|
355 | else | ||
356 | inline void synchronize(const std::shared_ptr<Variable>& var, const std::shared_ptr<Variable>& with) |
|
|||
357 | { |
|
356 | { | |
358 | _maps.synchronize(var, with); |
|
357 | SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN"); | |
359 | } |
|
358 | } | |
|
359 | } | |||
360 |
|
360 | |||
361 |
|
|
361 | void changeRange(const std::shared_ptr<Variable>& variable, DateTimeRange r) | |
|
362 | { | |||
|
363 | asyncChangeRange(variable, r); | |||
|
364 | while(hasPendingTransactions(variable)) | |||
362 | { |
|
365 | { | |
363 | return _maps.variables(); |
|
366 | QCoreApplication::processEvents(); | |
364 | } |
|
367 | } | |
365 |
|
368 | } | ||
|
369 | ||||
|
370 | inline void synchronize(const std::shared_ptr<Variable>& var, | |||
|
371 | const std::shared_ptr<Variable>& with) | |||
|
372 | { | |||
|
373 | _maps.synchronize(var, with); | |||
|
374 | } | |||
|
375 | ||||
|
376 | inline const std::vector<std::shared_ptr<Variable>> variables() | |||
|
377 | { | |||
|
378 | return _maps.variables(); | |||
|
379 | } | |||
366 | }; |
|
380 | }; | |
367 |
|
381 | |||
368 | VariableController2::VariableController2() |
|
382 | VariableController2::VariableController2() | |
369 | :impl{spimpl::make_unique_impl<VariableController2Private>()} |
|
383 | : impl{spimpl::make_unique_impl<VariableController2Private>()} | |
370 | {} |
|
384 | {} | |
371 |
|
385 | |||
372 | std::shared_ptr<Variable> VariableController2::createVariable(const QString &name, const QVariantHash &metadata, const std::shared_ptr<IDataProvider>& provider, const DateTimeRange &range) |
|
386 | std::shared_ptr<Variable> VariableController2::createVariable( | |
|
387 | const QString& name, const QVariantHash& metadata, | |||
|
388 | const std::shared_ptr<IDataProvider>& provider, const DateTimeRange& range) | |||
373 | { |
|
389 | { | |
374 |
|
|
390 | auto var = impl->createVariable(name, metadata, provider); | |
375 |
|
|
391 | var->setRange(range); // even with no data this is it's range | |
376 |
|
|
392 | if(!DateTimeRangeHelper::hasnan(range)) | |
377 |
|
|
393 | impl->asyncChangeRange(var, range); | |
378 |
|
|
394 | else | |
379 |
|
|
395 | SCIQLOP_ERROR(VariableController2, "Creating a variable with default " | |
380 | emit variableAdded(var); |
|
396 | "constructed DateTimeRange is an error"); | |
381 | return var; |
|
397 | emit variableAdded(var); | |
|
398 | return var; | |||
382 | } |
|
399 | } | |
383 |
|
400 | |||
384 | std::shared_ptr<Variable> VariableController2::cloneVariable(const std::shared_ptr<Variable> &variable) |
|
401 | std::shared_ptr<Variable> | |
|
402 | VariableController2::cloneVariable(const std::shared_ptr<Variable>& variable) | |||
385 | { |
|
403 | { | |
386 |
|
|
404 | return impl->cloneVariable(variable); | |
387 | } |
|
405 | } | |
388 |
|
406 | |||
389 |
void VariableController2::deleteVariable( |
|
407 | void VariableController2::deleteVariable( | |
|
408 | const std::shared_ptr<Variable>& variable) | |||
390 | { |
|
409 | { | |
391 |
|
|
410 | impl->deleteVariable(variable); | |
392 |
|
|
411 | emit variableDeleted(variable); | |
393 | } |
|
412 | } | |
394 |
|
413 | |||
395 |
void VariableController2::changeRange(const std::shared_ptr<Variable>& variable, |
|
414 | void VariableController2::changeRange(const std::shared_ptr<Variable>& variable, | |
|
415 | const DateTimeRange& r) | |||
396 | { |
|
416 | { | |
397 |
|
|
417 | impl->changeRange(variable, r); | |
398 | } |
|
418 | } | |
399 |
|
419 | |||
400 | void VariableController2::asyncChangeRange(const std::shared_ptr<Variable> &variable, const DateTimeRange &r) |
|
420 | void VariableController2::asyncChangeRange( | |
|
421 | const std::shared_ptr<Variable>& variable, const DateTimeRange& r) | |||
401 | { |
|
422 | { | |
402 |
|
|
423 | impl->asyncChangeRange(variable, r); | |
403 | } |
|
424 | } | |
404 |
|
425 | |||
405 |
const std::vector<std::shared_ptr<Variable> |
|
426 | const std::vector<std::shared_ptr<Variable>> VariableController2::variables() | |
406 | { |
|
427 | { | |
407 |
|
|
428 | return impl->variables(); | |
408 | } |
|
429 | } | |
409 |
|
430 | |||
410 |
bool VariableController2::isReady(const std::shared_ptr<Variable> |
|
431 | bool VariableController2::isReady(const std::shared_ptr<Variable>& variable) | |
411 | { |
|
432 | { | |
412 |
|
|
433 | return !impl->hasPendingTransactions(variable); | |
413 | } |
|
434 | } | |
414 |
|
435 | |||
415 | bool VariableController2::isReady() |
|
436 | bool VariableController2::isReady() { return !impl->hasPendingTransactions(); } | |
416 | { |
|
|||
417 | return !impl->hasPendingTransactions(); |
|
|||
418 | } |
|
|||
419 |
|
437 | |||
420 |
void VariableController2::synchronize(const std::shared_ptr<Variable> |
|
438 | void VariableController2::synchronize(const std::shared_ptr<Variable>& var, | |
|
439 | const std::shared_ptr<Variable>& with) | |||
421 | { |
|
440 | { | |
422 |
|
|
441 | impl->synchronize(var, with); | |
423 | } |
|
442 | } | |
424 |
|
443 | |||
425 | const std::vector<std::shared_ptr<Variable>> VariableController2::variables(const std::vector<QUuid> &ids) |
|
444 | const std::vector<std::shared_ptr<Variable>> | |
|
445 | VariableController2::variables(const std::vector<QUuid>& ids) | |||
426 | { |
|
446 | { | |
427 |
|
|
447 | std::vector<std::shared_ptr<Variable>> variables; | |
428 | for (const auto& id : ids) { |
|
448 | std::transform(std::cbegin(ids), std::cend(ids), | |
429 | variables.push_back(impl->variable(id)); |
|
449 | std::back_inserter(variables), | |
430 | } |
|
450 | [this](const auto& id) { return impl->variable(id); }); | |
431 |
|
|
451 | return variables; | |
432 | } |
|
452 | } |
@@ -1,157 +1,177 | |||||
1 | #include <pybind11/pybind11.h> |
|
1 | #include "CoreWrappers.h" | |
2 | #include <pybind11/operators.h> |
|
|||
3 | #include <pybind11/embed.h> |
|
|||
4 | #include <pybind11/numpy.h> |
|
|||
5 | #include <pybind11/chrono.h> |
|
|||
6 | #include <pybind11/functional.h> |
|
|||
7 | #include <pybind11/stl.h> |
|
|||
8 |
|
||||
9 |
|
||||
10 | #include <string> |
|
|||
11 | #include <sstream> |
|
|||
12 |
|
2 | |||
13 | #include "pywrappers_common.h" |
|
3 | #include "pywrappers_common.h" | |
14 | #include "CoreWrappers.h" |
|
|||
15 |
|
4 | |||
16 | #include <Data/DataSeriesType.h> |
|
5 | #include <Data/DataSeriesType.h> | |
|
6 | #include <Data/IDataProvider.h> | |||
|
7 | #include <Data/OptionalAxis.h> | |||
17 | #include <Data/ScalarSeries.h> |
|
8 | #include <Data/ScalarSeries.h> | |
18 | #include <Data/VectorSeries.h> |
|
|||
19 | #include <Data/SpectrogramSeries.h> |
|
9 | #include <Data/SpectrogramSeries.h> | |
20 | #include <Data/Unit.h> |
|
10 | #include <Data/Unit.h> | |
21 |
#include <Data/ |
|
11 | #include <Data/VectorSeries.h> | |
22 | #include <Data/IDataProvider.h> |
|
|||
23 |
|
||||
24 | #include <Variable/VariableController2.h> |
|
|||
25 |
|
||||
26 | #include <Time/TimeController.h> |
|
|||
27 |
|
||||
28 | #include <Network/Downloader.h> |
|
12 | #include <Network/Downloader.h> | |
29 |
|
13 | #include <Time/TimeController.h> | ||
30 |
|
14 | #include <Variable/VariableController2.h> | ||
|
15 | #include <pybind11/chrono.h> | |||
|
16 | #include <pybind11/embed.h> | |||
|
17 | #include <pybind11/functional.h> | |||
|
18 | #include <pybind11/numpy.h> | |||
|
19 | #include <pybind11/operators.h> | |||
|
20 | #include <pybind11/pybind11.h> | |||
|
21 | #include <pybind11/stl.h> | |||
|
22 | #include <sstream> | |||
|
23 | #include <string> | |||
31 |
|
24 | |||
32 | namespace py = pybind11; |
|
25 | namespace py = pybind11; | |
33 | using namespace std::chrono; |
|
26 | using namespace std::chrono; | |
34 |
|
27 | |||
35 |
PYBIND11_MODULE(pysciqlopcore,m) |
|
28 | PYBIND11_MODULE(pysciqlopcore, m) | |
36 |
|
29 | { | ||
37 |
|
|
30 | py::enum_<DataSeriesType>(m, "DataSeriesType") | |
38 |
|
|
31 | .value("SCALAR", DataSeriesType::SCALAR) | |
39 |
|
|
32 | .value("SPECTROGRAM", DataSeriesType::SPECTROGRAM) | |
40 |
|
|
33 | .value("VECTOR", DataSeriesType::VECTOR) | |
41 |
|
|
34 | .value("UNKNOWN", DataSeriesType::UNKNOWN) | |
42 |
|
|
35 | .export_values(); | |
43 |
|
36 | |||
44 |
|
|
37 | py::class_<Unit>(m, "Unit") | |
45 |
|
|
38 | .def_readwrite("name", &Unit::m_Name) | |
46 |
|
|
39 | .def_readwrite("time_unit", &Unit::m_TimeUnit) | |
47 |
|
|
40 | .def(py::self == py::self) | |
48 |
|
|
41 | .def(py::self != py::self) | |
49 |
|
|
42 | .def("__repr__", __repr__<Unit>); | |
50 |
|
43 | |||
51 |
|
|
44 | py::class_<Response>(m, "Response") | |
52 |
|
|
45 | .def("status_code", &Response::status_code); | |
53 |
|
46 | |||
54 |
|
|
47 | py::class_<Downloader>(m, "Downloader") | |
55 |
|
|
48 | .def_static("get", Downloader::get) | |
56 |
|
|
49 | .def_static("getAsync", Downloader::getAsync) | |
57 |
|
|
50 | .def_static("downloadFinished", Downloader::downloadFinished); | |
58 |
|
51 | |||
59 |
|
|
52 | py::class_<ArrayDataIteratorValue>(m, "ArrayDataIteratorValue") | |
60 |
|
|
53 | .def_property_readonly("value", &ArrayDataIteratorValue::first); | |
61 |
|
54 | |||
62 |
|
|
55 | py::class_<OptionalAxis>(m, "OptionalAxis") | |
63 |
|
|
56 | .def("__len__", &OptionalAxis::size) | |
64 |
|
|
57 | .def_property_readonly("size", &OptionalAxis::size) | |
65 | .def("__getitem__", [](OptionalAxis& ax, int key) { |
|
58 | .def("__getitem__", | |
66 | return (*(ax.begin()+key)).first(); |
|
59 | [](OptionalAxis& ax, int key) { | |
67 | }, py::is_operator()) |
|
60 | return (*(ax.begin() + key)).first(); | |
68 | .def("__iter__", [](OptionalAxis& ax) { |
|
61 | }, | |
69 | return py::make_iterator(ax.begin(), ax.end()); |
|
62 | py::is_operator()) | |
70 | }, py::keep_alive<0, 1>()); |
|
63 | .def("__iter__", | |
71 |
|
64 | [](OptionalAxis& ax) { | ||
72 | py::class_<DataSeriesIteratorValue>(m,"DataSeriesIteratorValue") |
|
65 | return py::make_iterator(ax.begin(), ax.end()); | |
73 | .def_property_readonly("x", &DataSeriesIteratorValue::x) |
|
66 | }, | |
74 | .def_property_readonly("y", &DataSeriesIteratorValue::y) |
|
67 | py::keep_alive<0, 1>()); | |
75 | .def("value", py::overload_cast<>(&DataSeriesIteratorValue::value, py::const_)) |
|
68 | ||
76 | .def("value", py::overload_cast<int>(&DataSeriesIteratorValue::value, py::const_)) |
|
69 | py::class_<DataSeriesIteratorValue>(m, "DataSeriesIteratorValue") | |
77 |
|
|
70 | .def_property_readonly("x", &DataSeriesIteratorValue::x) | |
78 |
|
71 | .def_property_readonly("y", &DataSeriesIteratorValue::y) | ||
79 | py::class_<IDataSeries, std::shared_ptr<IDataSeries>>(m, "IDataSeries") |
|
72 | .def("value", | |
80 | .def("nbPoints", &IDataSeries::nbPoints) |
|
73 | py::overload_cast<>(&DataSeriesIteratorValue::value, py::const_)) | |
81 | .def_property_readonly("xAxisUnit", &IDataSeries::xAxisUnit) |
|
74 | .def("value", | |
82 | .def_property_readonly("yAxisUnit", &IDataSeries::yAxisUnit) |
|
75 | py::overload_cast<int>(&DataSeriesIteratorValue::value, py::const_)) | |
83 |
|
|
76 | .def("values", &DataSeriesIteratorValue::values); | |
84 | .def("__getitem__", [](IDataSeries& serie, int key) { |
|
77 | ||
85 | return *(serie.begin()+key); |
|
78 | py::class_<IDataSeries, std::shared_ptr<IDataSeries>>(m, "IDataSeries") | |
86 | }, py::is_operator()) |
|
79 | .def("nbPoints", &IDataSeries::nbPoints) | |
87 | .def("__len__", &IDataSeries::nbPoints) |
|
80 | .def_property_readonly("xAxisUnit", &IDataSeries::xAxisUnit) | |
88 | .def("__iter__", [](IDataSeries& serie) { |
|
81 | .def_property_readonly("yAxisUnit", &IDataSeries::yAxisUnit) | |
89 | return py::make_iterator(serie.begin(), serie.end()); |
|
82 | .def_property_readonly("valuesUnit", &IDataSeries::valuesUnit) | |
90 | }, py::keep_alive<0, 1>()) |
|
83 | .def("__getitem__", | |
91 | .def("__repr__",__repr__<IDataSeries>); |
|
84 | [](IDataSeries& serie, int key) { return *(serie.begin() + key); }, | |
92 |
|
85 | py::is_operator()) | ||
93 | py::class_<ArrayData<1>, std::shared_ptr<ArrayData<1>> >(m,"ArrayData1d") |
|
86 | .def("__len__", &IDataSeries::nbPoints) | |
94 | .def("cdata", [](ArrayData<1>& array) {return array.cdata();}); |
|
87 | .def("__iter__", | |
95 |
|
88 | [](IDataSeries& serie) { | ||
96 | py::class_<ScalarSeries, std::shared_ptr<ScalarSeries>, IDataSeries>(m, "ScalarSeries") |
|
89 | return py::make_iterator(serie.begin(), serie.end()); | |
97 | .def("nbPoints", &ScalarSeries::nbPoints); |
|
90 | }, | |
98 |
|
91 | py::keep_alive<0, 1>()) | ||
99 | py::class_<VectorSeries, std::shared_ptr<VectorSeries>, IDataSeries>(m, "VectorSeries") |
|
92 | .def("__repr__", __repr__<IDataSeries>); | |
100 | .def("nbPoints", &VectorSeries::nbPoints); |
|
93 | ||
101 |
|
94 | py::class_<ArrayData<1>, std::shared_ptr<ArrayData<1>>>(m, "ArrayData1d") | ||
102 | py::class_<DataSeries<2>, std::shared_ptr<DataSeries<2>>, IDataSeries>(m,"DataSeries2d") |
|
95 | .def("cdata", [](ArrayData<1>& array) { return array.cdata(); }); | |
103 | .def_property_readonly("xAxis", py::overload_cast<>(&DataSeries<2>::xAxisData, py::const_)) |
|
96 | ||
104 | .def_property_readonly("yAxis", py::overload_cast<>(&DataSeries<2>::yAxis, py::const_)); |
|
97 | py::class_<ScalarSeries, std::shared_ptr<ScalarSeries>, IDataSeries>( | |
105 |
|
98 | m, "ScalarSeries") | ||
106 | py::class_<SpectrogramSeries, std::shared_ptr<SpectrogramSeries>, DataSeries<2>>(m, "SpectrogramSeries") |
|
99 | .def("nbPoints", &ScalarSeries::nbPoints); | |
107 | .def("nbPoints", &SpectrogramSeries::nbPoints) |
|
100 | ||
108 | .def("xRes", &SpectrogramSeries::xResolution); |
|
101 | py::class_<VectorSeries, std::shared_ptr<VectorSeries>, IDataSeries>( | |
109 |
|
102 | m, "VectorSeries") | ||
110 |
|
103 | .def("nbPoints", &VectorSeries::nbPoints); | ||
111 | py::class_<IDataProvider, std::shared_ptr<IDataProvider>>(m, "IDataProvider"); |
|
104 | ||
112 |
|
105 | py::class_<DataSeries<2>, std::shared_ptr<DataSeries<2>>, IDataSeries>( | ||
113 |
|
106 | m, "DataSeries2d") | ||
114 | py::class_<Variable,std::shared_ptr<Variable>>(m, "Variable") |
|
107 | .def_property_readonly( | |
115 | .def(py::init<const QString&>()) |
|
108 | "xAxis", py::overload_cast<>(&DataSeries<2>::xAxisData, py::const_)) | |
116 | .def_property("name", &Variable::name, &Variable::setName) |
|
109 | .def_property_readonly( | |
117 | .def_property("range", &Variable::range, &Variable::setRange) |
|
110 | "yAxis", py::overload_cast<>(&DataSeries<2>::yAxis, py::const_)); | |
118 | .def_property("cacheRange", &Variable::cacheRange, &Variable::setCacheRange) |
|
111 | ||
119 | .def_property_readonly("nbPoints", &Variable::nbPoints) |
|
112 | py::class_<SpectrogramSeries, std::shared_ptr<SpectrogramSeries>, | |
120 | .def_property_readonly("dataSeries", &Variable::dataSeries) |
|
113 | DataSeries<2>>(m, "SpectrogramSeries") | |
121 | .def("__len__", [](Variable& variable) { |
|
114 | .def("nbPoints", &SpectrogramSeries::nbPoints) | |
122 | auto rng = variable.dataSeries()->xAxisRange(variable.range().m_TStart,variable.range().m_TEnd); |
|
115 | .def("xRes", &SpectrogramSeries::xResolution); | |
123 | return std::distance(rng.first,rng.second); |
|
116 | ||
124 | }) |
|
117 | py::class_<IDataProvider, std::shared_ptr<IDataProvider>>(m, "IDataProvider"); | |
125 | .def("__iter__", [](Variable& variable) { |
|
118 | ||
126 | auto rng = variable.dataSeries()->xAxisRange(variable.range().m_TStart,variable.range().m_TEnd); |
|
119 | py::class_<Variable, std::shared_ptr<Variable>>(m, "Variable") | |
127 | return py::make_iterator(rng.first, rng.second); |
|
120 | .def(py::init<const QString&>()) | |
128 | }, py::keep_alive<0, 1>()) |
|
121 | .def_property("name", &Variable::name, &Variable::setName) | |
129 | .def("__getitem__", [](Variable& variable, int key) { |
|
122 | .def_property("range", &Variable::range, &Variable::setRange) | |
130 | //insane and slow! |
|
123 | .def_property("cacheRange", &Variable::cacheRange, | |
131 | auto rng = variable.dataSeries()->xAxisRange(variable.range().m_TStart,variable.range().m_TEnd); |
|
124 | &Variable::setCacheRange) | |
132 | if(key<0) |
|
125 | .def_property_readonly("nbPoints", &Variable::nbPoints) | |
133 | return *(rng.second+key); |
|
126 | .def_property_readonly("dataSeries", &Variable::dataSeries) | |
134 | else |
|
127 | .def("__len__", | |
135 | return *(rng.first+key); |
|
128 | [](Variable& variable) { | |
136 | }) |
|
129 | auto rng = variable.dataSeries()->xAxisRange( | |
137 | .def("__repr__",__repr__<Variable>); |
|
130 | variable.range().m_TStart, variable.range().m_TEnd); | |
138 |
|
131 | return std::distance(rng.first, rng.second); | ||
139 |
|
132 | }) | ||
140 | py::class_<DateTimeRange>(m,"SqpRange") |
|
133 | .def("__iter__", | |
141 | //.def("fromDateTime", &DateTimeRange::fromDateTime, py::return_value_policy::move) |
|
134 | [](Variable& variable) { | |
142 | .def(py::init([](double start, double stop){return DateTimeRange{start, stop};})) |
|
135 | auto rng = variable.dataSeries()->xAxisRange( | |
143 | .def(py::init([](system_clock::time_point start, system_clock::time_point stop) |
|
136 | variable.range().m_TStart, variable.range().m_TEnd); | |
144 | { |
|
137 | return py::make_iterator(rng.first, rng.second); | |
145 | double start_ = 0.001 * duration_cast<milliseconds>(start.time_since_epoch()).count(); |
|
138 | }, | |
146 | double stop_ = 0.001 * duration_cast<milliseconds>(stop.time_since_epoch()).count(); |
|
139 | py::keep_alive<0, 1>()) | |
147 | return DateTimeRange{start_, stop_}; |
|
140 | .def("__getitem__", | |
148 | })) |
|
141 | [](Variable& variable, int key) { | |
149 | .def_property_readonly("start", [](const DateTimeRange& range){ |
|
142 | // insane and slow! | |
150 | return system_clock::from_time_t(range.m_TStart); |
|
143 | auto rng = variable.dataSeries()->xAxisRange( | |
151 | }) |
|
144 | variable.range().m_TStart, variable.range().m_TEnd); | |
152 | .def_property_readonly("stop", [](const DateTimeRange& range){ |
|
145 | if(key < 0) | |
153 | return system_clock::from_time_t(range.m_TEnd); |
|
146 | return *(rng.second + key); | |
154 | }) |
|
147 | else | |
155 | .def("__repr__", __repr__<DateTimeRange>); |
|
148 | return *(rng.first + key); | |
156 |
|
149 | }) | ||
|
150 | .def("__repr__", __repr__<Variable>); | |||
|
151 | ||||
|
152 | py::class_<DateTimeRange>(m, "SqpRange") | |||
|
153 | //.def("fromDateTime", &DateTimeRange::fromDateTime, | |||
|
154 | //py::return_value_policy::move) | |||
|
155 | .def(py::init([](double start, double stop) { | |||
|
156 | return DateTimeRange{start, stop}; | |||
|
157 | })) | |||
|
158 | .def(py::init( | |||
|
159 | [](system_clock::time_point start, system_clock::time_point stop) { | |||
|
160 | double start_ = | |||
|
161 | 0.001 * | |||
|
162 | duration_cast<milliseconds>(start.time_since_epoch()).count(); | |||
|
163 | double stop_ = | |||
|
164 | 0.001 * | |||
|
165 | duration_cast<milliseconds>(stop.time_since_epoch()).count(); | |||
|
166 | return DateTimeRange{start_, stop_}; | |||
|
167 | })) | |||
|
168 | .def_property_readonly("start", | |||
|
169 | [](const DateTimeRange& range) { | |||
|
170 | return system_clock::from_time_t(range.m_TStart); | |||
|
171 | }) | |||
|
172 | .def_property_readonly("stop", | |||
|
173 | [](const DateTimeRange& range) { | |||
|
174 | return system_clock::from_time_t(range.m_TEnd); | |||
|
175 | }) | |||
|
176 | .def("__repr__", __repr__<DateTimeRange>); | |||
157 | } |
|
177 | } |
General Comments 0
You need to be logged in to leave comments.
Login now