##// END OF EJS Templates
Creates iterator for DataSeries
Alexandre Leroux -
r524:cbc24d18371d
parent child
Show More
@@ -1,190 +1,267
1 #ifndef SCIQLOP_DATASERIES_H
1 #ifndef SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
3
3
4 #include <Common/SortUtils.h>
4 #include <Common/SortUtils.h>
5
5
6 #include <Data/ArrayData.h>
6 #include <Data/ArrayData.h>
7 #include <Data/IDataSeries.h>
7 #include <Data/IDataSeries.h>
8
8
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10
10
11 #include <QReadLocker>
11 #include <QReadLocker>
12 #include <QReadWriteLock>
12 #include <QReadWriteLock>
13 #include <memory>
13 #include <memory>
14
14
15 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
16 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
16 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
17
17
18
18
19 /**
19 /**
20 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
20 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
21 *
21 *
22 * It proposes to set a dimension for the values ​​data.
22 * It proposes to set a dimension for the values ​​data.
23 *
23 *
24 * A DataSeries is always sorted on its x-axis data.
24 * A DataSeries is always sorted on its x-axis data.
25 *
25 *
26 * @tparam Dim The dimension of the values data
26 * @tparam Dim The dimension of the values data
27 *
27 *
28 */
28 */
29 template <int Dim>
29 template <int Dim>
30 class DataSeries : public IDataSeries {
30 class DataSeries : public IDataSeries {
31 public:
31 public:
32 class IteratorValue {
33 public:
34 explicit IteratorValue(const DataSeries &dataSeries, bool begin)
35 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
36 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
37 : dataSeries.valuesData()->cend())
38 {
39 }
40
41 double x() const { return m_XIt->at(0); }
42 double value() const { return m_ValuesIt->at(0); }
43 double value(int componentIndex) const { return m_ValuesIt->at(componentIndex); }
44
45 void next()
46 {
47 ++m_XIt;
48 ++m_ValuesIt;
49 }
50
51 bool operator==(const IteratorValue &other) const
52 {
53 return std::tie(m_XIt, m_ValuesIt) == std::tie(other.m_XIt, other.m_ValuesIt);
54 }
55
56 private:
57 ArrayData<1>::Iterator m_XIt;
58 typename ArrayData<Dim>::Iterator m_ValuesIt;
59 };
60
61 class Iterator {
62 public:
63 using iterator_category = std::forward_iterator_tag;
64 using value_type = const IteratorValue;
65 using difference_type = std::ptrdiff_t;
66 using pointer = value_type *;
67 using reference = value_type &;
68
69 Iterator(const DataSeries &dataSeries, bool begin) : m_CurrentValue{dataSeries, begin} {}
70 virtual ~Iterator() noexcept = default;
71 Iterator(const Iterator &) = default;
72 Iterator(Iterator &&) = default;
73 Iterator &operator=(const Iterator &) = default;
74 Iterator &operator=(Iterator &&) = default;
75
76 Iterator &operator++()
77 {
78 m_CurrentValue.next();
79 return *this;
80 }
81
82 pointer operator->() const { return &m_CurrentValue; }
83
84 reference operator*() const { return m_CurrentValue; }
85
86 bool operator==(const Iterator &other) const
87 {
88 return m_CurrentValue == other.m_CurrentValue;
89 }
90
91 bool operator!=(const Iterator &other) const { return !(*this == other); }
92
93 private:
94 IteratorValue m_CurrentValue;
95 };
96
32 /// @sa IDataSeries::xAxisData()
97 /// @sa IDataSeries::xAxisData()
33 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
98 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
34 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
99 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
35
100
36 /// @sa IDataSeries::xAxisUnit()
101 /// @sa IDataSeries::xAxisUnit()
37 Unit xAxisUnit() const override { return m_XAxisUnit; }
102 Unit xAxisUnit() const override { return m_XAxisUnit; }
38
103
39 /// @return the values dataset
104 /// @return the values dataset
40 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
105 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
41 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
106 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
42
107
43 /// @sa IDataSeries::valuesUnit()
108 /// @sa IDataSeries::valuesUnit()
44 Unit valuesUnit() const override { return m_ValuesUnit; }
109 Unit valuesUnit() const override { return m_ValuesUnit; }
45
110
46
111
47 SqpRange range() const override
112 SqpRange range() const override
48 {
113 {
49 if (!m_XAxisData->cdata().isEmpty()) {
114 if (!m_XAxisData->cdata().isEmpty()) {
50 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
115 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
51 }
116 }
52
117
53 return SqpRange{};
118 return SqpRange{};
54 }
119 }
55
120
56 void clear()
121 void clear()
57 {
122 {
58 m_XAxisData->clear();
123 m_XAxisData->clear();
59 m_ValuesData->clear();
124 m_ValuesData->clear();
60 }
125 }
61
126
62 /// Merges into the data series an other data series
127 /// Merges into the data series an other data series
63 /// @remarks the data series to merge with is cleared after the operation
128 /// @remarks the data series to merge with is cleared after the operation
64 void merge(IDataSeries *dataSeries) override
129 void merge(IDataSeries *dataSeries) override
65 {
130 {
66 dataSeries->lockWrite();
131 dataSeries->lockWrite();
67 lockWrite();
132 lockWrite();
68
133
69 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
134 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
70 const auto &otherXAxisData = other->xAxisData()->cdata();
135 const auto &otherXAxisData = other->xAxisData()->cdata();
71 const auto &xAxisData = m_XAxisData->cdata();
136 const auto &xAxisData = m_XAxisData->cdata();
72
137
73 // As data series are sorted, we can improve performances of merge, by call the sort
138 // As data series are sorted, we can improve performances of merge, by call the sort
74 // method only if the two data series overlap.
139 // method only if the two data series overlap.
75 if (!otherXAxisData.empty()) {
140 if (!otherXAxisData.empty()) {
76 auto firstValue = otherXAxisData.front();
141 auto firstValue = otherXAxisData.front();
77 auto lastValue = otherXAxisData.back();
142 auto lastValue = otherXAxisData.back();
78
143
79 auto xAxisDataBegin = xAxisData.cbegin();
144 auto xAxisDataBegin = xAxisData.cbegin();
80 auto xAxisDataEnd = xAxisData.cend();
145 auto xAxisDataEnd = xAxisData.cend();
81
146
82 bool prepend;
147 bool prepend;
83 bool sortNeeded;
148 bool sortNeeded;
84
149
85 if (std::lower_bound(xAxisDataBegin, xAxisDataEnd, firstValue) == xAxisDataEnd) {
150 if (std::lower_bound(xAxisDataBegin, xAxisDataEnd, firstValue) == xAxisDataEnd) {
86 // Other data series if after data series
151 // Other data series if after data series
87 prepend = false;
152 prepend = false;
88 sortNeeded = false;
153 sortNeeded = false;
89 }
154 }
90 else if (std::upper_bound(xAxisDataBegin, xAxisDataEnd, lastValue)
155 else if (std::upper_bound(xAxisDataBegin, xAxisDataEnd, lastValue)
91 == xAxisDataBegin) {
156 == xAxisDataBegin) {
92 // Other data series if before data series
157 // Other data series if before data series
93 prepend = true;
158 prepend = true;
94 sortNeeded = false;
159 sortNeeded = false;
95 }
160 }
96 else {
161 else {
97 // The two data series overlap
162 // The two data series overlap
98 prepend = false;
163 prepend = false;
99 sortNeeded = true;
164 sortNeeded = true;
100 }
165 }
101
166
102 // Makes the merge
167 // Makes the merge
103 m_XAxisData->add(*other->xAxisData(), prepend);
168 m_XAxisData->add(*other->xAxisData(), prepend);
104 m_ValuesData->add(*other->valuesData(), prepend);
169 m_ValuesData->add(*other->valuesData(), prepend);
105
170
106 if (sortNeeded) {
171 if (sortNeeded) {
107 sort();
172 sort();
108 }
173 }
109 }
174 }
110
175
111 // Clears the other data series
176 // Clears the other data series
112 other->clear();
177 other->clear();
113 }
178 }
114 else {
179 else {
115 qCWarning(LOG_DataSeries())
180 qCWarning(LOG_DataSeries())
116 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
181 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
117 }
182 }
118 unlock();
183 unlock();
119 dataSeries->unlock();
184 dataSeries->unlock();
120 }
185 }
121
186
187 // ///////// //
188 // Iterators //
189 // ///////// //
190
191 Iterator cbegin() const { return Iterator{*this, true}; }
192
193 Iterator cend() const { return Iterator{*this, false}; }
194
195 // /////// //
196 // Mutexes //
197 // /////// //
198
122 virtual void lockRead() { m_Lock.lockForRead(); }
199 virtual void lockRead() { m_Lock.lockForRead(); }
123 virtual void lockWrite() { m_Lock.lockForWrite(); }
200 virtual void lockWrite() { m_Lock.lockForWrite(); }
124 virtual void unlock() { m_Lock.unlock(); }
201 virtual void unlock() { m_Lock.unlock(); }
125
202
126 protected:
203 protected:
127 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
204 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
128 /// DataSeries with no values will be created.
205 /// DataSeries with no values will be created.
129 /// @remarks data series is automatically sorted on its x-axis data
206 /// @remarks data series is automatically sorted on its x-axis data
130 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
207 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
131 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
208 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
132 : m_XAxisData{xAxisData},
209 : m_XAxisData{xAxisData},
133 m_XAxisUnit{xAxisUnit},
210 m_XAxisUnit{xAxisUnit},
134 m_ValuesData{valuesData},
211 m_ValuesData{valuesData},
135 m_ValuesUnit{valuesUnit}
212 m_ValuesUnit{valuesUnit}
136 {
213 {
137 if (m_XAxisData->size() != m_ValuesData->size()) {
214 if (m_XAxisData->size() != m_ValuesData->size()) {
138 clear();
215 clear();
139 }
216 }
140
217
141 // Sorts data if it's not the case
218 // Sorts data if it's not the case
142 const auto &xAxisCData = m_XAxisData->cdata();
219 const auto &xAxisCData = m_XAxisData->cdata();
143 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
220 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
144 sort();
221 sort();
145 }
222 }
146 }
223 }
147
224
148 /// Copy ctor
225 /// Copy ctor
149 explicit DataSeries(const DataSeries<Dim> &other)
226 explicit DataSeries(const DataSeries<Dim> &other)
150 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
227 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
151 m_XAxisUnit{other.m_XAxisUnit},
228 m_XAxisUnit{other.m_XAxisUnit},
152 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
229 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
153 m_ValuesUnit{other.m_ValuesUnit}
230 m_ValuesUnit{other.m_ValuesUnit}
154 {
231 {
155 // Since a series is ordered from its construction and is always ordered, it is not
232 // Since a series is ordered from its construction and is always ordered, it is not
156 // necessary to call the sort method here ('other' is sorted)
233 // necessary to call the sort method here ('other' is sorted)
157 }
234 }
158
235
159 /// Assignment operator
236 /// Assignment operator
160 template <int D>
237 template <int D>
161 DataSeries &operator=(DataSeries<D> other)
238 DataSeries &operator=(DataSeries<D> other)
162 {
239 {
163 std::swap(m_XAxisData, other.m_XAxisData);
240 std::swap(m_XAxisData, other.m_XAxisData);
164 std::swap(m_XAxisUnit, other.m_XAxisUnit);
241 std::swap(m_XAxisUnit, other.m_XAxisUnit);
165 std::swap(m_ValuesData, other.m_ValuesData);
242 std::swap(m_ValuesData, other.m_ValuesData);
166 std::swap(m_ValuesUnit, other.m_ValuesUnit);
243 std::swap(m_ValuesUnit, other.m_ValuesUnit);
167
244
168 return *this;
245 return *this;
169 }
246 }
170
247
171 private:
248 private:
172 /**
249 /**
173 * Sorts data series on its x-axis data
250 * Sorts data series on its x-axis data
174 */
251 */
175 void sort() noexcept
252 void sort() noexcept
176 {
253 {
177 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
254 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
178 m_XAxisData = m_XAxisData->sort(permutation);
255 m_XAxisData = m_XAxisData->sort(permutation);
179 m_ValuesData = m_ValuesData->sort(permutation);
256 m_ValuesData = m_ValuesData->sort(permutation);
180 }
257 }
181
258
182 std::shared_ptr<ArrayData<1> > m_XAxisData;
259 std::shared_ptr<ArrayData<1> > m_XAxisData;
183 Unit m_XAxisUnit;
260 Unit m_XAxisUnit;
184 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
261 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
185 Unit m_ValuesUnit;
262 Unit m_ValuesUnit;
186
263
187 QReadWriteLock m_Lock;
264 QReadWriteLock m_Lock;
188 };
265 };
189
266
190 #endif // SCIQLOP_DATASERIES_H
267 #endif // SCIQLOP_DATASERIES_H
General Comments 0
You need to be logged in to leave comments. Login now