##// END OF EJS Templates
Removed old IDataProvider interface, added small tweak in downloader...
jeandet -
r28:a05b0ab23493
parent child
Show More
@@ -1,112 +1,55
1 1 #ifndef SCIQLOP_IDATAPROVIDER_H
2 2 #define SCIQLOP_IDATAPROVIDER_H
3 3
4 4 #include "CoreGlobal.h"
5 5 #include <Common/deprecate.h>
6 6
7 7 #include <memory>
8 8
9 9 #include <QObject>
10 10 #include <QUuid>
11 11
12 12 #include <Common/MetaTypes.h>
13 13
14 14 #include <Data/DateTimeRange.h>
15 15
16 16 #include <functional>
17 17
18 18 class DataProviderParameters;
19 19 class IDataSeries;
20 20 DEPRECATE(
21 21 class QNetworkReply;
22 22 class QNetworkRequest;
23 23 )
24 24
25 25 /**
26 26 * @brief The IDataProvider interface aims to declare a data provider.
27 27 *
28 28 * A data provider is an entity that generates data and returns it according to various parameters
29 29 * (time interval, product to retrieve the data, etc.)
30 * Since its client mihgt use it from different threads it has to be either stateless and/or thread safe
30 31 *
31 32 * @sa IDataSeries
32 33 */
33 34 class SCIQLOP_CORE_EXPORT IDataProvider : public QObject {
34 35
35 36 Q_OBJECT
36 37 public:
37 38 virtual ~IDataProvider() noexcept = default;
38 39 virtual std::shared_ptr<IDataProvider> clone() const = 0;
39 40
40 DEPRECATE(
41 /**
42 * @brief requestDataLoading provide datas for the data identified by acqIdentifier and
43 * parameters
44 */
45 virtual void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
46 = 0;
47 )
48
49 41 // Synchronous call -> asyncGetData may be written for asynchronous get
50 virtual IDataSeries* getData(const DataProviderParameters &parameters)
51 {
52 Q_UNUSED(parameters);
53 return nullptr;
54 }
55
56
57 DEPRECATE(
58 /**
59 * @brief requestDataAborting stop data loading of the data identified by acqIdentifier
60 */
61 virtual void requestDataAborting(QUuid acqIdentifier) = 0;
62 )
63
64 virtual void abort(QUuid requestID){Q_UNUSED(requestID);}
42 virtual IDataSeries* getData(const DataProviderParameters &parameters) = 0;
65 43
66 44 signals:
67 DEPRECATE(
68 /**
69 * @brief dataProvided send dataSeries under dateTime and that corresponds of the data
70 * identified by acqIdentifier
71 */
72 void dataProvided(QUuid acqIdentifier, std::shared_ptr<IDataSeries> dateSeriesAcquired,
73 const DateTimeRange &dataRangeAcquired);
74 )
75
76 void finished(QUuid requestID, std::shared_ptr<IDataSeries> dataSerie,
77 const DateTimeRange &range);
78
79 DEPRECATE(
80 /**
81 * @brief dataProvidedProgress notify the progression of the data identifier by acqIdentifier
82 */
83 void dataProvidedProgress(QUuid acqIdentifier, double progress);
84 )
85 45
86 46 void progress(QUuid requestID, double progress);
87 47
88 DEPRECATE(
89 /**
90 * @brief dataProvidedFailed notify that data acquisition has failed
91 */
92 void dataProvidedFailed(QUuid acqIdentifier);
93 )
94
95 void failed(QUuid requestID);
96
97 /**
98 * @brief requestConstructed send a request for the data identified by acqIdentifier
99 * @callback is the methode call by the reply of the request when it is finished.
100 */
101 DEPRECATE(
102 void requestConstructed(std::shared_ptr<QNetworkRequest> request, QUuid acqIdentifier,
103 std::function<void(QNetworkReply *, QUuid)> callback);
104 )
105 48 };
106 49
107 50 // Required for using shared_ptr in signals/slots
108 51 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY, std::shared_ptr<IDataProvider>)
109 52 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_FUNCTION_REGISTRY,
110 53 std::function<void(QNetworkReply *, QUuid)>)
111 54
112 55 #endif // SCIQLOP_IDATAPROVIDER_H
@@ -1,126 +1,128
1 1 #include <QThreadPool>
2 2 #include <QRunnable>
3 3 #include <QObject>
4 4 #include <QReadWriteLock>
5 5
6 6 #include "Variable/VariableSynchronizationGroup2.h"
7 7 #include <Variable/Variable.h>
8 8 #include <Common/containers.h>
9 9 #include <Common/debug.h>
10 10 #include <Data/DataProviderParameters.h>
11 11 #include <Data/DateTimeRangeHelper.h>
12 12 #include <Data/DateTimeRange.h>
13 13 #include <Data/IDataProvider.h>
14 14
15 15 struct VCTransaction
16 16 {
17 17 VCTransaction(QUuid refVar, DateTimeRange range, int varCount)
18 18 :refVar{refVar},range{range},_remainingVars{varCount}
19 19 {}
20 20
21 21 QUuid refVar;
22 22 DateTimeRange range;
23 23 bool ready()
24 24 {
25 25 QReadLocker lock{&_lock};
26 26 return _remainingVars == 0;
27 27 }
28 28
29 29 bool done()
30 30 {
31 31 QWriteLocker lock{&_lock};
32 32 _remainingVars-=1;
33 33 return _remainingVars == 0;
34 34 }
35 35 private:
36 36 QReadWriteLock _lock;
37 37 int _remainingVars;
38 38 };
39 39
40 40 class TransactionExe:public QObject,public QRunnable
41 41 {
42 42 Q_OBJECT
43 43 std::shared_ptr<Variable> _variable;
44 44 std::shared_ptr<IDataProvider> _provider;
45 45 std::vector<DateTimeRange> _ranges;
46 46 DateTimeRange _range;
47 47 DateTimeRange _cacheRange;
48 48 public:
49 49 TransactionExe(const std::shared_ptr<Variable>& variable, const std::shared_ptr<IDataProvider>& provider,
50 50 const std::vector<DateTimeRange>& ranges, DateTimeRange range, DateTimeRange cacheRange)
51 51 :_variable{variable}, _provider{provider},_ranges{ranges},_range{range},_cacheRange{cacheRange}
52 52 {
53 53 setAutoDelete(true);
54 54 }
55 55 void run()override
56 56 {
57 57 std::vector<IDataSeries*> data;
58 58 for(auto range:_ranges)
59 59 {
60 data.push_back(_provider->getData(DataProviderParameters{{range}, _variable->metadata()}));
60 auto ds = _provider->getData(DataProviderParameters{{range}, _variable->metadata()});
61 if(ds)
62 data.push_back(ds);
61 63 }
62 64 _variable->updateData(data, _range, _cacheRange, true);
63 65 emit transactionComplete();
64 66 }
65 67 signals:
66 68 void transactionComplete();
67 69 };
68 70
69 71 class VCTransactionsQueues
70 72 {
71 73 QReadWriteLock _mutex{QReadWriteLock::Recursive};
72 74 std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> _nextTransactions;
73 75 std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> _pendingTransactions;
74 76 public:
75 77 void addEntry(QUuid id)
76 78 {
77 79 QWriteLocker lock{&_mutex};
78 80 _nextTransactions[id] = std::nullopt;
79 81 _pendingTransactions[id] = std::nullopt;
80 82 }
81 83
82 84 void removeEntry(QUuid id)
83 85 {
84 86 QWriteLocker lock{&_mutex};
85 87 _nextTransactions.erase(id);
86 88 _pendingTransactions.erase(id);
87 89 }
88 90
89 91 std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> pendingTransactions()
90 92 {
91 93 QReadLocker lock{&_mutex};
92 94 return _pendingTransactions;
93 95 }
94 96
95 97 std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> nextTransactions()
96 98 {
97 99 QReadLocker lock{&_mutex};
98 100 return _nextTransactions;
99 101 }
100 102
101 103 std::optional<std::shared_ptr<VCTransaction>> start(QUuid id)
102 104 {
103 105 QWriteLocker lock{&_mutex};
104 106 _pendingTransactions[id] = _nextTransactions[id];
105 107 _nextTransactions[id] = std::nullopt;
106 108 return _pendingTransactions[id];
107 109 }
108 110
109 111 void enqueue(QUuid id, std::shared_ptr<VCTransaction> transaction)
110 112 {
111 113 QWriteLocker lock{&_mutex};
112 114 _nextTransactions[id] = transaction;
113 115 }
114 116
115 117 void complete(QUuid id)
116 118 {
117 119 QWriteLocker lock{&_mutex};
118 120 _pendingTransactions[id] = std::nullopt;
119 121 }
120 122
121 123 bool active(QUuid id)
122 124 {
123 125 QReadLocker lock{&_mutex};
124 126 return _nextTransactions[id].has_value() || _pendingTransactions[id].has_value();
125 127 }
126 128 };
@@ -1,123 +1,127
1 1 #include <Network/Downloader.h>
2 2 #include <memory>
3 3
4 4 #include <QNetworkRequest>
5 5 #include <QNetworkReply>
6 6 #include <QNetworkAccessManager>
7 7 #include <QAuthenticator>
8 8 #include <QVariant>
9 9 #include <QHash>
10 10 #include <QPair>
11 11 #include <QCoreApplication>
12 12 #include <QReadWriteLock>
13 #include <QThread>
13 14
14 15 class Downloader::p_Downloader
15 16 {
16 17 using login_pair=QPair<QString,QString>;
17 18 QNetworkAccessManager manager;
18 19 QHash<QString,login_pair> auth;
19 20 QReadWriteLock pending_requests_lock;
20 21 QHash<QUuid,QNetworkReply*> pending_requests;
21 22
22 23 QNetworkRequest buildRequest(const QString& url, const QString &user="", const QString &passwd="")
23 24 {
24 25 QNetworkRequest request;
25 26 request.setUrl(QUrl(url));
26 27 request.setRawHeader("User-Agent", "SciQLop 1.0");
27 28 if(user!="" and passwd!="")
28 29 {
29 30 //might grow quickly since we can have tons of URLs for the same host
30 31 auth[url]=login_pair(user,passwd);
31 32 QString login = "Basic "+user+":"+passwd;
32 33 request.setRawHeader("Authorization",login.toLocal8Bit());
33 34 }
34 35 return request;
35 36 }
36 37
37 38 public:
38 39 explicit p_Downloader()
39 40 {
40 41
41 42 auto login_bambda = [this](QNetworkReply * reply, QAuthenticator * authenticator)
42 43 {
43 44 if(auth.contains(reply->url().toString()))
44 45 {
45 46 auto login = auth[reply->url().toString()];
46 47 authenticator->setUser(login.first);
47 48 authenticator->setPassword(login.second);
48 49 }
49 50 };
50 51
51 52 QObject::connect(&manager, &QNetworkAccessManager::authenticationRequired, login_bambda);
52 53 }
53 54
54 55 Response get(const QString& url, const QString &user="", const QString &passwd="")
55 56 {
56 57 QNetworkRequest request = buildRequest(url, user, passwd);
57 58 QNetworkReply *reply = manager.get(request);
58 59 while (!reply->isFinished())
60 {
59 61 QCoreApplication::processEvents();
62 QThread::usleep(10000);
63 }
60 64 QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
61 65 Response resp = Response(reply->readAll(), status_code.toInt());
62 66 delete reply;
63 67 if(user!="" and passwd!="")
64 68 auth.remove(url);
65 69 return resp;
66 70 }
67 71
68 72 QUuid getAsync(const QString &url, std::function<void (QUuid ,Response)> callback, const QString &user, const QString &passwd)
69 73 {
70 74 auto uuid = QUuid::createUuid();
71 75 QNetworkRequest request = buildRequest(url, user, passwd);
72 76 QNetworkReply *reply = manager.get(request);
73 77 auto callback_wrapper = [url, uuid, callback, this](){
74 78 QNetworkReply* reply;
75 79 {
76 80 QWriteLocker locker(&pending_requests_lock);
77 81 reply = pending_requests.take(uuid);
78 82 }
79 83 QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
80 84 Response resp = Response(reply->readAll(), status_code.toInt());
81 85 auth.remove(url);
82 86 delete reply;
83 87 callback(uuid, resp);
84 88 };
85 89 QObject::connect(reply, &QNetworkReply::finished, callback_wrapper);
86 90 {
87 91 QWriteLocker locker(&pending_requests_lock);
88 92 pending_requests[uuid] = reply;
89 93 }
90 94 return uuid;
91 95 }
92 96 bool downloadFinished(QUuid uuid)
93 97 {
94 98 QReadLocker locker(&pending_requests_lock);
95 99 if(pending_requests.contains(uuid))
96 100 {
97 101 auto req = pending_requests[uuid];
98 102 return req->isFinished();
99 103 }
100 104 return true;
101 105 }
102 106 };
103 107
104 108 Response Downloader::get(const QString &url, const QString &user, const QString &passwd)
105 109 {
106 110 return Downloader::instance().impl->get(url, user, passwd);
107 111 }
108 112
109 113 QUuid Downloader::getAsync(const QString &url, std::function<void (QUuid ,Response)> callback, const QString &user, const QString &passwd)
110 114 {
111 115 return Downloader::instance().impl->getAsync(url, callback, user, passwd);
112 116 }
113 117
114 118 bool Downloader::downloadFinished(QUuid uuid)
115 119 {
116 120 return Downloader::instance().impl->downloadFinished(uuid);
117 121 }
118 122
119 123 Downloader::Downloader()
120 124 :impl(spimpl::make_unique_impl<p_Downloader>())
121 125 {
122 126 }
123 127
@@ -1,392 +1,390
1 1 #include <QQueue>
2 2 #include <QThreadPool>
3 3 #include <QRunnable>
4 4 #include <QObject>
5 5 #include <QDataStream>
6 6
7 7 #include "Variable/VariableController2.h"
8 8 #include "Variable/VariableSynchronizationGroup2.h"
9 9 #include <Common/containers.h>
10 10 #include <Common/debug.h>
11 11 #include <Data/DataProviderParameters.h>
12 12 #include <Data/DateTimeRangeHelper.h>
13 13 #include <Data/DateTimeRange.h>
14 14 #include <Variable/VariableCacheStrategyFactory.h>
15 15 #include <Variable/private/VCTransaction.h>
16 16 #include <QCoreApplication>
17 17
18 18
19 19
20 20 class VariableController2::VariableController2Private
21 21 {
22 22 struct threadSafeVaraiblesMaps
23 23 {
24 24 inline void addVariable(const std::shared_ptr<Variable>& variable, const std::shared_ptr<IDataProvider>& provider, const std::shared_ptr<VariableSynchronizationGroup2>& synchronizationGroup)
25 25 {
26 26 QWriteLocker lock{&_lock};
27 27 _variables[*variable] = variable;
28 28 _providers[*variable] = provider;
29 29 _synchronizationGroups[*variable] = synchronizationGroup;
30 30 }
31 31
32 32 inline void removeVariable(const std::shared_ptr<Variable>& variable)
33 33 {
34 34 QWriteLocker lock{&_lock};
35 35 _variables.erase(*variable);
36 36 _providers.remove(*variable);
37 37 _synchronizationGroups.remove(*variable);
38 38 }
39 39
40 40 inline void synchronize(const std::shared_ptr<Variable>& variable, const std::optional<std::shared_ptr<Variable>>& with)
41 41 {
42 42 QWriteLocker lock{&_lock};
43 43 if(with.has_value())
44 44 {
45 45 auto newGroup = _synchronizationGroups[*with.value()];
46 46 newGroup->addVariable(*variable);
47 47 _synchronizationGroups[*variable] = newGroup;
48 48 }
49 49 else
50 50 {
51 51 _synchronizationGroups[*variable] = std::make_shared<VariableSynchronizationGroup2>(*variable);
52 52 }
53 53 }
54 54
55 55 inline std::shared_ptr<Variable> variable(QUuid variable)
56 56 {
57 57 QReadLocker lock{&_lock};
58 58 auto it = _variables.find(variable);
59 59 [[unlikely]]
60 60 if(it==_variables.end())
61 61 SCIQLOP_ERROR(threadSafeVaraiblesMaps,"Unknown Variable");
62 62 return (*it).second;
63 63 }
64 64
65 65 inline std::shared_ptr<Variable> variable(int index)
66 66 {
67 67 QReadLocker lock{&_lock};
68 68 [[unlikely]]
69 69 if(!_variables.size() > index)
70 70 SCIQLOP_ERROR(threadSafeVaraiblesMaps,"Index is out of bounds");
71 71 auto it = _variables.cbegin();
72 72 while (index!=0) {
73 73 index-=1;
74 74 it++;
75 75 }
76 76 return (*it).second;
77 77 }
78 78
79 79 inline const std::vector<std::shared_ptr<Variable>> variables()
80 80 {
81 81 std::vector<std::shared_ptr<Variable>> vars;
82 82 QReadLocker lock{&_lock};
83 83 for(const auto&[id, var]:_variables)
84 84 {
85 85 vars.push_back(var);
86 86 }
87 87 return vars;
88 88 }
89 89
90 90 inline std::shared_ptr<IDataProvider> provider(QUuid variable)
91 91 {
92 92 QReadLocker lock{&_lock};
93 93 [[unlikely]]
94 94 if(!_providers.contains(variable))
95 95 SCIQLOP_ERROR(threadSafeVaraiblesMaps,"Unknown Variable");
96 96 return _providers[variable];
97 97 }
98 98
99 99 inline std::shared_ptr<VariableSynchronizationGroup2> group(QUuid variable)
100 100 {
101 101 QReadLocker lock{&_lock};
102 102 [[unlikely]]
103 103 if(!_synchronizationGroups.contains(variable))
104 104 SCIQLOP_ERROR(threadSafeVaraiblesMaps,"Unknown Variable");
105 105 return _synchronizationGroups[variable];
106 106 }
107 107
108 108 inline bool has(const std::shared_ptr<Variable>& variable)
109 109 {
110 110 QReadLocker lock{&_lock};
111 111 return _variables.find(*variable)==_variables.end();
112 112 }
113 113
114 114 private:
115 115 std::map<QUuid,std::shared_ptr<Variable>> _variables;
116 116 QMap<QUuid,std::shared_ptr<IDataProvider>> _providers;
117 117 QMap<QUuid,std::shared_ptr<VariableSynchronizationGroup2>> _synchronizationGroups;
118 118 QReadWriteLock _lock{QReadWriteLock::Recursive};
119 119 }_maps;
120 QThreadPool _ThreadPool;
120 QThreadPool* _ThreadPool;
121 121 VCTransactionsQueues _transactions;
122 122 std::unique_ptr<VariableCacheStrategy> _cacheStrategy;
123 123
124 124 void _transactionComplete(QUuid group, std::shared_ptr<VCTransaction> transaction)
125 125 {
126 126 if(transaction->done())
127 127 {
128 128 _transactions.complete(group);
129 129 }
130 130 this->_processTransactions();
131 131 }
132 132 void _processTransactions()
133 133 {
134 134 auto nextTransactions = _transactions.nextTransactions();
135 135 auto pendingTransactions = _transactions.pendingTransactions();
136 136 for( auto [groupID, newTransaction] : nextTransactions)
137 137 {
138 138 if(newTransaction.has_value() && !pendingTransactions[groupID].has_value())
139 139 {
140 140 _transactions.start(groupID);
141 141 auto refVar = _maps.variable(newTransaction.value()->refVar);
142 142 auto ranges = _computeAllRangesInGroup(refVar,newTransaction.value()->range);
143 143 for( auto const& [ID, range] : ranges)
144 144 {
145 145 auto provider = _maps.provider(ID);
146 146 auto variable = _maps.variable(ID);
147 147 auto [missingRanges, newCacheRange] = _computeMissingRanges(variable,range);
148 148 auto exe = new TransactionExe(variable, provider, missingRanges, range, newCacheRange);
149 149 QObject::connect(exe,
150 150 &TransactionExe::transactionComplete,
151 151 [groupID=groupID,transaction=newTransaction.value(),this]()
152 152 {
153 153 this->_transactionComplete(groupID, transaction);
154 154 }
155 155 );
156 _ThreadPool.start(exe);
156 _ThreadPool->start(exe);
157 157 }
158 158 }
159 159 }
160 160 }
161 161
162 162 std::map<QUuid,DateTimeRange> _computeAllRangesInGroup(const std::shared_ptr<Variable>& refVar, DateTimeRange r)
163 163 {
164 164 std::map<QUuid,DateTimeRange> ranges;
165 165 if(!DateTimeRangeHelper::hasnan(r))
166 166 {
167 167 auto group = _maps.group(*refVar);
168 168 if(auto transformation = DateTimeRangeHelper::computeTransformation(refVar->range(),r);
169 169 transformation.has_value())
170 170 {
171 171 for(auto varId:group->variables())
172 172 {
173 173 auto var = _maps.variable(varId);
174 174 auto newRange = var->range().transform(transformation.value());
175 175 ranges[varId] = newRange;
176 176 }
177 177 }
178 178 else // force new range to all variables -> may be weird if more than one var in the group
179 179 // @TODO ensure that there is no side effects
180 180 {
181 181 for(auto varId:group->variables())
182 182 {
183 183 auto var = _maps.variable(varId);
184 184 ranges[varId] = r;
185 185 }
186 186 }
187 187 }
188 188 else
189 189 {
190 190 SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN");
191 191 }
192 192 return ranges;
193 193 }
194 194
195 195 std::pair<std::vector<DateTimeRange>,DateTimeRange> _computeMissingRanges(const std::shared_ptr<Variable>& var, DateTimeRange r)
196 196 {
197 197 DateTimeRange newCacheRange;
198 198 std::vector<DateTimeRange> missingRanges;
199 199 if(DateTimeRangeHelper::hasnan(var->cacheRange()))
200 200 {
201 201 newCacheRange = _cacheStrategy->computeRange(r,r);
202 202 missingRanges = {newCacheRange};
203 203 }
204 204 else
205 205 {
206 206 newCacheRange = _cacheStrategy->computeRange(var->cacheRange(),r);
207 207 missingRanges = newCacheRange - var->cacheRange();
208 208 }
209 209 return {missingRanges,newCacheRange};
210 210 }
211 211
212 212 void _changeRange(QUuid id, DateTimeRange r)
213 213 {
214 214 _changeRange(_maps.variable(id) ,r);
215 215 }
216 216 void _changeRange(const std::shared_ptr<Variable>& var, DateTimeRange r)
217 217 {
218 218 auto provider = _maps.provider(*var);
219 219 auto [missingRanges, newCacheRange] = _computeMissingRanges(var,r);
220 220 std::vector<IDataSeries*> data;
221 221 for(auto range:missingRanges)
222 222 {
223 223 data.push_back(provider->getData(DataProviderParameters{{range}, var->metadata()}));
224 224 }
225 225 var->updateData(data, r, newCacheRange, true);
226 226 }
227 227 public:
228 228 VariableController2Private(QObject* parent=Q_NULLPTR)
229 229 :_cacheStrategy(VariableCacheStrategyFactory::createCacheStrategy(CacheStrategy::SingleThreshold))
230 230 {
231 231 Q_UNUSED(parent);
232 this->_ThreadPool.setMaxThreadCount(32);
232 this->_ThreadPool = new QThreadPool();
233 this->_ThreadPool->setMaxThreadCount(32);
233 234 }
234 235
235 236 /*
236 237 * This dtor has to like this even if this is ugly, because default dtor would rely on
237 238 * declaration order to destruct members and that would always lead to regressions when
238 239 * modifying class members
239 240 */
240 241 ~VariableController2Private()
241 242 {
242 while (this->_ThreadPool.activeThreadCount())
243 {
244 this->_ThreadPool.waitForDone(100);
245 }
243 delete this->_ThreadPool;
246 244 }
247 245
248 246 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata, std::shared_ptr<IDataProvider> provider)
249 247 {
250 248 auto newVar = std::make_shared<Variable>(name,metadata);
251 249 auto group = std::make_shared<VariableSynchronizationGroup2>(newVar->ID());
252 250 _maps.addVariable(newVar,std::move(provider),group);
253 251 this->_transactions.addEntry(*group);
254 252 return newVar;
255 253 }
256 254
257 255 std::shared_ptr<Variable> variable(QUuid ID)
258 256 {
259 257 return _maps.variable(ID);
260 258 }
261 259
262 260 std::shared_ptr<Variable> variable(int index)
263 261 {
264 262 return _maps.variable(index);
265 263 }
266 264
267 265 std::shared_ptr<Variable> cloneVariable(const std::shared_ptr<Variable>& variable)
268 266 {
269 267 auto newVar = variable->clone();
270 268 _maps.synchronize(newVar,std::nullopt);
271 269 _maps.addVariable(newVar,_maps.provider(*variable),_maps.group(*newVar));
272 270 this->_transactions.addEntry(*_maps.group(*newVar));
273 271 return newVar;
274 272 }
275 273
276 274 bool hasPendingTransactions(const std::shared_ptr<Variable>& variable)
277 275 {
278 276 return _transactions.active(*_maps.group(*variable));
279 277 }
280 278
281 279 void deleteVariable(const std::shared_ptr<Variable>& variable)
282 280 {
283 281 _maps.removeVariable(variable);
284 282 }
285 283
286 284 void asyncChangeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r)
287 285 {
288 286 if(!DateTimeRangeHelper::hasnan(r))
289 287 {
290 288 auto group = _maps.group(*variable);
291 289 // Just overwrite next transaction
292 290 {
293 291 _transactions.enqueue(*group,std::make_shared<VCTransaction>(variable->ID(), r, static_cast<int>(group->variables().size())));
294 292 }
295 293 _processTransactions();
296 294 }
297 295 else
298 296 {
299 297 SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN");
300 298 }
301 299 }
302 300
303 301 void changeRange(const std::shared_ptr<Variable>& variable, DateTimeRange r)
304 302 {
305 303 asyncChangeRange(variable,r);
306 304 while (hasPendingTransactions(variable))
307 305 {
308 306 QCoreApplication::processEvents();
309 307 }
310 308 }
311 309
312 310 inline void synchronize(const std::shared_ptr<Variable>& var, const std::shared_ptr<Variable>& with)
313 311 {
314 312 _maps.synchronize(var, with);
315 313 }
316 314
317 315 inline const std::vector<std::shared_ptr<Variable>> variables()
318 316 {
319 317 return _maps.variables();
320 318 }
321 319
322 320 };
323 321
324 322 VariableController2::VariableController2()
325 323 :impl{spimpl::make_unique_impl<VariableController2Private>()}
326 324 {}
327 325
328 326 std::shared_ptr<Variable> VariableController2::createVariable(const QString &name, const QVariantHash &metadata, const std::shared_ptr<IDataProvider>& provider, const DateTimeRange &range)
329 327 {
330 328 auto var = impl->createVariable(name, metadata, provider);
331 329 emit variableAdded(var);
332 330 if(!DateTimeRangeHelper::hasnan(range))
333 impl->changeRange(var,range);
331 impl->asyncChangeRange(var,range);
334 332 else
335 333 SCIQLOP_ERROR(VariableController2, "Creating a variable with default constructed DateTimeRange is an error");
336 334 return var;
337 335 }
338 336
339 337 std::shared_ptr<Variable> VariableController2::cloneVariable(const std::shared_ptr<Variable> &variable)
340 338 {
341 339 return impl->cloneVariable(variable);
342 340 }
343 341
344 342 void VariableController2::deleteVariable(const std::shared_ptr<Variable>& variable)
345 343 {
346 344 impl->deleteVariable(variable);
347 345 emit variableDeleted(variable);
348 346 }
349 347
350 348 void VariableController2::changeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r)
351 349 {
352 350 impl->changeRange(variable, r);
353 351 }
354 352
355 353 void VariableController2::asyncChangeRange(const std::shared_ptr<Variable> &variable, const DateTimeRange &r)
356 354 {
357 355 impl->asyncChangeRange(variable, r);
358 356 }
359 357
360 358 const std::vector<std::shared_ptr<Variable> > VariableController2::variables()
361 359 {
362 360 return impl->variables();
363 361 }
364 362
365 363 bool VariableController2::isReady(const std::shared_ptr<Variable> &variable)
366 364 {
367 365 return impl->hasPendingTransactions(variable);
368 366 }
369 367
370 368 void VariableController2::synchronize(const std::shared_ptr<Variable> &var, const std::shared_ptr<Variable> &with)
371 369 {
372 370 impl->synchronize(var, with);
373 371 }
374 372
375 373 const std::vector<std::shared_ptr<Variable>> VariableController2::variables(const std::vector<QUuid> &ids)
376 374 {
377 375 std::vector<std::shared_ptr<Variable>> variables;
378 376 for (const auto& id : ids) {
379 377 variables.push_back(impl->variable(id));
380 378 }
381 379 return variables;
382 380 }
383 381
384 382 const std::shared_ptr<Variable> &VariableController2::operator[](int index) const
385 383 {
386 384 return impl->variable (index);
387 385 }
388 386
389 387 std::shared_ptr<Variable> VariableController2::operator[](int index)
390 388 {
391 389 return impl->variable (index);
392 390 }
@@ -1,96 +1,83
1 1 #ifndef TESTPROVIDER_H
2 2 #define TESTPROVIDER_H
3 3
4 4 #include <memory>
5 5 #include <cmath>
6 6 #include <algorithm>
7 7 #include <numeric>
8 8
9 9 #include <QUuid>
10 10 #include <QtGlobal>
11 11 #include <QtTest>
12 12
13 13 #include <Data/IDataProvider.h>
14 14 #include <Data/DataProviderParameters.h>
15 15 #include <Data/DataSeries.h>
16 16 #include <Data/ScalarSeries.h>
17 17 #include <Variable/Variable.h>
18 18
19 19
20 20 template<int slope>
21 21 class SimpleRange: public IDataProvider
22 22 {
23 23 public:
24 24 SimpleRange() = default;
25 25
26 26 int callCounter = 0;
27 27 std::shared_ptr<IDataProvider> clone() const override{ return std::make_shared<SimpleRange>(); }
28 28
29 29 IDataSeries* getData(const DataProviderParameters &parameters) override
30 30 {
31 31 callCounter+=1;
32 32 auto tstart = parameters.m_Times[0].m_TStart;
33 33 auto tend = parameters.m_Times[0].m_TEnd;
34 34 std::vector<double> x;
35 35 std::vector<double> y;
36 36 for(double i = ceil(tstart);i<=floor(tend);i+=1.) //1 seconde data resolution
37 37 {
38 38 x.push_back(i);
39 39 y.push_back(i*slope);
40 40 }
41 41 auto serie = new ScalarSeries(std::move(x),std::move(y),Unit("Secondes",true),Unit("Volts",false));
42 42 return serie;
43 43 }
44 44
45
46
47 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
48 {
49 Q_UNUSED(acqIdentifier)
50 Q_UNUSED(parameters)
51 }
52
53 void requestDataAborting(QUuid acqIdentifier) override
54 {
55 Q_UNUSED(acqIdentifier)
56 }
57
58 45 };
59 46
60 47
61 48 template <class T>
62 49 auto sumdiff(T begin, T end)
63 50 {
64 51 std::vector<double> diff_vect(end-begin-1);
65 52 auto diff = [](auto next,auto item)
66 53 {
67 54 return next.value() - item.value();
68 55 };
69 56 std::transform (begin+1, end, begin, diff_vect.begin(),diff);
70 57 return std::accumulate(diff_vect.cbegin(), diff_vect.cend(), 0);
71 58 }
72 59
73 60 template <int slope=1>
74 61 struct RangeType
75 62 {
76 63 static void check_properties(std::shared_ptr<Variable> v, DateTimeRange r)
77 64 {
78 65 auto bounds = v->dataSeries()->valuesBounds(r.m_TStart, r.m_TEnd);
79 66 auto s = sumdiff(bounds.first, bounds.second) / slope;
80 67 auto nbpoints = bounds.second - bounds.first+1.;
81 68 QCOMPARE(nbpoints, int(s)+2);//<- @TODO weird has to be investigated why +2?
82 69 QCOMPARE(bounds.first->x(), bounds.first->value()/slope);
83 70 }
84 71 };
85 72
86 73 template <class T>
87 74 void check_variable_state(std::shared_ptr<Variable> v, DateTimeRange r)
88 75 {
89 76 auto bounds = v->dataSeries()->valuesBounds(r.m_TStart, r.m_TEnd);
90 77 //generated data has to be inside range
91 78 QVERIFY(bounds.first->x() >= r.m_TStart);
92 79 QVERIFY(bounds.second->x() <= r.m_TEnd);
93 80 T::check_properties(v,r);
94 81 }
95 82
96 83 #endif
General Comments 0
You need to be logged in to leave comments. Login now