##// END OF EJS Templates
Improves purge method
Alexandre Leroux -
r690:03eea8848b1d
parent child
Show More
@@ -1,399 +1,410
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 {
57 int distance(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 m_XIt->distance(*otherImpl.m_XIt);
59 return m_XIt->distance(*otherImpl.m_XIt);
60 }
60 }
61 catch (const std::bad_cast &) {
61 catch (const std::bad_cast &) {
62 return 0;
62 return 0;
63 }
63 }
64
64
65 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
65 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
66 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
66 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
67 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);
68 }
68 }
69 catch (const std::bad_cast &) {
69 catch (const std::bad_cast &) {
70 return false;
70 return false;
71 }
71 }
72
72
73 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
73 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
74 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
74 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
75 return m_XIt->lowerThan(*otherImpl.m_XIt);
75 return m_XIt->lowerThan(*otherImpl.m_XIt);
76 }
76 }
77 catch (const std::bad_cast &) {
77 catch (const std::bad_cast &) {
78 return false;
78 return false;
79 }
79 }
80
80
81 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
81 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
82 {
82 {
83 auto result = clone();
83 auto result = clone();
84 while (offset--) {
84 while (offset--) {
85 result->next();
85 result->next();
86 }
86 }
87 return result;
87 return result;
88 }
88 }
89
89
90 void next() override
90 void next() override
91 {
91 {
92 ++m_XIt;
92 ++m_XIt;
93 ++m_ValuesIt;
93 ++m_ValuesIt;
94 }
94 }
95
95
96 void prev() override
96 void prev() override
97 {
97 {
98 --m_XIt;
98 --m_XIt;
99 --m_ValuesIt;
99 --m_ValuesIt;
100 }
100 }
101
101
102 double x() const override { return m_XIt->at(0); }
102 double x() const override { return m_XIt->at(0); }
103 double value() const override { return m_ValuesIt->at(0); }
103 double value() const override { return m_ValuesIt->at(0); }
104 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
104 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
105 double minValue() const override { return m_ValuesIt->min(); }
105 double minValue() const override { return m_ValuesIt->min(); }
106 double maxValue() const override { return m_ValuesIt->max(); }
106 double maxValue() const override { return m_ValuesIt->max(); }
107 QVector<double> values() const override { return m_ValuesIt->values(); }
107 QVector<double> values() const override { return m_ValuesIt->values(); }
108
108
109 void swap(DataSeriesIteratorValue::Impl &other) override
109 void swap(DataSeriesIteratorValue::Impl &other) override
110 {
110 {
111 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
111 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
112 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
112 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
113 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
113 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
114 }
114 }
115
115
116 private:
116 private:
117 ArrayDataIterator m_XIt;
117 ArrayDataIterator m_XIt;
118 ArrayDataIterator m_ValuesIt;
118 ArrayDataIterator m_ValuesIt;
119 };
119 };
120 } // namespace dataseries_detail
120 } // namespace dataseries_detail
121
121
122 /**
122 /**
123 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
123 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
124 *
124 *
125 * It proposes to set a dimension for the values ​​data.
125 * It proposes to set a dimension for the values ​​data.
126 *
126 *
127 * A DataSeries is always sorted on its x-axis data.
127 * A DataSeries is always sorted on its x-axis data.
128 *
128 *
129 * @tparam Dim The dimension of the values data
129 * @tparam Dim The dimension of the values data
130 *
130 *
131 */
131 */
132 template <int Dim>
132 template <int Dim>
133 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
133 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
134 friend class DataSeriesMergeHelper;
134 friend class DataSeriesMergeHelper;
135
135
136 public:
136 public:
137 /// Tag needed to define the push_back() method
137 /// Tag needed to define the push_back() method
138 /// @sa push_back()
138 /// @sa push_back()
139 using value_type = DataSeriesIteratorValue;
139 using value_type = DataSeriesIteratorValue;
140
140
141 /// @sa IDataSeries::xAxisData()
141 /// @sa IDataSeries::xAxisData()
142 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
142 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
143 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
143 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
144
144
145 /// @sa IDataSeries::xAxisUnit()
145 /// @sa IDataSeries::xAxisUnit()
146 Unit xAxisUnit() const override { return m_XAxisUnit; }
146 Unit xAxisUnit() const override { return m_XAxisUnit; }
147
147
148 /// @return the values dataset
148 /// @return the values dataset
149 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
149 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
150 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
150 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
151
151
152 /// @sa IDataSeries::valuesUnit()
152 /// @sa IDataSeries::valuesUnit()
153 Unit valuesUnit() const override { return m_ValuesUnit; }
153 Unit valuesUnit() const override { return m_ValuesUnit; }
154
154
155
155
156 SqpRange range() const override
156 SqpRange range() const override
157 {
157 {
158 if (!m_XAxisData->cdata().isEmpty()) {
158 if (!m_XAxisData->cdata().isEmpty()) {
159 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
159 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
160 }
160 }
161
161
162 return SqpRange{};
162 return SqpRange{};
163 }
163 }
164
164
165 void clear()
165 void clear()
166 {
166 {
167 m_XAxisData->clear();
167 m_XAxisData->clear();
168 m_ValuesData->clear();
168 m_ValuesData->clear();
169 }
169 }
170
170
171 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
171 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
172
172
173 /// Merges into the data series an other data series
173 /// Merges into the data series an other data series
174 /// @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
175 void merge(IDataSeries *dataSeries) override
175 void merge(IDataSeries *dataSeries) override
176 {
176 {
177 dataSeries->lockWrite();
177 dataSeries->lockWrite();
178 lockWrite();
178 lockWrite();
179
179
180 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
180 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
181 DataSeriesMergeHelper::merge(*other, *this);
181 DataSeriesMergeHelper::merge(*other, *this);
182 }
182 }
183 else {
183 else {
184 qCWarning(LOG_DataSeries())
184 qCWarning(LOG_DataSeries())
185 << 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 !");
186 }
186 }
187 unlock();
187 unlock();
188 dataSeries->unlock();
188 dataSeries->unlock();
189 }
189 }
190
190
191 void purge(double min, double max) override
191 void purge(double min, double max) override
192 {
192 {
193 // Nothing to purge if series is empty
194 if (isEmpty()) {
195 return;
196 }
197
193 if (min > max) {
198 if (min > max) {
194 std::swap(min, max);
199 std::swap(min, max);
195 }
200 }
196
201
197 lockWrite();
202 // Nothing to purge if series min/max are inside purge range
198
203 auto xMin = cbegin()->x();
199 auto it = std::remove_if(
204 auto xMax = (--cend())->x();
200 begin(), end(), [min, max](const auto &it) { return it.x() < min || it.x() > max; });
205 if (xMin >= min && xMax <= max) {
201 erase(it, end());
206 return;
207 }
202
208
203 unlock();
209 auto lowerIt = std::lower_bound(
210 begin(), end(), min, [](const auto &it, const auto &val) { return it.x() < val; });
211 erase(begin(), lowerIt);
212 auto upperIt = std::upper_bound(
213 begin(), end(), max, [](const auto &val, const auto &it) { return val < it.x(); });
214 erase(upperIt, end());
204 }
215 }
205
216
206 // ///////// //
217 // ///////// //
207 // Iterators //
218 // Iterators //
208 // ///////// //
219 // ///////// //
209
220
210 DataSeriesIterator begin() override
221 DataSeriesIterator begin() override
211 {
222 {
212 return DataSeriesIterator{DataSeriesIteratorValue{
223 return DataSeriesIterator{DataSeriesIteratorValue{
213 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
224 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
214 }
225 }
215
226
216 DataSeriesIterator end() override
227 DataSeriesIterator end() override
217 {
228 {
218 return DataSeriesIterator{DataSeriesIteratorValue{
229 return DataSeriesIterator{DataSeriesIteratorValue{
219 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
230 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
220 }
231 }
221
232
222 DataSeriesIterator cbegin() const override
233 DataSeriesIterator cbegin() const override
223 {
234 {
224 return DataSeriesIterator{DataSeriesIteratorValue{
235 return DataSeriesIterator{DataSeriesIteratorValue{
225 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
236 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
226 }
237 }
227
238
228 DataSeriesIterator cend() const override
239 DataSeriesIterator cend() const override
229 {
240 {
230 return DataSeriesIterator{DataSeriesIteratorValue{
241 return DataSeriesIterator{DataSeriesIteratorValue{
231 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
242 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
232 }
243 }
233
244
234 void erase(DataSeriesIterator first, DataSeriesIterator last)
245 void erase(DataSeriesIterator first, DataSeriesIterator last)
235 {
246 {
236 auto firstImpl
247 auto firstImpl
237 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
248 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
238 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
249 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
239
250
240 if (firstImpl && lastImpl) {
251 if (firstImpl && lastImpl) {
241 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
252 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
242 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
253 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
243 }
254 }
244 }
255 }
245
256
246 /// @sa IDataSeries::minXAxisData()
257 /// @sa IDataSeries::minXAxisData()
247 DataSeriesIterator minXAxisData(double minXAxisData) const override
258 DataSeriesIterator minXAxisData(double minXAxisData) const override
248 {
259 {
249 return std::lower_bound(
260 return std::lower_bound(
250 cbegin(), cend(), minXAxisData,
261 cbegin(), cend(), minXAxisData,
251 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
262 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
252 }
263 }
253
264
254 /// @sa IDataSeries::maxXAxisData()
265 /// @sa IDataSeries::maxXAxisData()
255 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
266 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
256 {
267 {
257 // Gets the first element that greater than max value
268 // Gets the first element that greater than max value
258 auto it = std::upper_bound(
269 auto it = std::upper_bound(
259 cbegin(), cend(), maxXAxisData,
270 cbegin(), cend(), maxXAxisData,
260 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
271 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
261
272
262 return it == cbegin() ? cend() : --it;
273 return it == cbegin() ? cend() : --it;
263 }
274 }
264
275
265 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
276 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
266 double maxXAxisData) const override
277 double maxXAxisData) const override
267 {
278 {
268 if (minXAxisData > maxXAxisData) {
279 if (minXAxisData > maxXAxisData) {
269 std::swap(minXAxisData, maxXAxisData);
280 std::swap(minXAxisData, maxXAxisData);
270 }
281 }
271
282
272 auto begin = cbegin();
283 auto begin = cbegin();
273 auto end = cend();
284 auto end = cend();
274
285
275 auto lowerIt = std::lower_bound(
286 auto lowerIt = std::lower_bound(
276 begin, end, minXAxisData,
287 begin, end, minXAxisData,
277 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
288 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
278 auto upperIt = std::upper_bound(
289 auto upperIt = std::upper_bound(
279 begin, end, maxXAxisData,
290 begin, end, maxXAxisData,
280 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
291 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
281
292
282 return std::make_pair(lowerIt, upperIt);
293 return std::make_pair(lowerIt, upperIt);
283 }
294 }
284
295
285 std::pair<DataSeriesIterator, DataSeriesIterator>
296 std::pair<DataSeriesIterator, DataSeriesIterator>
286 valuesBounds(double minXAxisData, double maxXAxisData) const override
297 valuesBounds(double minXAxisData, double maxXAxisData) const override
287 {
298 {
288 // Places iterators to the correct x-axis range
299 // Places iterators to the correct x-axis range
289 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
300 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
290
301
291 // Returns end iterators if the range is empty
302 // Returns end iterators if the range is empty
292 if (xAxisRangeIts.first == xAxisRangeIts.second) {
303 if (xAxisRangeIts.first == xAxisRangeIts.second) {
293 return std::make_pair(cend(), cend());
304 return std::make_pair(cend(), cend());
294 }
305 }
295
306
296 // Gets the iterator on the min of all values data
307 // Gets the iterator on the min of all values data
297 auto minIt = std::min_element(
308 auto minIt = std::min_element(
298 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
309 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
299 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
310 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
300 });
311 });
301
312
302 // Gets the iterator on the max of all values data
313 // Gets the iterator on the max of all values data
303 auto maxIt = std::max_element(
314 auto maxIt = std::max_element(
304 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
315 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
305 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
316 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
306 });
317 });
307
318
308 return std::make_pair(minIt, maxIt);
319 return std::make_pair(minIt, maxIt);
309 }
320 }
310
321
311 // /////// //
322 // /////// //
312 // Mutexes //
323 // Mutexes //
313 // /////// //
324 // /////// //
314
325
315 virtual void lockRead() { m_Lock.lockForRead(); }
326 virtual void lockRead() { m_Lock.lockForRead(); }
316 virtual void lockWrite() { m_Lock.lockForWrite(); }
327 virtual void lockWrite() { m_Lock.lockForWrite(); }
317 virtual void unlock() { m_Lock.unlock(); }
328 virtual void unlock() { m_Lock.unlock(); }
318
329
319 // ///// //
330 // ///// //
320 // Other //
331 // Other //
321 // ///// //
332 // ///// //
322
333
323 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
334 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
324 /// method is intended to be used in the context of generating a back insert iterator
335 /// method is intended to be used in the context of generating a back insert iterator
325 /// @param iteratorValue the iterator value containing the values to insert
336 /// @param iteratorValue the iterator value containing the values to insert
326 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
337 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
327 /// @sa merge()
338 /// @sa merge()
328 /// @sa value_type
339 /// @sa value_type
329 void push_back(const value_type &iteratorValue)
340 void push_back(const value_type &iteratorValue)
330 {
341 {
331 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
342 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
332 m_ValuesData->push_back(iteratorValue.values());
343 m_ValuesData->push_back(iteratorValue.values());
333 }
344 }
334
345
335 protected:
346 protected:
336 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
347 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
337 /// DataSeries with no values will be created.
348 /// DataSeries with no values will be created.
338 /// @remarks data series is automatically sorted on its x-axis data
349 /// @remarks data series is automatically sorted on its x-axis data
339 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
350 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
340 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
351 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
341 : m_XAxisData{xAxisData},
352 : m_XAxisData{xAxisData},
342 m_XAxisUnit{xAxisUnit},
353 m_XAxisUnit{xAxisUnit},
343 m_ValuesData{valuesData},
354 m_ValuesData{valuesData},
344 m_ValuesUnit{valuesUnit}
355 m_ValuesUnit{valuesUnit}
345 {
356 {
346 if (m_XAxisData->size() != m_ValuesData->size()) {
357 if (m_XAxisData->size() != m_ValuesData->size()) {
347 clear();
358 clear();
348 }
359 }
349
360
350 // Sorts data if it's not the case
361 // Sorts data if it's not the case
351 const auto &xAxisCData = m_XAxisData->cdata();
362 const auto &xAxisCData = m_XAxisData->cdata();
352 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
363 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
353 sort();
364 sort();
354 }
365 }
355 }
366 }
356
367
357 /// Copy ctor
368 /// Copy ctor
358 explicit DataSeries(const DataSeries<Dim> &other)
369 explicit DataSeries(const DataSeries<Dim> &other)
359 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
370 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
360 m_XAxisUnit{other.m_XAxisUnit},
371 m_XAxisUnit{other.m_XAxisUnit},
361 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
372 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
362 m_ValuesUnit{other.m_ValuesUnit}
373 m_ValuesUnit{other.m_ValuesUnit}
363 {
374 {
364 // Since a series is ordered from its construction and is always ordered, it is not
375 // Since a series is ordered from its construction and is always ordered, it is not
365 // necessary to call the sort method here ('other' is sorted)
376 // necessary to call the sort method here ('other' is sorted)
366 }
377 }
367
378
368 /// Assignment operator
379 /// Assignment operator
369 template <int D>
380 template <int D>
370 DataSeries &operator=(DataSeries<D> other)
381 DataSeries &operator=(DataSeries<D> other)
371 {
382 {
372 std::swap(m_XAxisData, other.m_XAxisData);
383 std::swap(m_XAxisData, other.m_XAxisData);
373 std::swap(m_XAxisUnit, other.m_XAxisUnit);
384 std::swap(m_XAxisUnit, other.m_XAxisUnit);
374 std::swap(m_ValuesData, other.m_ValuesData);
385 std::swap(m_ValuesData, other.m_ValuesData);
375 std::swap(m_ValuesUnit, other.m_ValuesUnit);
386 std::swap(m_ValuesUnit, other.m_ValuesUnit);
376
387
377 return *this;
388 return *this;
378 }
389 }
379
390
380 private:
391 private:
381 /**
392 /**
382 * Sorts data series on its x-axis data
393 * Sorts data series on its x-axis data
383 */
394 */
384 void sort() noexcept
395 void sort() noexcept
385 {
396 {
386 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
397 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
387 m_XAxisData = m_XAxisData->sort(permutation);
398 m_XAxisData = m_XAxisData->sort(permutation);
388 m_ValuesData = m_ValuesData->sort(permutation);
399 m_ValuesData = m_ValuesData->sort(permutation);
389 }
400 }
390
401
391 std::shared_ptr<ArrayData<1> > m_XAxisData;
402 std::shared_ptr<ArrayData<1> > m_XAxisData;
392 Unit m_XAxisUnit;
403 Unit m_XAxisUnit;
393 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
404 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
394 Unit m_ValuesUnit;
405 Unit m_ValuesUnit;
395
406
396 QReadWriteLock m_Lock;
407 QReadWriteLock m_Lock;
397 };
408 };
398
409
399 #endif // SCIQLOP_DATASERIES_H
410 #endif // SCIQLOP_DATASERIES_H
General Comments 0
You need to be logged in to leave comments. Login now