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