##// END OF EJS Templates
Merge branch 'feature/PurgeDataSeries' into develop
Alexandre Leroux -
r633:e899bacb01d9 merge
parent child
Show More
@@ -1,282 +1,353
1 #ifndef SCIQLOP_ARRAYDATA_H
1 #ifndef SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
3
3
4 #include "Data/ArrayDataIterator.h"
4 #include "Data/ArrayDataIterator.h"
5 #include <Common/SortUtils.h>
5 #include <Common/SortUtils.h>
6
6
7 #include <QReadLocker>
7 #include <QReadLocker>
8 #include <QReadWriteLock>
8 #include <QReadWriteLock>
9 #include <QVector>
9 #include <QVector>
10
10
11 #include <memory>
11 #include <memory>
12
12
13 template <int Dim>
13 template <int Dim>
14 class ArrayData;
14 class ArrayData;
15
15
16 using DataContainer = QVector<double>;
16 using DataContainer = QVector<double>;
17
17
18 namespace arraydata_detail {
18 namespace arraydata_detail {
19
19
20 /// Struct used to sort ArrayData
20 /// Struct used to sort ArrayData
21 template <int Dim>
21 template <int Dim>
22 struct Sort {
22 struct Sort {
23 static std::shared_ptr<ArrayData<Dim> > sort(const DataContainer &data, int nbComponents,
23 static std::shared_ptr<ArrayData<Dim> > sort(const DataContainer &data, int nbComponents,
24 const std::vector<int> &sortPermutation)
24 const std::vector<int> &sortPermutation)
25 {
25 {
26 return std::make_shared<ArrayData<Dim> >(
26 return std::make_shared<ArrayData<Dim> >(
27 SortUtils::sort(data, nbComponents, sortPermutation), nbComponents);
27 SortUtils::sort(data, nbComponents, sortPermutation), nbComponents);
28 }
28 }
29 };
29 };
30
30
31 /// Specialization for uni-dimensional ArrayData
31 /// Specialization for uni-dimensional ArrayData
32 template <>
32 template <>
33 struct Sort<1> {
33 struct Sort<1> {
34 static std::shared_ptr<ArrayData<1> > sort(const DataContainer &data, int nbComponents,
34 static std::shared_ptr<ArrayData<1> > sort(const DataContainer &data, int nbComponents,
35 const std::vector<int> &sortPermutation)
35 const std::vector<int> &sortPermutation)
36 {
36 {
37 Q_UNUSED(nbComponents)
37 Q_UNUSED(nbComponents)
38 return std::make_shared<ArrayData<1> >(SortUtils::sort(data, 1, sortPermutation));
38 return std::make_shared<ArrayData<1> >(SortUtils::sort(data, 1, sortPermutation));
39 }
39 }
40 };
40 };
41
41
42 template <int Dim, bool IsConst>
43 class IteratorValue;
44
45 template <int Dim, bool IsConst>
46 struct IteratorValueBuilder {
47 };
48
49 template <int Dim>
50 struct IteratorValueBuilder<Dim, true> {
51 using DataContainerIterator = DataContainer::const_iterator;
52
53 static void swap(IteratorValue<Dim, true> &o1, IteratorValue<Dim, true> &o2) {}
54 };
55
42 template <int Dim>
56 template <int Dim>
57 struct IteratorValueBuilder<Dim, false> {
58 using DataContainerIterator = DataContainer::iterator;
59
60 static void swap(IteratorValue<Dim, false> &o1, IteratorValue<Dim, false> &o2)
61 {
62 for (auto i = 0; i < o1.m_NbComponents; ++i) {
63 std::iter_swap(o1.m_It + i, o2.m_It + i);
64 }
65 }
66 };
67
68 template <int Dim, bool IsConst>
43 class IteratorValue : public ArrayDataIteratorValue::Impl {
69 class IteratorValue : public ArrayDataIteratorValue::Impl {
44 public:
70 public:
71 friend class ArrayData<Dim>;
72 friend class IteratorValueBuilder<Dim, IsConst>;
73
74 using DataContainerIterator =
75 typename IteratorValueBuilder<Dim, IsConst>::DataContainerIterator;
76
77 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
45 explicit IteratorValue(const DataContainer &container, int nbComponents, bool begin)
78 explicit IteratorValue(const DataContainer &container, int nbComponents, bool begin)
46 : m_It{begin ? container.cbegin() : container.cend()}, m_NbComponents{nbComponents}
79 : m_It{begin ? container.cbegin() : container.cend()}, m_NbComponents{nbComponents}
47 {
80 {
48 }
81 }
49
82
83 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
84 explicit IteratorValue(DataContainer &container, int nbComponents, bool begin)
85 : m_It{begin ? container.begin() : container.end()}, m_NbComponents{nbComponents}
86 {
87 }
88
50 IteratorValue(const IteratorValue &other) = default;
89 IteratorValue(const IteratorValue &other) = default;
51
90
52 std::unique_ptr<ArrayDataIteratorValue::Impl> clone() const override
91 std::unique_ptr<ArrayDataIteratorValue::Impl> clone() const override
53 {
92 {
54 return std::make_unique<IteratorValue<Dim> >(*this);
93 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
55 }
94 }
56
95
57 bool equals(const ArrayDataIteratorValue::Impl &other) const override try {
96 bool equals(const ArrayDataIteratorValue::Impl &other) const override try {
58 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
97 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
59 return std::tie(m_It, m_NbComponents) == std::tie(otherImpl.m_It, otherImpl.m_NbComponents);
98 return std::tie(m_It, m_NbComponents) == std::tie(otherImpl.m_It, otherImpl.m_NbComponents);
60 }
99 }
61 catch (const std::bad_cast &) {
100 catch (const std::bad_cast &) {
62 return false;
101 return false;
63 }
102 }
64
103
65 void next() override { std::advance(m_It, m_NbComponents); }
104 void next() override { std::advance(m_It, m_NbComponents); }
66 void prev() override { std::advance(m_It, -m_NbComponents); }
105 void prev() override { std::advance(m_It, -m_NbComponents); }
67
106
68 double at(int componentIndex) const override { return *(m_It + componentIndex); }
107 double at(int componentIndex) const override { return *(m_It + componentIndex); }
69 double first() const override { return *m_It; }
108 double first() const override { return *m_It; }
70 double min() const override
109 double min() const override
71 {
110 {
72 auto values = this->values();
111 auto values = this->values();
73 auto end = values.cend();
112 auto end = values.cend();
74 auto it = std::min_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
113 auto it = std::min_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
75 return SortUtils::minCompareWithNaN(v1, v2);
114 return SortUtils::minCompareWithNaN(v1, v2);
76 });
115 });
77
116
78 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
117 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
79 }
118 }
80 double max() const override
119 double max() const override
81 {
120 {
82 auto values = this->values();
121 auto values = this->values();
83 auto end = values.cend();
122 auto end = values.cend();
84 auto it = std::max_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
123 auto it = std::max_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
85 return SortUtils::maxCompareWithNaN(v1, v2);
124 return SortUtils::maxCompareWithNaN(v1, v2);
86 });
125 });
87 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
126 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
88 }
127 }
89
128
90 QVector<double> values() const override
129 QVector<double> values() const override
91 {
130 {
92 auto result = QVector<double>{};
131 auto result = QVector<double>{};
93 for (auto i = 0; i < m_NbComponents; ++i) {
132 for (auto i = 0; i < m_NbComponents; ++i) {
94 result.push_back(*(m_It + i));
133 result.push_back(*(m_It + i));
95 }
134 }
96
135
97 return result;
136 return result;
98 }
137 }
99
138
139 void swap(ArrayDataIteratorValue::Impl &other) override
140 {
141 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
142 IteratorValueBuilder<Dim, IsConst>::swap(*this, otherImpl);
143 }
144
100 private:
145 private:
101 DataContainer::const_iterator m_It;
146 DataContainerIterator m_It;
102 int m_NbComponents;
147 int m_NbComponents;
103 };
148 };
104
149
105 } // namespace arraydata_detail
150 } // namespace arraydata_detail
106
151
107 /**
152 /**
108 * @brief The ArrayData class represents a dataset for a data series.
153 * @brief The ArrayData class represents a dataset for a data series.
109 *
154 *
110 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
155 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
111 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
156 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
112 * number of values
157 * number of values
113 *
158 *
114 * @tparam Dim the dimension of the ArrayData (one or two)
159 * @tparam Dim the dimension of the ArrayData (one or two)
115 * @sa IDataSeries
160 * @sa IDataSeries
116 */
161 */
117 template <int Dim>
162 template <int Dim>
118 class ArrayData {
163 class ArrayData {
119 public:
164 public:
120 // ///// //
165 // ///// //
121 // Ctors //
166 // Ctors //
122 // ///// //
167 // ///// //
123
168
124 /**
169 /**
125 * Ctor for a unidimensional ArrayData
170 * Ctor for a unidimensional ArrayData
126 * @param data the data the ArrayData will hold
171 * @param data the data the ArrayData will hold
127 */
172 */
128 template <int D = Dim, typename = std::enable_if_t<D == 1> >
173 template <int D = Dim, typename = std::enable_if_t<D == 1> >
129 explicit ArrayData(DataContainer data) : m_Data{std::move(data)}, m_NbComponents{1}
174 explicit ArrayData(DataContainer data) : m_Data{std::move(data)}, m_NbComponents{1}
130 {
175 {
131 }
176 }
132
177
133 /**
178 /**
134 * Ctor for a two-dimensional ArrayData. The number of components (number of lines) must be
179 * Ctor for a two-dimensional ArrayData. The number of components (number of lines) must be
135 * greater than 2 and must be a divisor of the total number of data in the vector
180 * greater than 2 and must be a divisor of the total number of data in the vector
136 * @param data the data the ArrayData will hold
181 * @param data the data the ArrayData will hold
137 * @param nbComponents the number of components
182 * @param nbComponents the number of components
138 * @throws std::invalid_argument if the number of components is less than 2 or is not a divisor
183 * @throws std::invalid_argument if the number of components is less than 2 or is not a divisor
139 * of the size of the data
184 * of the size of the data
140 */
185 */
141 template <int D = Dim, typename = std::enable_if_t<D == 2> >
186 template <int D = Dim, typename = std::enable_if_t<D == 2> >
142 explicit ArrayData(DataContainer data, int nbComponents)
187 explicit ArrayData(DataContainer data, int nbComponents)
143 : m_Data{std::move(data)}, m_NbComponents{nbComponents}
188 : m_Data{std::move(data)}, m_NbComponents{nbComponents}
144 {
189 {
145 if (nbComponents < 2) {
190 if (nbComponents < 2) {
146 throw std::invalid_argument{
191 throw std::invalid_argument{
147 QString{"A multidimensional ArrayData must have at least 2 components (found: %1)"}
192 QString{"A multidimensional ArrayData must have at least 2 components (found: %1)"}
148 .arg(nbComponents)
193 .arg(nbComponents)
149 .toStdString()};
194 .toStdString()};
150 }
195 }
151
196
152 if (m_Data.size() % m_NbComponents != 0) {
197 if (m_Data.size() % m_NbComponents != 0) {
153 throw std::invalid_argument{QString{
198 throw std::invalid_argument{QString{
154 "The number of components (%1) is inconsistent with the total number of data (%2)"}
199 "The number of components (%1) is inconsistent with the total number of data (%2)"}
155 .arg(m_Data.size(), nbComponents)
200 .arg(m_Data.size(), nbComponents)
156 .toStdString()};
201 .toStdString()};
157 }
202 }
158 }
203 }
159
204
160 /// Copy ctor
205 /// Copy ctor
161 explicit ArrayData(const ArrayData &other)
206 explicit ArrayData(const ArrayData &other)
162 {
207 {
163 QReadLocker otherLocker{&other.m_Lock};
208 QReadLocker otherLocker{&other.m_Lock};
164 m_Data = other.m_Data;
209 m_Data = other.m_Data;
165 m_NbComponents = other.m_NbComponents;
210 m_NbComponents = other.m_NbComponents;
166 }
211 }
167
212
168 // /////////////// //
213 // /////////////// //
169 // General methods //
214 // General methods //
170 // /////////////// //
215 // /////////////// //
171
216
172 /**
217 /**
173 * Merges into the array data an other array data. The two array datas must have the same number
218 * Merges into the array data an other array data. The two array datas must have the same number
174 * of components so the merge can be done
219 * of components so the merge can be done
175 * @param other the array data to merge with
220 * @param other the array data to merge with
176 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
221 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
177 * inserted at the end
222 * inserted at the end
178 */
223 */
179 void add(const ArrayData<Dim> &other, bool prepend = false)
224 void add(const ArrayData<Dim> &other, bool prepend = false)
180 {
225 {
181 QWriteLocker locker{&m_Lock};
226 QWriteLocker locker{&m_Lock};
182 QReadLocker otherLocker{&other.m_Lock};
227 QReadLocker otherLocker{&other.m_Lock};
183
228
184 if (m_NbComponents != other.componentCount()) {
229 if (m_NbComponents != other.componentCount()) {
185 return;
230 return;
186 }
231 }
187
232
188 if (prepend) {
233 if (prepend) {
189 auto otherDataSize = other.m_Data.size();
234 auto otherDataSize = other.m_Data.size();
190 m_Data.insert(m_Data.begin(), otherDataSize, 0.);
235 m_Data.insert(m_Data.begin(), otherDataSize, 0.);
191 for (auto i = 0; i < otherDataSize; ++i) {
236 for (auto i = 0; i < otherDataSize; ++i) {
192 m_Data.replace(i, other.m_Data.at(i));
237 m_Data.replace(i, other.m_Data.at(i));
193 }
238 }
194 }
239 }
195 else {
240 else {
196 m_Data.append(other.m_Data);
241 m_Data.append(other.m_Data);
197 }
242 }
198 }
243 }
199
244
200 void clear()
245 void clear()
201 {
246 {
202 QWriteLocker locker{&m_Lock};
247 QWriteLocker locker{&m_Lock};
203 m_Data.clear();
248 m_Data.clear();
204 }
249 }
205
250
206 int componentCount() const noexcept { return m_NbComponents; }
251 int componentCount() const noexcept { return m_NbComponents; }
207
252
208 /// @return the size (i.e. number of values) of a single component
253 /// @return the size (i.e. number of values) of a single component
209 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
254 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
210 int size() const
255 int size() const
211 {
256 {
212 QReadLocker locker{&m_Lock};
257 QReadLocker locker{&m_Lock};
213 return m_Data.size() / m_NbComponents;
258 return m_Data.size() / m_NbComponents;
214 }
259 }
215
260
216 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
261 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
217 {
262 {
218 QReadLocker locker{&m_Lock};
263 QReadLocker locker{&m_Lock};
219 return arraydata_detail::Sort<Dim>::sort(m_Data, m_NbComponents, sortPermutation);
264 return arraydata_detail::Sort<Dim>::sort(m_Data, m_NbComponents, sortPermutation);
220 }
265 }
221
266
222 // ///////// //
267 // ///////// //
223 // Iterators //
268 // Iterators //
224 // ///////// //
269 // ///////// //
225
270
271 ArrayDataIterator begin()
272 {
273 return ArrayDataIterator{
274 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
275 m_Data, m_NbComponents, true)}};
276 }
277
278 ArrayDataIterator end()
279 {
280 return ArrayDataIterator{
281 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
282 m_Data, m_NbComponents, false)}};
283 }
284
226 ArrayDataIterator cbegin() const
285 ArrayDataIterator cbegin() const
227 {
286 {
228 return ArrayDataIterator{ArrayDataIteratorValue{
287 return ArrayDataIterator{
229 std::make_unique<arraydata_detail::IteratorValue<Dim> >(m_Data, m_NbComponents, true)}};
288 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
289 m_Data, m_NbComponents, true)}};
230 }
290 }
291
231 ArrayDataIterator cend() const
292 ArrayDataIterator cend() const
232 {
293 {
233 return ArrayDataIterator{
294 return ArrayDataIterator{
234 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim> >(
295 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
235 m_Data, m_NbComponents, false)}};
296 m_Data, m_NbComponents, false)}};
236 }
297 }
237
298
299 void erase(ArrayDataIterator first, ArrayDataIterator last)
300 {
301 auto firstImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(first->impl());
302 auto lastImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(last->impl());
303
304 if (firstImpl && lastImpl) {
305 m_Data.erase(firstImpl->m_It, lastImpl->m_It);
306 }
307 }
308
238 /// Inserts at the end of the array data the values passed as a parameter. This
309 /// Inserts at the end of the array data the values passed as a parameter. This
239 /// method is intended to be used in the context of generating a back insert iterator, or only
310 /// method is intended to be used in the context of generating a back insert iterator, or only
240 /// if it's ensured that the total size of the vector is consistent with the number of
311 /// if it's ensured that the total size of the vector is consistent with the number of
241 /// components of the array data
312 /// components of the array data
242 /// @param values the values to insert
313 /// @param values the values to insert
243 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
314 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
244 void push_back(const QVector<double> &values)
315 void push_back(const QVector<double> &values)
245 {
316 {
246 Q_ASSERT(values.size() % m_NbComponents == 0);
317 Q_ASSERT(values.size() % m_NbComponents == 0);
247 m_Data.append(values);
318 m_Data.append(values);
248 }
319 }
249
320
250 /**
321 /**
251 * @return the data at a specified index
322 * @return the data at a specified index
252 * @remarks index must be a valid position
323 * @remarks index must be a valid position
253 */
324 */
254 double at(int index) const noexcept
325 double at(int index) const noexcept
255 {
326 {
256 QReadLocker locker{&m_Lock};
327 QReadLocker locker{&m_Lock};
257 return m_Data.at(index);
328 return m_Data.at(index);
258 }
329 }
259
330
260 // ///////////// //
331 // ///////////// //
261 // 1-dim methods //
332 // 1-dim methods //
262 // ///////////// //
333 // ///////////// //
263
334
264 /**
335 /**
265 * @return the data as a vector, as a const reference
336 * @return the data as a vector, as a const reference
266 * @remarks this method is only available for a unidimensional ArrayData
337 * @remarks this method is only available for a unidimensional ArrayData
267 */
338 */
268 template <int D = Dim, typename = std::enable_if_t<D == 1> >
339 template <int D = Dim, typename = std::enable_if_t<D == 1> >
269 const QVector<double> &cdata() const noexcept
340 const QVector<double> &cdata() const noexcept
270 {
341 {
271 QReadLocker locker{&m_Lock};
342 QReadLocker locker{&m_Lock};
272 return m_Data;
343 return m_Data;
273 }
344 }
274
345
275 private:
346 private:
276 DataContainer m_Data;
347 DataContainer m_Data;
277 /// Number of components (lines). Is always 1 in a 1-dim ArrayData
348 /// Number of components (lines). Is always 1 in a 1-dim ArrayData
278 int m_NbComponents;
349 int m_NbComponents;
279 mutable QReadWriteLock m_Lock;
350 mutable QReadWriteLock m_Lock;
280 };
351 };
281
352
282 #endif // SCIQLOP_ARRAYDATA_H
353 #endif // SCIQLOP_ARRAYDATA_H
@@ -1,60 +1,68
1 #ifndef SCIQLOP_ARRAYDATAITERATOR_H
1 #ifndef SCIQLOP_ARRAYDATAITERATOR_H
2 #define SCIQLOP_ARRAYDATAITERATOR_H
2 #define SCIQLOP_ARRAYDATAITERATOR_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5 #include "Data/SqpIterator.h"
5 #include "Data/SqpIterator.h"
6
6
7 #include <QVector>
7 #include <QVector>
8 #include <memory>
8 #include <memory>
9
9
10 /**
10 /**
11 * @brief The ArrayDataIteratorValue class represents the current value of an array data iterator.
11 * @brief The ArrayDataIteratorValue class represents the current value of an array data iterator.
12 * It offers standard access methods for the data in the series (at(), first()), but it is up to
12 * It offers standard access methods for the data in the series (at(), first()), but it is up to
13 * each array data to define its own implementation of how to retrieve this data (one-dim or two-dim
13 * each array data to define its own implementation of how to retrieve this data (one-dim or two-dim
14 * array), by implementing the ArrayDataIteratorValue::Impl interface
14 * array), by implementing the ArrayDataIteratorValue::Impl interface
15 * @sa ArrayDataIterator
15 * @sa ArrayDataIterator
16 */
16 */
17 class SCIQLOP_CORE_EXPORT ArrayDataIteratorValue {
17 class SCIQLOP_CORE_EXPORT ArrayDataIteratorValue {
18 public:
18 public:
19 struct Impl {
19 struct Impl {
20 virtual ~Impl() noexcept = default;
20 virtual ~Impl() noexcept = default;
21 virtual std::unique_ptr<Impl> clone() const = 0;
21 virtual std::unique_ptr<Impl> clone() const = 0;
22 virtual bool equals(const Impl &other) const = 0;
22 virtual bool equals(const Impl &other) const = 0;
23 virtual void next() = 0;
23 virtual void next() = 0;
24 virtual void prev() = 0;
24 virtual void prev() = 0;
25 virtual double at(int componentIndex) const = 0;
25 virtual double at(int componentIndex) const = 0;
26 virtual double first() const = 0;
26 virtual double first() const = 0;
27 virtual double min() const = 0;
27 virtual double min() const = 0;
28 virtual double max() const = 0;
28 virtual double max() const = 0;
29 virtual QVector<double> values() const = 0;
29 virtual QVector<double> values() const = 0;
30
31 virtual void swap(Impl &other) = 0;
30 };
32 };
31
33
32 explicit ArrayDataIteratorValue(std::unique_ptr<Impl> impl);
34 explicit ArrayDataIteratorValue(std::unique_ptr<Impl> impl);
33 ArrayDataIteratorValue(const ArrayDataIteratorValue &other);
35 ArrayDataIteratorValue(const ArrayDataIteratorValue &other);
34 ArrayDataIteratorValue(ArrayDataIteratorValue &&other) = default;
35 ArrayDataIteratorValue &operator=(ArrayDataIteratorValue other);
36 ArrayDataIteratorValue &operator=(ArrayDataIteratorValue other);
36
37
37 bool equals(const ArrayDataIteratorValue &other) const;
38 bool equals(const ArrayDataIteratorValue &other) const;
38
39
39 /// Advances to the next value
40 /// Advances to the next value
40 void next();
41 void next();
41 /// Moves back to the previous value
42 /// Moves back to the previous value
42 void prev();
43 void prev();
43 /// Gets value of a specified component
44 /// Gets value of a specified component
44 double at(int componentIndex) const;
45 double at(int componentIndex) const;
45 /// Gets value of first component
46 /// Gets value of first component
46 double first() const;
47 double first() const;
47 /// Gets min value among all components
48 /// Gets min value among all components
48 double min() const;
49 double min() const;
49 /// Gets max value among all components
50 /// Gets max value among all components
50 double max() const;
51 double max() const;
51 /// Gets all values
52 /// Gets all values
52 QVector<double> values() const;
53 QVector<double> values() const;
53
54
55 Impl *impl();
56
57 friend void swap(ArrayDataIteratorValue &lhs, ArrayDataIteratorValue &rhs)
58 {
59 std::swap(lhs.m_Impl, rhs.m_Impl);
60 }
61
54 private:
62 private:
55 std::unique_ptr<Impl> m_Impl;
63 std::unique_ptr<Impl> m_Impl;
56 };
64 };
57
65
58 using ArrayDataIterator = SqpIterator<ArrayDataIteratorValue>;
66 using ArrayDataIterator = SqpIterator<ArrayDataIteratorValue>;
59
67
60 #endif // SCIQLOP_ARRAYDATAITERATOR_H
68 #endif // SCIQLOP_ARRAYDATAITERATOR_H
@@ -1,317 +1,374
1 #ifndef SCIQLOP_DATASERIES_H
1 #ifndef SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Common/SortUtils.h>
6 #include <Common/SortUtils.h>
7
7
8 #include <Data/ArrayData.h>
8 #include <Data/ArrayData.h>
9 #include <Data/DataSeriesMergeHelper.h>
9 #include <Data/DataSeriesMergeHelper.h>
10 #include <Data/IDataSeries.h>
10 #include <Data/IDataSeries.h>
11
11
12 #include <QLoggingCategory>
12 #include <QLoggingCategory>
13 #include <QReadLocker>
13 #include <QReadLocker>
14 #include <QReadWriteLock>
14 #include <QReadWriteLock>
15 #include <memory>
15 #include <memory>
16
16
17 // We don't use the Qt macro since the log is used in the header file, which causes multiple log
17 // We don't use the Qt macro since the log is used in the header file, which causes multiple log
18 // definitions with inheritance. Inline method is used instead
18 // definitions with inheritance. Inline method is used instead
19 inline const QLoggingCategory &LOG_DataSeries()
19 inline const QLoggingCategory &LOG_DataSeries()
20 {
20 {
21 static const QLoggingCategory category{"DataSeries"};
21 static const QLoggingCategory category{"DataSeries"};
22 return category;
22 return category;
23 }
23 }
24
24
25 template <int Dim>
25 template <int Dim>
26 class DataSeries;
26 class DataSeries;
27
27
28 namespace dataseries_detail {
28 namespace dataseries_detail {
29
29
30 template <int Dim>
30 template <int Dim, bool IsConst>
31 class IteratorValue : public DataSeriesIteratorValue::Impl {
31 class IteratorValue : public DataSeriesIteratorValue::Impl {
32 public:
32 public:
33 friend class DataSeries<Dim>;
34
35 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
36 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
37 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
38 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end())
39 {
40 }
41
42 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
33 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
43 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
34 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
44 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
35 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
45 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
36 : dataSeries.valuesData()->cend())
46 : dataSeries.valuesData()->cend())
37 {
47 {
38 }
48 }
49
39 IteratorValue(const IteratorValue &other) = default;
50 IteratorValue(const IteratorValue &other) = default;
40
51
41 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
52 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
42 {
53 {
43 return std::make_unique<IteratorValue<Dim> >(*this);
54 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
44 }
55 }
45
56
46 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
57 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
47 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
58 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
48 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
59 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
49 }
60 }
50 catch (const std::bad_cast &) {
61 catch (const std::bad_cast &) {
51 return false;
62 return false;
52 }
63 }
53
64
54 void next() override
65 void next() override
55 {
66 {
56 ++m_XIt;
67 ++m_XIt;
57 ++m_ValuesIt;
68 ++m_ValuesIt;
58 }
69 }
59
70
60 void prev() override
71 void prev() override
61 {
72 {
62 --m_XIt;
73 --m_XIt;
63 --m_ValuesIt;
74 --m_ValuesIt;
64 }
75 }
65
76
66 double x() const override { return m_XIt->at(0); }
77 double x() const override { return m_XIt->at(0); }
67 double value() const override { return m_ValuesIt->at(0); }
78 double value() const override { return m_ValuesIt->at(0); }
68 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
79 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
69 double minValue() const override { return m_ValuesIt->min(); }
80 double minValue() const override { return m_ValuesIt->min(); }
70 double maxValue() const override { return m_ValuesIt->max(); }
81 double maxValue() const override { return m_ValuesIt->max(); }
71 QVector<double> values() const override { return m_ValuesIt->values(); }
82 QVector<double> values() const override { return m_ValuesIt->values(); }
72
83
84 void swap(DataSeriesIteratorValue::Impl &other) override
85 {
86 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
87 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
88 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
89 }
90
73 private:
91 private:
74 ArrayDataIterator m_XIt;
92 ArrayDataIterator m_XIt;
75 ArrayDataIterator m_ValuesIt;
93 ArrayDataIterator m_ValuesIt;
76 };
94 };
77 } // namespace dataseries_detail
95 } // namespace dataseries_detail
78
96
79 /**
97 /**
80 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
98 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
81 *
99 *
82 * It proposes to set a dimension for the values ​​data.
100 * It proposes to set a dimension for the values ​​data.
83 *
101 *
84 * A DataSeries is always sorted on its x-axis data.
102 * A DataSeries is always sorted on its x-axis data.
85 *
103 *
86 * @tparam Dim The dimension of the values data
104 * @tparam Dim The dimension of the values data
87 *
105 *
88 */
106 */
89 template <int Dim>
107 template <int Dim>
90 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
108 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
91 friend class DataSeriesMergeHelper;
109 friend class DataSeriesMergeHelper;
92
110
93 public:
111 public:
94 /// Tag needed to define the push_back() method
112 /// Tag needed to define the push_back() method
95 /// @sa push_back()
113 /// @sa push_back()
96 using value_type = DataSeriesIteratorValue;
114 using value_type = DataSeriesIteratorValue;
97
115
98 /// @sa IDataSeries::xAxisData()
116 /// @sa IDataSeries::xAxisData()
99 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
117 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
100 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
118 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
101
119
102 /// @sa IDataSeries::xAxisUnit()
120 /// @sa IDataSeries::xAxisUnit()
103 Unit xAxisUnit() const override { return m_XAxisUnit; }
121 Unit xAxisUnit() const override { return m_XAxisUnit; }
104
122
105 /// @return the values dataset
123 /// @return the values dataset
106 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
124 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
107 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
125 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
108
126
109 /// @sa IDataSeries::valuesUnit()
127 /// @sa IDataSeries::valuesUnit()
110 Unit valuesUnit() const override { return m_ValuesUnit; }
128 Unit valuesUnit() const override { return m_ValuesUnit; }
111
129
112
130
113 SqpRange range() const override
131 SqpRange range() const override
114 {
132 {
115 if (!m_XAxisData->cdata().isEmpty()) {
133 if (!m_XAxisData->cdata().isEmpty()) {
116 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
134 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
117 }
135 }
118
136
119 return SqpRange{};
137 return SqpRange{};
120 }
138 }
121
139
122 void clear()
140 void clear()
123 {
141 {
124 m_XAxisData->clear();
142 m_XAxisData->clear();
125 m_ValuesData->clear();
143 m_ValuesData->clear();
126 }
144 }
127
145
128 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
146 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
129
147
130 /// Merges into the data series an other data series
148 /// Merges into the data series an other data series
131 /// @remarks the data series to merge with is cleared after the operation
149 /// @remarks the data series to merge with is cleared after the operation
132 void merge(IDataSeries *dataSeries) override
150 void merge(IDataSeries *dataSeries) override
133 {
151 {
134 dataSeries->lockWrite();
152 dataSeries->lockWrite();
135 lockWrite();
153 lockWrite();
136
154
137 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
155 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
138 DataSeriesMergeHelper::merge(*other, *this);
156 DataSeriesMergeHelper::merge(*other, *this);
139 }
157 }
140 else {
158 else {
141 qCWarning(LOG_DataSeries())
159 qCWarning(LOG_DataSeries())
142 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
160 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
143 }
161 }
144 unlock();
162 unlock();
145 dataSeries->unlock();
163 dataSeries->unlock();
146 }
164 }
147
165
166 void purge(double min, double max) override
167 {
168 if (min > max) {
169 std::swap(min, max);
170 }
171
172 lockWrite();
173
174 auto it = std::remove_if(
175 begin(), end(), [min, max](const auto &it) { return it.x() < min || it.x() > max; });
176 erase(it, end());
177
178 unlock();
179 }
180
148 // ///////// //
181 // ///////// //
149 // Iterators //
182 // Iterators //
150 // ///////// //
183 // ///////// //
151
184
185 DataSeriesIterator begin() override
186 {
187 return DataSeriesIterator{DataSeriesIteratorValue{
188 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
189 }
190
191 DataSeriesIterator end() override
192 {
193 return DataSeriesIterator{DataSeriesIteratorValue{
194 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
195 }
196
152 DataSeriesIterator cbegin() const override
197 DataSeriesIterator cbegin() const override
153 {
198 {
154 return DataSeriesIterator{DataSeriesIteratorValue{
199 return DataSeriesIterator{DataSeriesIteratorValue{
155 std::make_unique<dataseries_detail::IteratorValue<Dim> >(*this, true)}};
200 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
156 }
201 }
157
202
158 DataSeriesIterator cend() const override
203 DataSeriesIterator cend() const override
159 {
204 {
160 return DataSeriesIterator{DataSeriesIteratorValue{
205 return DataSeriesIterator{DataSeriesIteratorValue{
161 std::make_unique<dataseries_detail::IteratorValue<Dim> >(*this, false)}};
206 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
207 }
208
209 void erase(DataSeriesIterator first, DataSeriesIterator last)
210 {
211 auto firstImpl
212 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
213 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
214
215 if (firstImpl && lastImpl) {
216 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
217 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
218 }
162 }
219 }
163
220
164 /// @sa IDataSeries::minXAxisData()
221 /// @sa IDataSeries::minXAxisData()
165 DataSeriesIterator minXAxisData(double minXAxisData) const override
222 DataSeriesIterator minXAxisData(double minXAxisData) const override
166 {
223 {
167 return std::lower_bound(
224 return std::lower_bound(
168 cbegin(), cend(), minXAxisData,
225 cbegin(), cend(), minXAxisData,
169 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
226 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
170 }
227 }
171
228
172 /// @sa IDataSeries::maxXAxisData()
229 /// @sa IDataSeries::maxXAxisData()
173 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
230 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
174 {
231 {
175 // Gets the first element that greater than max value
232 // Gets the first element that greater than max value
176 auto it = std::upper_bound(
233 auto it = std::upper_bound(
177 cbegin(), cend(), maxXAxisData,
234 cbegin(), cend(), maxXAxisData,
178 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
235 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
179
236
180 return it == cbegin() ? cend() : --it;
237 return it == cbegin() ? cend() : --it;
181 }
238 }
182
239
183 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
240 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
184 double maxXAxisData) const override
241 double maxXAxisData) const override
185 {
242 {
186 if (minXAxisData > maxXAxisData) {
243 if (minXAxisData > maxXAxisData) {
187 std::swap(minXAxisData, maxXAxisData);
244 std::swap(minXAxisData, maxXAxisData);
188 }
245 }
189
246
190 auto begin = cbegin();
247 auto begin = cbegin();
191 auto end = cend();
248 auto end = cend();
192
249
193 auto lowerIt = std::lower_bound(
250 auto lowerIt = std::lower_bound(
194 begin, end, minXAxisData,
251 begin, end, minXAxisData,
195 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
252 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
196 auto upperIt = std::upper_bound(
253 auto upperIt = std::upper_bound(
197 begin, end, maxXAxisData,
254 begin, end, maxXAxisData,
198 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
255 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
199
256
200 return std::make_pair(lowerIt, upperIt);
257 return std::make_pair(lowerIt, upperIt);
201 }
258 }
202
259
203 std::pair<DataSeriesIterator, DataSeriesIterator>
260 std::pair<DataSeriesIterator, DataSeriesIterator>
204 valuesBounds(double minXAxisData, double maxXAxisData) const override
261 valuesBounds(double minXAxisData, double maxXAxisData) const override
205 {
262 {
206 // Places iterators to the correct x-axis range
263 // Places iterators to the correct x-axis range
207 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
264 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
208
265
209 // Returns end iterators if the range is empty
266 // Returns end iterators if the range is empty
210 if (xAxisRangeIts.first == xAxisRangeIts.second) {
267 if (xAxisRangeIts.first == xAxisRangeIts.second) {
211 return std::make_pair(cend(), cend());
268 return std::make_pair(cend(), cend());
212 }
269 }
213
270
214 // Gets the iterator on the min of all values data
271 // Gets the iterator on the min of all values data
215 auto minIt = std::min_element(
272 auto minIt = std::min_element(
216 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
273 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
217 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
274 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
218 });
275 });
219
276
220 // Gets the iterator on the max of all values data
277 // Gets the iterator on the max of all values data
221 auto maxIt = std::max_element(
278 auto maxIt = std::max_element(
222 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
279 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
223 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
280 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
224 });
281 });
225
282
226 return std::make_pair(minIt, maxIt);
283 return std::make_pair(minIt, maxIt);
227 }
284 }
228
285
229 // /////// //
286 // /////// //
230 // Mutexes //
287 // Mutexes //
231 // /////// //
288 // /////// //
232
289
233 virtual void lockRead() { m_Lock.lockForRead(); }
290 virtual void lockRead() { m_Lock.lockForRead(); }
234 virtual void lockWrite() { m_Lock.lockForWrite(); }
291 virtual void lockWrite() { m_Lock.lockForWrite(); }
235 virtual void unlock() { m_Lock.unlock(); }
292 virtual void unlock() { m_Lock.unlock(); }
236
293
237 // ///// //
294 // ///// //
238 // Other //
295 // Other //
239 // ///// //
296 // ///// //
240
297
241 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
298 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
242 /// method is intended to be used in the context of generating a back insert iterator
299 /// method is intended to be used in the context of generating a back insert iterator
243 /// @param iteratorValue the iterator value containing the values to insert
300 /// @param iteratorValue the iterator value containing the values to insert
244 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
301 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
245 /// @sa merge()
302 /// @sa merge()
246 /// @sa value_type
303 /// @sa value_type
247 void push_back(const value_type &iteratorValue)
304 void push_back(const value_type &iteratorValue)
248 {
305 {
249 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
306 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
250 m_ValuesData->push_back(iteratorValue.values());
307 m_ValuesData->push_back(iteratorValue.values());
251 }
308 }
252
309
253 protected:
310 protected:
254 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
311 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
255 /// DataSeries with no values will be created.
312 /// DataSeries with no values will be created.
256 /// @remarks data series is automatically sorted on its x-axis data
313 /// @remarks data series is automatically sorted on its x-axis data
257 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
314 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
258 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
315 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
259 : m_XAxisData{xAxisData},
316 : m_XAxisData{xAxisData},
260 m_XAxisUnit{xAxisUnit},
317 m_XAxisUnit{xAxisUnit},
261 m_ValuesData{valuesData},
318 m_ValuesData{valuesData},
262 m_ValuesUnit{valuesUnit}
319 m_ValuesUnit{valuesUnit}
263 {
320 {
264 if (m_XAxisData->size() != m_ValuesData->size()) {
321 if (m_XAxisData->size() != m_ValuesData->size()) {
265 clear();
322 clear();
266 }
323 }
267
324
268 // Sorts data if it's not the case
325 // Sorts data if it's not the case
269 const auto &xAxisCData = m_XAxisData->cdata();
326 const auto &xAxisCData = m_XAxisData->cdata();
270 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
327 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
271 sort();
328 sort();
272 }
329 }
273 }
330 }
274
331
275 /// Copy ctor
332 /// Copy ctor
276 explicit DataSeries(const DataSeries<Dim> &other)
333 explicit DataSeries(const DataSeries<Dim> &other)
277 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
334 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
278 m_XAxisUnit{other.m_XAxisUnit},
335 m_XAxisUnit{other.m_XAxisUnit},
279 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
336 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
280 m_ValuesUnit{other.m_ValuesUnit}
337 m_ValuesUnit{other.m_ValuesUnit}
281 {
338 {
282 // Since a series is ordered from its construction and is always ordered, it is not
339 // Since a series is ordered from its construction and is always ordered, it is not
283 // necessary to call the sort method here ('other' is sorted)
340 // necessary to call the sort method here ('other' is sorted)
284 }
341 }
285
342
286 /// Assignment operator
343 /// Assignment operator
287 template <int D>
344 template <int D>
288 DataSeries &operator=(DataSeries<D> other)
345 DataSeries &operator=(DataSeries<D> other)
289 {
346 {
290 std::swap(m_XAxisData, other.m_XAxisData);
347 std::swap(m_XAxisData, other.m_XAxisData);
291 std::swap(m_XAxisUnit, other.m_XAxisUnit);
348 std::swap(m_XAxisUnit, other.m_XAxisUnit);
292 std::swap(m_ValuesData, other.m_ValuesData);
349 std::swap(m_ValuesData, other.m_ValuesData);
293 std::swap(m_ValuesUnit, other.m_ValuesUnit);
350 std::swap(m_ValuesUnit, other.m_ValuesUnit);
294
351
295 return *this;
352 return *this;
296 }
353 }
297
354
298 private:
355 private:
299 /**
356 /**
300 * Sorts data series on its x-axis data
357 * Sorts data series on its x-axis data
301 */
358 */
302 void sort() noexcept
359 void sort() noexcept
303 {
360 {
304 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
361 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
305 m_XAxisData = m_XAxisData->sort(permutation);
362 m_XAxisData = m_XAxisData->sort(permutation);
306 m_ValuesData = m_ValuesData->sort(permutation);
363 m_ValuesData = m_ValuesData->sort(permutation);
307 }
364 }
308
365
309 std::shared_ptr<ArrayData<1> > m_XAxisData;
366 std::shared_ptr<ArrayData<1> > m_XAxisData;
310 Unit m_XAxisUnit;
367 Unit m_XAxisUnit;
311 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
368 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
312 Unit m_ValuesUnit;
369 Unit m_ValuesUnit;
313
370
314 QReadWriteLock m_Lock;
371 QReadWriteLock m_Lock;
315 };
372 };
316
373
317 #endif // SCIQLOP_DATASERIES_H
374 #endif // SCIQLOP_DATASERIES_H
@@ -1,64 +1,72
1 #ifndef SCIQLOP_DATASERIESITERATOR_H
1 #ifndef SCIQLOP_DATASERIESITERATOR_H
2 #define SCIQLOP_DATASERIESITERATOR_H
2 #define SCIQLOP_DATASERIESITERATOR_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5 #include "Data/SqpIterator.h"
5 #include "Data/SqpIterator.h"
6
6
7 #include <QVector>
7 #include <QVector>
8 #include <memory>
8 #include <memory>
9
9
10 /**
10 /**
11 * @brief The DataSeriesIteratorValue class represents the current value of a data series iterator.
11 * @brief The DataSeriesIteratorValue class represents the current value of a data series iterator.
12 * It offers standard access methods for the data in the series (x-axis, values), but it is up to
12 * It offers standard access methods for the data in the series (x-axis, values), but it is up to
13 * each series to define its own implementation of how to retrieve this data, by implementing the
13 * each series to define its own implementation of how to retrieve this data, by implementing the
14 * DataSeriesIteratorValue::Impl interface
14 * DataSeriesIteratorValue::Impl interface
15 *
15 *
16 * @sa DataSeriesIterator
16 * @sa DataSeriesIterator
17 */
17 */
18 class SCIQLOP_CORE_EXPORT DataSeriesIteratorValue {
18 class SCIQLOP_CORE_EXPORT DataSeriesIteratorValue {
19 public:
19 public:
20 struct Impl {
20 struct Impl {
21 virtual ~Impl() noexcept = default;
21 virtual ~Impl() noexcept = default;
22 virtual std::unique_ptr<Impl> clone() const = 0;
22 virtual std::unique_ptr<Impl> clone() const = 0;
23 virtual bool equals(const Impl &other) const = 0;
23 virtual bool equals(const Impl &other) const = 0;
24 virtual void next() = 0;
24 virtual void next() = 0;
25 virtual void prev() = 0;
25 virtual void prev() = 0;
26 virtual double x() const = 0;
26 virtual double x() const = 0;
27 virtual double value() const = 0;
27 virtual double value() const = 0;
28 virtual double value(int componentIndex) const = 0;
28 virtual double value(int componentIndex) const = 0;
29 virtual double minValue() const = 0;
29 virtual double minValue() const = 0;
30 virtual double maxValue() const = 0;
30 virtual double maxValue() const = 0;
31 virtual QVector<double> values() const = 0;
31 virtual QVector<double> values() const = 0;
32
33 virtual void swap(Impl &other) = 0;
32 };
34 };
33
35
34 explicit DataSeriesIteratorValue(std::unique_ptr<Impl> impl);
36 explicit DataSeriesIteratorValue(std::unique_ptr<Impl> impl);
35 DataSeriesIteratorValue(const DataSeriesIteratorValue &other);
37 DataSeriesIteratorValue(const DataSeriesIteratorValue &other);
36 DataSeriesIteratorValue(DataSeriesIteratorValue &&other) = default;
37 DataSeriesIteratorValue &operator=(DataSeriesIteratorValue other);
38 DataSeriesIteratorValue &operator=(DataSeriesIteratorValue other);
38
39
39 bool equals(const DataSeriesIteratorValue &other) const;
40 bool equals(const DataSeriesIteratorValue &other) const;
40
41
41 /// Advances to the next value
42 /// Advances to the next value
42 void next();
43 void next();
43 /// Moves back to the previous value
44 /// Moves back to the previous value
44 void prev();
45 void prev();
45 /// Gets x-axis data
46 /// Gets x-axis data
46 double x() const;
47 double x() const;
47 /// Gets value data
48 /// Gets value data
48 double value() const;
49 double value() const;
49 /// Gets value data depending on an index
50 /// Gets value data depending on an index
50 double value(int componentIndex) const;
51 double value(int componentIndex) const;
51 /// Gets min of all values data
52 /// Gets min of all values data
52 double minValue() const;
53 double minValue() const;
53 /// Gets max of all values data
54 /// Gets max of all values data
54 double maxValue() const;
55 double maxValue() const;
55 /// Gets all values data
56 /// Gets all values data
56 QVector<double> values() const;
57 QVector<double> values() const;
57
58
59 Impl *impl();
60
61 friend void swap(DataSeriesIteratorValue &lhs, DataSeriesIteratorValue &rhs)
62 {
63 std::swap(lhs.m_Impl, rhs.m_Impl);
64 }
65
58 private:
66 private:
59 std::unique_ptr<Impl> m_Impl;
67 std::unique_ptr<Impl> m_Impl;
60 };
68 };
61
69
62 using DataSeriesIterator = SqpIterator<DataSeriesIteratorValue>;
70 using DataSeriesIterator = SqpIterator<DataSeriesIteratorValue>;
63
71
64 #endif // SCIQLOP_DATASERIESITERATOR_H
72 #endif // SCIQLOP_DATASERIESITERATOR_H
@@ -1,104 +1,109
1 #ifndef SCIQLOP_IDATASERIES_H
1 #ifndef SCIQLOP_IDATASERIES_H
2 #define SCIQLOP_IDATASERIES_H
2 #define SCIQLOP_IDATASERIES_H
3
3
4 #include <Common/MetaTypes.h>
4 #include <Common/MetaTypes.h>
5 #include <Data/DataSeriesIterator.h>
5 #include <Data/DataSeriesIterator.h>
6 #include <Data/SqpRange.h>
6 #include <Data/SqpRange.h>
7
7
8 #include <memory>
8 #include <memory>
9
9
10 #include <QString>
10 #include <QString>
11
11
12 template <int Dim>
12 template <int Dim>
13 class ArrayData;
13 class ArrayData;
14
14
15 struct Unit {
15 struct Unit {
16 explicit Unit(const QString &name = {}, bool timeUnit = false)
16 explicit Unit(const QString &name = {}, bool timeUnit = false)
17 : m_Name{name}, m_TimeUnit{timeUnit}
17 : m_Name{name}, m_TimeUnit{timeUnit}
18 {
18 {
19 }
19 }
20
20
21 inline bool operator==(const Unit &other) const
21 inline bool operator==(const Unit &other) const
22 {
22 {
23 return std::tie(m_Name, m_TimeUnit) == std::tie(other.m_Name, other.m_TimeUnit);
23 return std::tie(m_Name, m_TimeUnit) == std::tie(other.m_Name, other.m_TimeUnit);
24 }
24 }
25 inline bool operator!=(const Unit &other) const { return !(*this == other); }
25 inline bool operator!=(const Unit &other) const { return !(*this == other); }
26
26
27 QString m_Name; ///< Unit name
27 QString m_Name; ///< Unit name
28 bool m_TimeUnit; ///< The unit is a unit of time (UTC)
28 bool m_TimeUnit; ///< The unit is a unit of time (UTC)
29 };
29 };
30
30
31 /**
31 /**
32 * @brief The IDataSeries aims to declare a data series.
32 * @brief The IDataSeries aims to declare a data series.
33 *
33 *
34 * A data series is an entity that contains at least :
34 * A data series is an entity that contains at least :
35 * - one dataset representing the x-axis
35 * - one dataset representing the x-axis
36 * - one dataset representing the values
36 * - one dataset representing the values
37 *
37 *
38 * Each dataset is represented by an ArrayData, and is associated with a unit.
38 * Each dataset is represented by an ArrayData, and is associated with a unit.
39 *
39 *
40 * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the
40 * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the
41 * IDataSeries. The x-axis dataset is always unidimensional.
41 * IDataSeries. The x-axis dataset is always unidimensional.
42 *
42 *
43 * @sa ArrayData
43 * @sa ArrayData
44 */
44 */
45 class IDataSeries {
45 class IDataSeries {
46 public:
46 public:
47 virtual ~IDataSeries() noexcept = default;
47 virtual ~IDataSeries() noexcept = default;
48
48
49 /// Returns the x-axis dataset
49 /// Returns the x-axis dataset
50 virtual std::shared_ptr<ArrayData<1> > xAxisData() = 0;
50 virtual std::shared_ptr<ArrayData<1> > xAxisData() = 0;
51
51
52 /// Returns the x-axis dataset (as const)
52 /// Returns the x-axis dataset (as const)
53 virtual const std::shared_ptr<ArrayData<1> > xAxisData() const = 0;
53 virtual const std::shared_ptr<ArrayData<1> > xAxisData() const = 0;
54
54
55 virtual Unit xAxisUnit() const = 0;
55 virtual Unit xAxisUnit() const = 0;
56
56
57 virtual Unit valuesUnit() const = 0;
57 virtual Unit valuesUnit() const = 0;
58
58
59 virtual void merge(IDataSeries *dataSeries) = 0;
59 virtual void merge(IDataSeries *dataSeries) = 0;
60 /// Removes from data series all entries whose value on the x-axis is not between min and max
61 virtual void purge(double min, double max) = 0;
62
60 /// @todo Review the name and signature of this method
63 /// @todo Review the name and signature of this method
61 virtual std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) = 0;
64 virtual std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) = 0;
62
65
63 virtual std::unique_ptr<IDataSeries> clone() const = 0;
66 virtual std::unique_ptr<IDataSeries> clone() const = 0;
64 virtual SqpRange range() const = 0;
67 virtual SqpRange range() const = 0;
65
68
66 // ///////// //
69 // ///////// //
67 // Iterators //
70 // Iterators //
68 // ///////// //
71 // ///////// //
69
72
70 virtual DataSeriesIterator cbegin() const = 0;
73 virtual DataSeriesIterator cbegin() const = 0;
71 virtual DataSeriesIterator cend() const = 0;
74 virtual DataSeriesIterator cend() const = 0;
75 virtual DataSeriesIterator begin() = 0;
76 virtual DataSeriesIterator end() = 0;
72
77
73 /// @return the iterator to the first entry of the data series whose x-axis data is greater than
78 /// @return the iterator to the first entry of the data series whose x-axis data is greater than
74 /// or equal to the value passed in parameter, or the end iterator if there is no matching value
79 /// or equal to the value passed in parameter, or the end iterator if there is no matching value
75 virtual DataSeriesIterator minXAxisData(double minXAxisData) const = 0;
80 virtual DataSeriesIterator minXAxisData(double minXAxisData) const = 0;
76
81
77 /// @return the iterator to the last entry of the data series whose x-axis data is less than or
82 /// @return the iterator to the last entry of the data series whose x-axis data is less than or
78 /// equal to the value passed in parameter, or the end iterator if there is no matching value
83 /// equal to the value passed in parameter, or the end iterator if there is no matching value
79 virtual DataSeriesIterator maxXAxisData(double maxXAxisData) const = 0;
84 virtual DataSeriesIterator maxXAxisData(double maxXAxisData) const = 0;
80
85
81 /// @return the iterators pointing to the range of data whose x-axis values are between min and
86 /// @return the iterators pointing to the range of data whose x-axis values are between min and
82 /// max passed in parameters
87 /// max passed in parameters
83 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
88 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
84 xAxisRange(double minXAxisData, double maxXAxisData) const = 0;
89 xAxisRange(double minXAxisData, double maxXAxisData) const = 0;
85
90
86 /// @return two iterators pointing to the data that have respectively the min and the max value
91 /// @return two iterators pointing to the data that have respectively the min and the max value
87 /// data of a data series' range. The search is performed for a given x-axis range.
92 /// data of a data series' range. The search is performed for a given x-axis range.
88 /// @sa xAxisRange()
93 /// @sa xAxisRange()
89 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
94 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
90 valuesBounds(double minXAxisData, double maxXAxisData) const = 0;
95 valuesBounds(double minXAxisData, double maxXAxisData) const = 0;
91
96
92 // /////// //
97 // /////// //
93 // Mutexes //
98 // Mutexes //
94 // /////// //
99 // /////// //
95
100
96 virtual void lockRead() = 0;
101 virtual void lockRead() = 0;
97 virtual void lockWrite() = 0;
102 virtual void lockWrite() = 0;
98 virtual void unlock() = 0;
103 virtual void unlock() = 0;
99 };
104 };
100
105
101 // Required for using shared_ptr in signals/slots
106 // Required for using shared_ptr in signals/slots
102 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
107 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
103
108
104 #endif // SCIQLOP_IDATASERIES_H
109 #endif // SCIQLOP_IDATASERIES_H
@@ -1,54 +1,54
1 #ifndef SCIQLOP_SQPITERATOR_H
1 #ifndef SCIQLOP_SQPITERATOR_H
2 #define SCIQLOP_SQPITERATOR_H
2 #define SCIQLOP_SQPITERATOR_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 /**
6 /**
7 * @brief The SqpIterator class represents an iterator used in SciQlop. It defines all operators
7 * @brief The SqpIterator class represents an iterator used in SciQlop. It defines all operators
8 * needed for a standard forward iterator
8 * needed for a standard forward iterator
9 * @tparam T the type of object handled in iterator
9 * @tparam T the type of object handled in iterator
10 * @sa http://www.cplusplus.com/reference/iterator/
10 * @sa http://www.cplusplus.com/reference/iterator/
11 */
11 */
12 template <typename T>
12 template <typename T>
13 class SCIQLOP_CORE_EXPORT SqpIterator {
13 class SCIQLOP_CORE_EXPORT SqpIterator {
14 public:
14 public:
15 using iterator_category = std::forward_iterator_tag;
15 using iterator_category = std::forward_iterator_tag;
16 using value_type = const T;
16 using value_type = const T;
17 using difference_type = std::ptrdiff_t;
17 using difference_type = std::ptrdiff_t;
18 using pointer = value_type *;
18 using pointer = value_type *;
19 using reference = value_type &;
19 using reference = value_type &;
20
20
21 explicit SqpIterator(T value) : m_CurrentValue{std::move(value)} {}
21 explicit SqpIterator(T value) : m_CurrentValue{std::move(value)} {}
22
22
23 virtual ~SqpIterator() noexcept = default;
23 virtual ~SqpIterator() noexcept = default;
24 SqpIterator(const SqpIterator &) = default;
24 SqpIterator(const SqpIterator &) = default;
25 SqpIterator(SqpIterator &&) = default;
25 SqpIterator &operator=(SqpIterator other) { swap(m_CurrentValue, other.m_CurrentValue); }
26 SqpIterator &operator=(const SqpIterator &) = default;
27 SqpIterator &operator=(SqpIterator &&) = default;
28
26
29 SqpIterator &operator++()
27 SqpIterator &operator++()
30 {
28 {
31 m_CurrentValue.next();
29 m_CurrentValue.next();
32 return *this;
30 return *this;
33 }
31 }
34
32
35 SqpIterator &operator--()
33 SqpIterator &operator--()
36 {
34 {
37 m_CurrentValue.prev();
35 m_CurrentValue.prev();
38 return *this;
36 return *this;
39 }
37 }
40
38
41 pointer operator->() const { return &m_CurrentValue; }
39 const T *operator->() const { return &m_CurrentValue; }
42 reference operator*() const { return m_CurrentValue; }
40 const T &operator*() const { return m_CurrentValue; }
41 T *operator->() { return &m_CurrentValue; }
42 T &operator*() { return m_CurrentValue; }
43
43
44 bool operator==(const SqpIterator &other) const
44 bool operator==(const SqpIterator &other) const
45 {
45 {
46 return m_CurrentValue.equals(other.m_CurrentValue);
46 return m_CurrentValue.equals(other.m_CurrentValue);
47 }
47 }
48 bool operator!=(const SqpIterator &other) const { return !(*this == other); }
48 bool operator!=(const SqpIterator &other) const { return !(*this == other); }
49
49
50 private:
50 private:
51 T m_CurrentValue;
51 T m_CurrentValue;
52 };
52 };
53
53
54 #endif // SCIQLOP_SQPITERATOR_H
54 #endif // SCIQLOP_SQPITERATOR_H
@@ -1,75 +1,74
1 #ifndef SCIQLOP_VARIABLE_H
1 #ifndef SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/DataSeriesIterator.h>
6 #include <Data/DataSeriesIterator.h>
7 #include <Data/SqpRange.h>
7 #include <Data/SqpRange.h>
8
8
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10 #include <QObject>
10 #include <QObject>
11
11
12 #include <Common/MetaTypes.h>
12 #include <Common/MetaTypes.h>
13 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
14
14
15 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
16
16
17 class IDataSeries;
17 class IDataSeries;
18 class QString;
18 class QString;
19
19
20 /**
20 /**
21 * @brief The Variable class represents a variable in SciQlop.
21 * @brief The Variable class represents a variable in SciQlop.
22 */
22 */
23 class SCIQLOP_CORE_EXPORT Variable : public QObject {
23 class SCIQLOP_CORE_EXPORT Variable : public QObject {
24
24
25 Q_OBJECT
25 Q_OBJECT
26
26
27 public:
27 public:
28 explicit Variable(const QString &name, const SqpRange &dateTime,
28 explicit Variable(const QString &name, const SqpRange &dateTime,
29 const QVariantHash &metadata = {});
29 const QVariantHash &metadata = {});
30
30
31 QString name() const noexcept;
31 QString name() const noexcept;
32 SqpRange range() const noexcept;
32 SqpRange range() const noexcept;
33 void setRange(const SqpRange &range) noexcept;
33 void setRange(const SqpRange &range) noexcept;
34 SqpRange cacheRange() const noexcept;
34 SqpRange cacheRange() const noexcept;
35 void setCacheRange(const SqpRange &cacheRange) noexcept;
35 void setCacheRange(const SqpRange &cacheRange) noexcept;
36
36
37 /// Returns the real range of the variable, i.e. the min and max x-axis values of the data
37 /// Returns the real range of the variable, i.e. the min and max x-axis values of the data
38 /// series between the range of the variable. The real range is updated each time the variable
38 /// series between the range of the variable. The real range is updated each time the variable
39 /// range or the data series changed
39 /// range or the data series changed
40 /// @return the real range, invalid range if the data series is null or empty
40 /// @return the real range, invalid range if the data series is null or empty
41 /// @sa setDataSeries()
41 /// @sa setDataSeries()
42 /// @sa setRange()
42 /// @sa setRange()
43 SqpRange realRange() const noexcept;
43 SqpRange realRange() const noexcept;
44
44
45 /// @return the data of the variable, nullptr if there is no data
45 /// @return the data of the variable, nullptr if there is no data
46 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
46 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
47
47
48 QVariantHash metadata() const noexcept;
48 QVariantHash metadata() const noexcept;
49
49
50 bool contains(const SqpRange &range) const noexcept;
50 bool contains(const SqpRange &range) const noexcept;
51 bool intersect(const SqpRange &range) const noexcept;
51 bool intersect(const SqpRange &range) const noexcept;
52 bool isInside(const SqpRange &range) const noexcept;
52 bool isInside(const SqpRange &range) const noexcept;
53
53
54 bool cacheContains(const SqpRange &range) const noexcept;
54 bool cacheContains(const SqpRange &range) const noexcept;
55 bool cacheIntersect(const SqpRange &range) const noexcept;
55 bool cacheIntersect(const SqpRange &range) const noexcept;
56 bool cacheIsInside(const SqpRange &range) const noexcept;
56 bool cacheIsInside(const SqpRange &range) const noexcept;
57
57
58 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
58 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
59 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
59 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
60 void setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
61 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
60 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
62
61
63 signals:
62 signals:
64 void updated();
63 void updated();
65
64
66 private:
65 private:
67 class VariablePrivate;
66 class VariablePrivate;
68 spimpl::unique_impl_ptr<VariablePrivate> impl;
67 spimpl::unique_impl_ptr<VariablePrivate> impl;
69 };
68 };
70
69
71 // Required for using shared_ptr in signals/slots
70 // Required for using shared_ptr in signals/slots
72 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
71 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
73 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
72 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
74
73
75 #endif // SCIQLOP_VARIABLE_H
74 #endif // SCIQLOP_VARIABLE_H
@@ -1,57 +1,62
1 #include "Data/ArrayDataIterator.h"
1 #include "Data/ArrayDataIterator.h"
2
2
3 ArrayDataIteratorValue::ArrayDataIteratorValue(std::unique_ptr<ArrayDataIteratorValue::Impl> impl)
3 ArrayDataIteratorValue::ArrayDataIteratorValue(std::unique_ptr<ArrayDataIteratorValue::Impl> impl)
4 : m_Impl{std::move(impl)}
4 : m_Impl{std::move(impl)}
5 {
5 {
6 }
6 }
7
7
8 ArrayDataIteratorValue::ArrayDataIteratorValue(const ArrayDataIteratorValue &other)
8 ArrayDataIteratorValue::ArrayDataIteratorValue(const ArrayDataIteratorValue &other)
9 : m_Impl{other.m_Impl->clone()}
9 : m_Impl{other.m_Impl->clone()}
10 {
10 {
11 }
11 }
12
12
13 ArrayDataIteratorValue &ArrayDataIteratorValue::operator=(ArrayDataIteratorValue other)
13 ArrayDataIteratorValue &ArrayDataIteratorValue::operator=(ArrayDataIteratorValue other)
14 {
14 {
15 std::swap(m_Impl, other.m_Impl);
15 m_Impl->swap(*other.m_Impl);
16 return *this;
16 return *this;
17 }
17 }
18
18
19 bool ArrayDataIteratorValue::equals(const ArrayDataIteratorValue &other) const
19 bool ArrayDataIteratorValue::equals(const ArrayDataIteratorValue &other) const
20 {
20 {
21 return m_Impl->equals(*other.m_Impl);
21 return m_Impl->equals(*other.m_Impl);
22 }
22 }
23
23
24 void ArrayDataIteratorValue::next()
24 void ArrayDataIteratorValue::next()
25 {
25 {
26 m_Impl->next();
26 m_Impl->next();
27 }
27 }
28
28
29 void ArrayDataIteratorValue::prev()
29 void ArrayDataIteratorValue::prev()
30 {
30 {
31 m_Impl->prev();
31 m_Impl->prev();
32 }
32 }
33
33
34 double ArrayDataIteratorValue::at(int componentIndex) const
34 double ArrayDataIteratorValue::at(int componentIndex) const
35 {
35 {
36 return m_Impl->at(componentIndex);
36 return m_Impl->at(componentIndex);
37 }
37 }
38
38
39 double ArrayDataIteratorValue::first() const
39 double ArrayDataIteratorValue::first() const
40 {
40 {
41 return m_Impl->first();
41 return m_Impl->first();
42 }
42 }
43
43
44 double ArrayDataIteratorValue::min() const
44 double ArrayDataIteratorValue::min() const
45 {
45 {
46 return m_Impl->min();
46 return m_Impl->min();
47 }
47 }
48
48
49 double ArrayDataIteratorValue::max() const
49 double ArrayDataIteratorValue::max() const
50 {
50 {
51 return m_Impl->max();
51 return m_Impl->max();
52 }
52 }
53
53
54 QVector<double> ArrayDataIteratorValue::values() const
54 QVector<double> ArrayDataIteratorValue::values() const
55 {
55 {
56 return m_Impl->values();
56 return m_Impl->values();
57 }
57 }
58
59 ArrayDataIteratorValue::Impl *ArrayDataIteratorValue::impl()
60 {
61 return m_Impl.get();
62 }
@@ -1,63 +1,68
1 #include "Data/DataSeriesIterator.h"
1 #include "Data/DataSeriesIterator.h"
2
2
3 DataSeriesIteratorValue::DataSeriesIteratorValue(
3 DataSeriesIteratorValue::DataSeriesIteratorValue(
4 std::unique_ptr<DataSeriesIteratorValue::Impl> impl)
4 std::unique_ptr<DataSeriesIteratorValue::Impl> impl)
5 : m_Impl{std::move(impl)}
5 : m_Impl{std::move(impl)}
6 {
6 {
7 }
7 }
8
8
9 DataSeriesIteratorValue::DataSeriesIteratorValue(const DataSeriesIteratorValue &other)
9 DataSeriesIteratorValue::DataSeriesIteratorValue(const DataSeriesIteratorValue &other)
10 : m_Impl{other.m_Impl->clone()}
10 : m_Impl{other.m_Impl->clone()}
11 {
11 {
12 }
12 }
13
13
14 DataSeriesIteratorValue &DataSeriesIteratorValue::operator=(DataSeriesIteratorValue other)
14 DataSeriesIteratorValue &DataSeriesIteratorValue::operator=(DataSeriesIteratorValue other)
15 {
15 {
16 std::swap(m_Impl, other.m_Impl);
16 m_Impl->swap(*other.m_Impl);
17 return *this;
17 return *this;
18 }
18 }
19
19
20 bool DataSeriesIteratorValue::equals(const DataSeriesIteratorValue &other) const
20 bool DataSeriesIteratorValue::equals(const DataSeriesIteratorValue &other) const
21 {
21 {
22 return m_Impl->equals(*other.m_Impl);
22 return m_Impl->equals(*other.m_Impl);
23 }
23 }
24
24
25 void DataSeriesIteratorValue::next()
25 void DataSeriesIteratorValue::next()
26 {
26 {
27 m_Impl->next();
27 m_Impl->next();
28 }
28 }
29
29
30 void DataSeriesIteratorValue::prev()
30 void DataSeriesIteratorValue::prev()
31 {
31 {
32 m_Impl->prev();
32 m_Impl->prev();
33 }
33 }
34
34
35 double DataSeriesIteratorValue::x() const
35 double DataSeriesIteratorValue::x() const
36 {
36 {
37 return m_Impl->x();
37 return m_Impl->x();
38 }
38 }
39
39
40 double DataSeriesIteratorValue::value() const
40 double DataSeriesIteratorValue::value() const
41 {
41 {
42 return m_Impl->value();
42 return m_Impl->value();
43 }
43 }
44
44
45 double DataSeriesIteratorValue::value(int componentIndex) const
45 double DataSeriesIteratorValue::value(int componentIndex) const
46 {
46 {
47 return m_Impl->value(componentIndex);
47 return m_Impl->value(componentIndex);
48 }
48 }
49
49
50 double DataSeriesIteratorValue::minValue() const
50 double DataSeriesIteratorValue::minValue() const
51 {
51 {
52 return m_Impl->minValue();
52 return m_Impl->minValue();
53 }
53 }
54
54
55 double DataSeriesIteratorValue::maxValue() const
55 double DataSeriesIteratorValue::maxValue() const
56 {
56 {
57 return m_Impl->maxValue();
57 return m_Impl->maxValue();
58 }
58 }
59
59
60 QVector<double> DataSeriesIteratorValue::values() const
60 QVector<double> DataSeriesIteratorValue::values() const
61 {
61 {
62 return m_Impl->values();
62 return m_Impl->values();
63 }
63 }
64
65 DataSeriesIteratorValue::Impl *DataSeriesIteratorValue::impl()
66 {
67 return m_Impl.get();
68 }
@@ -1,279 +1,270
1 #include "Variable/Variable.h"
1 #include "Variable/Variable.h"
2
2
3 #include <Data/IDataSeries.h>
3 #include <Data/IDataSeries.h>
4 #include <Data/SqpRange.h>
4 #include <Data/SqpRange.h>
5
5
6 #include <QMutex>
6 #include <QMutex>
7 #include <QReadWriteLock>
7 #include <QReadWriteLock>
8 #include <QThread>
8 #include <QThread>
9
9
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11
11
12 struct Variable::VariablePrivate {
12 struct Variable::VariablePrivate {
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
14 const QVariantHash &metadata)
14 const QVariantHash &metadata)
15 : m_Name{name},
15 : m_Name{name},
16 m_Range{dateTime},
16 m_Range{dateTime},
17 m_Metadata{metadata},
17 m_Metadata{metadata},
18 m_DataSeries{nullptr},
18 m_DataSeries{nullptr},
19 m_RealRange{INVALID_RANGE}
19 m_RealRange{INVALID_RANGE}
20 {
20 {
21 }
21 }
22
22
23 void lockRead() { m_Lock.lockForRead(); }
23 void lockRead() { m_Lock.lockForRead(); }
24 void lockWrite() { m_Lock.lockForWrite(); }
24 void lockWrite() { m_Lock.lockForWrite(); }
25 void unlock() { m_Lock.unlock(); }
25 void unlock() { m_Lock.unlock(); }
26
26
27 void purgeDataSeries()
28 {
29 if (m_DataSeries) {
30 m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd);
31 }
32 updateRealRange();
33 }
34
27 /// Updates real range according to current variable range and data series
35 /// Updates real range according to current variable range and data series
28 void updateRealRange()
36 void updateRealRange()
29 {
37 {
30 if (m_DataSeries) {
38 if (m_DataSeries) {
31 m_DataSeries->lockRead();
39 m_DataSeries->lockRead();
32 auto end = m_DataSeries->cend();
40 auto end = m_DataSeries->cend();
33 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
41 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
34 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
42 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
35
43
36 m_RealRange = (minXAxisIt != end && maxXAxisIt != end)
44 m_RealRange = (minXAxisIt != end && maxXAxisIt != end)
37 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
45 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
38 : INVALID_RANGE;
46 : INVALID_RANGE;
39 m_DataSeries->unlock();
47 m_DataSeries->unlock();
40 }
48 }
41 else {
49 else {
42 m_RealRange = INVALID_RANGE;
50 m_RealRange = INVALID_RANGE;
43 }
51 }
44 }
52 }
45
53
46 QString m_Name;
54 QString m_Name;
47
55
48 SqpRange m_Range;
56 SqpRange m_Range;
49 SqpRange m_CacheRange;
57 SqpRange m_CacheRange;
50 QVariantHash m_Metadata;
58 QVariantHash m_Metadata;
51 std::shared_ptr<IDataSeries> m_DataSeries;
59 std::shared_ptr<IDataSeries> m_DataSeries;
52 SqpRange m_RealRange;
60 SqpRange m_RealRange;
53
61
54 QReadWriteLock m_Lock;
62 QReadWriteLock m_Lock;
55 };
63 };
56
64
57 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
65 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
58 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
66 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
59 {
67 {
60 }
68 }
61
69
62 QString Variable::name() const noexcept
70 QString Variable::name() const noexcept
63 {
71 {
64 impl->lockRead();
72 impl->lockRead();
65 auto name = impl->m_Name;
73 auto name = impl->m_Name;
66 impl->unlock();
74 impl->unlock();
67 return name;
75 return name;
68 }
76 }
69
77
70 SqpRange Variable::range() const noexcept
78 SqpRange Variable::range() const noexcept
71 {
79 {
72 impl->lockRead();
80 impl->lockRead();
73 auto range = impl->m_Range;
81 auto range = impl->m_Range;
74 impl->unlock();
82 impl->unlock();
75 return range;
83 return range;
76 }
84 }
77
85
78 void Variable::setRange(const SqpRange &range) noexcept
86 void Variable::setRange(const SqpRange &range) noexcept
79 {
87 {
80 impl->lockWrite();
88 impl->lockWrite();
81 impl->m_Range = range;
89 impl->m_Range = range;
82 impl->updateRealRange();
90 impl->updateRealRange();
83 impl->unlock();
91 impl->unlock();
84 }
92 }
85
93
86 SqpRange Variable::cacheRange() const noexcept
94 SqpRange Variable::cacheRange() const noexcept
87 {
95 {
88 impl->lockRead();
96 impl->lockRead();
89 auto cacheRange = impl->m_CacheRange;
97 auto cacheRange = impl->m_CacheRange;
90 impl->unlock();
98 impl->unlock();
91 return cacheRange;
99 return cacheRange;
92 }
100 }
93
101
94 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
102 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
95 {
103 {
96 impl->lockWrite();
104 impl->lockWrite();
97 impl->m_CacheRange = cacheRange;
105 if (cacheRange != impl->m_CacheRange) {
106 impl->m_CacheRange = cacheRange;
107 impl->purgeDataSeries();
108 }
98 impl->unlock();
109 impl->unlock();
99 }
110 }
100
111
101 SqpRange Variable::realRange() const noexcept
112 SqpRange Variable::realRange() const noexcept
102 {
113 {
103 return impl->m_RealRange;
114 return impl->m_RealRange;
104 }
115 }
105
116
106 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
107 {
108 qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries"
109 << QThread::currentThread()->objectName();
110 if (!dataSeries) {
111 /// @todo ALX : log
112 return;
113 }
114 impl->lockWrite();
115 impl->m_DataSeries = dataSeries->clone();
116 impl->updateRealRange();
117 impl->unlock();
118 }
119
120 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
117 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
121 {
118 {
122 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
119 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
123 << QThread::currentThread()->objectName();
120 << QThread::currentThread()->objectName();
124 if (!dataSeries) {
121 if (!dataSeries) {
125 /// @todo ALX : log
122 /// @todo ALX : log
126 return;
123 return;
127 }
124 }
128
125
129 // Add or merge the data
126 // Add or merge the data
130 // Inits the data series of the variable
131 impl->lockWrite();
127 impl->lockWrite();
132 if (!impl->m_DataSeries) {
128 if (!impl->m_DataSeries) {
133 impl->m_DataSeries = dataSeries->clone();
129 impl->m_DataSeries = dataSeries->clone();
134 }
130 }
135 else {
131 else {
136 impl->m_DataSeries->merge(dataSeries.get());
132 impl->m_DataSeries->merge(dataSeries.get());
137 }
133 }
134 impl->purgeDataSeries();
138 impl->unlock();
135 impl->unlock();
139
140 // sub the data
141 auto subData = this->dataSeries()->subDataSeries(this->cacheRange());
142 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range();
143 this->setDataSeries(subData);
144 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries set" << this->dataSeries()->range();
145 }
136 }
146
137
147 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
138 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
148 {
139 {
149 impl->lockRead();
140 impl->lockRead();
150 auto dataSeries = impl->m_DataSeries;
141 auto dataSeries = impl->m_DataSeries;
151 impl->unlock();
142 impl->unlock();
152
143
153 return dataSeries;
144 return dataSeries;
154 }
145 }
155
146
156 QVariantHash Variable::metadata() const noexcept
147 QVariantHash Variable::metadata() const noexcept
157 {
148 {
158 impl->lockRead();
149 impl->lockRead();
159 auto metadata = impl->m_Metadata;
150 auto metadata = impl->m_Metadata;
160 impl->unlock();
151 impl->unlock();
161 return metadata;
152 return metadata;
162 }
153 }
163
154
164 bool Variable::contains(const SqpRange &range) const noexcept
155 bool Variable::contains(const SqpRange &range) const noexcept
165 {
156 {
166 impl->lockRead();
157 impl->lockRead();
167 auto res = impl->m_Range.contains(range);
158 auto res = impl->m_Range.contains(range);
168 impl->unlock();
159 impl->unlock();
169 return res;
160 return res;
170 }
161 }
171
162
172 bool Variable::intersect(const SqpRange &range) const noexcept
163 bool Variable::intersect(const SqpRange &range) const noexcept
173 {
164 {
174
165
175 impl->lockRead();
166 impl->lockRead();
176 auto res = impl->m_Range.intersect(range);
167 auto res = impl->m_Range.intersect(range);
177 impl->unlock();
168 impl->unlock();
178 return res;
169 return res;
179 }
170 }
180
171
181 bool Variable::isInside(const SqpRange &range) const noexcept
172 bool Variable::isInside(const SqpRange &range) const noexcept
182 {
173 {
183 impl->lockRead();
174 impl->lockRead();
184 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
175 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
185 impl->unlock();
176 impl->unlock();
186 return res;
177 return res;
187 }
178 }
188
179
189 bool Variable::cacheContains(const SqpRange &range) const noexcept
180 bool Variable::cacheContains(const SqpRange &range) const noexcept
190 {
181 {
191 impl->lockRead();
182 impl->lockRead();
192 auto res = impl->m_CacheRange.contains(range);
183 auto res = impl->m_CacheRange.contains(range);
193 impl->unlock();
184 impl->unlock();
194 return res;
185 return res;
195 }
186 }
196
187
197 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
188 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
198 {
189 {
199 impl->lockRead();
190 impl->lockRead();
200 auto res = impl->m_CacheRange.intersect(range);
191 auto res = impl->m_CacheRange.intersect(range);
201 impl->unlock();
192 impl->unlock();
202 return res;
193 return res;
203 }
194 }
204
195
205 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
196 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
206 {
197 {
207 impl->lockRead();
198 impl->lockRead();
208 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
199 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
209 impl->unlock();
200 impl->unlock();
210 return res;
201 return res;
211 }
202 }
212
203
213
204
214 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
205 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
215 {
206 {
216 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
207 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
217
208
218 auto notInCache = QVector<SqpRange>{};
209 auto notInCache = QVector<SqpRange>{};
219
210
220 if (!this->cacheContains(range)) {
211 if (!this->cacheContains(range)) {
221 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
212 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
222 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
213 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
223 notInCache << range;
214 notInCache << range;
224 }
215 }
225 else if (range.m_TStart < impl->m_CacheRange.m_TStart
216 else if (range.m_TStart < impl->m_CacheRange.m_TStart
226 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
217 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
227 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
218 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
228 }
219 }
229 else if (range.m_TStart < impl->m_CacheRange.m_TStart
220 else if (range.m_TStart < impl->m_CacheRange.m_TStart
230 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
221 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
231 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
222 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
232 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
223 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
233 }
224 }
234 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
225 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
235 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
226 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
236 }
227 }
237 else {
228 else {
238 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
229 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
239 << QThread::currentThread();
230 << QThread::currentThread();
240 }
231 }
241 }
232 }
242
233
243 return notInCache;
234 return notInCache;
244 }
235 }
245
236
246 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
237 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
247 {
238 {
248 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
239 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
249
240
250 auto inCache = QVector<SqpRange>{};
241 auto inCache = QVector<SqpRange>{};
251
242
252
243
253 if (this->intersect(range)) {
244 if (this->intersect(range)) {
254 if (range.m_TStart <= impl->m_CacheRange.m_TStart
245 if (range.m_TStart <= impl->m_CacheRange.m_TStart
255 && range.m_TEnd >= impl->m_CacheRange.m_TStart
246 && range.m_TEnd >= impl->m_CacheRange.m_TStart
256 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
247 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
257 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
248 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
258 }
249 }
259
250
260 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
251 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
261 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
252 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
262 inCache << range;
253 inCache << range;
263 }
254 }
264 else if (range.m_TStart > impl->m_CacheRange.m_TStart
255 else if (range.m_TStart > impl->m_CacheRange.m_TStart
265 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
256 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
266 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
257 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
267 }
258 }
268 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
259 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
269 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
260 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
270 inCache << impl->m_CacheRange;
261 inCache << impl->m_CacheRange;
271 }
262 }
272 else {
263 else {
273 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
264 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
274 << QThread::currentThread();
265 << QThread::currentThread();
275 }
266 }
276 }
267 }
277
268
278 return inCache;
269 return inCache;
279 }
270 }
@@ -1,519 +1,638
1 #include "Data/DataSeries.h"
1 #include "Data/DataSeries.h"
2 #include "Data/ScalarSeries.h"
2 #include "Data/ScalarSeries.h"
3 #include "Data/VectorSeries.h"
3 #include "Data/VectorSeries.h"
4
4
5 #include <cmath>
5 #include <cmath>
6
6
7 #include <QObject>
7 #include <QObject>
8 #include <QtTest>
8 #include <QtTest>
9
9
10 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
10 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
11 Q_DECLARE_METATYPE(std::shared_ptr<VectorSeries>)
11 Q_DECLARE_METATYPE(std::shared_ptr<VectorSeries>)
12
12
13 namespace {
13 namespace {
14
14
15 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const QVector<double> &xData,
15 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const QVector<double> &xData,
16 const QVector<double> &valuesData)
16 const QVector<double> &valuesData)
17 {
17 {
18 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
18 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
19 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
19 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
20 QVERIFY(std::equal(
20 QVERIFY(std::equal(
21 first, last, valuesData.cbegin(), valuesData.cend(),
21 first, last, valuesData.cbegin(), valuesData.cend(),
22 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
22 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
23 }
23 }
24
24
25 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const QVector<double> &xData,
26 const QVector<QVector<double> > &valuesData)
27 {
28 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
29 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
30 for (auto i = 0; i < valuesData.size(); ++i) {
31 auto componentData = valuesData.at(i);
32
33 QVERIFY(std::equal(
34 first, last, componentData.cbegin(), componentData.cend(),
35 [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; }));
36 }
37 }
38
25 } // namespace
39 } // namespace
26
40
27 class TestDataSeries : public QObject {
41 class TestDataSeries : public QObject {
28 Q_OBJECT
42 Q_OBJECT
29 private:
43 private:
30 template <typename T>
44 template <typename T>
31 void testValuesBoundsStructure()
45 void testValuesBoundsStructure()
32 {
46 {
33 // ////////////// //
47 // ////////////// //
34 // Test structure //
48 // Test structure //
35 // ////////////// //
49 // ////////////// //
36
50
37 // Data series to get values bounds
51 // Data series to get values bounds
38 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
52 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
39
53
40 // x-axis range
54 // x-axis range
41 QTest::addColumn<double>("minXAxis");
55 QTest::addColumn<double>("minXAxis");
42 QTest::addColumn<double>("maxXAxis");
56 QTest::addColumn<double>("maxXAxis");
43
57
44 // Expected results
58 // Expected results
45 QTest::addColumn<bool>(
59 QTest::addColumn<bool>(
46 "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators)
60 "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators)
47 QTest::addColumn<double>("expectedMinValue");
61 QTest::addColumn<double>("expectedMinValue");
48 QTest::addColumn<double>("expectedMaxValue");
62 QTest::addColumn<double>("expectedMaxValue");
49 }
63 }
50
64
51 template <typename T>
65 template <typename T>
52 void testValuesBounds()
66 void testValuesBounds()
53 {
67 {
54 QFETCH(std::shared_ptr<T>, dataSeries);
68 QFETCH(std::shared_ptr<T>, dataSeries);
55 QFETCH(double, minXAxis);
69 QFETCH(double, minXAxis);
56 QFETCH(double, maxXAxis);
70 QFETCH(double, maxXAxis);
57
71
58 QFETCH(bool, expectedOK);
72 QFETCH(bool, expectedOK);
59 QFETCH(double, expectedMinValue);
73 QFETCH(double, expectedMinValue);
60 QFETCH(double, expectedMaxValue);
74 QFETCH(double, expectedMaxValue);
61
75
62 auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis);
76 auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis);
63 auto end = dataSeries->cend();
77 auto end = dataSeries->cend();
64
78
65 // Checks iterators with expected result
79 // Checks iterators with expected result
66 QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end);
80 QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end);
67
81
68 if (expectedOK) {
82 if (expectedOK) {
69 auto compare = [](const auto &v1, const auto &v2) {
83 auto compare = [](const auto &v1, const auto &v2) {
70 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
84 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
71 };
85 };
72
86
73 QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue()));
87 QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue()));
74 QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue()));
88 QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue()));
75 }
89 }
76 }
90 }
77
91
92 template <typename T>
93 void testPurgeStructure()
94 {
95 // ////////////// //
96 // Test structure //
97 // ////////////// //
98
99 // Data series to purge
100 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
101 QTest::addColumn<double>("min");
102 QTest::addColumn<double>("max");
103
104 // Expected values after purge
105 QTest::addColumn<QVector<double> >("expectedXAxisData");
106 QTest::addColumn<QVector<QVector<double> > >("expectedValuesData");
107 }
108
109 template <typename T>
110 void testPurge()
111 {
112 QFETCH(std::shared_ptr<T>, dataSeries);
113 QFETCH(double, min);
114 QFETCH(double, max);
115
116 dataSeries->purge(min, max);
117
118 // Validates results
119 QFETCH(QVector<double>, expectedXAxisData);
120 QFETCH(QVector<QVector<double> >, expectedValuesData);
121
122 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData,
123 expectedValuesData);
124 }
125
78 private slots:
126 private slots:
127
79 /// Input test data
128 /// Input test data
80 /// @sa testCtor()
129 /// @sa testCtor()
81 void testCtor_data();
130 void testCtor_data();
82
131
83 /// Tests construction of a data series
132 /// Tests construction of a data series
84 void testCtor();
133 void testCtor();
85
134
86 /// Input test data
135 /// Input test data
87 /// @sa testMerge()
136 /// @sa testMerge()
88 void testMerge_data();
137 void testMerge_data();
89
138
90 /// Tests merge of two data series
139 /// Tests merge of two data series
91 void testMerge();
140 void testMerge();
92
141
93 /// Input test data
142 /// Input test data
143 /// @sa testPurgeScalar()
144 void testPurgeScalar_data();
145
146 /// Tests purge of a scalar series
147 void testPurgeScalar();
148
149 /// Input test data
150 /// @sa testPurgeVector()
151 void testPurgeVector_data();
152
153 /// Tests purge of a vector series
154 void testPurgeVector();
155
156 /// Input test data
94 /// @sa testMinXAxisData()
157 /// @sa testMinXAxisData()
95 void testMinXAxisData_data();
158 void testMinXAxisData_data();
96
159
97 /// Tests get min x-axis data of a data series
160 /// Tests get min x-axis data of a data series
98 void testMinXAxisData();
161 void testMinXAxisData();
99
162
100 /// Input test data
163 /// Input test data
101 /// @sa testMaxXAxisData()
164 /// @sa testMaxXAxisData()
102 void testMaxXAxisData_data();
165 void testMaxXAxisData_data();
103
166
104 /// Tests get max x-axis data of a data series
167 /// Tests get max x-axis data of a data series
105 void testMaxXAxisData();
168 void testMaxXAxisData();
106
169
107 /// Input test data
170 /// Input test data
108 /// @sa testXAxisRange()
171 /// @sa testXAxisRange()
109 void testXAxisRange_data();
172 void testXAxisRange_data();
110
173
111 /// Tests get x-axis range of a data series
174 /// Tests get x-axis range of a data series
112 void testXAxisRange();
175 void testXAxisRange();
113
176
114 /// Input test data
177 /// Input test data
115 /// @sa testValuesBoundsScalar()
178 /// @sa testValuesBoundsScalar()
116 void testValuesBoundsScalar_data();
179 void testValuesBoundsScalar_data();
117
180
118 /// Tests get values bounds of a scalar series
181 /// Tests get values bounds of a scalar series
119 void testValuesBoundsScalar();
182 void testValuesBoundsScalar();
120
183
121 /// Input test data
184 /// Input test data
122 /// @sa testValuesBoundsVector()
185 /// @sa testValuesBoundsVector()
123 void testValuesBoundsVector_data();
186 void testValuesBoundsVector_data();
124
187
125 /// Tests get values bounds of a vector series
188 /// Tests get values bounds of a vector series
126 void testValuesBoundsVector();
189 void testValuesBoundsVector();
127 };
190 };
128
191
129 void TestDataSeries::testCtor_data()
192 void TestDataSeries::testCtor_data()
130 {
193 {
131 // ////////////// //
194 // ////////////// //
132 // Test structure //
195 // Test structure //
133 // ////////////// //
196 // ////////////// //
134
197
135 // x-axis data
198 // x-axis data
136 QTest::addColumn<QVector<double> >("xAxisData");
199 QTest::addColumn<QVector<double> >("xAxisData");
137 // values data
200 // values data
138 QTest::addColumn<QVector<double> >("valuesData");
201 QTest::addColumn<QVector<double> >("valuesData");
139
202
140 // expected x-axis data
203 // expected x-axis data
141 QTest::addColumn<QVector<double> >("expectedXAxisData");
204 QTest::addColumn<QVector<double> >("expectedXAxisData");
142 // expected values data
205 // expected values data
143 QTest::addColumn<QVector<double> >("expectedValuesData");
206 QTest::addColumn<QVector<double> >("expectedValuesData");
144
207
145 // ////////// //
208 // ////////// //
146 // Test cases //
209 // Test cases //
147 // ////////// //
210 // ////////// //
148
211
149 QTest::newRow("invalidData (different sizes of vectors)")
212 QTest::newRow("invalidData (different sizes of vectors)")
150 << QVector<double>{1., 2., 3., 4., 5.} << QVector<double>{100., 200., 300.}
213 << QVector<double>{1., 2., 3., 4., 5.} << QVector<double>{100., 200., 300.}
151 << QVector<double>{} << QVector<double>{};
214 << QVector<double>{} << QVector<double>{};
152
215
153 QTest::newRow("sortedData") << QVector<double>{1., 2., 3., 4., 5.}
216 QTest::newRow("sortedData") << QVector<double>{1., 2., 3., 4., 5.}
154 << QVector<double>{100., 200., 300., 400., 500.}
217 << QVector<double>{100., 200., 300., 400., 500.}
155 << QVector<double>{1., 2., 3., 4., 5.}
218 << QVector<double>{1., 2., 3., 4., 5.}
156 << QVector<double>{100., 200., 300., 400., 500.};
219 << QVector<double>{100., 200., 300., 400., 500.};
157
220
158 QTest::newRow("unsortedData") << QVector<double>{5., 4., 3., 2., 1.}
221 QTest::newRow("unsortedData") << QVector<double>{5., 4., 3., 2., 1.}
159 << QVector<double>{100., 200., 300., 400., 500.}
222 << QVector<double>{100., 200., 300., 400., 500.}
160 << QVector<double>{1., 2., 3., 4., 5.}
223 << QVector<double>{1., 2., 3., 4., 5.}
161 << QVector<double>{500., 400., 300., 200., 100.};
224 << QVector<double>{500., 400., 300., 200., 100.};
162
225
163 QTest::newRow("unsortedData2")
226 QTest::newRow("unsortedData2")
164 << QVector<double>{1., 4., 3., 5., 2.} << QVector<double>{100., 200., 300., 400., 500.}
227 << QVector<double>{1., 4., 3., 5., 2.} << QVector<double>{100., 200., 300., 400., 500.}
165 << QVector<double>{1., 2., 3., 4., 5.} << QVector<double>{100., 500., 300., 200., 400.};
228 << QVector<double>{1., 2., 3., 4., 5.} << QVector<double>{100., 500., 300., 200., 400.};
166 }
229 }
167
230
168 void TestDataSeries::testCtor()
231 void TestDataSeries::testCtor()
169 {
232 {
170 // Creates series
233 // Creates series
171 QFETCH(QVector<double>, xAxisData);
234 QFETCH(QVector<double>, xAxisData);
172 QFETCH(QVector<double>, valuesData);
235 QFETCH(QVector<double>, valuesData);
173
236
174 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
237 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
175 Unit{}, Unit{});
238 Unit{}, Unit{});
176
239
177 // Validates results : we check that the data series is sorted on its x-axis data
240 // Validates results : we check that the data series is sorted on its x-axis data
178 QFETCH(QVector<double>, expectedXAxisData);
241 QFETCH(QVector<double>, expectedXAxisData);
179 QFETCH(QVector<double>, expectedValuesData);
242 QFETCH(QVector<double>, expectedValuesData);
180
243
181 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData);
244 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData);
182 }
245 }
183
246
184 namespace {
247 namespace {
185
248
186 std::shared_ptr<ScalarSeries> createScalarSeries(QVector<double> xAxisData,
249 std::shared_ptr<ScalarSeries> createScalarSeries(QVector<double> xAxisData,
187 QVector<double> valuesData)
250 QVector<double> valuesData)
188 {
251 {
189 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
252 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
190 Unit{});
253 Unit{});
191 }
254 }
192
255
193 std::shared_ptr<VectorSeries> createVectorSeries(QVector<double> xAxisData,
256 std::shared_ptr<VectorSeries> createVectorSeries(QVector<double> xAxisData,
194 QVector<double> xValuesData,
257 QVector<double> xValuesData,
195 QVector<double> yValuesData,
258 QVector<double> yValuesData,
196 QVector<double> zValuesData)
259 QVector<double> zValuesData)
197 {
260 {
198 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(xValuesData),
261 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(xValuesData),
199 std::move(yValuesData), std::move(zValuesData), Unit{},
262 std::move(yValuesData), std::move(zValuesData), Unit{},
200 Unit{});
263 Unit{});
201 }
264 }
202
265
203 } // namespace
266 } // namespace
204
267
205 void TestDataSeries::testMerge_data()
268 void TestDataSeries::testMerge_data()
206 {
269 {
207 // ////////////// //
270 // ////////////// //
208 // Test structure //
271 // Test structure //
209 // ////////////// //
272 // ////////////// //
210
273
211 // Data series to merge
274 // Data series to merge
212 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
275 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
213 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries2");
276 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries2");
214
277
215 // Expected values in the first data series after merge
278 // Expected values in the first data series after merge
216 QTest::addColumn<QVector<double> >("expectedXAxisData");
279 QTest::addColumn<QVector<double> >("expectedXAxisData");
217 QTest::addColumn<QVector<double> >("expectedValuesData");
280 QTest::addColumn<QVector<double> >("expectedValuesData");
218
281
219 // ////////// //
282 // ////////// //
220 // Test cases //
283 // Test cases //
221 // ////////// //
284 // ////////// //
222
285
223 QTest::newRow("sortedMerge")
286 QTest::newRow("sortedMerge")
224 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
287 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
225 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
288 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
226 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
289 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
227 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
290 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
228
291
229 QTest::newRow("unsortedMerge")
292 QTest::newRow("unsortedMerge")
230 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
293 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
231 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
294 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
232 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
295 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
233 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
296 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
234
297
235 QTest::newRow("unsortedMerge2")
298 QTest::newRow("unsortedMerge2")
236 << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 300., 400., 500.})
299 << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 300., 400., 500.})
237 << createScalarSeries({3., 4., 5., 6., 7.}, {600., 700., 800., 900., 1000.})
300 << createScalarSeries({3., 4., 5., 6., 7.}, {600., 700., 800., 900., 1000.})
238 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
301 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
239 << QVector<double>{100., 200., 600., 700., 800., 900., 1000., 300., 400., 500.};
302 << QVector<double>{100., 200., 600., 700., 800., 900., 1000., 300., 400., 500.};
240
303
241 QTest::newRow("unsortedMerge3")
304 QTest::newRow("unsortedMerge3")
242 << createScalarSeries({3., 5., 8., 7., 2}, {100., 200., 300., 400., 500.})
305 << createScalarSeries({3., 5., 8., 7., 2}, {100., 200., 300., 400., 500.})
243 << createScalarSeries({6., 4., 9., 10., 1.}, {600., 700., 800., 900., 1000.})
306 << createScalarSeries({6., 4., 9., 10., 1.}, {600., 700., 800., 900., 1000.})
244 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
307 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
245 << QVector<double>{1000., 500., 100., 700., 200., 600., 400., 300., 800., 900.};
308 << QVector<double>{1000., 500., 100., 700., 200., 600., 400., 300., 800., 900.};
246 }
309 }
247
310
248 void TestDataSeries::testMerge()
311 void TestDataSeries::testMerge()
249 {
312 {
250 // Merges series
313 // Merges series
251 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
314 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
252 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries2);
315 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries2);
253
316
254 dataSeries->merge(dataSeries2.get());
317 dataSeries->merge(dataSeries2.get());
255
318
256 // Validates results : we check that the merge is valid and the data series is sorted on its
319 // Validates results : we check that the merge is valid and the data series is sorted on its
257 // x-axis data
320 // x-axis data
258 QFETCH(QVector<double>, expectedXAxisData);
321 QFETCH(QVector<double>, expectedXAxisData);
259 QFETCH(QVector<double>, expectedValuesData);
322 QFETCH(QVector<double>, expectedValuesData);
260
323
261 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData);
324 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData);
262 }
325 }
263
326
327 void TestDataSeries::testPurgeScalar_data()
328 {
329 testPurgeStructure<ScalarSeries>();
330
331 // ////////// //
332 // Test cases //
333 // ////////// //
334
335 QTest::newRow("purgeScalar") << createScalarSeries({1., 2., 3., 4., 5.},
336 {100., 200., 300., 400., 500.})
337 << 2. << 4. << QVector<double>{2., 3., 4.}
338 << QVector<QVector<double> >{{200., 300., 400.}};
339 QTest::newRow("purgeScalar2") << createScalarSeries({1., 2., 3., 4., 5.},
340 {100., 200., 300., 400., 500.})
341 << 0. << 2.5 << QVector<double>{1., 2.}
342 << QVector<QVector<double> >{{100., 200.}};
343 QTest::newRow("purgeScalar3") << createScalarSeries({1., 2., 3., 4., 5.},
344 {100., 200., 300., 400., 500.})
345 << 3.5 << 7. << QVector<double>{4., 5.}
346 << QVector<QVector<double> >{{400., 500.}};
347 QTest::newRow("purgeScalar4") << createScalarSeries({1., 2., 3., 4., 5.},
348 {100., 200., 300., 400., 500.})
349 << 0. << 7. << QVector<double>{1., 2., 3., 4., 5.}
350 << QVector<QVector<double> >{{100., 200., 300., 400., 500.}};
351 QTest::newRow("purgeScalar5") << createScalarSeries({1., 2., 3., 4., 5.},
352 {100., 200., 300., 400., 500.})
353 << 5.5 << 7. << QVector<double>{}
354 << QVector<QVector<double> >{{}};
355 }
356
357 void TestDataSeries::testPurgeScalar()
358 {
359 testPurge<ScalarSeries>();
360 }
361
362 void TestDataSeries::testPurgeVector_data()
363 {
364 testPurgeStructure<VectorSeries>();
365
366 // ////////// //
367 // Test cases //
368 // ////////// //
369
370 QTest::newRow("purgeVector") << createVectorSeries({1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.},
371 {11., 12., 13., 14., 15.},
372 {16., 17., 18., 19., 20.})
373 << 2. << 4. << QVector<double>{2., 3., 4.}
374 << QVector<QVector<double> >{
375 {7., 8., 9.}, {12., 13., 14.}, {17., 18., 19.}};
376 }
377
378 void TestDataSeries::testPurgeVector()
379 {
380 testPurge<VectorSeries>();
381 }
382
264 void TestDataSeries::testMinXAxisData_data()
383 void TestDataSeries::testMinXAxisData_data()
265 {
384 {
266 // ////////////// //
385 // ////////////// //
267 // Test structure //
386 // Test structure //
268 // ////////////// //
387 // ////////////// //
269
388
270 // Data series to get min data
389 // Data series to get min data
271 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
390 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
272
391
273 // Min data
392 // Min data
274 QTest::addColumn<double>("min");
393 QTest::addColumn<double>("min");
275
394
276 // Expected results
395 // Expected results
277 QTest::addColumn<bool>(
396 QTest::addColumn<bool>(
278 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
397 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
279 QTest::addColumn<double>(
398 QTest::addColumn<double>(
280 "expectedMin"); // Expected value when method doesn't return end iterator
399 "expectedMin"); // Expected value when method doesn't return end iterator
281
400
282 // ////////// //
401 // ////////// //
283 // Test cases //
402 // Test cases //
284 // ////////// //
403 // ////////// //
285
404
286 QTest::newRow("minData1") << createScalarSeries({1., 2., 3., 4., 5.},
405 QTest::newRow("minData1") << createScalarSeries({1., 2., 3., 4., 5.},
287 {100., 200., 300., 400., 500.})
406 {100., 200., 300., 400., 500.})
288 << 0. << true << 1.;
407 << 0. << true << 1.;
289 QTest::newRow("minData2") << createScalarSeries({1., 2., 3., 4., 5.},
408 QTest::newRow("minData2") << createScalarSeries({1., 2., 3., 4., 5.},
290 {100., 200., 300., 400., 500.})
409 {100., 200., 300., 400., 500.})
291 << 1. << true << 1.;
410 << 1. << true << 1.;
292 QTest::newRow("minData3") << createScalarSeries({1., 2., 3., 4., 5.},
411 QTest::newRow("minData3") << createScalarSeries({1., 2., 3., 4., 5.},
293 {100., 200., 300., 400., 500.})
412 {100., 200., 300., 400., 500.})
294 << 1.1 << true << 2.;
413 << 1.1 << true << 2.;
295 QTest::newRow("minData4") << createScalarSeries({1., 2., 3., 4., 5.},
414 QTest::newRow("minData4") << createScalarSeries({1., 2., 3., 4., 5.},
296 {100., 200., 300., 400., 500.})
415 {100., 200., 300., 400., 500.})
297 << 5. << true << 5.;
416 << 5. << true << 5.;
298 QTest::newRow("minData5") << createScalarSeries({1., 2., 3., 4., 5.},
417 QTest::newRow("minData5") << createScalarSeries({1., 2., 3., 4., 5.},
299 {100., 200., 300., 400., 500.})
418 {100., 200., 300., 400., 500.})
300 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
419 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
301 QTest::newRow("minData6") << createScalarSeries({}, {}) << 1.1 << false
420 QTest::newRow("minData6") << createScalarSeries({}, {}) << 1.1 << false
302 << std::numeric_limits<double>::quiet_NaN();
421 << std::numeric_limits<double>::quiet_NaN();
303 }
422 }
304
423
305 void TestDataSeries::testMinXAxisData()
424 void TestDataSeries::testMinXAxisData()
306 {
425 {
307 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
426 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
308 QFETCH(double, min);
427 QFETCH(double, min);
309
428
310 QFETCH(bool, expectedOK);
429 QFETCH(bool, expectedOK);
311 QFETCH(double, expectedMin);
430 QFETCH(double, expectedMin);
312
431
313 auto it = dataSeries->minXAxisData(min);
432 auto it = dataSeries->minXAxisData(min);
314
433
315 QCOMPARE(expectedOK, it != dataSeries->cend());
434 QCOMPARE(expectedOK, it != dataSeries->cend());
316
435
317 // If the method doesn't return a end iterator, checks with expected value
436 // If the method doesn't return a end iterator, checks with expected value
318 if (expectedOK) {
437 if (expectedOK) {
319 QCOMPARE(expectedMin, it->x());
438 QCOMPARE(expectedMin, it->x());
320 }
439 }
321 }
440 }
322
441
323 void TestDataSeries::testMaxXAxisData_data()
442 void TestDataSeries::testMaxXAxisData_data()
324 {
443 {
325 // ////////////// //
444 // ////////////// //
326 // Test structure //
445 // Test structure //
327 // ////////////// //
446 // ////////////// //
328
447
329 // Data series to get max data
448 // Data series to get max data
330 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
449 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
331
450
332 // Max data
451 // Max data
333 QTest::addColumn<double>("max");
452 QTest::addColumn<double>("max");
334
453
335 // Expected results
454 // Expected results
336 QTest::addColumn<bool>(
455 QTest::addColumn<bool>(
337 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
456 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
338 QTest::addColumn<double>(
457 QTest::addColumn<double>(
339 "expectedMax"); // Expected value when method doesn't return end iterator
458 "expectedMax"); // Expected value when method doesn't return end iterator
340
459
341 // ////////// //
460 // ////////// //
342 // Test cases //
461 // Test cases //
343 // ////////// //
462 // ////////// //
344
463
345 QTest::newRow("maxData1") << createScalarSeries({1., 2., 3., 4., 5.},
464 QTest::newRow("maxData1") << createScalarSeries({1., 2., 3., 4., 5.},
346 {100., 200., 300., 400., 500.})
465 {100., 200., 300., 400., 500.})
347 << 6. << true << 5.;
466 << 6. << true << 5.;
348 QTest::newRow("maxData2") << createScalarSeries({1., 2., 3., 4., 5.},
467 QTest::newRow("maxData2") << createScalarSeries({1., 2., 3., 4., 5.},
349 {100., 200., 300., 400., 500.})
468 {100., 200., 300., 400., 500.})
350 << 5. << true << 5.;
469 << 5. << true << 5.;
351 QTest::newRow("maxData3") << createScalarSeries({1., 2., 3., 4., 5.},
470 QTest::newRow("maxData3") << createScalarSeries({1., 2., 3., 4., 5.},
352 {100., 200., 300., 400., 500.})
471 {100., 200., 300., 400., 500.})
353 << 4.9 << true << 4.;
472 << 4.9 << true << 4.;
354 QTest::newRow("maxData4") << createScalarSeries({1., 2., 3., 4., 5.},
473 QTest::newRow("maxData4") << createScalarSeries({1., 2., 3., 4., 5.},
355 {100., 200., 300., 400., 500.})
474 {100., 200., 300., 400., 500.})
356 << 1.1 << true << 1.;
475 << 1.1 << true << 1.;
357 QTest::newRow("maxData5") << createScalarSeries({1., 2., 3., 4., 5.},
476 QTest::newRow("maxData5") << createScalarSeries({1., 2., 3., 4., 5.},
358 {100., 200., 300., 400., 500.})
477 {100., 200., 300., 400., 500.})
359 << 1. << true << 1.;
478 << 1. << true << 1.;
360 QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false
479 QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false
361 << std::numeric_limits<double>::quiet_NaN();
480 << std::numeric_limits<double>::quiet_NaN();
362 }
481 }
363
482
364 void TestDataSeries::testMaxXAxisData()
483 void TestDataSeries::testMaxXAxisData()
365 {
484 {
366 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
485 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
367 QFETCH(double, max);
486 QFETCH(double, max);
368
487
369 QFETCH(bool, expectedOK);
488 QFETCH(bool, expectedOK);
370 QFETCH(double, expectedMax);
489 QFETCH(double, expectedMax);
371
490
372 auto it = dataSeries->maxXAxisData(max);
491 auto it = dataSeries->maxXAxisData(max);
373
492
374 QCOMPARE(expectedOK, it != dataSeries->cend());
493 QCOMPARE(expectedOK, it != dataSeries->cend());
375
494
376 // If the method doesn't return a end iterator, checks with expected value
495 // If the method doesn't return a end iterator, checks with expected value
377 if (expectedOK) {
496 if (expectedOK) {
378 QCOMPARE(expectedMax, it->x());
497 QCOMPARE(expectedMax, it->x());
379 }
498 }
380 }
499 }
381
500
382 void TestDataSeries::testXAxisRange_data()
501 void TestDataSeries::testXAxisRange_data()
383 {
502 {
384 // ////////////// //
503 // ////////////// //
385 // Test structure //
504 // Test structure //
386 // ////////////// //
505 // ////////////// //
387
506
388 // Data series to get x-axis range
507 // Data series to get x-axis range
389 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
508 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
390
509
391 // Min/max values
510 // Min/max values
392 QTest::addColumn<double>("min");
511 QTest::addColumn<double>("min");
393 QTest::addColumn<double>("max");
512 QTest::addColumn<double>("max");
394
513
395 // Expected values
514 // Expected values
396 QTest::addColumn<QVector<double> >("expectedXAxisData");
515 QTest::addColumn<QVector<double> >("expectedXAxisData");
397 QTest::addColumn<QVector<double> >("expectedValuesData");
516 QTest::addColumn<QVector<double> >("expectedValuesData");
398
517
399 // ////////// //
518 // ////////// //
400 // Test cases //
519 // Test cases //
401 // ////////// //
520 // ////////// //
402
521
403 QTest::newRow("xAxisRange1") << createScalarSeries({1., 2., 3., 4., 5.},
522 QTest::newRow("xAxisRange1") << createScalarSeries({1., 2., 3., 4., 5.},
404 {100., 200., 300., 400., 500.})
523 {100., 200., 300., 400., 500.})
405 << -1. << 3.2 << QVector<double>{1., 2., 3.}
524 << -1. << 3.2 << QVector<double>{1., 2., 3.}
406 << QVector<double>{100., 200., 300.};
525 << QVector<double>{100., 200., 300.};
407 QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.},
526 QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.},
408 {100., 200., 300., 400., 500.})
527 {100., 200., 300., 400., 500.})
409 << 1. << 4. << QVector<double>{1., 2., 3., 4.}
528 << 1. << 4. << QVector<double>{1., 2., 3., 4.}
410 << QVector<double>{100., 200., 300., 400.};
529 << QVector<double>{100., 200., 300., 400.};
411 QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.},
530 QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.},
412 {100., 200., 300., 400., 500.})
531 {100., 200., 300., 400., 500.})
413 << 1. << 3.9 << QVector<double>{1., 2., 3.}
532 << 1. << 3.9 << QVector<double>{1., 2., 3.}
414 << QVector<double>{100., 200., 300.};
533 << QVector<double>{100., 200., 300.};
415 QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.},
534 QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.},
416 {100., 200., 300., 400., 500.})
535 {100., 200., 300., 400., 500.})
417 << 0. << 0.9 << QVector<double>{} << QVector<double>{};
536 << 0. << 0.9 << QVector<double>{} << QVector<double>{};
418 QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.},
537 QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.},
419 {100., 200., 300., 400., 500.})
538 {100., 200., 300., 400., 500.})
420 << 0. << 1. << QVector<double>{1.} << QVector<double>{100.};
539 << 0. << 1. << QVector<double>{1.} << QVector<double>{100.};
421 QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.},
540 QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.},
422 {100., 200., 300., 400., 500.})
541 {100., 200., 300., 400., 500.})
423 << 2.1 << 6. << QVector<double>{3., 4., 5.}
542 << 2.1 << 6. << QVector<double>{3., 4., 5.}
424 << QVector<double>{300., 400., 500.};
543 << QVector<double>{300., 400., 500.};
425 QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.},
544 QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.},
426 {100., 200., 300., 400., 500.})
545 {100., 200., 300., 400., 500.})
427 << 6. << 9. << QVector<double>{} << QVector<double>{};
546 << 6. << 9. << QVector<double>{} << QVector<double>{};
428 QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.},
547 QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.},
429 {100., 200., 300., 400., 500.})
548 {100., 200., 300., 400., 500.})
430 << 5. << 9. << QVector<double>{5.} << QVector<double>{500.};
549 << 5. << 9. << QVector<double>{5.} << QVector<double>{500.};
431 }
550 }
432
551
433 void TestDataSeries::testXAxisRange()
552 void TestDataSeries::testXAxisRange()
434 {
553 {
435 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
554 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
436 QFETCH(double, min);
555 QFETCH(double, min);
437 QFETCH(double, max);
556 QFETCH(double, max);
438
557
439 QFETCH(QVector<double>, expectedXAxisData);
558 QFETCH(QVector<double>, expectedXAxisData);
440 QFETCH(QVector<double>, expectedValuesData);
559 QFETCH(QVector<double>, expectedValuesData);
441
560
442 auto bounds = dataSeries->xAxisRange(min, max);
561 auto bounds = dataSeries->xAxisRange(min, max);
443 validateRange(bounds.first, bounds.second, expectedXAxisData, expectedValuesData);
562 validateRange(bounds.first, bounds.second, expectedXAxisData, expectedValuesData);
444 }
563 }
445
564
446 void TestDataSeries::testValuesBoundsScalar_data()
565 void TestDataSeries::testValuesBoundsScalar_data()
447 {
566 {
448 testValuesBoundsStructure<ScalarSeries>();
567 testValuesBoundsStructure<ScalarSeries>();
449
568
450 // ////////// //
569 // ////////// //
451 // Test cases //
570 // Test cases //
452 // ////////// //
571 // ////////// //
453 auto nan = std::numeric_limits<double>::quiet_NaN();
572 auto nan = std::numeric_limits<double>::quiet_NaN();
454
573
455 QTest::newRow("scalarBounds1")
574 QTest::newRow("scalarBounds1")
456 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 6.
575 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 6.
457 << true << 100. << 500.;
576 << true << 100. << 500.;
458 QTest::newRow("scalarBounds2")
577 QTest::newRow("scalarBounds2")
459 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 2. << 4.
578 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 2. << 4.
460 << true << 200. << 400.;
579 << true << 200. << 400.;
461 QTest::newRow("scalarBounds3")
580 QTest::newRow("scalarBounds3")
462 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 0.5
581 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 0.5
463 << false << nan << nan;
582 << false << nan << nan;
464 QTest::newRow("scalarBounds4")
583 QTest::newRow("scalarBounds4")
465 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 5.1 << 6.
584 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 5.1 << 6.
466 << false << nan << nan;
585 << false << nan << nan;
467 QTest::newRow("scalarBounds5") << createScalarSeries({1.}, {100.}) << 0. << 2. << true << 100.
586 QTest::newRow("scalarBounds5") << createScalarSeries({1.}, {100.}) << 0. << 2. << true << 100.
468 << 100.;
587 << 100.;
469 QTest::newRow("scalarBounds6") << createScalarSeries({}, {}) << 0. << 2. << false << nan << nan;
588 QTest::newRow("scalarBounds6") << createScalarSeries({}, {}) << 0. << 2. << false << nan << nan;
470
589
471 // Tests with NaN values: NaN values are not included in min/max search
590 // Tests with NaN values: NaN values are not included in min/max search
472 QTest::newRow("scalarBounds7")
591 QTest::newRow("scalarBounds7")
473 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, 200., 300., 400., nan}) << 0. << 6.
592 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, 200., 300., 400., nan}) << 0. << 6.
474 << true << 200. << 400.;
593 << true << 200. << 400.;
475 QTest::newRow("scalarBounds8")
594 QTest::newRow("scalarBounds8")
476 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, nan, nan, nan, nan}) << 0. << 6. << true
595 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, nan, nan, nan, nan}) << 0. << 6. << true
477 << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN();
596 << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN();
478 }
597 }
479
598
480 void TestDataSeries::testValuesBoundsScalar()
599 void TestDataSeries::testValuesBoundsScalar()
481 {
600 {
482 testValuesBounds<ScalarSeries>();
601 testValuesBounds<ScalarSeries>();
483 }
602 }
484
603
485 void TestDataSeries::testValuesBoundsVector_data()
604 void TestDataSeries::testValuesBoundsVector_data()
486 {
605 {
487 testValuesBoundsStructure<VectorSeries>();
606 testValuesBoundsStructure<VectorSeries>();
488
607
489 // ////////// //
608 // ////////// //
490 // Test cases //
609 // Test cases //
491 // ////////// //
610 // ////////// //
492 auto nan = std::numeric_limits<double>::quiet_NaN();
611 auto nan = std::numeric_limits<double>::quiet_NaN();
493
612
494 QTest::newRow("vectorBounds1")
613 QTest::newRow("vectorBounds1")
495 << createVectorSeries({1., 2., 3., 4., 5.}, {10., 15., 20., 13., 12.},
614 << createVectorSeries({1., 2., 3., 4., 5.}, {10., 15., 20., 13., 12.},
496 {35., 24., 10., 9., 0.3}, {13., 14., 12., 9., 24.})
615 {35., 24., 10., 9., 0.3}, {13., 14., 12., 9., 24.})
497 << 0. << 6. << true << 0.3 << 35.; // min/max in same component
616 << 0. << 6. << true << 0.3 << 35.; // min/max in same component
498 QTest::newRow("vectorBounds2")
617 QTest::newRow("vectorBounds2")
499 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
618 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
500 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
619 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
501 << 0. << 6. << true << 2.3 << 35.; // min/max in same entry
620 << 0. << 6. << true << 2.3 << 35.; // min/max in same entry
502 QTest::newRow("vectorBounds3")
621 QTest::newRow("vectorBounds3")
503 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
622 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
504 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
623 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
505 << 2. << 3. << true << 10. << 24.;
624 << 2. << 3. << true << 10. << 24.;
506
625
507 // Tests with NaN values: NaN values are not included in min/max search
626 // Tests with NaN values: NaN values are not included in min/max search
508 QTest::newRow("vectorBounds4")
627 QTest::newRow("vectorBounds4")
509 << createVectorSeries({1., 2.}, {nan, nan}, {nan, nan}, {nan, nan}) << 0. << 6. << true
628 << createVectorSeries({1., 2.}, {nan, nan}, {nan, nan}, {nan, nan}) << 0. << 6. << true
510 << nan << nan;
629 << nan << nan;
511 }
630 }
512
631
513 void TestDataSeries::testValuesBoundsVector()
632 void TestDataSeries::testValuesBoundsVector()
514 {
633 {
515 testValuesBounds<VectorSeries>();
634 testValuesBounds<VectorSeries>();
516 }
635 }
517
636
518 QTEST_MAIN(TestDataSeries)
637 QTEST_MAIN(TestDataSeries)
519 #include "TestDataSeries.moc"
638 #include "TestDataSeries.moc"
@@ -1,45 +1,52
1 # On ignore toutes les règles vera++ pour le fichier spimpl
1 # On ignore toutes les règles vera++ pour le fichier spimpl
2 Common/spimpl\.h:\d+:.*
2 Common/spimpl\.h:\d+:.*
3
3
4 # Ignore false positive relative to two class definitions in a same file
4 # Ignore false positive relative to two class definitions in a same file
5 ArrayData\.h:\d+:.*IPSIS_S01.*
5 ArrayData\.h:\d+:.*IPSIS_S01.*
6 ArrayDataIterator\.h:\d+:.*IPSIS_S01.*
6 ArrayDataIterator\.h:\d+:.*IPSIS_S01.*
7 DataSourceItem\.h:\d+:.*IPSIS_S01.*
7 DataSourceItem\.h:\d+:.*IPSIS_S01.*
8 DataSeries\.h:\d+:.*IPSIS_S01.*
8 DataSeries\.h:\d+:.*IPSIS_S01.*
9 DataSeriesIterator\.h:\d+:.*IPSIS_S01.*
9 DataSeriesIterator\.h:\d+:.*IPSIS_S01.*
10 DataSeriesMergeHelper\.h:\d+:.*IPSIS_S01.*
10 DataSeriesMergeHelper\.h:\d+:.*IPSIS_S01.*
11
11
12 # Ignore false positive relative to a template class
12 # Ignore false positive relative to a template class
13 ArrayData\.h:\d+:.*IPSIS_S04_METHOD.*found: push_back
13 ArrayData\.h:\d+:.*IPSIS_S04_METHOD.*found: push_back
14 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (const_iterator)
14 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (D)
15 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (D)
16 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (IC)
15 ArrayData\.h:\d+:.*IPSIS_S04_NAMESPACE.*found: (arraydata_detail)
17 ArrayData\.h:\d+:.*IPSIS_S04_NAMESPACE.*found: (arraydata_detail)
16 ArrayData\.h:\d+:.*IPSIS_S06.*found: (D)
18 ArrayData\.h:\d+:.*IPSIS_S06.*found: (D)
17 ArrayData\.h:\d+:.*IPSIS_S06.*found: (Dim)
19 ArrayData\.h:\d+:.*IPSIS_S06.*found: (Dim)
20 ArrayData\.h:\d+:.*IPSIS_S06.*found: (IC)
21 ArrayData\.h:\d+:.*IPSIS_S06.*found: (IsConst)
18 DataSeries\.h:\d+:.*IPSIS_S04_METHOD.*found: LOG_DataSeries
22 DataSeries\.h:\d+:.*IPSIS_S04_METHOD.*found: LOG_DataSeries
19 DataSeries\.h:\d+:.*IPSIS_S04_METHOD.*found: push_back
23 DataSeries\.h:\d+:.*IPSIS_S04_METHOD.*found: push_back
20 DataSeries\.h:\d+:.*IPSIS_S04_VARIABLE.*
24 DataSeries\.h:\d+:.*IPSIS_S04_VARIABLE.*
21 DataSeries\.h:\d+:.*IPSIS_S04_NAMESPACE.*found: (dataseries_detail)
25 DataSeries\.h:\d+:.*IPSIS_S04_NAMESPACE.*found: (dataseries_detail)
22 DataSeries\.h:\d+:.*IPSIS_S05.*
26 DataSeries\.h:\d+:.*IPSIS_S05.*
23 DataSeries\.h:\d+:.*IPSIS_S06.*found: (value_type)
27 DataSeries\.h:\d+:.*IPSIS_S06.*found: (value_type)
24 DataSeries\.h:\d+:.*IPSIS_S06.*found: (DataSeriesIteratorValue)
28 DataSeries\.h:\d+:.*IPSIS_S06.*found: (DataSeriesIteratorValue)
29 DataSeries\.h:\d+:.*IPSIS_S06.*found: (Dim)
30 DataSeries\.h:\d+:.*IPSIS_S06.*found: (IC)
31 DataSeries\.h:\d+:.*IPSIS_S06.*found: (IsConst)
25
32
26 # Ignore false positive relative to iterators
33 # Ignore false positive relative to iterators
27 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (forward_iterator_tag)
34 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (forward_iterator_tag)
28 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (T)
35 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (T)
29 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (ptrdiff_t)
36 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (ptrdiff_t)
30 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (value_type)
37 SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (value_type)
31 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (iterator_category)
38 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (iterator_category)
32 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (forward_iterator_tag)
39 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (forward_iterator_tag)
33 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (value_type)
40 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (value_type)
34 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (T)
41 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (T)
35 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (difference_type)
42 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (difference_type)
36 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (ptrdiff_t)
43 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (ptrdiff_t)
37 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (pointer)
44 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (pointer)
38 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (reference)
45 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (reference)
39 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (value_type)
46 SqpIterator\.h:\d+:.*IPSIS_S06.*found: (value_type)
40
47
41 # Ignore false positive relative to an alias
48 # Ignore false positive relative to an alias
42 DataSourceItemAction\.h:\d+:.*IPSIS_S06.*found: (ExecuteFunction)
49 DataSourceItemAction\.h:\d+:.*IPSIS_S06.*found: (ExecuteFunction)
43
50
44 # Ignore false positive relative to unnamed namespace
51 # Ignore false positive relative to unnamed namespace
45 VariableController\.cpp:\d+:.*IPSIS_F13.*
52 VariableController\.cpp:\d+:.*IPSIS_F13.*
General Comments 0
You need to be logged in to leave comments. Login now