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