##// END OF EJS Templates
Adapts add() method to 2-dim array data
Alexandre Leroux -
r506:0599461b95ff
parent child
Show More
@@ -1,201 +1,218
1 1 #ifndef SCIQLOP_ARRAYDATA_H
2 2 #define SCIQLOP_ARRAYDATA_H
3 3
4 4 #include <Common/SortUtils.h>
5 5
6 6 #include <QReadLocker>
7 7 #include <QReadWriteLock>
8 8 #include <QVector>
9 9
10 10 #include <memory>
11 11
12 12 template <int Dim>
13 13 class ArrayData;
14 14
15 15 using DataContainer = QVector<QVector<double> >;
16 16
17 17 namespace arraydata_detail {
18 18
19 19 /// Struct used to sort ArrayData
20 20 template <int Dim>
21 21 struct Sort {
22 22 static std::shared_ptr<ArrayData<Dim> > sort(const DataContainer &data,
23 23 const std::vector<int> &sortPermutation)
24 24 {
25 25 auto nbComponents = data.size();
26 26 auto sortedData = DataContainer(nbComponents);
27 27
28 28 for (auto i = 0; i < nbComponents; ++i) {
29 29 sortedData[i] = SortUtils::sort(data.at(i), sortPermutation);
30 30 }
31 31
32 32 return std::make_shared<ArrayData<Dim> >(std::move(sortedData));
33 33 }
34 34 };
35 35
36 36 /// Specialization for uni-dimensional ArrayData
37 37 template <>
38 38 struct Sort<1> {
39 39 static std::shared_ptr<ArrayData<1> > sort(const DataContainer &data,
40 40 const std::vector<int> &sortPermutation)
41 41 {
42 42 return std::make_shared<ArrayData<1> >(SortUtils::sort(data.at(0), sortPermutation));
43 43 }
44 44 };
45 45
46 46 } // namespace arraydata_detail
47 47
48 48 /**
49 49 * @brief The ArrayData class represents a dataset for a data series.
50 50 *
51 51 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
52 52 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
53 53 * number of values
54 54 *
55 55 * @tparam Dim the dimension of the ArrayData (one or two)
56 56 * @sa IDataSeries
57 57 */
58 58 template <int Dim>
59 59 class ArrayData {
60 60 public:
61 61 /**
62 62 * Ctor for a unidimensional ArrayData
63 63 * @param data the data the ArrayData will hold
64 64 */
65 65 template <int D = Dim, typename = std::enable_if_t<D == 1> >
66 66 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
67 67 {
68 68 m_Data[0] = std::move(data);
69 69 }
70 70
71 71 /**
72 72 * Ctor for a two-dimensional ArrayData. The number of components (number of vectors) must be
73 73 * greater than 2 and each component must have the same number of values
74 74 * @param data the data the ArrayData will hold
75 75 * @throws std::invalid_argument if the number of components is less than 2
76 76 * @remarks if the number of values is not the same for each component, no value is set
77 77 */
78 78 template <int D = Dim, typename = std::enable_if_t<D == 2> >
79 79 explicit ArrayData(DataContainer data)
80 80 {
81 81 auto nbComponents = data.size();
82 82 if (nbComponents < 2) {
83 83 throw std::invalid_argument{
84 84 QString{"A multidimensional ArrayData must have at least 2 components (found: %1"}
85 85 .arg(data.size())
86 86 .toStdString()};
87 87 }
88 88
89 89 auto nbValues = data.front().size();
90 90 if (std::all_of(data.cbegin(), data.cend(), [nbValues](const auto &component) {
91 91 return component.size() == nbValues;
92 92 })) {
93 93 m_Data = std::move(data);
94 94 }
95 95 else {
96 96 m_Data = DataContainer{nbComponents, QVector<double>{}};
97 97 }
98 98 }
99 99
100 100 /// Copy ctor
101 101 explicit ArrayData(const ArrayData &other)
102 102 {
103 103 QReadLocker otherLocker{&other.m_Lock};
104 104 m_Data = other.m_Data;
105 105 }
106 106
107 107 /**
108 108 * @return the data at a specified index
109 109 * @remarks index must be a valid position
110 110 * @remarks this method is only available for a unidimensional ArrayData
111 111 */
112 112 template <int D = Dim, typename = std::enable_if_t<D == 1> >
113 113 double at(int index) const noexcept
114 114 {
115 115 QReadLocker locker{&m_Lock};
116 116 return m_Data[0].at(index);
117 117 }
118 118
119 119 /**
120 120 * @return the data as a vector
121 121 * @remarks this method is only available for a unidimensional ArrayData
122 122 */
123 123 template <int D = Dim, typename = std::enable_if_t<D == 1> >
124 124 QVector<double> data() const noexcept
125 125 {
126 126 QReadLocker locker{&m_Lock};
127 127 return m_Data[0];
128 128 }
129 129
130 130 /**
131 * @return the data of a component
132 * @param componentIndex the index of the component to retrieve the data
133 * @return the component's data, empty vector if the index is invalid
134 */
135 QVector<double> data(int componentIndex) const noexcept
136 {
137 QReadLocker locker{&m_Lock};
138
139 return (componentIndex >= 0 && componentIndex < m_Data.size()) ? m_Data.at(componentIndex)
140 : QVector<double>{};
141 }
142
143 /**
131 144 * @return the data as a vector, as a const reference
132 145 * @remarks this method is only available for a unidimensional ArrayData
133 146 */
134 147 template <int D = Dim, typename = std::enable_if_t<D == 1> >
135 148 const QVector<double> &cdata() const noexcept
136 149 {
137 150 QReadLocker locker{&m_Lock};
138 151 return m_Data.at(0);
139 152 }
140 153
141 154 /**
142 * Merges into the array data an other array data
155 * Merges into the array data an other array data. The two array datas must have the same number
156 * of components so the merge can be done
143 157 * @param other the array data to merge with
144 158 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
145 159 * inserted at the end
146 * @remarks this method is only available for a unidimensional ArrayData
147 160 */
148 template <int D = Dim, typename = std::enable_if_t<D == 1> >
149 void add(const ArrayData<1> &other, bool prepend = false)
161 void add(const ArrayData<Dim> &other, bool prepend = false)
150 162 {
151 163 QWriteLocker locker{&m_Lock};
152 if (!m_Data.empty()) {
153 QReadLocker otherLocker{&other.m_Lock};
164 QReadLocker otherLocker{&other.m_Lock};
165
166 auto nbComponents = m_Data.size();
167 if (nbComponents != other.m_Data.size()) {
168 return;
169 }
154 170
171 for (auto componentIndex = 0; componentIndex < nbComponents; ++componentIndex) {
155 172 if (prepend) {
156 const auto &otherData = other.data();
173 const auto &otherData = other.data(componentIndex);
157 174 const auto otherDataSize = otherData.size();
158 175
159 auto &data = m_Data[0];
176 auto &data = m_Data[componentIndex];
160 177 data.insert(data.begin(), otherDataSize, 0.);
161 178
162 179 for (auto i = 0; i < otherDataSize; ++i) {
163 180 data.replace(i, otherData.at(i));
164 181 }
165 182 }
166 183 else {
167 m_Data[0] += other.data();
184 m_Data[componentIndex] += other.data(componentIndex);
168 185 }
169 186 }
170 187 }
171 188
172 189 /// @return the size (i.e. number of values) of a single component
173 190 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
174 191 int size() const
175 192 {
176 193 QReadLocker locker{&m_Lock};
177 194 return m_Data[0].size();
178 195 }
179 196
180 197 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
181 198 {
182 199 QReadLocker locker{&m_Lock};
183 200 return arraydata_detail::Sort<Dim>::sort(m_Data, sortPermutation);
184 201 }
185 202
186 203 void clear()
187 204 {
188 205 QWriteLocker locker{&m_Lock};
189 206
190 207 auto nbComponents = m_Data.size();
191 208 for (auto i = 0; i < nbComponents; ++i) {
192 209 m_Data[i].clear();
193 210 }
194 211 }
195 212
196 213 private:
197 214 DataContainer m_Data;
198 215 mutable QReadWriteLock m_Lock;
199 216 };
200 217
201 218 #endif // SCIQLOP_ARRAYDATA_H
General Comments 0
You need to be logged in to leave comments. Login now