@@ -0,0 +1,53 | |||
|
1 | #include <QThreadPool> | |
|
2 | #include <QRunnable> | |
|
3 | #include <QObject> | |
|
4 | #include <QReadWriteLock> | |
|
5 | ||
|
6 | #include "Variable/VariableSynchronizationGroup2.h" | |
|
7 | #include <Variable/Variable.h> | |
|
8 | #include <Common/containers.h> | |
|
9 | #include <Common/debug.h> | |
|
10 | #include <Data/DataProviderParameters.h> | |
|
11 | #include <Data/DateTimeRangeHelper.h> | |
|
12 | #include <Data/DateTimeRange.h> | |
|
13 | #include <Data/IDataProvider.h> | |
|
14 | ||
|
15 | struct VCTransaction | |
|
16 | { | |
|
17 | VCTransaction(QUuid refVar, DateTimeRange range, int ready) | |
|
18 | :refVar{refVar},range{range},ready{ready} | |
|
19 | {} | |
|
20 | QUuid refVar; | |
|
21 | DateTimeRange range; | |
|
22 | int ready; | |
|
23 | QReadWriteLock lock; | |
|
24 | }; | |
|
25 | ||
|
26 | class TransactionExe:public QObject,public QRunnable | |
|
27 | { | |
|
28 | Q_OBJECT | |
|
29 | std::shared_ptr<Variable> _variable; | |
|
30 | std::shared_ptr<IDataProvider> _provider; | |
|
31 | std::vector<DateTimeRange> _ranges; | |
|
32 | DateTimeRange _range; | |
|
33 | DateTimeRange _cacheRange; | |
|
34 | public: | |
|
35 | TransactionExe(const std::shared_ptr<Variable>& variable, const std::shared_ptr<IDataProvider>& provider, | |
|
36 | const std::vector<DateTimeRange>& ranges, DateTimeRange range, DateTimeRange cacheRange) | |
|
37 | :_variable{variable}, _provider{provider},_ranges{ranges},_range{range},_cacheRange{cacheRange} | |
|
38 | { | |
|
39 | setAutoDelete(true); | |
|
40 | } | |
|
41 | void run()override | |
|
42 | { | |
|
43 | std::vector<IDataSeries*> data; | |
|
44 | for(auto range:_ranges) | |
|
45 | { | |
|
46 | data.push_back(_provider->getData(DataProviderParameters{{range}, _variable->metadata()})); | |
|
47 | } | |
|
48 | _variable->updateData(data, _range, _cacheRange, true); | |
|
49 | emit transactionComplete(); | |
|
50 | } | |
|
51 | signals: | |
|
52 | void transactionComplete(); | |
|
53 | }; |
@@ -0,0 +1,67 | |||
|
1 | #include <cmath> | |
|
2 | #include <algorithm> | |
|
3 | #include <numeric> | |
|
4 | #include <QtTest> | |
|
5 | #include <QObject> | |
|
6 | #include <Variable/VariableController2.h> | |
|
7 | #include <Data/DateTimeRange.h> | |
|
8 | #include <Data/IDataProvider.h> | |
|
9 | #include <Data/ScalarSeries.h> | |
|
10 | #include <Data/DataProviderParameters.h> | |
|
11 | #include <Common/containers.h> | |
|
12 | ||
|
13 | #include <TestUtils/TestProviders.h> | |
|
14 | ||
|
15 | #define TEST_VC2_FIXTURE(slope) \ | |
|
16 | VariableController2 vc; \ | |
|
17 | auto provider = std::make_shared<SimpleRange<slope>>();\ | |
|
18 | ||
|
19 | #define TEST_VC2_CREATE_DEFAULT_VARS(name1, name2, name3)\ | |
|
20 | auto range = DateTimeRange::fromDateTime(QDate(2018,8,7),QTime(14,00),\ | |
|
21 | QDate(2018,8,7),QTime(16,00));\ | |
|
22 | auto name1 = vc.createVariable("name1", {}, provider, range);\ | |
|
23 | auto name2 = vc.createVariable("name1", {}, provider, range);\ | |
|
24 | auto name3 = vc.createVariable("name1", {}, provider, range);\ | |
|
25 | vc.synchronize(name1,name2);\ | |
|
26 | ||
|
27 | ||
|
28 | class TestVariableController2Async : public QObject | |
|
29 | { | |
|
30 | Q_OBJECT | |
|
31 | public: | |
|
32 | explicit TestVariableController2Async(QObject *parent = nullptr) : QObject(parent){} | |
|
33 | signals: | |
|
34 | ||
|
35 | private slots: | |
|
36 | void initTestCase(){} | |
|
37 | void cleanupTestCase(){} | |
|
38 | ||
|
39 | void testSimplePan() | |
|
40 | { | |
|
41 | TEST_VC2_FIXTURE(2); | |
|
42 | auto range = DateTimeRange::fromDateTime(QDate(2018,8,7),QTime(14,00), | |
|
43 | QDate(2018,8,7),QTime(16,00)); | |
|
44 | int variableUpdated=0; | |
|
45 | auto var1 = vc.createVariable("var1", {}, provider, range); | |
|
46 | auto var2 = vc.createVariable("var2", {}, provider, range); | |
|
47 | auto var3 = vc.createVariable("var3", {}, provider, range); | |
|
48 | connect(&(*var2),&Variable::updated, [&variableUpdated](){variableUpdated+=1;}); | |
|
49 | vc.synchronize(var1,var2); | |
|
50 | vc.asyncChangeRange(var1,range+Seconds<double>{10000.}); | |
|
51 | vc.asyncChangeRange(var1,range+Seconds<double>{50000.}); | |
|
52 | vc.asyncChangeRange(var1,range+Seconds<double>{100000.}); | |
|
53 | vc.asyncChangeRange(var1,range+Seconds<double>{150000.}); | |
|
54 | while(!vc.isReady(var1) || !vc.isReady(var2)) | |
|
55 | { | |
|
56 | QCoreApplication::processEvents(); | |
|
57 | } | |
|
58 | } | |
|
59 | ||
|
60 | ||
|
61 | }; | |
|
62 | ||
|
63 | ||
|
64 | QTEST_MAIN(TestVariableController2Async) | |
|
65 | ||
|
66 | #include "TestVariableController2Async.moc" | |
|
67 |
@@ -1,191 +1,192 | |||
|
1 | 1 | cmake_minimum_required(VERSION 3.6) |
|
2 | 2 | project(SciQLOPCore CXX) |
|
3 | 3 | |
|
4 | 4 | OPTION (CPPCHECK "Analyzes the source code with cppcheck" OFF) |
|
5 | 5 | OPTION (CLANG_TIDY "Analyzes the source code with Clang Tidy" OFF) |
|
6 | 6 | OPTION (IWYU "Analyzes the source code with Include What You Use" OFF) |
|
7 | 7 | |
|
8 | 8 | OPTION (Catalog "builds catalog API" OFF) |
|
9 | 9 | |
|
10 | 10 | set(CMAKE_CXX_STANDARD 17) |
|
11 | 11 | |
|
12 | 12 | set(CMAKE_AUTOMOC ON) |
|
13 | 13 | #https://gitlab.kitware.com/cmake/cmake/issues/15227 |
|
14 | 14 | #set(CMAKE_AUTOUIC ON) |
|
15 | 15 | if(POLICY CMP0071) |
|
16 | 16 | cmake_policy(SET CMP0071 OLD) |
|
17 | 17 | endif() |
|
18 | 18 | set(CMAKE_AUTORCC ON) |
|
19 | 19 | set(CMAKE_INCLUDE_CURRENT_DIR ON) |
|
20 | 20 | |
|
21 | 21 | find_package(Qt5 COMPONENTS Core Widgets Network PrintSupport Svg Test REQUIRED) |
|
22 | 22 | |
|
23 | 23 | find_package(pybind11 CONFIG QUIET) |
|
24 | 24 | if (NOT pybind11_FOUND) |
|
25 | 25 | execute_process(COMMAND git submodule init external/pybind11 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) |
|
26 | 26 | execute_process(COMMAND git submodule update external/pybind11 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) |
|
27 | 27 | add_subdirectory(external/pybind11) |
|
28 | 28 | endif() |
|
29 | 29 | |
|
30 | 30 | macro(declare_test testname testexe sources libraries) |
|
31 | 31 | add_executable(${testexe} ${sources}) |
|
32 | 32 | target_link_libraries(${testexe} ${libraries}) |
|
33 | 33 | add_test(NAME ${testname} COMMAND ${testexe}) |
|
34 | 34 | endmacro(declare_test) |
|
35 | 35 | |
|
36 | 36 | enable_testing() |
|
37 | 37 | |
|
38 | 38 | FILE (GLOB_RECURSE core_SRCS |
|
39 | 39 | ./include/DataSource/DataSourceItemMergeHelper.h |
|
40 | 40 | ./include/DataSource/DataSourceItemAction.h |
|
41 | 41 | ./include/DataSource/DataSourceItem.h |
|
42 | 42 | ./include/DataSource/DataSourceController.h |
|
43 | 43 | ./include/Common/SortUtils.h |
|
44 | 44 | ./include/Common/spimpl.h |
|
45 | 45 | ./include/Common/MimeTypesDef.h |
|
46 | 46 | ./include/Common/MetaTypes.h |
|
47 | 47 | ./include/Common/StringUtils.h |
|
48 | 48 | ./include/Common/SignalWaiter.h |
|
49 | 49 | ./include/Common/DateUtils.h |
|
50 | 50 | ./include/Common/Numeric.h |
|
51 | 51 | ./include/Common/deprecate.h |
|
52 | 52 | ./include/Common/containers.h |
|
53 | 53 | ./include/Common/debug.h |
|
54 | 54 | ./include/Plugin/IPlugin.h |
|
55 | 55 | ./include/Data/ArrayDataIterator.h |
|
56 | 56 | ./include/Data/VariableRequest.h |
|
57 | 57 | ./include/Data/VectorSeries.h |
|
58 | 58 | ./include/Data/DateTimeRange.h |
|
59 | 59 | ./include/Data/DateTimeRangeHelper.h |
|
60 | 60 | ./include/Data/ScalarSeries.h |
|
61 | 61 | ./include/Data/DataSeriesMergeHelper.h |
|
62 | 62 | ./include/Data/DataSeries.h |
|
63 | 63 | ./include/Data/AcquisitionDataPacket.h |
|
64 | 64 | ./include/Data/DataSeriesType.h |
|
65 | 65 | ./include/Data/AcquisitionRequest.h |
|
66 | 66 | ./include/Data/SqpIterator.h |
|
67 | 67 | ./include/Data/ArrayData.h |
|
68 | 68 | ./include/Data/DataSeriesIterator.h |
|
69 | 69 | ./include/Data/DataSeriesUtils.h |
|
70 | 70 | ./include/Data/SpectrogramSeries.h |
|
71 | 71 | ./include/Data/Unit.h |
|
72 | 72 | ./include/Data/DataProviderParameters.h |
|
73 | 73 | ./include/Data/OptionalAxis.h |
|
74 | 74 | ./include/Data/IDataProvider.h |
|
75 | 75 | ./include/Data/IDataSeries.h |
|
76 | 76 | ./include/Network/NetworkController.h |
|
77 | 77 | ./include/Network/Downloader.h |
|
78 | 78 | ./include/Version.h |
|
79 | 79 | ./include/CoreGlobal.h |
|
80 | 80 | ./include/Visualization/VisualizationController.h |
|
81 | 81 | ./include/PluginManager/PluginManager.h |
|
82 | 82 | ./include/Variable/VariableModel.h |
|
83 | 83 | ./include/Variable/VariableAcquisitionWorker.h |
|
84 | 84 | ./include/Variable/VariableCacheStrategy.h |
|
85 | 85 | ./include/Variable/VariableSynchronizationGroup.h |
|
86 | 86 | ./include/Variable/VariableSynchronizationGroup2.h |
|
87 | 87 | ./include/Variable/ProportionalCacheStrategy.h |
|
88 | 88 | ./include/Variable/SingleThresholdCacheStrategy.h |
|
89 | 89 | ./include/Variable/VariableCacheStrategyFactory.h |
|
90 | 90 | ./include/Variable/Variable.h |
|
91 | 91 | ./include/Variable/VariableCacheController.h |
|
92 | 92 | ./include/Variable/VariableController.h |
|
93 | 93 | ./include/Variable/VariableController2.h |
|
94 | ./include/Variable/private/VCTransaction.h | |
|
94 | 95 | ./include/Time/TimeController.h |
|
95 | 96 | ./include/Settings/ISqpSettingsBindable.h |
|
96 | 97 | ./include/Settings/SqpSettingsDefs.h |
|
97 | 98 | |
|
98 | 99 | ./src/DataSource/DataSourceItem.cpp |
|
99 | 100 | ./src/DataSource/DataSourceItemAction.cpp |
|
100 | 101 | ./src/DataSource/DataSourceItemMergeHelper.cpp |
|
101 | 102 | ./src/DataSource/DataSourceController.cpp |
|
102 | 103 | ./src/Common/DateUtils.cpp |
|
103 | 104 | ./src/Common/MimeTypesDef.cpp |
|
104 | 105 | ./src/Common/StringUtils.cpp |
|
105 | 106 | ./src/Common/SignalWaiter.cpp |
|
106 | 107 | ./src/Data/ScalarSeries.cpp |
|
107 | 108 | ./src/Data/DataSeriesIterator.cpp |
|
108 | 109 | ./src/Data/OptionalAxis.cpp |
|
109 | 110 | ./src/Data/ArrayDataIterator.cpp |
|
110 | 111 | ./src/Data/SpectrogramSeries.cpp |
|
111 | 112 | ./src/Data/DataSeriesUtils.cpp |
|
112 | 113 | ./src/Data/VectorSeries.cpp |
|
113 | 114 | ./src/Network/NetworkController.cpp |
|
114 | 115 | ./src/Network/Downloader.cpp |
|
115 | 116 | ./src/Visualization/VisualizationController.cpp |
|
116 | 117 | ./src/PluginManager/PluginManager.cpp |
|
117 | 118 | ./src/Variable/VariableController.cpp |
|
118 | 119 | ./src/Variable/VariableController2.cpp |
|
119 | 120 | ./src/Variable/VariableModel.cpp |
|
120 | 121 | ./src/Variable/VariableCacheController.cpp |
|
121 | 122 | ./src/Variable/VariableSynchronizationGroup.cpp |
|
122 | 123 | ./src/Variable/VariableSynchronizationGroup2.cpp |
|
123 | 124 | ./src/Variable/Variable.cpp |
|
124 | 125 | ./src/Variable/VariableAcquisitionWorker.cpp |
|
125 | 126 | ./src/Version.cpp |
|
126 | 127 | ./src/Time/TimeController.cpp |
|
127 | 128 | ./src/Settings/SqpSettingsDefs.cpp |
|
128 | 129 | |
|
129 | 130 | ) |
|
130 | 131 | |
|
131 | 132 | |
|
132 | 133 | IF(Catalog) |
|
133 | 134 | FILE (GLOB_RECURSE core_catalog_SRCS |
|
134 | 135 | ./src/Catalogue/CatalogueController.cpp |
|
135 | 136 | ./include/Catalogue/CatalogueController.h |
|
136 | 137 | ) |
|
137 | 138 | ELSE() |
|
138 | 139 | FILE (GLOB_RECURSE core_catalog_SRCS |
|
139 | 140 | ) |
|
140 | 141 | ENDIF(Catalog) |
|
141 | 142 | |
|
142 | 143 | add_definitions(-DCORE_STATIC) |
|
143 | 144 | #add_definitions(-DHIDE_DEPRECATED) |
|
144 | 145 | add_definitions(-DSCIQLOP_CRASH_ON_ERROR) |
|
145 | 146 | |
|
146 | 147 | add_library(sciqlopcore ${core_SRCS} ${core_catalog_SRCS}) |
|
147 | 148 | SET_TARGET_PROPERTIES(sciqlopcore PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE) |
|
148 | 149 | |
|
149 | 150 | target_include_directories(sciqlopcore PUBLIC |
|
150 | 151 | $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> |
|
151 | 152 | $<INSTALL_INTERFACE:include/SciQLOP> |
|
152 | 153 | ) |
|
153 | 154 | |
|
154 | 155 | target_link_libraries(sciqlopcore PUBLIC |
|
155 | 156 | Qt5::Core |
|
156 | 157 | Qt5::Network |
|
157 | 158 | ) |
|
158 | 159 | |
|
159 | 160 | if(Catalog) |
|
160 | 161 | target_link_libraries(sciqlopcore PUBLIC |
|
161 | 162 | catalogs |
|
162 | 163 | ) |
|
163 | 164 | endif() |
|
164 | 165 | |
|
165 | 166 | |
|
166 | 167 | pybind11_add_module(sciqlopqt src/pybind11_wrappers/QtWrappers.cpp) |
|
167 | 168 | target_link_libraries(sciqlopqt PUBLIC Qt5::Core) |
|
168 | 169 | |
|
169 | 170 | pybind11_add_module(pysciqlopcore src/pybind11_wrappers/CoreWrappers.cpp) |
|
170 | 171 | target_link_libraries(pysciqlopcore PUBLIC sciqlopcore) |
|
171 | 172 | |
|
172 | 173 | add_library(pysciqlop src/pybind11_wrappers/pywrappers_common.h) |
|
173 | 174 | target_link_libraries(pysciqlop PUBLIC Qt5::Core) |
|
174 | 175 | target_include_directories(pysciqlop PUBLIC |
|
175 | 176 | $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/pybind11_wrappers/> |
|
176 | 177 | $<INSTALL_INTERFACE:include/SciQLOP/py_wrappers> |
|
177 | 178 | ) |
|
178 | 179 | |
|
179 | 180 | SET_PROPERTY(GLOBAL PROPERTY CORE_PYTHON_PATH ${CMAKE_CURRENT_BINARY_DIR}) |
|
180 | 181 | |
|
181 | 182 | |
|
182 | 183 | install(TARGETS sciqlopcore EXPORT SciQLOPCoreConfig |
|
183 | 184 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} |
|
184 | 185 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} |
|
185 | 186 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) |
|
186 | 187 | |
|
187 | 188 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SciQLOP) |
|
188 | 189 | install(EXPORT SciQLOPCoreConfig DESTINATION share/SciQLOPCore/cmake) |
|
189 | 190 | export(TARGETS sciqlopcore FILE SciQLOPCoreConfig.cmake) |
|
190 | 191 | |
|
191 | 192 | add_subdirectory(tests) |
@@ -1,219 +1,224 | |||
|
1 | 1 | #ifndef SCIQLOP_DATETIMERANGE_H |
|
2 | 2 | #define SCIQLOP_DATETIMERANGE_H |
|
3 | 3 | |
|
4 | 4 | #include <cmath> |
|
5 | 5 | #include <QObject> |
|
6 | 6 | |
|
7 | 7 | #include <QDebug> |
|
8 | 8 | |
|
9 | 9 | #include <opaque/numeric_typedef.hpp> |
|
10 | 10 | #include <Common/DateUtils.h> |
|
11 | 11 | #include <Common/MetaTypes.h> |
|
12 | 12 | #include <Common/Numeric.h> |
|
13 | 13 | |
|
14 | 14 | |
|
15 | 15 | template <typename T> |
|
16 | 16 | struct Seconds : opaque::numeric_typedef<T, Seconds<T>> , |
|
17 | 17 | opaque::binop::multipliable <Seconds<T>, true , Seconds<T>, T, T>, |
|
18 | 18 | opaque::binop::dividable <Seconds<T>, true , Seconds<T>, T, T>, |
|
19 | 19 | opaque::binop::addable <Seconds<T>, true , Seconds<T>, T, T>, |
|
20 | 20 | opaque::binop::subtractable <Seconds<T>, true , Seconds<T>, T, T> |
|
21 | 21 | |
|
22 | 22 | { |
|
23 | 23 | using base = opaque::numeric_typedef<T, Seconds<T>>; |
|
24 | 24 | using base::base; |
|
25 | 25 | operator T () const {return this->value;} |
|
26 | 26 | }; |
|
27 | 27 | |
|
28 | 28 | struct InvalidDateTimeRangeTransformation{}; |
|
29 | 29 | |
|
30 | 30 | struct DateTimeRangeTransformation |
|
31 | 31 | { |
|
32 | 32 | double zoom; |
|
33 | 33 | Seconds<double> shift; |
|
34 | 34 | bool operator==(const DateTimeRangeTransformation& other) const |
|
35 | 35 | { |
|
36 | 36 | return SciQLop::numeric::almost_equal(zoom, other.zoom, 1) && |
|
37 | 37 | SciQLop::numeric::almost_equal<double>(shift, other.shift, 1); |
|
38 | 38 | } |
|
39 | DateTimeRangeTransformation merge(const DateTimeRangeTransformation& other) const | |
|
40 | { | |
|
41 | return DateTimeRangeTransformation{zoom*other.zoom,shift+other.shift}; | |
|
42 | } | |
|
39 | 43 | }; |
|
40 | 44 | |
|
41 | 45 | /** |
|
42 | 46 | * @brief The SqpRange struct holds the information of time parameters |
|
43 | 47 | */ |
|
44 | 48 | struct DateTimeRange { |
|
45 | 49 | DateTimeRange() |
|
46 | 50 | :m_TStart(std::nan("")), m_TEnd(std::nan("")) |
|
47 | 51 | {} |
|
48 | 52 | DateTimeRange(double TStart, double TEnd) |
|
49 | 53 | :m_TStart(TStart), m_TEnd(TEnd) |
|
50 | 54 | {} |
|
51 | 55 | /// Creates SqpRange from dates and times |
|
52 | 56 | static DateTimeRange fromDateTime(const QDate &startDate, const QTime &startTime, |
|
53 | 57 | const QDate &endDate, const QTime &endTime) |
|
54 | 58 | { |
|
55 | 59 | return {DateUtils::secondsSinceEpoch(QDateTime{startDate, startTime, Qt::UTC}), |
|
56 | 60 | DateUtils::secondsSinceEpoch(QDateTime{endDate, endTime, Qt::UTC})}; |
|
57 | 61 | } |
|
58 | 62 | |
|
59 | 63 | static DateTimeRange fromDateTime(const QDateTime &start, const QDateTime &end) |
|
60 | 64 | { |
|
61 | 65 | return {DateUtils::secondsSinceEpoch(start), |
|
62 | 66 | DateUtils::secondsSinceEpoch(end)}; |
|
63 | 67 | } |
|
64 | 68 | |
|
65 | 69 | /// Start time (UTC) |
|
66 | 70 | double m_TStart; |
|
67 | 71 | /// End time (UTC) |
|
68 | 72 | double m_TEnd; |
|
69 | 73 | |
|
70 | 74 | Seconds<double> delta()const noexcept{return Seconds<double>{this->m_TEnd - this->m_TStart};} |
|
71 | 75 | |
|
72 | 76 | bool contains(const DateTimeRange &dateTime) const noexcept |
|
73 | 77 | { |
|
74 | 78 | return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd); |
|
75 | 79 | } |
|
76 | 80 | |
|
77 | 81 | Seconds<double> center() const noexcept |
|
78 | 82 | { |
|
79 | 83 | return Seconds<double>((m_TStart + m_TEnd) / 2.); |
|
80 | 84 | } |
|
81 | 85 | |
|
82 | 86 | bool intersect(const DateTimeRange &dateTime) const noexcept |
|
83 | 87 | { |
|
84 | 88 | return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd); |
|
85 | 89 | } |
|
86 | 90 | |
|
87 | 91 | inline DateTimeRange transform(const DateTimeRangeTransformation& tr)const noexcept; |
|
88 | 92 | |
|
89 | 93 | bool operator==(const DateTimeRange &other) const |
|
90 | 94 | { |
|
91 | 95 | return SciQLop::numeric::almost_equal(m_TStart, other.m_TStart, 1) && |
|
92 | 96 | SciQLop::numeric::almost_equal(m_TEnd, other.m_TEnd, 1); |
|
93 | 97 | } |
|
94 | 98 | |
|
95 | 99 | bool operator!=(const DateTimeRange &other) const { return !(*this == other); } |
|
96 | 100 | |
|
97 | 101 | void grow(double factor)noexcept |
|
98 | 102 | { |
|
99 | 103 | double grow_v{delta()*(factor - 1.)/2.}; |
|
100 | 104 | m_TStart -= grow_v; |
|
101 | 105 | m_TEnd += grow_v; |
|
102 | 106 | } |
|
103 | 107 | |
|
104 | 108 | void shrink(double factor)noexcept |
|
105 | 109 | { |
|
106 | 110 | double shrink_v{this->delta()*(1. - factor)/2.}; |
|
107 | 111 | m_TStart += shrink_v; |
|
108 | 112 | m_TEnd -= shrink_v; |
|
109 | 113 | } |
|
110 | 114 | |
|
111 | 115 | DateTimeRange& operator*=(double k) |
|
112 | 116 | { |
|
113 | 117 | this->grow(k); |
|
114 | 118 | return *this; |
|
115 | 119 | } |
|
116 | 120 | |
|
117 | 121 | DateTimeRange& operator/=(double k) |
|
118 | 122 | { |
|
119 | 123 | this->shrink(k); |
|
120 | 124 | return *this; |
|
121 | 125 | } |
|
122 | 126 | |
|
123 | 127 | // compute set difference |
|
124 | 128 | std::vector<DateTimeRange> operator-(const DateTimeRange& other)const |
|
125 | 129 | { |
|
126 | 130 | std::vector<DateTimeRange> result; |
|
127 | 131 | if(std::isnan(other.m_TStart)||std::isnan(other.m_TEnd)||!this->intersect(other)) |
|
128 | 132 | { |
|
129 | 133 | result.emplace_back(m_TStart, m_TEnd); |
|
130 | 134 | } |
|
131 | 135 | else |
|
132 | 136 | { |
|
133 | 137 | if(this->m_TStart<other.m_TStart) |
|
134 | 138 | { |
|
135 | 139 | result.emplace_back(this->m_TStart, other.m_TStart); |
|
136 | 140 | } |
|
137 | 141 | if(this->m_TEnd>other.m_TEnd) |
|
138 | 142 | { |
|
139 | 143 | result.emplace_back(this->m_TEnd, other.m_TEnd); |
|
140 | 144 | } |
|
141 | 145 | } |
|
142 | 146 | return result; |
|
143 | 147 | } |
|
144 | 148 | |
|
145 | 149 | }; |
|
146 | 150 | |
|
147 | 151 | template <class T> |
|
148 | 152 | DateTimeRange& operator+=(DateTimeRange&r, Seconds<T> offset) |
|
149 | 153 | { |
|
150 | 154 | shift(r,offset); |
|
151 | 155 | return r; |
|
152 | 156 | } |
|
153 | 157 | |
|
154 | 158 | template <class T> |
|
155 | 159 | DateTimeRange& operator-=(DateTimeRange&r, Seconds<T> offset) |
|
156 | 160 | { |
|
157 | 161 | shift(r,-offset); |
|
162 | return r; | |
|
158 | 163 | } |
|
159 | 164 | |
|
160 | 165 | template <class T> |
|
161 | 166 | void shift(DateTimeRange& r, Seconds<T> offset) |
|
162 | 167 | { |
|
163 | 168 | r.m_TEnd+=static_cast<double>(offset); |
|
164 | 169 | r.m_TStart+=static_cast<double>(offset); |
|
165 | 170 | } |
|
166 | 171 | |
|
167 | 172 | inline DateTimeRange operator*(const DateTimeRange& r, double k) |
|
168 | 173 | { |
|
169 | 174 | DateTimeRange result{r}; |
|
170 | 175 | result.grow(k); |
|
171 | 176 | return result; |
|
172 | 177 | } |
|
173 | 178 | |
|
174 | 179 | inline DateTimeRange operator/(const DateTimeRange& r, double k) |
|
175 | 180 | { |
|
176 | 181 | DateTimeRange result{r}; |
|
177 | 182 | result.shrink(k); |
|
178 | 183 | return result; |
|
179 | 184 | } |
|
180 | 185 | |
|
181 | 186 | template<class T> |
|
182 | 187 | DateTimeRange operator+(const DateTimeRange& r, Seconds<T> offset) |
|
183 | 188 | { |
|
184 | 189 | DateTimeRange result{r}; |
|
185 | 190 | shift(result,offset); |
|
186 | 191 | return result; |
|
187 | 192 | } |
|
188 | 193 | |
|
189 | 194 | template<class T> |
|
190 | 195 | DateTimeRange operator-(const DateTimeRange& r, Seconds<T> offset) |
|
191 | 196 | { |
|
192 | 197 | DateTimeRange result{r}; |
|
193 | 198 | shift(result,-offset); |
|
194 | 199 | return result; |
|
195 | 200 | } |
|
196 | 201 | |
|
197 | 202 | const auto INVALID_RANGE |
|
198 | 203 | = DateTimeRange{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()}; |
|
199 | 204 | |
|
200 | 205 | inline QDebug operator<<(QDebug d, DateTimeRange obj) |
|
201 | 206 | { |
|
202 | 207 | auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart); |
|
203 | 208 | auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd); |
|
204 | 209 | |
|
205 | 210 | d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd; |
|
206 | 211 | return d; |
|
207 | 212 | } |
|
208 | 213 | |
|
209 | 214 | |
|
210 | 215 | |
|
211 | 216 | DateTimeRange DateTimeRange::transform(const DateTimeRangeTransformation &tr) const noexcept |
|
212 | 217 | { |
|
213 | 218 | return DateTimeRange{*this} * tr.zoom + tr.shift; |
|
214 | 219 | } |
|
215 | 220 | |
|
216 | 221 | // Required for using shared_ptr in signals/slots |
|
217 | 222 | SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, DateTimeRange) |
|
218 | 223 | |
|
219 | 224 | #endif // SCIQLOP_DATETIMERANGE_H |
@@ -1,112 +1,108 | |||
|
1 | 1 | #ifndef SCIQLOP_VARIABLE_H |
|
2 | 2 | #define SCIQLOP_VARIABLE_H |
|
3 | 3 | |
|
4 | 4 | #include <QLoggingCategory> |
|
5 | 5 | #include <QObject> |
|
6 | 6 | #include <QUuid> |
|
7 | 7 | #include <QReadWriteLock> |
|
8 | 8 | |
|
9 | 9 | #include "CoreGlobal.h" |
|
10 | 10 | #include <Data/DataSeriesIterator.h> |
|
11 | 11 | #include <Data/DataSeriesType.h> |
|
12 | 12 | #include <Data/DateTimeRange.h> |
|
13 | 13 | |
|
14 | 14 | |
|
15 | 15 | #include <Common/deprecate.h> |
|
16 | 16 | #include <Common/MetaTypes.h> |
|
17 | 17 | #include <Common/spimpl.h> |
|
18 | 18 | |
|
19 | 19 | Q_DECLARE_LOGGING_CATEGORY(LOG_Variable) |
|
20 | 20 | |
|
21 | 21 | class IDataSeries; |
|
22 | 22 | class QString; |
|
23 | 23 | |
|
24 | 24 | /** |
|
25 | 25 | * @brief The Variable class represents a variable in SciQlop. |
|
26 | 26 | */ |
|
27 | 27 | class SCIQLOP_CORE_EXPORT Variable : public QObject { |
|
28 | 28 | |
|
29 | 29 | Q_OBJECT |
|
30 | 30 | |
|
31 | 31 | public: |
|
32 | 32 | explicit Variable(const QString &name, const QVariantHash &metadata = {}); |
|
33 | 33 | |
|
34 | 34 | /// Copy ctor |
|
35 | 35 | explicit Variable(const Variable &other); |
|
36 | 36 | |
|
37 | 37 | std::shared_ptr<Variable> clone() const; |
|
38 | 38 | |
|
39 | 39 | QString name() const noexcept; |
|
40 | 40 | void setName(const QString &name) noexcept; |
|
41 | 41 | DateTimeRange range() const noexcept; |
|
42 | 42 | void setRange(const DateTimeRange &range, bool notify=false) noexcept; |
|
43 | 43 | DateTimeRange cacheRange() const noexcept; |
|
44 | 44 | void setCacheRange(const DateTimeRange &cacheRange) noexcept; |
|
45 | 45 | |
|
46 | 46 | /// @return the number of points hold by the variable. The number of points is updated each time |
|
47 | 47 | /// the data series changes |
|
48 | 48 | unsigned int nbPoints() const noexcept; |
|
49 | 49 | |
|
50 | 50 | /// Returns the real range of the variable, i.e. the min and max x-axis values of the data |
|
51 | 51 | /// series between the range of the variable. The real range is updated each time the variable |
|
52 | 52 | /// range or the data series changed |
|
53 | 53 | /// @return the real range, invalid range if the data series is null or empty |
|
54 | 54 | /// @sa setDataSeries() |
|
55 | 55 | /// @sa setRange() |
|
56 | 56 | std::optional<DateTimeRange> realRange() const noexcept; |
|
57 | 57 | |
|
58 | 58 | /// @return the data of the variable, nullptr if there is no data |
|
59 | 59 | std::shared_ptr<IDataSeries> dataSeries() const noexcept; |
|
60 | 60 | |
|
61 | 61 | /// @return the type of data that the variable holds |
|
62 | 62 | DataSeriesType type() const noexcept; |
|
63 | 63 | |
|
64 | 64 | QVariantHash metadata() const noexcept; |
|
65 | ||
|
66 | void updateData(const std::vector<IDataSeries*>& dataSeries, | |
|
67 | const DateTimeRange& newRange, const DateTimeRange& newCacheRange, | |
|
68 | bool notify=true); | |
|
69 | ||
|
65 | 70 | DEPRECATE( |
|
71 | ||
|
66 | 72 | bool contains(const DateTimeRange &range) const noexcept; |
|
67 | 73 | bool intersect(const DateTimeRange &range) const noexcept; |
|
68 | 74 | bool isInside(const DateTimeRange &range) const noexcept; |
|
69 | 75 | |
|
70 | 76 | bool cacheContains(const DateTimeRange &range) const noexcept; |
|
71 | 77 | bool cacheIntersect(const DateTimeRange &range) const noexcept; |
|
72 | 78 | bool cacheIsInside(const DateTimeRange &range) const noexcept; |
|
73 | ) | |
|
74 | DEPRECATE( | |
|
75 | 79 | QVector<DateTimeRange> provideNotInCacheRangeList(const DateTimeRange &range) const noexcept; |
|
76 | 80 | QVector<DateTimeRange> provideInCacheRangeList(const DateTimeRange &range) const noexcept; |
|
77 | ) | |
|
78 | DEPRECATE( | |
|
79 | 81 | void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept; |
|
80 | ) | |
|
81 | ||
|
82 | void updateData(const std::vector<IDataSeries*>& dataSeries, | |
|
83 | const DateTimeRange& newRange, const DateTimeRange& newCacheRange, | |
|
84 | bool notify=true); | |
|
85 | ||
|
86 | DEPRECATE( | |
|
87 | 82 | static QVector<DateTimeRange> provideNotInCacheRangeList(const DateTimeRange &oldRange, |
|
88 | const DateTimeRange &nextRange); | |
|
83 | const DateTimeRange &nextRange); | |
|
89 | 84 | |
|
90 | 85 | static QVector<DateTimeRange> provideInCacheRangeList(const DateTimeRange &oldRange, |
|
91 | const DateTimeRange &nextRange); | |
|
92 | ) | |
|
86 | const DateTimeRange &nextRange); | |
|
87 | ) | |
|
93 | 88 | |
|
89 | operator QUuid() {return _uuid;} | |
|
94 | 90 | QUuid ID(){return _uuid;} |
|
95 | 91 | signals: |
|
96 | 92 | void updated(); |
|
97 | DEPRECATE( | |
|
98 | /// Signal emitted when when the data series of the variable is loaded for the first time | |
|
99 | void dataInitialized(); | |
|
93 | DEPRECATE( | |
|
94 | /// Signal emitted when when the data series of the variable is loaded for the first time | |
|
95 | void dataInitialized(); | |
|
100 | 96 | ) |
|
101 | private: | |
|
102 | class VariablePrivate; | |
|
97 | private: | |
|
98 | class VariablePrivate; | |
|
103 | 99 | spimpl::unique_impl_ptr<VariablePrivate> impl; |
|
104 | 100 | QUuid _uuid; |
|
105 | 101 | QReadWriteLock m_lock; |
|
106 | 102 | }; |
|
107 | 103 | |
|
108 | 104 | // Required for using shared_ptr in signals/slots |
|
109 | 105 | SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>) |
|
110 | 106 | SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >) |
|
111 | 107 | |
|
112 | 108 | #endif // SCIQLOP_VARIABLE_H |
@@ -1,41 +1,43 | |||
|
1 | 1 | #include <memory> |
|
2 | 2 | #include <vector> |
|
3 | 3 | #include <set> |
|
4 | 4 | #include <QHash> |
|
5 | 5 | #include <QObject> |
|
6 | 6 | #include <QMutexLocker> |
|
7 | 7 | #include <QUuid> |
|
8 | 8 | #include <QItemSelectionModel> |
|
9 | 9 | #include <Common/spimpl.h> |
|
10 | 10 | #include <Variable/Variable.h> |
|
11 | 11 | //#include <Variable/VariableSynchronizationGroup.h> |
|
12 | 12 | #include <Variable/VariableModel.h> |
|
13 | 13 | #include <Data/IDataProvider.h> |
|
14 | 14 | #include "Data/DateTimeRange.h" |
|
15 | 15 | |
|
16 | 16 | class VariableController2: public QObject |
|
17 | 17 | { |
|
18 | 18 | class VariableController2Private; |
|
19 | 19 | Q_OBJECT |
|
20 | 20 | |
|
21 | 21 | spimpl::unique_impl_ptr<VariableController2Private> impl; |
|
22 | 22 | |
|
23 | 23 | public: |
|
24 | 24 | explicit VariableController2(); |
|
25 | 25 | std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata, |
|
26 | 26 | const std::shared_ptr<IDataProvider>& provider, |
|
27 | 27 | const DateTimeRange &range); |
|
28 | 28 | |
|
29 | 29 | void deleteVariable(const std::shared_ptr<Variable>& variable); |
|
30 | 30 | void changeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r); |
|
31 | 31 | void asyncChangeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r); |
|
32 | 32 | const std::set<std::shared_ptr<Variable>> variables(); |
|
33 | 33 | |
|
34 | bool isReady(const std::shared_ptr<Variable>& variable); | |
|
35 | ||
|
34 | 36 | void synchronize(const std::shared_ptr<Variable>& var, const std::shared_ptr<Variable>& with); |
|
35 | 37 | |
|
36 | 38 | |
|
37 | 39 | signals: |
|
38 | 40 | void variableAdded(const std::shared_ptr<Variable>&); |
|
39 | 41 | void variableDeleted(const std::shared_ptr<Variable>&); |
|
40 | 42 | |
|
41 | 43 | }; |
@@ -1,71 +1,75 | |||
|
1 | 1 | #ifndef SCIQLOP_VARIABLESYNCHRONIZATIONGROUP2_H |
|
2 | 2 | #define SCIQLOP_VARIABLESYNCHRONIZATIONGROUP2_H |
|
3 | 3 | |
|
4 | 4 | #include <QUuid> |
|
5 | 5 | #include <set> |
|
6 | 6 | |
|
7 | 7 | #include "CoreGlobal.h" |
|
8 | 8 | #include <Common/spimpl.h> |
|
9 | 9 | #include <Common/containers.h> |
|
10 | 10 | |
|
11 | 11 | /** |
|
12 | 12 | * @brief The VariableSynchronizationGroup2 class holds a list of Variables uuid which are synchronized |
|
13 | 13 | * @note This class is part of SciQLop internals, as a normal user you shouldn't have to care about it |
|
14 | 14 | */ |
|
15 | 15 | class SCIQLOP_CORE_EXPORT VariableSynchronizationGroup2 |
|
16 | 16 | { |
|
17 | 17 | |
|
18 | 18 | public: |
|
19 | 19 | explicit VariableSynchronizationGroup2()=default; |
|
20 | 20 | /** |
|
21 | 21 | * @brief VariableSynchronizationGroup2 is a convenience ctor to build a group with a default variable |
|
22 | 22 | * @param variable |
|
23 | 23 | */ |
|
24 | 24 | explicit VariableSynchronizationGroup2(QUuid variable) |
|
25 | 25 | :_variables{{variable}} |
|
26 | 26 | {} |
|
27 | 27 | |
|
28 | 28 | /** |
|
29 | 29 | * @brief addVariable adds the given variable to the group, does nothing if the varaible is alredy in the group |
|
30 | 30 | * @param variable |
|
31 | 31 | * @sa removeVariable |
|
32 | 32 | */ |
|
33 | 33 | void addVariable(QUuid variable) noexcept |
|
34 | 34 | { |
|
35 | 35 | this->_variables.insert(variable); |
|
36 | 36 | } |
|
37 | 37 | |
|
38 | 38 | /** |
|
39 | 39 | * @brief removeVariable removes the given variable from the group, does nothing if the varaible is not in the group |
|
40 | 40 | * @param variable |
|
41 | 41 | * @sa addVariable |
|
42 | 42 | */ |
|
43 | 43 | void removeVariable(QUuid variable) noexcept |
|
44 | 44 | { |
|
45 | 45 | this->_variables.erase(variable); |
|
46 | 46 | } |
|
47 | 47 | |
|
48 | 48 | /** |
|
49 | 49 | * @brief contains checks if the given variable is in the group |
|
50 | 50 | * @param variable |
|
51 | 51 | * @return true if the variable is in the group |
|
52 | 52 | */ |
|
53 | 53 | bool contains(QUuid variable) const noexcept |
|
54 | 54 | { |
|
55 | 55 | return SciQLop::containers::contains(this->_variables,variable); |
|
56 | 56 | } |
|
57 | 57 | |
|
58 | 58 | /** |
|
59 | 59 | * @brief variables |
|
60 | 60 | * @return the list of synchronized variables in this group as a std::set |
|
61 | 61 | */ |
|
62 | 62 | const std::set<QUuid> &variables() const noexcept |
|
63 | 63 | { |
|
64 | 64 | return this->_variables; |
|
65 | 65 | } |
|
66 | 66 | |
|
67 | inline QUuid ID(){return _ID;} | |
|
68 | ||
|
69 | operator QUuid() {return _ID;} | |
|
67 | 70 | private: |
|
68 | 71 | std::set<QUuid> _variables; |
|
72 | QUuid _ID = QUuid::createUuid(); | |
|
69 | 73 | }; |
|
70 | 74 | |
|
71 | 75 | #endif // SCIQLOP_VARIABLESYNCHRONIZATIONGROUP2_H |
@@ -1,199 +1,380 | |||
|
1 | #include <QQueue> | |
|
2 | #include <QThreadPool> | |
|
3 | #include <QRunnable> | |
|
4 | #include <QObject> | |
|
5 | ||
|
1 | 6 | #include "Variable/VariableController2.h" |
|
2 | 7 | #include "Variable/VariableSynchronizationGroup2.h" |
|
3 | 8 | #include <Common/containers.h> |
|
4 | 9 | #include <Common/debug.h> |
|
5 | 10 | #include <Data/DataProviderParameters.h> |
|
6 | 11 | #include <Data/DateTimeRangeHelper.h> |
|
12 | #include <Data/DateTimeRange.h> | |
|
7 | 13 | #include <Variable/VariableCacheStrategyFactory.h> |
|
14 | #include <Variable/private/VCTransaction.h> | |
|
15 | ||
|
16 | class Transactions | |
|
17 | { | |
|
18 | QReadWriteLock _mutex{QReadWriteLock::Recursive}; | |
|
19 | std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> _nextTransactions; | |
|
20 | std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> _pendingTransactions; | |
|
21 | public: | |
|
22 | void addEntry(QUuid id) | |
|
23 | { | |
|
24 | QWriteLocker lock{&_mutex}; | |
|
25 | _nextTransactions[id] = std::nullopt; | |
|
26 | _pendingTransactions[id] = std::nullopt; | |
|
27 | } | |
|
28 | ||
|
29 | void removeEntry(QUuid id) | |
|
30 | { | |
|
31 | QWriteLocker lock{&_mutex}; | |
|
32 | _nextTransactions.erase(id); | |
|
33 | _pendingTransactions.erase(id); | |
|
34 | } | |
|
35 | ||
|
36 | std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> pendingTransactions() | |
|
37 | { | |
|
38 | QReadLocker lock{&_mutex}; | |
|
39 | return _pendingTransactions; | |
|
40 | } | |
|
41 | ||
|
42 | std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> nextTransactions() | |
|
43 | { | |
|
44 | QReadLocker lock{&_mutex}; | |
|
45 | return _nextTransactions; | |
|
46 | } | |
|
47 | ||
|
48 | std::optional<std::shared_ptr<VCTransaction>> start(QUuid id) | |
|
49 | { | |
|
50 | QWriteLocker lock{&_mutex}; | |
|
51 | _pendingTransactions[id] = _nextTransactions[id]; | |
|
52 | _nextTransactions[id] = std::nullopt; | |
|
53 | return _pendingTransactions[id]; | |
|
54 | } | |
|
55 | ||
|
56 | void enqueue(QUuid id, std::shared_ptr<VCTransaction> transaction) | |
|
57 | { | |
|
58 | QWriteLocker lock{&_mutex}; | |
|
59 | _nextTransactions[id] = transaction; | |
|
60 | } | |
|
61 | ||
|
62 | void complete(QUuid id) | |
|
63 | { | |
|
64 | QWriteLocker lock{&_mutex}; | |
|
65 | _pendingTransactions[id] = std::nullopt; | |
|
66 | } | |
|
67 | ||
|
68 | bool active(QUuid id) | |
|
69 | { | |
|
70 | QReadLocker lock{&_mutex}; | |
|
71 | return _nextTransactions[id].has_value() && _pendingTransactions[id].has_value(); | |
|
72 | } | |
|
73 | }; | |
|
8 | 74 | |
|
9 | 75 | class VariableController2::VariableController2Private |
|
10 | 76 | { |
|
77 | QThreadPool _ThreadPool; | |
|
11 | 78 | QMap<QUuid,std::shared_ptr<Variable>> _variables; |
|
12 | 79 | QMap<QUuid,std::shared_ptr<IDataProvider>> _providers; |
|
13 | 80 | QMap<QUuid,std::shared_ptr<VariableSynchronizationGroup2>> _synchronizationGroups; |
|
81 | Transactions _transactions; | |
|
82 | QReadWriteLock _lock{QReadWriteLock::Recursive}; | |
|
14 | 83 | std::unique_ptr<VariableCacheStrategy> _cacheStrategy; |
|
84 | ||
|
15 | 85 | bool p_contains(const std::shared_ptr<Variable>& variable) |
|
16 | 86 | { |
|
17 | return _providers.contains(variable->ID()); | |
|
87 | QReadLocker lock{&_lock}; | |
|
88 | return _providers.contains(*variable); | |
|
18 | 89 | } |
|
19 | 90 | bool v_contains(const std::shared_ptr<Variable>& variable) |
|
20 | 91 | { |
|
92 | QReadLocker lock{&_lock}; | |
|
21 | 93 | return SciQLop::containers::contains(this->_variables, variable); |
|
22 | 94 | } |
|
23 | 95 | bool sg_contains(const std::shared_ptr<Variable>& variable) |
|
24 | 96 | { |
|
25 | return _synchronizationGroups.contains(variable->ID()); | |
|
97 | QReadLocker lock{&_lock}; | |
|
98 | return _synchronizationGroups.contains(*variable); | |
|
26 | 99 | } |
|
27 | 100 | |
|
28 | void _changeRange(const std::shared_ptr<Variable>& var, DateTimeRange r) | |
|
101 | void _transactionComplete(QUuid group, std::shared_ptr<VCTransaction> transaction) | |
|
102 | { | |
|
103 | { | |
|
104 | QWriteLocker lock{&transaction->lock}; | |
|
105 | transaction->ready -=1; | |
|
106 | } | |
|
107 | if(transaction->ready==0) | |
|
108 | { | |
|
109 | _transactions.complete(group); | |
|
110 | } | |
|
111 | this->_processTransactions(); | |
|
112 | } | |
|
113 | void _processTransactions() | |
|
114 | { | |
|
115 | QWriteLocker lock{&_lock}; | |
|
116 | auto nextTransactions = _transactions.nextTransactions(); | |
|
117 | auto pendingTransactions = _transactions.pendingTransactions(); | |
|
118 | for( auto [groupID, newTransaction] : nextTransactions) | |
|
119 | { | |
|
120 | if(newTransaction.has_value() && !pendingTransactions[groupID].has_value()) | |
|
121 | { | |
|
122 | _transactions.start(groupID); | |
|
123 | auto refVar = _variables[newTransaction.value()->refVar]; | |
|
124 | auto ranges = _computeAllRangesInGroup(refVar,newTransaction.value()->range); | |
|
125 | for( auto const& [ID, range] : ranges) | |
|
126 | { | |
|
127 | auto provider = _providers[ID]; | |
|
128 | auto variable = _variables[ID]; | |
|
129 | auto [missingRanges, newCacheRange] = _computeMissingRanges(variable,range); | |
|
130 | auto exe = new TransactionExe(_variables[ID], provider, missingRanges, range, newCacheRange); | |
|
131 | QObject::connect(exe, | |
|
132 | &TransactionExe::transactionComplete, | |
|
133 | [groupID=groupID,transaction=newTransaction.value(),this]() | |
|
134 | { | |
|
135 | this->_transactionComplete(groupID, transaction); | |
|
136 | } | |
|
137 | ); | |
|
138 | _ThreadPool.start(exe); | |
|
139 | } | |
|
140 | } | |
|
141 | } | |
|
142 | } | |
|
143 | ||
|
144 | std::map<QUuid,DateTimeRange> _computeAllRangesInGroup(const std::shared_ptr<Variable>& refVar, DateTimeRange r) | |
|
145 | { | |
|
146 | std::map<QUuid,DateTimeRange> ranges; | |
|
147 | if(!DateTimeRangeHelper::hasnan(r)) | |
|
148 | { | |
|
149 | auto group = _synchronizationGroups[*refVar]; | |
|
150 | if(auto transformation = DateTimeRangeHelper::computeTransformation(refVar->range(),r); | |
|
151 | transformation.has_value()) | |
|
152 | { | |
|
153 | for(auto varId:group->variables()) | |
|
154 | { | |
|
155 | auto var = _variables[varId]; | |
|
156 | auto newRange = var->range().transform(transformation.value()); | |
|
157 | ranges[varId] = newRange; | |
|
158 | } | |
|
159 | } | |
|
160 | else // force new range to all variables -> may be weird if more than one var in the group | |
|
161 | // @TODO ensure that there is no side effects | |
|
162 | { | |
|
163 | for(auto varId:group->variables()) | |
|
164 | { | |
|
165 | auto var = _variables[varId]; | |
|
166 | ranges[varId] = r; | |
|
167 | } | |
|
168 | } | |
|
169 | } | |
|
170 | else | |
|
171 | { | |
|
172 | SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN"); | |
|
173 | } | |
|
174 | return ranges; | |
|
175 | } | |
|
176 | ||
|
177 | std::pair<std::vector<DateTimeRange>,DateTimeRange> _computeMissingRanges(const std::shared_ptr<Variable>& var, DateTimeRange r) | |
|
29 | 178 | { |
|
30 | auto provider = _providers[var->ID()]; | |
|
31 | 179 | DateTimeRange newCacheRange; |
|
32 | 180 | std::vector<DateTimeRange> missingRanges; |
|
33 | 181 | if(DateTimeRangeHelper::hasnan(var->cacheRange())) |
|
34 | 182 | { |
|
35 | 183 | newCacheRange = _cacheStrategy->computeRange(r,r); |
|
36 | 184 | missingRanges = {newCacheRange}; |
|
37 | 185 | } |
|
38 | 186 | else |
|
39 | 187 | { |
|
40 | 188 | newCacheRange = _cacheStrategy->computeRange(var->cacheRange(),r); |
|
41 | 189 | missingRanges = newCacheRange - var->cacheRange(); |
|
42 | 190 | } |
|
191 | return {missingRanges,newCacheRange}; | |
|
192 | } | |
|
193 | ||
|
194 | void _changeRange(QUuid id, DateTimeRange r) | |
|
195 | { | |
|
196 | _lock.lockForRead(); | |
|
197 | auto var = _variables[id]; | |
|
198 | _lock.unlock(); | |
|
199 | _changeRange(var,r); | |
|
200 | } | |
|
201 | void _changeRange(const std::shared_ptr<Variable>& var, DateTimeRange r) | |
|
202 | { | |
|
203 | auto provider = _providers[*var]; | |
|
204 | auto [missingRanges, newCacheRange] = _computeMissingRanges(var,r); | |
|
43 | 205 | std::vector<IDataSeries*> data; |
|
44 | 206 | for(auto range:missingRanges) |
|
45 | 207 | { |
|
46 | data.push_back(provider->getData(DataProviderParameters{{range},var->metadata()})); | |
|
208 | data.push_back(provider->getData(DataProviderParameters{{range}, var->metadata()})); | |
|
47 | 209 | } |
|
48 | var->updateData(data,r,newCacheRange,true); | |
|
210 | var->updateData(data, r, newCacheRange, true); | |
|
49 | 211 | } |
|
50 | 212 | public: |
|
51 | 213 | VariableController2Private(QObject* parent=Q_NULLPTR) |
|
52 | 214 | :_cacheStrategy(VariableCacheStrategyFactory::createCacheStrategy(CacheStrategy::SingleThreshold)) |
|
53 | 215 | { |
|
54 | 216 | Q_UNUSED(parent); |
|
217 | this->_ThreadPool.setMaxThreadCount(32); | |
|
55 | 218 | } |
|
56 | 219 | |
|
57 |
~VariableController2Private() |
|
|
220 | ~VariableController2Private() | |
|
221 | { | |
|
222 | while (this->_ThreadPool.activeThreadCount()) | |
|
223 | { | |
|
224 | this->_ThreadPool.waitForDone(100); | |
|
225 | } | |
|
226 | } | |
|
58 | 227 | |
|
59 | 228 | std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata, std::shared_ptr<IDataProvider> provider) |
|
60 | 229 | { |
|
230 | QWriteLocker lock{&_lock}; | |
|
61 | 231 | auto newVar = std::make_shared<Variable>(name,metadata); |
|
62 |
this->_variables[newVar |
|
|
63 |
this->_providers[newVar |
|
|
64 |
|
|
|
232 | this->_variables[*newVar] = newVar; | |
|
233 | this->_providers[*newVar] = std::move(provider); | |
|
234 | auto group = std::make_shared<VariableSynchronizationGroup2>(newVar->ID()); | |
|
235 | this->_synchronizationGroups[*newVar] = group; | |
|
236 | this->_transactions.addEntry(*group); | |
|
65 | 237 | return newVar; |
|
66 | 238 | } |
|
67 | 239 | |
|
240 | bool hasPendingTransactions(const std::shared_ptr<Variable>& variable) | |
|
241 | { | |
|
242 | QReadLocker lock{&_lock}; | |
|
243 | auto group = _synchronizationGroups[*variable]; | |
|
244 | return _transactions.active(*group); | |
|
245 | } | |
|
246 | ||
|
68 | 247 | void deleteVariable(const std::shared_ptr<Variable>& variable) |
|
69 | 248 | { |
|
70 | 249 | /* |
|
71 | 250 | * Removing twice a var is ok but a var without provider has to be a hard error |
|
72 | 251 | * this means we got the var controller in an inconsistent state |
|
73 | 252 | */ |
|
74 | 253 | if(v_contains(variable)) |
|
75 | this->_variables.remove(variable->ID()); | |
|
254 | { | |
|
255 | QWriteLocker lock{&_lock}; | |
|
256 | this->_variables.remove(*variable); | |
|
257 | } | |
|
76 | 258 | if(p_contains(variable)) |
|
77 | this->_providers.remove(variable->ID()); | |
|
259 | { | |
|
260 | QWriteLocker lock{&_lock}; | |
|
261 | this->_providers.remove(*variable); | |
|
262 | } | |
|
78 | 263 | else |
|
79 | 264 | SCIQLOP_ERROR(VariableController2Private, "No provider found for given variable"); |
|
80 | 265 | } |
|
81 | 266 | |
|
82 | 267 | void asyncChangeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r) |
|
83 | 268 | { |
|
84 | ||
|
85 | } | |
|
86 | ||
|
87 | void changeRange(const std::shared_ptr<Variable>& variable, DateTimeRange r) | |
|
88 | { | |
|
89 | 269 | if(p_contains(variable)) |
|
90 | 270 | { |
|
91 | 271 | if(!DateTimeRangeHelper::hasnan(r)) |
|
92 | 272 | { |
|
93 |
auto group = _synchronizationGroups[variable |
|
|
94 | if(auto transformation = DateTimeRangeHelper::computeTransformation(variable->range(),r); | |
|
95 | transformation.has_value()) | |
|
96 | { | |
|
97 | for(auto varId:group->variables()) | |
|
98 | { | |
|
99 | auto var = _variables[varId]; | |
|
100 | auto newRange = var->range().transform(transformation.value()); | |
|
101 | _changeRange(var,newRange); | |
|
102 | } | |
|
103 | } | |
|
104 | else // force new range to all variables -> may be weird if more than one var in the group | |
|
105 | // @TODO ensure that there is no side effects | |
|
273 | auto group = _synchronizationGroups[*variable]; | |
|
274 | // Just overwrite next transaction | |
|
106 | 275 | { |
|
107 | for(auto varId:group->variables()) | |
|
108 | { | |
|
109 | auto var = _variables[varId]; | |
|
110 | _changeRange(var,r); | |
|
111 | } | |
|
276 | QWriteLocker lock{&_lock}; | |
|
277 | _transactions.enqueue(*group,std::make_shared<VCTransaction>(variable->ID(), r, static_cast<int>(group->variables().size()))); | |
|
112 | 278 | } |
|
279 | _processTransactions(); | |
|
113 | 280 | } |
|
114 | 281 | else |
|
115 | 282 | { |
|
116 | 283 | SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN"); |
|
117 | 284 | } |
|
118 | 285 | } |
|
119 | 286 | else |
|
120 | 287 | { |
|
121 | 288 | SCIQLOP_ERROR(VariableController2Private, "No provider found for given variable"); |
|
122 | 289 | } |
|
123 | 290 | } |
|
124 | 291 | |
|
292 | void changeRange(const std::shared_ptr<Variable>& variable, DateTimeRange r) | |
|
293 | { | |
|
294 | auto ranges = _computeAllRangesInGroup(variable,r); | |
|
295 | for( auto const& [ID, range] : ranges) | |
|
296 | { | |
|
297 | _changeRange(ID,range); | |
|
298 | } | |
|
299 | } | |
|
300 | ||
|
125 | 301 | void synchronize(const std::shared_ptr<Variable>& var, const std::shared_ptr<Variable>& with) |
|
126 | 302 | { |
|
127 | 303 | if(v_contains(var) && v_contains(with)) |
|
128 | 304 | { |
|
129 | 305 | if(sg_contains(var) && sg_contains(with)) |
|
130 | 306 | { |
|
131 | ||
|
307 | QWriteLocker lock{&_lock}; | |
|
132 | 308 | auto dest_group = this->_synchronizationGroups[with->ID()]; |
|
133 |
this->_synchronizationGroups[var |
|
|
134 |
dest_group->addVariable(var |
|
|
309 | this->_synchronizationGroups[*var] = dest_group; | |
|
310 | dest_group->addVariable(*var); | |
|
135 | 311 | } |
|
136 | 312 | else |
|
137 | 313 | { |
|
138 | 314 | SCIQLOP_ERROR(VariableController2Private, "At least one of the given variables isn't in a sync group"); |
|
139 | 315 | } |
|
140 | 316 | } |
|
141 | 317 | else |
|
142 | 318 | { |
|
143 | 319 | SCIQLOP_ERROR(VariableController2Private, "At least one of the given variables is not found"); |
|
144 | 320 | } |
|
145 | 321 | } |
|
146 | 322 | |
|
147 | 323 | const std::set<std::shared_ptr<Variable>> variables() |
|
148 | 324 | { |
|
149 | 325 | std::set<std::shared_ptr<Variable>> vars; |
|
326 | QReadLocker lock{&_lock}; | |
|
150 | 327 | for(const auto &var:_variables) |
|
151 | 328 | { |
|
152 | 329 | vars.insert(var); |
|
153 | 330 | } |
|
154 | 331 | return vars; |
|
155 | 332 | } |
|
156 | 333 | |
|
157 | 334 | }; |
|
158 | 335 | |
|
159 | 336 | VariableController2::VariableController2() |
|
160 | 337 | :impl{spimpl::make_unique_impl<VariableController2Private>()} |
|
161 | 338 | {} |
|
162 | 339 | |
|
163 | 340 | std::shared_ptr<Variable> VariableController2::createVariable(const QString &name, const QVariantHash &metadata, const std::shared_ptr<IDataProvider>& provider, const DateTimeRange &range) |
|
164 | 341 | { |
|
165 | 342 | auto var = impl->createVariable(name, metadata, provider); |
|
166 | 343 | emit variableAdded(var); |
|
167 | 344 | if(!DateTimeRangeHelper::hasnan(range)) |
|
168 | 345 | impl->changeRange(var,range); |
|
169 | 346 | else |
|
170 | 347 | SCIQLOP_ERROR(VariableController2, "Creating a variable with default constructed DateTimeRange is an error"); |
|
171 | 348 | return var; |
|
172 | 349 | } |
|
173 | 350 | |
|
174 | 351 | void VariableController2::deleteVariable(const std::shared_ptr<Variable>& variable) |
|
175 | 352 | { |
|
176 | 353 | impl->deleteVariable(variable); |
|
177 | 354 | emit variableDeleted(variable); |
|
178 | 355 | } |
|
179 | 356 | |
|
180 | 357 | void VariableController2::changeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r) |
|
181 | 358 | { |
|
182 | 359 | impl->changeRange(variable, r); |
|
183 | 360 | } |
|
184 | 361 | |
|
185 | 362 | void VariableController2::asyncChangeRange(const std::shared_ptr<Variable> &variable, const DateTimeRange &r) |
|
186 | 363 | { |
|
187 | 364 | impl->asyncChangeRange(variable, r); |
|
188 | 365 | } |
|
189 | 366 | |
|
190 | 367 | const std::set<std::shared_ptr<Variable> > VariableController2::variables() |
|
191 | 368 | { |
|
192 | 369 | return impl->variables(); |
|
193 | 370 | } |
|
194 | 371 | |
|
372 | bool VariableController2::isReady(const std::shared_ptr<Variable> &variable) | |
|
373 | { | |
|
374 | return impl->hasPendingTransactions(variable); | |
|
375 | } | |
|
376 | ||
|
195 | 377 | void VariableController2::synchronize(const std::shared_ptr<Variable> &var, const std::shared_ptr<Variable> &with) |
|
196 | 378 | { |
|
197 | 379 | impl->synchronize(var, with); |
|
198 | 380 | } |
|
199 |
@@ -1,49 +1,50 | |||
|
1 | 1 | add_definitions(-DCORE_TESTS_RESOURCES_DIR="${CMAKE_CURRENT_LIST_DIR}/../tests-resources") |
|
2 | 2 | |
|
3 | 3 | FILE (GLOB_RECURSE TestUtilsSources |
|
4 | 4 | TestUtils/TestProviders.h |
|
5 | 5 | TestUtils/TestProviders.cpp |
|
6 | 6 | ) |
|
7 | 7 | |
|
8 | 8 | add_library(TestUtils ${TestUtilsSources}) |
|
9 | 9 | target_link_libraries(TestUtils sciqlopcore Qt5::Test) |
|
10 | 10 | |
|
11 | 11 | declare_test(TestStringUtils TestStringUtils Common/TestStringUtils.cpp "sciqlopcore;Qt5::Test") |
|
12 | 12 | |
|
13 | 13 | declare_test(TestContainers TestContainers Common/TestContainers.cpp "sciqlopcore;Qt5::Test") |
|
14 | 14 | declare_test(TestSyncGroup TestSyncGroup Variable/TestSyncGroup.cpp "sciqlopcore;Qt5::Test") |
|
15 | 15 | |
|
16 | 16 | declare_test(TestDateTimeRange TestDateTimeRange Data/TestDateTimeRange.cpp "sciqlopcore;Qt5::Test") |
|
17 | 17 | |
|
18 | 18 | |
|
19 | 19 | declare_test(TestDataSeriesUtils TestDataSeriesUtils Data/TestDataSeriesUtils.cpp "sciqlopcore;Qt5::Test") |
|
20 | 20 | declare_test(TestOptionalAxis TestOptionalAxis Data/TestOptionalAxis.cpp "sciqlopcore;Qt5::Test") |
|
21 | 21 | declare_test(TestSpectrogramSeries TestSpectrogramSeries |
|
22 | 22 | "Data/TestSpectrogramSeries.cpp;Data/DataSeriesBuilders.h;Data/DataSeriesBuilders.cpp;Data/DataSeriesTestsUtils.h;Data/DataSeriesTestsUtils.cpp" |
|
23 | 23 | "sciqlopcore;Qt5::Test") |
|
24 | 24 | declare_test(TestOneDimArrayData TestOneDimArrayData Data/TestOneDimArrayData.cpp "sciqlopcore;Qt5::Test") |
|
25 | 25 | declare_test(TestScalarSeries TestScalarSeries |
|
26 | 26 | "Data/TestScalarSeries.cpp;Data/DataSeriesBuilders.h;Data/DataSeriesBuilders.cpp;Data/DataSeriesTestsUtils.h;Data/DataSeriesTestsUtils.cpp" |
|
27 | 27 | "sciqlopcore;Qt5::Test") |
|
28 | 28 | declare_test(TestTwoDimArrayData TestTwoDimArrayData Data/TestTwoDimArrayData.cpp "sciqlopcore;Qt5::Test") |
|
29 | 29 | declare_test(TestVectorSeries TestVectorSeries |
|
30 | 30 | "Data/TestVectorSeries.cpp;Data/DataSeriesBuilders.h;Data/DataSeriesBuilders.cpp;Data/DataSeriesTestsUtils.h;Data/DataSeriesTestsUtils.cpp" |
|
31 | 31 | "sciqlopcore;Qt5::Test") |
|
32 | 32 | |
|
33 | 33 | declare_test(TestDataSourceController TestDataSourceController |
|
34 | 34 | "DataSource/TestDataSourceController.cpp;DataSource/DataSourceItemBuilder.cpp" |
|
35 | 35 | "sciqlopcore;Qt5::Test") |
|
36 | 36 | declare_test(TestDataSourceItem TestDataSourceItem |
|
37 | 37 | "DataSource/TestDataSourceItem.cpp;DataSource/DataSourceItemBuilder.cpp" |
|
38 | 38 | "sciqlopcore;Qt5::Test") |
|
39 | 39 | |
|
40 | 40 | declare_test(TestVariable TestVariable Variable/TestVariable.cpp "sciqlopcore;Qt5::Test") |
|
41 | 41 | declare_test(TestVariableCacheController TestVariableCacheController Variable/TestVariableCacheController.cpp "sciqlopcore;Qt5::Test") |
|
42 | 42 | declare_test(TestVariableController TestVariableController Variable/TestVariableController.cpp "sciqlopcore;Qt5::Test") |
|
43 | 43 | declare_test(TestVariableSync TestVariableSync Variable/TestVariableSync.cpp "sciqlopcore;Qt5::Test") |
|
44 | 44 | |
|
45 | 45 | declare_test(TestDownloader TestDownloader Network/TestDownloader.cpp "sciqlopcore;Qt5::Test") |
|
46 | 46 | |
|
47 | 47 | |
|
48 | 48 | declare_test(TestVariableController2 TestVariableController2 Variable/TestVariableController2.cpp "sciqlopcore;TestUtils;Qt5::Test") |
|
49 | declare_test(TestVariableController2Async TestVariableController2Async Variable/TestVariableController2Async.cpp "sciqlopcore;TestUtils;Qt5::Test") | |
|
49 | 50 | declare_test(TestVariableController2WithSync TestVariableController2WithSync Variable/TestVariableController2WithSync.cpp "sciqlopcore;TestUtils;Qt5::Test") |
General Comments 0
You need to be logged in to leave comments.
Login now