##// END OF EJS Templates
Makes random access iterators...
Alexandre Leroux -
r689:8e901fd37cbc
parent child
Show More
@@ -1,353 +1,379
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>
42 template <int Dim, bool IsConst>
43 class IteratorValue;
43 class IteratorValue;
44
44
45 template <int Dim, bool IsConst>
45 template <int Dim, bool IsConst>
46 struct IteratorValueBuilder {
46 struct IteratorValueBuilder {
47 };
47 };
48
48
49 template <int Dim>
49 template <int Dim>
50 struct IteratorValueBuilder<Dim, true> {
50 struct IteratorValueBuilder<Dim, true> {
51 using DataContainerIterator = DataContainer::const_iterator;
51 using DataContainerIterator = DataContainer::const_iterator;
52
52
53 static void swap(IteratorValue<Dim, true> &o1, IteratorValue<Dim, true> &o2) {}
53 static void swap(IteratorValue<Dim, true> &o1, IteratorValue<Dim, true> &o2) {}
54 };
54 };
55
55
56 template <int Dim>
56 template <int Dim>
57 struct IteratorValueBuilder<Dim, false> {
57 struct IteratorValueBuilder<Dim, false> {
58 using DataContainerIterator = DataContainer::iterator;
58 using DataContainerIterator = DataContainer::iterator;
59
59
60 static void swap(IteratorValue<Dim, false> &o1, IteratorValue<Dim, false> &o2)
60 static void swap(IteratorValue<Dim, false> &o1, IteratorValue<Dim, false> &o2)
61 {
61 {
62 for (auto i = 0; i < o1.m_NbComponents; ++i) {
62 for (auto i = 0; i < o1.m_NbComponents; ++i) {
63 std::iter_swap(o1.m_It + i, o2.m_It + i);
63 std::iter_swap(o1.m_It + i, o2.m_It + i);
64 }
64 }
65 }
65 }
66 };
66 };
67
67
68 template <int Dim, bool IsConst>
68 template <int Dim, bool IsConst>
69 class IteratorValue : public ArrayDataIteratorValue::Impl {
69 class IteratorValue : public ArrayDataIteratorValue::Impl {
70 public:
70 public:
71 friend class ArrayData<Dim>;
71 friend class ArrayData<Dim>;
72 friend class IteratorValueBuilder<Dim, IsConst>;
72 friend class IteratorValueBuilder<Dim, IsConst>;
73
73
74 using DataContainerIterator =
74 using DataContainerIterator =
75 typename IteratorValueBuilder<Dim, IsConst>::DataContainerIterator;
75 typename IteratorValueBuilder<Dim, IsConst>::DataContainerIterator;
76
76
77 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
77 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
78 explicit IteratorValue(const DataContainer &container, int nbComponents, bool begin)
78 explicit IteratorValue(const DataContainer &container, int nbComponents, bool begin)
79 : m_It{begin ? container.cbegin() : container.cend()}, m_NbComponents{nbComponents}
79 : m_It{begin ? container.cbegin() : container.cend()}, m_NbComponents{nbComponents}
80 {
80 {
81 }
81 }
82
82
83 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
83 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
84 explicit IteratorValue(DataContainer &container, int nbComponents, bool begin)
84 explicit IteratorValue(DataContainer &container, int nbComponents, bool begin)
85 : m_It{begin ? container.begin() : container.end()}, m_NbComponents{nbComponents}
85 : m_It{begin ? container.begin() : container.end()}, m_NbComponents{nbComponents}
86 {
86 {
87 }
87 }
88
88
89 IteratorValue(const IteratorValue &other) = default;
89 IteratorValue(const IteratorValue &other) = default;
90
90
91 std::unique_ptr<ArrayDataIteratorValue::Impl> clone() const override
91 std::unique_ptr<ArrayDataIteratorValue::Impl> clone() const override
92 {
92 {
93 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
93 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
94 }
94 }
95
95
96 int distance(const ArrayDataIteratorValue::Impl &other) const override try {
97 /// @todo ALX : validate
98 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
99 return std::distance(otherImpl.m_It, m_It) / m_NbComponents;
100 }
101 catch (const std::bad_cast &) {
102 return 0;
103 }
104
96 bool equals(const ArrayDataIteratorValue::Impl &other) const override try {
105 bool equals(const ArrayDataIteratorValue::Impl &other) const override try {
97 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
106 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
98 return std::tie(m_It, m_NbComponents) == std::tie(otherImpl.m_It, otherImpl.m_NbComponents);
107 return std::tie(m_It, m_NbComponents) == std::tie(otherImpl.m_It, otherImpl.m_NbComponents);
99 }
108 }
100 catch (const std::bad_cast &) {
109 catch (const std::bad_cast &) {
101 return false;
110 return false;
102 }
111 }
103
112
113 bool lowerThan(const ArrayDataIteratorValue::Impl &other) const override try {
114 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
115 return m_It < otherImpl.m_It;
116 }
117 catch (const std::bad_cast &) {
118 return false;
119 }
120
121 std::unique_ptr<ArrayDataIteratorValue::Impl> advance(int offset) const override
122 {
123 auto result = clone();
124 while (offset--) {
125 result->next();
126 }
127 return result;
128 }
129
104 void next() override { std::advance(m_It, m_NbComponents); }
130 void next() override { std::advance(m_It, m_NbComponents); }
105 void prev() override { std::advance(m_It, -m_NbComponents); }
131 void prev() override { std::advance(m_It, -m_NbComponents); }
106
132
107 double at(int componentIndex) const override { return *(m_It + componentIndex); }
133 double at(int componentIndex) const override { return *(m_It + componentIndex); }
108 double first() const override { return *m_It; }
134 double first() const override { return *m_It; }
109 double min() const override
135 double min() const override
110 {
136 {
111 auto values = this->values();
137 auto values = this->values();
112 auto end = values.cend();
138 auto end = values.cend();
113 auto it = std::min_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
139 auto it = std::min_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
114 return SortUtils::minCompareWithNaN(v1, v2);
140 return SortUtils::minCompareWithNaN(v1, v2);
115 });
141 });
116
142
117 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
143 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
118 }
144 }
119 double max() const override
145 double max() const override
120 {
146 {
121 auto values = this->values();
147 auto values = this->values();
122 auto end = values.cend();
148 auto end = values.cend();
123 auto it = std::max_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
149 auto it = std::max_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
124 return SortUtils::maxCompareWithNaN(v1, v2);
150 return SortUtils::maxCompareWithNaN(v1, v2);
125 });
151 });
126 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
152 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
127 }
153 }
128
154
129 QVector<double> values() const override
155 QVector<double> values() const override
130 {
156 {
131 auto result = QVector<double>{};
157 auto result = QVector<double>{};
132 for (auto i = 0; i < m_NbComponents; ++i) {
158 for (auto i = 0; i < m_NbComponents; ++i) {
133 result.push_back(*(m_It + i));
159 result.push_back(*(m_It + i));
134 }
160 }
135
161
136 return result;
162 return result;
137 }
163 }
138
164
139 void swap(ArrayDataIteratorValue::Impl &other) override
165 void swap(ArrayDataIteratorValue::Impl &other) override
140 {
166 {
141 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
167 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
142 IteratorValueBuilder<Dim, IsConst>::swap(*this, otherImpl);
168 IteratorValueBuilder<Dim, IsConst>::swap(*this, otherImpl);
143 }
169 }
144
170
145 private:
171 private:
146 DataContainerIterator m_It;
172 DataContainerIterator m_It;
147 int m_NbComponents;
173 int m_NbComponents;
148 };
174 };
149
175
150 } // namespace arraydata_detail
176 } // namespace arraydata_detail
151
177
152 /**
178 /**
153 * @brief The ArrayData class represents a dataset for a data series.
179 * @brief The ArrayData class represents a dataset for a data series.
154 *
180 *
155 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
181 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
156 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
182 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
157 * number of values
183 * number of values
158 *
184 *
159 * @tparam Dim the dimension of the ArrayData (one or two)
185 * @tparam Dim the dimension of the ArrayData (one or two)
160 * @sa IDataSeries
186 * @sa IDataSeries
161 */
187 */
162 template <int Dim>
188 template <int Dim>
163 class ArrayData {
189 class ArrayData {
164 public:
190 public:
165 // ///// //
191 // ///// //
166 // Ctors //
192 // Ctors //
167 // ///// //
193 // ///// //
168
194
169 /**
195 /**
170 * Ctor for a unidimensional ArrayData
196 * Ctor for a unidimensional ArrayData
171 * @param data the data the ArrayData will hold
197 * @param data the data the ArrayData will hold
172 */
198 */
173 template <int D = Dim, typename = std::enable_if_t<D == 1> >
199 template <int D = Dim, typename = std::enable_if_t<D == 1> >
174 explicit ArrayData(DataContainer data) : m_Data{std::move(data)}, m_NbComponents{1}
200 explicit ArrayData(DataContainer data) : m_Data{std::move(data)}, m_NbComponents{1}
175 {
201 {
176 }
202 }
177
203
178 /**
204 /**
179 * Ctor for a two-dimensional ArrayData. The number of components (number of lines) must be
205 * Ctor for a two-dimensional ArrayData. The number of components (number of lines) must be
180 * greater than 2 and must be a divisor of the total number of data in the vector
206 * greater than 2 and must be a divisor of the total number of data in the vector
181 * @param data the data the ArrayData will hold
207 * @param data the data the ArrayData will hold
182 * @param nbComponents the number of components
208 * @param nbComponents the number of components
183 * @throws std::invalid_argument if the number of components is less than 2 or is not a divisor
209 * @throws std::invalid_argument if the number of components is less than 2 or is not a divisor
184 * of the size of the data
210 * of the size of the data
185 */
211 */
186 template <int D = Dim, typename = std::enable_if_t<D == 2> >
212 template <int D = Dim, typename = std::enable_if_t<D == 2> >
187 explicit ArrayData(DataContainer data, int nbComponents)
213 explicit ArrayData(DataContainer data, int nbComponents)
188 : m_Data{std::move(data)}, m_NbComponents{nbComponents}
214 : m_Data{std::move(data)}, m_NbComponents{nbComponents}
189 {
215 {
190 if (nbComponents < 2) {
216 if (nbComponents < 2) {
191 throw std::invalid_argument{
217 throw std::invalid_argument{
192 QString{"A multidimensional ArrayData must have at least 2 components (found: %1)"}
218 QString{"A multidimensional ArrayData must have at least 2 components (found: %1)"}
193 .arg(nbComponents)
219 .arg(nbComponents)
194 .toStdString()};
220 .toStdString()};
195 }
221 }
196
222
197 if (m_Data.size() % m_NbComponents != 0) {
223 if (m_Data.size() % m_NbComponents != 0) {
198 throw std::invalid_argument{QString{
224 throw std::invalid_argument{QString{
199 "The number of components (%1) is inconsistent with the total number of data (%2)"}
225 "The number of components (%1) is inconsistent with the total number of data (%2)"}
200 .arg(m_Data.size(), nbComponents)
226 .arg(m_Data.size(), nbComponents)
201 .toStdString()};
227 .toStdString()};
202 }
228 }
203 }
229 }
204
230
205 /// Copy ctor
231 /// Copy ctor
206 explicit ArrayData(const ArrayData &other)
232 explicit ArrayData(const ArrayData &other)
207 {
233 {
208 QReadLocker otherLocker{&other.m_Lock};
234 QReadLocker otherLocker{&other.m_Lock};
209 m_Data = other.m_Data;
235 m_Data = other.m_Data;
210 m_NbComponents = other.m_NbComponents;
236 m_NbComponents = other.m_NbComponents;
211 }
237 }
212
238
213 // /////////////// //
239 // /////////////// //
214 // General methods //
240 // General methods //
215 // /////////////// //
241 // /////////////// //
216
242
217 /**
243 /**
218 * Merges into the array data an other array data. The two array datas must have the same number
244 * Merges into the array data an other array data. The two array datas must have the same number
219 * of components so the merge can be done
245 * of components so the merge can be done
220 * @param other the array data to merge with
246 * @param other the array data to merge with
221 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
247 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
222 * inserted at the end
248 * inserted at the end
223 */
249 */
224 void add(const ArrayData<Dim> &other, bool prepend = false)
250 void add(const ArrayData<Dim> &other, bool prepend = false)
225 {
251 {
226 QWriteLocker locker{&m_Lock};
252 QWriteLocker locker{&m_Lock};
227 QReadLocker otherLocker{&other.m_Lock};
253 QReadLocker otherLocker{&other.m_Lock};
228
254
229 if (m_NbComponents != other.componentCount()) {
255 if (m_NbComponents != other.componentCount()) {
230 return;
256 return;
231 }
257 }
232
258
233 if (prepend) {
259 if (prepend) {
234 auto otherDataSize = other.m_Data.size();
260 auto otherDataSize = other.m_Data.size();
235 m_Data.insert(m_Data.begin(), otherDataSize, 0.);
261 m_Data.insert(m_Data.begin(), otherDataSize, 0.);
236 for (auto i = 0; i < otherDataSize; ++i) {
262 for (auto i = 0; i < otherDataSize; ++i) {
237 m_Data.replace(i, other.m_Data.at(i));
263 m_Data.replace(i, other.m_Data.at(i));
238 }
264 }
239 }
265 }
240 else {
266 else {
241 m_Data.append(other.m_Data);
267 m_Data.append(other.m_Data);
242 }
268 }
243 }
269 }
244
270
245 void clear()
271 void clear()
246 {
272 {
247 QWriteLocker locker{&m_Lock};
273 QWriteLocker locker{&m_Lock};
248 m_Data.clear();
274 m_Data.clear();
249 }
275 }
250
276
251 int componentCount() const noexcept { return m_NbComponents; }
277 int componentCount() const noexcept { return m_NbComponents; }
252
278
253 /// @return the size (i.e. number of values) of a single component
279 /// @return the size (i.e. number of values) of a single component
254 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
280 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
255 int size() const
281 int size() const
256 {
282 {
257 QReadLocker locker{&m_Lock};
283 QReadLocker locker{&m_Lock};
258 return m_Data.size() / m_NbComponents;
284 return m_Data.size() / m_NbComponents;
259 }
285 }
260
286
261 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
287 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
262 {
288 {
263 QReadLocker locker{&m_Lock};
289 QReadLocker locker{&m_Lock};
264 return arraydata_detail::Sort<Dim>::sort(m_Data, m_NbComponents, sortPermutation);
290 return arraydata_detail::Sort<Dim>::sort(m_Data, m_NbComponents, sortPermutation);
265 }
291 }
266
292
267 // ///////// //
293 // ///////// //
268 // Iterators //
294 // Iterators //
269 // ///////// //
295 // ///////// //
270
296
271 ArrayDataIterator begin()
297 ArrayDataIterator begin()
272 {
298 {
273 return ArrayDataIterator{
299 return ArrayDataIterator{
274 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
300 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
275 m_Data, m_NbComponents, true)}};
301 m_Data, m_NbComponents, true)}};
276 }
302 }
277
303
278 ArrayDataIterator end()
304 ArrayDataIterator end()
279 {
305 {
280 return ArrayDataIterator{
306 return ArrayDataIterator{
281 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
307 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
282 m_Data, m_NbComponents, false)}};
308 m_Data, m_NbComponents, false)}};
283 }
309 }
284
310
285 ArrayDataIterator cbegin() const
311 ArrayDataIterator cbegin() const
286 {
312 {
287 return ArrayDataIterator{
313 return ArrayDataIterator{
288 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
314 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
289 m_Data, m_NbComponents, true)}};
315 m_Data, m_NbComponents, true)}};
290 }
316 }
291
317
292 ArrayDataIterator cend() const
318 ArrayDataIterator cend() const
293 {
319 {
294 return ArrayDataIterator{
320 return ArrayDataIterator{
295 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
321 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
296 m_Data, m_NbComponents, false)}};
322 m_Data, m_NbComponents, false)}};
297 }
323 }
298
324
299 void erase(ArrayDataIterator first, ArrayDataIterator last)
325 void erase(ArrayDataIterator first, ArrayDataIterator last)
300 {
326 {
301 auto firstImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(first->impl());
327 auto firstImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(first->impl());
302 auto lastImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(last->impl());
328 auto lastImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(last->impl());
303
329
304 if (firstImpl && lastImpl) {
330 if (firstImpl && lastImpl) {
305 m_Data.erase(firstImpl->m_It, lastImpl->m_It);
331 m_Data.erase(firstImpl->m_It, lastImpl->m_It);
306 }
332 }
307 }
333 }
308
334
309 /// Inserts at the end of the array data the values passed as a parameter. This
335 /// Inserts at the end of the array data the values passed as a parameter. This
310 /// method is intended to be used in the context of generating a back insert iterator, or only
336 /// method is intended to be used in the context of generating a back insert iterator, or only
311 /// if it's ensured that the total size of the vector is consistent with the number of
337 /// if it's ensured that the total size of the vector is consistent with the number of
312 /// components of the array data
338 /// components of the array data
313 /// @param values the values to insert
339 /// @param values the values to insert
314 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
340 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
315 void push_back(const QVector<double> &values)
341 void push_back(const QVector<double> &values)
316 {
342 {
317 Q_ASSERT(values.size() % m_NbComponents == 0);
343 Q_ASSERT(values.size() % m_NbComponents == 0);
318 m_Data.append(values);
344 m_Data.append(values);
319 }
345 }
320
346
321 /**
347 /**
322 * @return the data at a specified index
348 * @return the data at a specified index
323 * @remarks index must be a valid position
349 * @remarks index must be a valid position
324 */
350 */
325 double at(int index) const noexcept
351 double at(int index) const noexcept
326 {
352 {
327 QReadLocker locker{&m_Lock};
353 QReadLocker locker{&m_Lock};
328 return m_Data.at(index);
354 return m_Data.at(index);
329 }
355 }
330
356
331 // ///////////// //
357 // ///////////// //
332 // 1-dim methods //
358 // 1-dim methods //
333 // ///////////// //
359 // ///////////// //
334
360
335 /**
361 /**
336 * @return the data as a vector, as a const reference
362 * @return the data as a vector, as a const reference
337 * @remarks this method is only available for a unidimensional ArrayData
363 * @remarks this method is only available for a unidimensional ArrayData
338 */
364 */
339 template <int D = Dim, typename = std::enable_if_t<D == 1> >
365 template <int D = Dim, typename = std::enable_if_t<D == 1> >
340 const QVector<double> &cdata() const noexcept
366 const QVector<double> &cdata() const noexcept
341 {
367 {
342 QReadLocker locker{&m_Lock};
368 QReadLocker locker{&m_Lock};
343 return m_Data;
369 return m_Data;
344 }
370 }
345
371
346 private:
372 private:
347 DataContainer m_Data;
373 DataContainer m_Data;
348 /// Number of components (lines). Is always 1 in a 1-dim ArrayData
374 /// Number of components (lines). Is always 1 in a 1-dim ArrayData
349 int m_NbComponents;
375 int m_NbComponents;
350 mutable QReadWriteLock m_Lock;
376 mutable QReadWriteLock m_Lock;
351 };
377 };
352
378
353 #endif // SCIQLOP_ARRAYDATA_H
379 #endif // SCIQLOP_ARRAYDATA_H
@@ -1,68 +1,74
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 int distance(const Impl &other) const = 0;
22 virtual bool equals(const Impl &other) const = 0;
23 virtual bool equals(const Impl &other) const = 0;
24 virtual bool lowerThan(const Impl &other) const = 0;
25 virtual std::unique_ptr<Impl> advance(int offset) const = 0;
23 virtual void next() = 0;
26 virtual void next() = 0;
24 virtual void prev() = 0;
27 virtual void prev() = 0;
25 virtual double at(int componentIndex) const = 0;
28 virtual double at(int componentIndex) const = 0;
26 virtual double first() const = 0;
29 virtual double first() const = 0;
27 virtual double min() const = 0;
30 virtual double min() const = 0;
28 virtual double max() const = 0;
31 virtual double max() const = 0;
29 virtual QVector<double> values() const = 0;
32 virtual QVector<double> values() const = 0;
30
33
31 virtual void swap(Impl &other) = 0;
34 virtual void swap(Impl &other) = 0;
32 };
35 };
33
36
34 explicit ArrayDataIteratorValue(std::unique_ptr<Impl> impl);
37 explicit ArrayDataIteratorValue(std::unique_ptr<Impl> impl);
35 ArrayDataIteratorValue(const ArrayDataIteratorValue &other);
38 ArrayDataIteratorValue(const ArrayDataIteratorValue &other);
36 ArrayDataIteratorValue &operator=(ArrayDataIteratorValue other);
39 ArrayDataIteratorValue &operator=(ArrayDataIteratorValue other);
37
40
41 int distance(const ArrayDataIteratorValue &other) const;
38 bool equals(const ArrayDataIteratorValue &other) const;
42 bool equals(const ArrayDataIteratorValue &other) const;
43 bool lowerThan(const ArrayDataIteratorValue &other) const;
39
44
45 ArrayDataIteratorValue advance(int offset) const;
40 /// Advances to the next value
46 /// Advances to the next value
41 void next();
47 void next();
42 /// Moves back to the previous value
48 /// Moves back to the previous value
43 void prev();
49 void prev();
44 /// Gets value of a specified component
50 /// Gets value of a specified component
45 double at(int componentIndex) const;
51 double at(int componentIndex) const;
46 /// Gets value of first component
52 /// Gets value of first component
47 double first() const;
53 double first() const;
48 /// Gets min value among all components
54 /// Gets min value among all components
49 double min() const;
55 double min() const;
50 /// Gets max value among all components
56 /// Gets max value among all components
51 double max() const;
57 double max() const;
52 /// Gets all values
58 /// Gets all values
53 QVector<double> values() const;
59 QVector<double> values() const;
54
60
55 Impl *impl();
61 Impl *impl();
56
62
57 friend void swap(ArrayDataIteratorValue &lhs, ArrayDataIteratorValue &rhs)
63 friend void swap(ArrayDataIteratorValue &lhs, ArrayDataIteratorValue &rhs)
58 {
64 {
59 std::swap(lhs.m_Impl, rhs.m_Impl);
65 std::swap(lhs.m_Impl, rhs.m_Impl);
60 }
66 }
61
67
62 private:
68 private:
63 std::unique_ptr<Impl> m_Impl;
69 std::unique_ptr<Impl> m_Impl;
64 };
70 };
65
71
66 using ArrayDataIterator = SqpIterator<ArrayDataIteratorValue>;
72 using ArrayDataIterator = SqpIterator<ArrayDataIteratorValue>;
67
73
68 #endif // SCIQLOP_ARRAYDATAITERATOR_H
74 #endif // SCIQLOP_ARRAYDATAITERATOR_H
@@ -1,374 +1,399
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, bool IsConst>
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>;
33 friend class DataSeries<Dim>;
34
34
35 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
35 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
36 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
36 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
37 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
37 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
38 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end())
38 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end())
39 {
39 {
40 }
40 }
41
41
42 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
42 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
43 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
43 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
44 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
44 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
45 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
45 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
46 : dataSeries.valuesData()->cend())
46 : dataSeries.valuesData()->cend())
47 {
47 {
48 }
48 }
49
49
50 IteratorValue(const IteratorValue &other) = default;
50 IteratorValue(const IteratorValue &other) = default;
51
51
52 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
52 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
53 {
53 {
54 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
54 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
55 }
55 }
56
56
57 int distance(const DataSeriesIteratorValue::Impl &other) const override try {
58 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
59 return m_XIt->distance(*otherImpl.m_XIt);
60 }
61 catch (const std::bad_cast &) {
62 return 0;
63 }
64
57 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
65 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
58 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
66 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
59 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
67 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
60 }
68 }
61 catch (const std::bad_cast &) {
69 catch (const std::bad_cast &) {
62 return false;
70 return false;
63 }
71 }
64
72
73 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
74 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
75 return m_XIt->lowerThan(*otherImpl.m_XIt);
76 }
77 catch (const std::bad_cast &) {
78 return false;
79 }
80
81 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
82 {
83 auto result = clone();
84 while (offset--) {
85 result->next();
86 }
87 return result;
88 }
89
65 void next() override
90 void next() override
66 {
91 {
67 ++m_XIt;
92 ++m_XIt;
68 ++m_ValuesIt;
93 ++m_ValuesIt;
69 }
94 }
70
95
71 void prev() override
96 void prev() override
72 {
97 {
73 --m_XIt;
98 --m_XIt;
74 --m_ValuesIt;
99 --m_ValuesIt;
75 }
100 }
76
101
77 double x() const override { return m_XIt->at(0); }
102 double x() const override { return m_XIt->at(0); }
78 double value() const override { return m_ValuesIt->at(0); }
103 double value() const override { return m_ValuesIt->at(0); }
79 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
104 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
80 double minValue() const override { return m_ValuesIt->min(); }
105 double minValue() const override { return m_ValuesIt->min(); }
81 double maxValue() const override { return m_ValuesIt->max(); }
106 double maxValue() const override { return m_ValuesIt->max(); }
82 QVector<double> values() const override { return m_ValuesIt->values(); }
107 QVector<double> values() const override { return m_ValuesIt->values(); }
83
108
84 void swap(DataSeriesIteratorValue::Impl &other) override
109 void swap(DataSeriesIteratorValue::Impl &other) override
85 {
110 {
86 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
111 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
87 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
112 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
88 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
113 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
89 }
114 }
90
115
91 private:
116 private:
92 ArrayDataIterator m_XIt;
117 ArrayDataIterator m_XIt;
93 ArrayDataIterator m_ValuesIt;
118 ArrayDataIterator m_ValuesIt;
94 };
119 };
95 } // namespace dataseries_detail
120 } // namespace dataseries_detail
96
121
97 /**
122 /**
98 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
123 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
99 *
124 *
100 * It proposes to set a dimension for the values ​​data.
125 * It proposes to set a dimension for the values ​​data.
101 *
126 *
102 * A DataSeries is always sorted on its x-axis data.
127 * A DataSeries is always sorted on its x-axis data.
103 *
128 *
104 * @tparam Dim The dimension of the values data
129 * @tparam Dim The dimension of the values data
105 *
130 *
106 */
131 */
107 template <int Dim>
132 template <int Dim>
108 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
133 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
109 friend class DataSeriesMergeHelper;
134 friend class DataSeriesMergeHelper;
110
135
111 public:
136 public:
112 /// Tag needed to define the push_back() method
137 /// Tag needed to define the push_back() method
113 /// @sa push_back()
138 /// @sa push_back()
114 using value_type = DataSeriesIteratorValue;
139 using value_type = DataSeriesIteratorValue;
115
140
116 /// @sa IDataSeries::xAxisData()
141 /// @sa IDataSeries::xAxisData()
117 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
142 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
118 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
143 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
119
144
120 /// @sa IDataSeries::xAxisUnit()
145 /// @sa IDataSeries::xAxisUnit()
121 Unit xAxisUnit() const override { return m_XAxisUnit; }
146 Unit xAxisUnit() const override { return m_XAxisUnit; }
122
147
123 /// @return the values dataset
148 /// @return the values dataset
124 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
149 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
125 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
150 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
126
151
127 /// @sa IDataSeries::valuesUnit()
152 /// @sa IDataSeries::valuesUnit()
128 Unit valuesUnit() const override { return m_ValuesUnit; }
153 Unit valuesUnit() const override { return m_ValuesUnit; }
129
154
130
155
131 SqpRange range() const override
156 SqpRange range() const override
132 {
157 {
133 if (!m_XAxisData->cdata().isEmpty()) {
158 if (!m_XAxisData->cdata().isEmpty()) {
134 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
159 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
135 }
160 }
136
161
137 return SqpRange{};
162 return SqpRange{};
138 }
163 }
139
164
140 void clear()
165 void clear()
141 {
166 {
142 m_XAxisData->clear();
167 m_XAxisData->clear();
143 m_ValuesData->clear();
168 m_ValuesData->clear();
144 }
169 }
145
170
146 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
171 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
147
172
148 /// Merges into the data series an other data series
173 /// Merges into the data series an other data series
149 /// @remarks the data series to merge with is cleared after the operation
174 /// @remarks the data series to merge with is cleared after the operation
150 void merge(IDataSeries *dataSeries) override
175 void merge(IDataSeries *dataSeries) override
151 {
176 {
152 dataSeries->lockWrite();
177 dataSeries->lockWrite();
153 lockWrite();
178 lockWrite();
154
179
155 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
180 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
156 DataSeriesMergeHelper::merge(*other, *this);
181 DataSeriesMergeHelper::merge(*other, *this);
157 }
182 }
158 else {
183 else {
159 qCWarning(LOG_DataSeries())
184 qCWarning(LOG_DataSeries())
160 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
185 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
161 }
186 }
162 unlock();
187 unlock();
163 dataSeries->unlock();
188 dataSeries->unlock();
164 }
189 }
165
190
166 void purge(double min, double max) override
191 void purge(double min, double max) override
167 {
192 {
168 if (min > max) {
193 if (min > max) {
169 std::swap(min, max);
194 std::swap(min, max);
170 }
195 }
171
196
172 lockWrite();
197 lockWrite();
173
198
174 auto it = std::remove_if(
199 auto it = std::remove_if(
175 begin(), end(), [min, max](const auto &it) { return it.x() < min || it.x() > max; });
200 begin(), end(), [min, max](const auto &it) { return it.x() < min || it.x() > max; });
176 erase(it, end());
201 erase(it, end());
177
202
178 unlock();
203 unlock();
179 }
204 }
180
205
181 // ///////// //
206 // ///////// //
182 // Iterators //
207 // Iterators //
183 // ///////// //
208 // ///////// //
184
209
185 DataSeriesIterator begin() override
210 DataSeriesIterator begin() override
186 {
211 {
187 return DataSeriesIterator{DataSeriesIteratorValue{
212 return DataSeriesIterator{DataSeriesIteratorValue{
188 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
213 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
189 }
214 }
190
215
191 DataSeriesIterator end() override
216 DataSeriesIterator end() override
192 {
217 {
193 return DataSeriesIterator{DataSeriesIteratorValue{
218 return DataSeriesIterator{DataSeriesIteratorValue{
194 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
219 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
195 }
220 }
196
221
197 DataSeriesIterator cbegin() const override
222 DataSeriesIterator cbegin() const override
198 {
223 {
199 return DataSeriesIterator{DataSeriesIteratorValue{
224 return DataSeriesIterator{DataSeriesIteratorValue{
200 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
225 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
201 }
226 }
202
227
203 DataSeriesIterator cend() const override
228 DataSeriesIterator cend() const override
204 {
229 {
205 return DataSeriesIterator{DataSeriesIteratorValue{
230 return DataSeriesIterator{DataSeriesIteratorValue{
206 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
231 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
207 }
232 }
208
233
209 void erase(DataSeriesIterator first, DataSeriesIterator last)
234 void erase(DataSeriesIterator first, DataSeriesIterator last)
210 {
235 {
211 auto firstImpl
236 auto firstImpl
212 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
237 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
213 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
238 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
214
239
215 if (firstImpl && lastImpl) {
240 if (firstImpl && lastImpl) {
216 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
241 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
217 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
242 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
218 }
243 }
219 }
244 }
220
245
221 /// @sa IDataSeries::minXAxisData()
246 /// @sa IDataSeries::minXAxisData()
222 DataSeriesIterator minXAxisData(double minXAxisData) const override
247 DataSeriesIterator minXAxisData(double minXAxisData) const override
223 {
248 {
224 return std::lower_bound(
249 return std::lower_bound(
225 cbegin(), cend(), minXAxisData,
250 cbegin(), cend(), minXAxisData,
226 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
251 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
227 }
252 }
228
253
229 /// @sa IDataSeries::maxXAxisData()
254 /// @sa IDataSeries::maxXAxisData()
230 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
255 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
231 {
256 {
232 // Gets the first element that greater than max value
257 // Gets the first element that greater than max value
233 auto it = std::upper_bound(
258 auto it = std::upper_bound(
234 cbegin(), cend(), maxXAxisData,
259 cbegin(), cend(), maxXAxisData,
235 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
260 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
236
261
237 return it == cbegin() ? cend() : --it;
262 return it == cbegin() ? cend() : --it;
238 }
263 }
239
264
240 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
265 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
241 double maxXAxisData) const override
266 double maxXAxisData) const override
242 {
267 {
243 if (minXAxisData > maxXAxisData) {
268 if (minXAxisData > maxXAxisData) {
244 std::swap(minXAxisData, maxXAxisData);
269 std::swap(minXAxisData, maxXAxisData);
245 }
270 }
246
271
247 auto begin = cbegin();
272 auto begin = cbegin();
248 auto end = cend();
273 auto end = cend();
249
274
250 auto lowerIt = std::lower_bound(
275 auto lowerIt = std::lower_bound(
251 begin, end, minXAxisData,
276 begin, end, minXAxisData,
252 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
277 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
253 auto upperIt = std::upper_bound(
278 auto upperIt = std::upper_bound(
254 begin, end, maxXAxisData,
279 begin, end, maxXAxisData,
255 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
280 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
256
281
257 return std::make_pair(lowerIt, upperIt);
282 return std::make_pair(lowerIt, upperIt);
258 }
283 }
259
284
260 std::pair<DataSeriesIterator, DataSeriesIterator>
285 std::pair<DataSeriesIterator, DataSeriesIterator>
261 valuesBounds(double minXAxisData, double maxXAxisData) const override
286 valuesBounds(double minXAxisData, double maxXAxisData) const override
262 {
287 {
263 // Places iterators to the correct x-axis range
288 // Places iterators to the correct x-axis range
264 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
289 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
265
290
266 // Returns end iterators if the range is empty
291 // Returns end iterators if the range is empty
267 if (xAxisRangeIts.first == xAxisRangeIts.second) {
292 if (xAxisRangeIts.first == xAxisRangeIts.second) {
268 return std::make_pair(cend(), cend());
293 return std::make_pair(cend(), cend());
269 }
294 }
270
295
271 // Gets the iterator on the min of all values data
296 // Gets the iterator on the min of all values data
272 auto minIt = std::min_element(
297 auto minIt = std::min_element(
273 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
298 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
274 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
299 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
275 });
300 });
276
301
277 // Gets the iterator on the max of all values data
302 // Gets the iterator on the max of all values data
278 auto maxIt = std::max_element(
303 auto maxIt = std::max_element(
279 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
304 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
280 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
305 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
281 });
306 });
282
307
283 return std::make_pair(minIt, maxIt);
308 return std::make_pair(minIt, maxIt);
284 }
309 }
285
310
286 // /////// //
311 // /////// //
287 // Mutexes //
312 // Mutexes //
288 // /////// //
313 // /////// //
289
314
290 virtual void lockRead() { m_Lock.lockForRead(); }
315 virtual void lockRead() { m_Lock.lockForRead(); }
291 virtual void lockWrite() { m_Lock.lockForWrite(); }
316 virtual void lockWrite() { m_Lock.lockForWrite(); }
292 virtual void unlock() { m_Lock.unlock(); }
317 virtual void unlock() { m_Lock.unlock(); }
293
318
294 // ///// //
319 // ///// //
295 // Other //
320 // Other //
296 // ///// //
321 // ///// //
297
322
298 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
323 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
299 /// method is intended to be used in the context of generating a back insert iterator
324 /// method is intended to be used in the context of generating a back insert iterator
300 /// @param iteratorValue the iterator value containing the values to insert
325 /// @param iteratorValue the iterator value containing the values to insert
301 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
326 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
302 /// @sa merge()
327 /// @sa merge()
303 /// @sa value_type
328 /// @sa value_type
304 void push_back(const value_type &iteratorValue)
329 void push_back(const value_type &iteratorValue)
305 {
330 {
306 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
331 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
307 m_ValuesData->push_back(iteratorValue.values());
332 m_ValuesData->push_back(iteratorValue.values());
308 }
333 }
309
334
310 protected:
335 protected:
311 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
336 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
312 /// DataSeries with no values will be created.
337 /// DataSeries with no values will be created.
313 /// @remarks data series is automatically sorted on its x-axis data
338 /// @remarks data series is automatically sorted on its x-axis data
314 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
339 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
315 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
340 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
316 : m_XAxisData{xAxisData},
341 : m_XAxisData{xAxisData},
317 m_XAxisUnit{xAxisUnit},
342 m_XAxisUnit{xAxisUnit},
318 m_ValuesData{valuesData},
343 m_ValuesData{valuesData},
319 m_ValuesUnit{valuesUnit}
344 m_ValuesUnit{valuesUnit}
320 {
345 {
321 if (m_XAxisData->size() != m_ValuesData->size()) {
346 if (m_XAxisData->size() != m_ValuesData->size()) {
322 clear();
347 clear();
323 }
348 }
324
349
325 // Sorts data if it's not the case
350 // Sorts data if it's not the case
326 const auto &xAxisCData = m_XAxisData->cdata();
351 const auto &xAxisCData = m_XAxisData->cdata();
327 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
352 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
328 sort();
353 sort();
329 }
354 }
330 }
355 }
331
356
332 /// Copy ctor
357 /// Copy ctor
333 explicit DataSeries(const DataSeries<Dim> &other)
358 explicit DataSeries(const DataSeries<Dim> &other)
334 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
359 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
335 m_XAxisUnit{other.m_XAxisUnit},
360 m_XAxisUnit{other.m_XAxisUnit},
336 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
361 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
337 m_ValuesUnit{other.m_ValuesUnit}
362 m_ValuesUnit{other.m_ValuesUnit}
338 {
363 {
339 // Since a series is ordered from its construction and is always ordered, it is not
364 // Since a series is ordered from its construction and is always ordered, it is not
340 // necessary to call the sort method here ('other' is sorted)
365 // necessary to call the sort method here ('other' is sorted)
341 }
366 }
342
367
343 /// Assignment operator
368 /// Assignment operator
344 template <int D>
369 template <int D>
345 DataSeries &operator=(DataSeries<D> other)
370 DataSeries &operator=(DataSeries<D> other)
346 {
371 {
347 std::swap(m_XAxisData, other.m_XAxisData);
372 std::swap(m_XAxisData, other.m_XAxisData);
348 std::swap(m_XAxisUnit, other.m_XAxisUnit);
373 std::swap(m_XAxisUnit, other.m_XAxisUnit);
349 std::swap(m_ValuesData, other.m_ValuesData);
374 std::swap(m_ValuesData, other.m_ValuesData);
350 std::swap(m_ValuesUnit, other.m_ValuesUnit);
375 std::swap(m_ValuesUnit, other.m_ValuesUnit);
351
376
352 return *this;
377 return *this;
353 }
378 }
354
379
355 private:
380 private:
356 /**
381 /**
357 * Sorts data series on its x-axis data
382 * Sorts data series on its x-axis data
358 */
383 */
359 void sort() noexcept
384 void sort() noexcept
360 {
385 {
361 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
386 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
362 m_XAxisData = m_XAxisData->sort(permutation);
387 m_XAxisData = m_XAxisData->sort(permutation);
363 m_ValuesData = m_ValuesData->sort(permutation);
388 m_ValuesData = m_ValuesData->sort(permutation);
364 }
389 }
365
390
366 std::shared_ptr<ArrayData<1> > m_XAxisData;
391 std::shared_ptr<ArrayData<1> > m_XAxisData;
367 Unit m_XAxisUnit;
392 Unit m_XAxisUnit;
368 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
393 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
369 Unit m_ValuesUnit;
394 Unit m_ValuesUnit;
370
395
371 QReadWriteLock m_Lock;
396 QReadWriteLock m_Lock;
372 };
397 };
373
398
374 #endif // SCIQLOP_DATASERIES_H
399 #endif // SCIQLOP_DATASERIES_H
@@ -1,72 +1,78
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 int distance(const Impl &other) const = 0;
23 virtual bool equals(const Impl &other) const = 0;
24 virtual bool equals(const Impl &other) const = 0;
25 virtual bool lowerThan(const Impl &other) const = 0;
26 virtual std::unique_ptr<Impl> advance(int offset) const = 0;
24 virtual void next() = 0;
27 virtual void next() = 0;
25 virtual void prev() = 0;
28 virtual void prev() = 0;
26 virtual double x() const = 0;
29 virtual double x() const = 0;
27 virtual double value() const = 0;
30 virtual double value() const = 0;
28 virtual double value(int componentIndex) const = 0;
31 virtual double value(int componentIndex) const = 0;
29 virtual double minValue() const = 0;
32 virtual double minValue() const = 0;
30 virtual double maxValue() const = 0;
33 virtual double maxValue() const = 0;
31 virtual QVector<double> values() const = 0;
34 virtual QVector<double> values() const = 0;
32
35
33 virtual void swap(Impl &other) = 0;
36 virtual void swap(Impl &other) = 0;
34 };
37 };
35
38
36 explicit DataSeriesIteratorValue(std::unique_ptr<Impl> impl);
39 explicit DataSeriesIteratorValue(std::unique_ptr<Impl> impl);
37 DataSeriesIteratorValue(const DataSeriesIteratorValue &other);
40 DataSeriesIteratorValue(const DataSeriesIteratorValue &other);
38 DataSeriesIteratorValue &operator=(DataSeriesIteratorValue other);
41 DataSeriesIteratorValue &operator=(DataSeriesIteratorValue other);
39
42
43 int distance(const DataSeriesIteratorValue &other) const;
40 bool equals(const DataSeriesIteratorValue &other) const;
44 bool equals(const DataSeriesIteratorValue &other) const;
45 bool lowerThan(const DataSeriesIteratorValue &other) const;
41
46
47 DataSeriesIteratorValue advance(int offset) const;
42 /// Advances to the next value
48 /// Advances to the next value
43 void next();
49 void next();
44 /// Moves back to the previous value
50 /// Moves back to the previous value
45 void prev();
51 void prev();
46 /// Gets x-axis data
52 /// Gets x-axis data
47 double x() const;
53 double x() const;
48 /// Gets value data
54 /// Gets value data
49 double value() const;
55 double value() const;
50 /// Gets value data depending on an index
56 /// Gets value data depending on an index
51 double value(int componentIndex) const;
57 double value(int componentIndex) const;
52 /// Gets min of all values data
58 /// Gets min of all values data
53 double minValue() const;
59 double minValue() const;
54 /// Gets max of all values data
60 /// Gets max of all values data
55 double maxValue() const;
61 double maxValue() const;
56 /// Gets all values data
62 /// Gets all values data
57 QVector<double> values() const;
63 QVector<double> values() const;
58
64
59 Impl *impl();
65 Impl *impl();
60
66
61 friend void swap(DataSeriesIteratorValue &lhs, DataSeriesIteratorValue &rhs)
67 friend void swap(DataSeriesIteratorValue &lhs, DataSeriesIteratorValue &rhs)
62 {
68 {
63 std::swap(lhs.m_Impl, rhs.m_Impl);
69 std::swap(lhs.m_Impl, rhs.m_Impl);
64 }
70 }
65
71
66 private:
72 private:
67 std::unique_ptr<Impl> m_Impl;
73 std::unique_ptr<Impl> m_Impl;
68 };
74 };
69
75
70 using DataSeriesIterator = SqpIterator<DataSeriesIteratorValue>;
76 using DataSeriesIterator = SqpIterator<DataSeriesIteratorValue>;
71
77
72 #endif // SCIQLOP_DATASERIESITERATOR_H
78 #endif // SCIQLOP_DATASERIESITERATOR_H
@@ -1,54 +1,110
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::random_access_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 &operator=(SqpIterator other) { swap(m_CurrentValue, other.m_CurrentValue); }
25 SqpIterator &operator=(SqpIterator other) { swap(m_CurrentValue, other.m_CurrentValue); }
26
26
27 SqpIterator &operator++()
27 SqpIterator &operator++()
28 {
28 {
29 m_CurrentValue.next();
29 m_CurrentValue.next();
30 return *this;
30 return *this;
31 }
31 }
32
32
33 SqpIterator &operator--()
33 SqpIterator &operator--()
34 {
34 {
35 m_CurrentValue.prev();
35 m_CurrentValue.prev();
36 return *this;
36 return *this;
37 }
37 }
38
38
39 SqpIterator operator++(int)const
40 {
41 auto result = *this;
42 this->operator++();
43 return result;
44 }
45 SqpIterator operator--(int)const
46 {
47 auto result = *this;
48 this->operator--();
49 return result;
50 }
51
52 SqpIterator &operator+=(int offset)
53 {
54 if (offset >= 0) {
55 while (offset--) {
56 m_CurrentValue.next();
57 }
58 }
59 else {
60 while (offset++) {
61 m_CurrentValue.prev();
62 }
63 }
64
65 return *this;
66 }
67 SqpIterator &operator-=(int offset) { return *this += -offset; }
68
69 SqpIterator operator+(int offset) const
70 {
71 auto result = *this;
72 result += offset;
73 return result;
74 }
75 SqpIterator operator-(int offset) const
76 {
77 auto result = *this;
78 result -= offset;
79 return result;
80 }
81
82 int operator-(const SqpIterator &other) const
83 {
84 return m_CurrentValue.distance(other.m_CurrentValue);
85 }
86
39 const T *operator->() const { return &m_CurrentValue; }
87 const T *operator->() const { return &m_CurrentValue; }
40 const T &operator*() const { return m_CurrentValue; }
88 const T &operator*() const { return m_CurrentValue; }
41 T *operator->() { return &m_CurrentValue; }
89 T *operator->() { return &m_CurrentValue; }
42 T &operator*() { return m_CurrentValue; }
90 T &operator*() { return m_CurrentValue; }
91 T &operator[](int offset) const { return m_CurrentValue.advance(offset); }
43
92
44 bool operator==(const SqpIterator &other) const
93 bool operator==(const SqpIterator &other) const
45 {
94 {
46 return m_CurrentValue.equals(other.m_CurrentValue);
95 return m_CurrentValue.equals(other.m_CurrentValue);
47 }
96 }
48 bool operator!=(const SqpIterator &other) const { return !(*this == other); }
97 bool operator!=(const SqpIterator &other) const { return !(*this == other); }
98 bool operator>(const SqpIterator &other) const { return other.m_CurrentValue.lowerThan(*this); }
99 bool operator<(const SqpIterator &other) const
100 {
101 return m_CurrentValue.lowerThan(other.m_CurrentValue);
102 }
103 bool operator>=(const SqpIterator &other) const { return !(*this < other); }
104 bool operator<=(const SqpIterator &other) const { return !(*this > other); }
49
105
50 private:
106 private:
51 T m_CurrentValue;
107 T m_CurrentValue;
52 };
108 };
53
109
54 #endif // SCIQLOP_SQPITERATOR_H
110 #endif // SCIQLOP_SQPITERATOR_H
@@ -1,62 +1,77
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 m_Impl->swap(*other.m_Impl);
15 m_Impl->swap(*other.m_Impl);
16 return *this;
16 return *this;
17 }
17 }
18
18
19 int ArrayDataIteratorValue::distance(const ArrayDataIteratorValue &other) const
20 {
21 return m_Impl->distance(*other.m_Impl);
22 }
23
19 bool ArrayDataIteratorValue::equals(const ArrayDataIteratorValue &other) const
24 bool ArrayDataIteratorValue::equals(const ArrayDataIteratorValue &other) const
20 {
25 {
21 return m_Impl->equals(*other.m_Impl);
26 return m_Impl->equals(*other.m_Impl);
22 }
27 }
23
28
29 bool ArrayDataIteratorValue::lowerThan(const ArrayDataIteratorValue &other) const
30 {
31 return m_Impl->lowerThan(*other.m_Impl);
32 }
33
34 ArrayDataIteratorValue ArrayDataIteratorValue::advance(int offset) const
35 {
36 return ArrayDataIteratorValue{m_Impl->advance(offset)};
37 }
38
24 void ArrayDataIteratorValue::next()
39 void ArrayDataIteratorValue::next()
25 {
40 {
26 m_Impl->next();
41 m_Impl->next();
27 }
42 }
28
43
29 void ArrayDataIteratorValue::prev()
44 void ArrayDataIteratorValue::prev()
30 {
45 {
31 m_Impl->prev();
46 m_Impl->prev();
32 }
47 }
33
48
34 double ArrayDataIteratorValue::at(int componentIndex) const
49 double ArrayDataIteratorValue::at(int componentIndex) const
35 {
50 {
36 return m_Impl->at(componentIndex);
51 return m_Impl->at(componentIndex);
37 }
52 }
38
53
39 double ArrayDataIteratorValue::first() const
54 double ArrayDataIteratorValue::first() const
40 {
55 {
41 return m_Impl->first();
56 return m_Impl->first();
42 }
57 }
43
58
44 double ArrayDataIteratorValue::min() const
59 double ArrayDataIteratorValue::min() const
45 {
60 {
46 return m_Impl->min();
61 return m_Impl->min();
47 }
62 }
48
63
49 double ArrayDataIteratorValue::max() const
64 double ArrayDataIteratorValue::max() const
50 {
65 {
51 return m_Impl->max();
66 return m_Impl->max();
52 }
67 }
53
68
54 QVector<double> ArrayDataIteratorValue::values() const
69 QVector<double> ArrayDataIteratorValue::values() const
55 {
70 {
56 return m_Impl->values();
71 return m_Impl->values();
57 }
72 }
58
73
59 ArrayDataIteratorValue::Impl *ArrayDataIteratorValue::impl()
74 ArrayDataIteratorValue::Impl *ArrayDataIteratorValue::impl()
60 {
75 {
61 return m_Impl.get();
76 return m_Impl.get();
62 }
77 }
@@ -1,68 +1,84
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 m_Impl->swap(*other.m_Impl);
16 m_Impl->swap(*other.m_Impl);
17 return *this;
17 return *this;
18 }
18 }
19
19
20 int DataSeriesIteratorValue::distance(const DataSeriesIteratorValue &other) const
21 {
22 auto dist = m_Impl->distance(*other.m_Impl);
23 return m_Impl->distance(*other.m_Impl);
24 }
25
20 bool DataSeriesIteratorValue::equals(const DataSeriesIteratorValue &other) const
26 bool DataSeriesIteratorValue::equals(const DataSeriesIteratorValue &other) const
21 {
27 {
22 return m_Impl->equals(*other.m_Impl);
28 return m_Impl->equals(*other.m_Impl);
23 }
29 }
24
30
31 bool DataSeriesIteratorValue::lowerThan(const DataSeriesIteratorValue &other) const
32 {
33 return m_Impl->lowerThan(*other.m_Impl);
34 }
35
36 DataSeriesIteratorValue DataSeriesIteratorValue::advance(int offset) const
37 {
38 return DataSeriesIteratorValue{m_Impl->advance(offset)};
39 }
40
25 void DataSeriesIteratorValue::next()
41 void DataSeriesIteratorValue::next()
26 {
42 {
27 m_Impl->next();
43 m_Impl->next();
28 }
44 }
29
45
30 void DataSeriesIteratorValue::prev()
46 void DataSeriesIteratorValue::prev()
31 {
47 {
32 m_Impl->prev();
48 m_Impl->prev();
33 }
49 }
34
50
35 double DataSeriesIteratorValue::x() const
51 double DataSeriesIteratorValue::x() const
36 {
52 {
37 return m_Impl->x();
53 return m_Impl->x();
38 }
54 }
39
55
40 double DataSeriesIteratorValue::value() const
56 double DataSeriesIteratorValue::value() const
41 {
57 {
42 return m_Impl->value();
58 return m_Impl->value();
43 }
59 }
44
60
45 double DataSeriesIteratorValue::value(int componentIndex) const
61 double DataSeriesIteratorValue::value(int componentIndex) const
46 {
62 {
47 return m_Impl->value(componentIndex);
63 return m_Impl->value(componentIndex);
48 }
64 }
49
65
50 double DataSeriesIteratorValue::minValue() const
66 double DataSeriesIteratorValue::minValue() const
51 {
67 {
52 return m_Impl->minValue();
68 return m_Impl->minValue();
53 }
69 }
54
70
55 double DataSeriesIteratorValue::maxValue() const
71 double DataSeriesIteratorValue::maxValue() const
56 {
72 {
57 return m_Impl->maxValue();
73 return m_Impl->maxValue();
58 }
74 }
59
75
60 QVector<double> DataSeriesIteratorValue::values() const
76 QVector<double> DataSeriesIteratorValue::values() const
61 {
77 {
62 return m_Impl->values();
78 return m_Impl->values();
63 }
79 }
64
80
65 DataSeriesIteratorValue::Impl *DataSeriesIteratorValue::impl()
81 DataSeriesIteratorValue::Impl *DataSeriesIteratorValue::impl()
66 {
82 {
67 return m_Impl.get();
83 return m_Impl.get();
68 }
84 }
General Comments 0
You need to be logged in to leave comments. Login now