##// END OF EJS Templates
Creates iterator for ArrayData
Alexandre Leroux -
r523:03bab5615207
parent child
Show More
@@ -1,230 +1,298
1 #ifndef SCIQLOP_ARRAYDATA_H
1 #ifndef SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
3
3
4 #include <Common/SortUtils.h>
4 #include <Common/SortUtils.h>
5
5
6 #include <QReadLocker>
6 #include <QReadLocker>
7 #include <QReadWriteLock>
7 #include <QReadWriteLock>
8 #include <QVector>
8 #include <QVector>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 template <int Dim>
12 template <int Dim>
13 class ArrayData;
13 class ArrayData;
14
14
15 using DataContainer = QVector<QVector<double> >;
15 using DataContainer = QVector<QVector<double> >;
16
16
17 namespace arraydata_detail {
17 namespace arraydata_detail {
18
18
19 /// Struct used to sort ArrayData
19 /// Struct used to sort ArrayData
20 template <int Dim>
20 template <int Dim>
21 struct Sort {
21 struct Sort {
22 static std::shared_ptr<ArrayData<Dim> > sort(const DataContainer &data,
22 static std::shared_ptr<ArrayData<Dim> > sort(const DataContainer &data,
23 const std::vector<int> &sortPermutation)
23 const std::vector<int> &sortPermutation)
24 {
24 {
25 auto nbComponents = data.size();
25 auto nbComponents = data.size();
26 auto sortedData = DataContainer(nbComponents);
26 auto sortedData = DataContainer(nbComponents);
27
27
28 for (auto i = 0; i < nbComponents; ++i) {
28 for (auto i = 0; i < nbComponents; ++i) {
29 sortedData[i] = SortUtils::sort(data.at(i), sortPermutation);
29 sortedData[i] = SortUtils::sort(data.at(i), sortPermutation);
30 }
30 }
31
31
32 return std::make_shared<ArrayData<Dim> >(std::move(sortedData));
32 return std::make_shared<ArrayData<Dim> >(std::move(sortedData));
33 }
33 }
34 };
34 };
35
35
36 /// Specialization for uni-dimensional ArrayData
36 /// Specialization for uni-dimensional ArrayData
37 template <>
37 template <>
38 struct Sort<1> {
38 struct Sort<1> {
39 static std::shared_ptr<ArrayData<1> > sort(const DataContainer &data,
39 static std::shared_ptr<ArrayData<1> > sort(const DataContainer &data,
40 const std::vector<int> &sortPermutation)
40 const std::vector<int> &sortPermutation)
41 {
41 {
42 return std::make_shared<ArrayData<1> >(SortUtils::sort(data.at(0), sortPermutation));
42 return std::make_shared<ArrayData<1> >(SortUtils::sort(data.at(0), sortPermutation));
43 }
43 }
44 };
44 };
45
45
46 } // namespace arraydata_detail
46 } // namespace arraydata_detail
47
47
48 /**
48 /**
49 * @brief The ArrayData class represents a dataset for a data series.
49 * @brief The ArrayData class represents a dataset for a data series.
50 *
50 *
51 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
51 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
52 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
52 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
53 * number of values
53 * number of values
54 *
54 *
55 * @tparam Dim the dimension of the ArrayData (one or two)
55 * @tparam Dim the dimension of the ArrayData (one or two)
56 * @sa IDataSeries
56 * @sa IDataSeries
57 */
57 */
58 template <int Dim>
58 template <int Dim>
59 class ArrayData {
59 class ArrayData {
60 public:
60 public:
61 class IteratorValue {
62 public:
63 explicit IteratorValue(const DataContainer &container, bool begin) : m_Its{}
64 {
65 for (auto i = 0; i < container.size(); ++i) {
66 m_Its.push_back(begin ? container.at(i).cbegin() : container.at(i).cend());
67 }
68 }
69
70 double at(int index) const { return *m_Its.at(index); }
71 double first() const { return *m_Its.front(); }
72
73 void next()
74 {
75 for (auto &it : m_Its) {
76 ++it;
77 }
78 }
79
80 bool operator==(const IteratorValue &other) const { return m_Its == other.m_Its; }
81
82 private:
83 std::vector<DataContainer::value_type::const_iterator> m_Its;
84 };
85
86 class Iterator {
87 public:
88 using iterator_category = std::forward_iterator_tag;
89 using value_type = const IteratorValue;
90 using difference_type = std::ptrdiff_t;
91 using pointer = value_type *;
92 using reference = value_type &;
93
94 Iterator(const DataContainer &container, bool begin) : m_CurrentValue{container, begin} {}
95
96 virtual ~Iterator() noexcept = default;
97 Iterator(const Iterator &) = default;
98 Iterator(Iterator &&) = default;
99 Iterator &operator=(const Iterator &) = default;
100 Iterator &operator=(Iterator &&) = default;
101
102 Iterator &operator++()
103 {
104 m_CurrentValue.next();
105 return *this;
106 }
107
108 pointer operator->() const { return &m_CurrentValue; }
109 reference operator*() const { return m_CurrentValue; }
110
111 bool operator==(const Iterator &other) const
112 {
113 return m_CurrentValue == other.m_CurrentValue;
114 }
115
116 bool operator!=(const Iterator &other) const { return !(*this == other); }
117
118 private:
119 IteratorValue m_CurrentValue;
120 };
121
61 // ///// //
122 // ///// //
62 // Ctors //
123 // Ctors //
63 // ///// //
124 // ///// //
64
125
65 /**
126 /**
66 * Ctor for a unidimensional ArrayData
127 * Ctor for a unidimensional ArrayData
67 * @param data the data the ArrayData will hold
128 * @param data the data the ArrayData will hold
68 */
129 */
69 template <int D = Dim, typename = std::enable_if_t<D == 1> >
130 template <int D = Dim, typename = std::enable_if_t<D == 1> >
70 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
131 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
71 {
132 {
72 m_Data[0] = std::move(data);
133 m_Data[0] = std::move(data);
73 }
134 }
74
135
75 /**
136 /**
76 * Ctor for a two-dimensional ArrayData. The number of components (number of vectors) must be
137 * Ctor for a two-dimensional ArrayData. The number of components (number of vectors) must be
77 * greater than 2 and each component must have the same number of values
138 * greater than 2 and each component must have the same number of values
78 * @param data the data the ArrayData will hold
139 * @param data the data the ArrayData will hold
79 * @throws std::invalid_argument if the number of components is less than 2
140 * @throws std::invalid_argument if the number of components is less than 2
80 * @remarks if the number of values is not the same for each component, no value is set
141 * @remarks if the number of values is not the same for each component, no value is set
81 */
142 */
82 template <int D = Dim, typename = std::enable_if_t<D == 2> >
143 template <int D = Dim, typename = std::enable_if_t<D == 2> >
83 explicit ArrayData(DataContainer data)
144 explicit ArrayData(DataContainer data)
84 {
145 {
85 auto nbComponents = data.size();
146 auto nbComponents = data.size();
86 if (nbComponents < 2) {
147 if (nbComponents < 2) {
87 throw std::invalid_argument{
148 throw std::invalid_argument{
88 QString{"A multidimensional ArrayData must have at least 2 components (found: %1"}
149 QString{"A multidimensional ArrayData must have at least 2 components (found: %1"}
89 .arg(data.size())
150 .arg(data.size())
90 .toStdString()};
151 .toStdString()};
91 }
152 }
92
153
93 auto nbValues = data.front().size();
154 auto nbValues = data.front().size();
94 if (std::all_of(data.cbegin(), data.cend(), [nbValues](const auto &component) {
155 if (std::all_of(data.cbegin(), data.cend(), [nbValues](const auto &component) {
95 return component.size() == nbValues;
156 return component.size() == nbValues;
96 })) {
157 })) {
97 m_Data = std::move(data);
158 m_Data = std::move(data);
98 }
159 }
99 else {
160 else {
100 m_Data = DataContainer{nbComponents, QVector<double>{}};
161 m_Data = DataContainer{nbComponents, QVector<double>{}};
101 }
162 }
102 }
163 }
103
164
104 /// Copy ctor
165 /// Copy ctor
105 explicit ArrayData(const ArrayData &other)
166 explicit ArrayData(const ArrayData &other)
106 {
167 {
107 QReadLocker otherLocker{&other.m_Lock};
168 QReadLocker otherLocker{&other.m_Lock};
108 m_Data = other.m_Data;
169 m_Data = other.m_Data;
109 }
170 }
110
171
111 // /////////////// //
172 // /////////////// //
112 // General methods //
173 // General methods //
113 // /////////////// //
174 // /////////////// //
114
175
115 /**
176 /**
116 * Merges into the array data an other array data. The two array datas must have the same number
177 * Merges into the array data an other array data. The two array datas must have the same number
117 * of components so the merge can be done
178 * of components so the merge can be done
118 * @param other the array data to merge with
179 * @param other the array data to merge with
119 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
180 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
120 * inserted at the end
181 * inserted at the end
121 */
182 */
122 void add(const ArrayData<Dim> &other, bool prepend = false)
183 void add(const ArrayData<Dim> &other, bool prepend = false)
123 {
184 {
124 QWriteLocker locker{&m_Lock};
185 QWriteLocker locker{&m_Lock};
125 QReadLocker otherLocker{&other.m_Lock};
186 QReadLocker otherLocker{&other.m_Lock};
126
187
127 auto nbComponents = m_Data.size();
188 auto nbComponents = m_Data.size();
128 if (nbComponents != other.m_Data.size()) {
189 if (nbComponents != other.m_Data.size()) {
129 return;
190 return;
130 }
191 }
131
192
132 for (auto componentIndex = 0; componentIndex < nbComponents; ++componentIndex) {
193 for (auto componentIndex = 0; componentIndex < nbComponents; ++componentIndex) {
133 if (prepend) {
194 if (prepend) {
134 const auto &otherData = other.data(componentIndex);
195 const auto &otherData = other.data(componentIndex);
135 const auto otherDataSize = otherData.size();
196 const auto otherDataSize = otherData.size();
136
197
137 auto &data = m_Data[componentIndex];
198 auto &data = m_Data[componentIndex];
138 data.insert(data.begin(), otherDataSize, 0.);
199 data.insert(data.begin(), otherDataSize, 0.);
139
200
140 for (auto i = 0; i < otherDataSize; ++i) {
201 for (auto i = 0; i < otherDataSize; ++i) {
141 data.replace(i, otherData.at(i));
202 data.replace(i, otherData.at(i));
142 }
203 }
143 }
204 }
144 else {
205 else {
145 m_Data[componentIndex] += other.data(componentIndex);
206 m_Data[componentIndex] += other.data(componentIndex);
146 }
207 }
147 }
208 }
148 }
209 }
149
210
150 void clear()
211 void clear()
151 {
212 {
152 QWriteLocker locker{&m_Lock};
213 QWriteLocker locker{&m_Lock};
153
214
154 auto nbComponents = m_Data.size();
215 auto nbComponents = m_Data.size();
155 for (auto i = 0; i < nbComponents; ++i) {
216 for (auto i = 0; i < nbComponents; ++i) {
156 m_Data[i].clear();
217 m_Data[i].clear();
157 }
218 }
158 }
219 }
159
220
160 /**
221 /**
161 * @return the data of a component
222 * @return the data of a component
162 * @param componentIndex the index of the component to retrieve the data
223 * @param componentIndex the index of the component to retrieve the data
163 * @return the component's data, empty vector if the index is invalid
224 * @return the component's data, empty vector if the index is invalid
164 */
225 */
165 QVector<double> data(int componentIndex) const noexcept
226 QVector<double> data(int componentIndex) const noexcept
166 {
227 {
167 QReadLocker locker{&m_Lock};
228 QReadLocker locker{&m_Lock};
168
229
169 return (componentIndex >= 0 && componentIndex < m_Data.size()) ? m_Data.at(componentIndex)
230 return (componentIndex >= 0 && componentIndex < m_Data.size()) ? m_Data.at(componentIndex)
170 : QVector<double>{};
231 : QVector<double>{};
171 }
232 }
172
233
173 /// @return the size (i.e. number of values) of a single component
234 /// @return the size (i.e. number of values) of a single component
174 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
235 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
175 int size() const
236 int size() const
176 {
237 {
177 QReadLocker locker{&m_Lock};
238 QReadLocker locker{&m_Lock};
178 return m_Data[0].size();
239 return m_Data[0].size();
179 }
240 }
180
241
181 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
242 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
182 {
243 {
183 QReadLocker locker{&m_Lock};
244 QReadLocker locker{&m_Lock};
184 return arraydata_detail::Sort<Dim>::sort(m_Data, sortPermutation);
245 return arraydata_detail::Sort<Dim>::sort(m_Data, sortPermutation);
185 }
246 }
186
247
248 // ///////// //
249 // Iterators //
250 // ///////// //
251
252 Iterator cbegin() const { return Iterator{m_Data, true}; }
253 Iterator cend() const { return Iterator{m_Data, false}; }
254
187 // ///////////// //
255 // ///////////// //
188 // 1-dim methods //
256 // 1-dim methods //
189 // ///////////// //
257 // ///////////// //
190
258
191 /**
259 /**
192 * @return the data at a specified index
260 * @return the data at a specified index
193 * @remarks index must be a valid position
261 * @remarks index must be a valid position
194 * @remarks this method is only available for a unidimensional ArrayData
262 * @remarks this method is only available for a unidimensional ArrayData
195 */
263 */
196 template <int D = Dim, typename = std::enable_if_t<D == 1> >
264 template <int D = Dim, typename = std::enable_if_t<D == 1> >
197 double at(int index) const noexcept
265 double at(int index) const noexcept
198 {
266 {
199 QReadLocker locker{&m_Lock};
267 QReadLocker locker{&m_Lock};
200 return m_Data[0].at(index);
268 return m_Data[0].at(index);
201 }
269 }
202
270
203 /**
271 /**
204 * @return the data as a vector, as a const reference
272 * @return the data as a vector, as a const reference
205 * @remarks this method is only available for a unidimensional ArrayData
273 * @remarks this method is only available for a unidimensional ArrayData
206 */
274 */
207 template <int D = Dim, typename = std::enable_if_t<D == 1> >
275 template <int D = Dim, typename = std::enable_if_t<D == 1> >
208 const QVector<double> &cdata() const noexcept
276 const QVector<double> &cdata() const noexcept
209 {
277 {
210 QReadLocker locker{&m_Lock};
278 QReadLocker locker{&m_Lock};
211 return m_Data.at(0);
279 return m_Data.at(0);
212 }
280 }
213
281
214 /**
282 /**
215 * @return the data as a vector
283 * @return the data as a vector
216 * @remarks this method is only available for a unidimensional ArrayData
284 * @remarks this method is only available for a unidimensional ArrayData
217 */
285 */
218 template <int D = Dim, typename = std::enable_if_t<D == 1> >
286 template <int D = Dim, typename = std::enable_if_t<D == 1> >
219 QVector<double> data() const noexcept
287 QVector<double> data() const noexcept
220 {
288 {
221 QReadLocker locker{&m_Lock};
289 QReadLocker locker{&m_Lock};
222 return m_Data[0];
290 return m_Data[0];
223 }
291 }
224
292
225 private:
293 private:
226 DataContainer m_Data;
294 DataContainer m_Data;
227 mutable QReadWriteLock m_Lock;
295 mutable QReadWriteLock m_Lock;
228 };
296 };
229
297
230 #endif // SCIQLOP_ARRAYDATA_H
298 #endif // SCIQLOP_ARRAYDATA_H
General Comments 0
You need to be logged in to leave comments. Login now