##// END OF EJS Templates
Makes a Data series be sorted (2)...
Alexandre Leroux -
r416:07e656efd83c
parent child
Show More
@@ -0,0 +1,38
1 #ifndef SCIQLOP_SORTUTILS_H
2 #define SCIQLOP_SORTUTILS_H
3
4 #include <algorithm>
5 #include <vector>
6
7 /**
8 * Utility class with methods for sorting data
9 */
10 struct SortUtils {
11 /**
12 * Generates a vector representing the index of insertion of each data of a container if this
13 * one had to be sorted according to a comparison function.
14 *
15 * For example:
16 * If the container is a vector {1; 4; 2; 5; 3} and the comparison function is std::less, the
17 * result would be : {0; 3; 1; 4; 2}
18 *
19 * @tparam Container the type of the container.
20 * @tparam Compare the type of the comparison function
21 * @param container the container from which to generate the result. The container must have a
22 * at() method that returns a value associated to an index
23 * @param compare the comparison function
24 */
25 template <typename Container, typename Compare>
26 static std::vector<int> sortPermutation(const Container &container, const Compare &compare)
27 {
28 auto permutation = std::vector<int>{};
29 permutation.resize(container.size());
30
31 std::iota(permutation.begin(), permutation.end(), 0);
32 std::sort(permutation.begin(), permutation.end(),
33 [&](int i, int j) { return compare(container.at(i), container.at(j)); });
34 return permutation;
35 }
36 };
37
38 #endif // SCIQLOP_SORTUTILS_H
@@ -1,116 +1,147
1 #ifndef SCIQLOP_ARRAYDATA_H
1 #ifndef SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
3
3
4 #include <QReadLocker>
4 #include <QReadLocker>
5 #include <QReadWriteLock>
5 #include <QReadWriteLock>
6 #include <QVector>
6 #include <QVector>
7
8 #include <memory>
9
7 /**
10 /**
8 * @brief The ArrayData class represents a dataset for a data series.
11 * @brief The ArrayData class represents a dataset for a data series.
9 *
12 *
10 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
13 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
11 * template-parameter.
14 * template-parameter.
12 *
15 *
13 * @tparam Dim the dimension of the ArrayData (one or two)
16 * @tparam Dim the dimension of the ArrayData (one or two)
14 * @sa IDataSeries
17 * @sa IDataSeries
15 */
18 */
16 template <int Dim>
19 template <int Dim>
17 class ArrayData {
20 class ArrayData {
18 public:
21 public:
19 /**
22 /**
20 * Ctor for a unidimensional ArrayData
23 * Ctor for a unidimensional ArrayData
21 * @param nbColumns the number of values the ArrayData will hold
24 * @param nbColumns the number of values the ArrayData will hold
22 */
25 */
23 template <int D = Dim, typename = std::enable_if_t<D == 1> >
26 template <int D = Dim, typename = std::enable_if_t<D == 1> >
24 explicit ArrayData(int nbColumns) : m_Data{1, QVector<double>{}}
27 explicit ArrayData(int nbColumns) : m_Data{1, QVector<double>{}}
25 {
28 {
26 QWriteLocker locker{&m_Lock};
29 QWriteLocker locker{&m_Lock};
27 m_Data[0].resize(nbColumns);
30 m_Data[0].resize(nbColumns);
28 }
31 }
29
32
30 /**
33 /**
31 * Ctor for a unidimensional ArrayData
34 * Ctor for a unidimensional ArrayData
32 * @param data the data the ArrayData will hold
35 * @param data the data the ArrayData will hold
33 */
36 */
34 template <int D = Dim, typename = std::enable_if_t<D == 1> >
37 template <int D = Dim, typename = std::enable_if_t<D == 1> >
35 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
38 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
36 {
39 {
37 QWriteLocker locker{&m_Lock};
40 QWriteLocker locker{&m_Lock};
38 m_Data[0] = std::move(data);
41 m_Data[0] = std::move(data);
39 }
42 }
40
43
41 /// Copy ctor
44 /// Copy ctor
42 explicit ArrayData(const ArrayData &other)
45 explicit ArrayData(const ArrayData &other)
43 {
46 {
44 QReadLocker otherLocker{&other.m_Lock};
47 QReadLocker otherLocker{&other.m_Lock};
45 QWriteLocker locker{&m_Lock};
48 QWriteLocker locker{&m_Lock};
46 m_Data = other.m_Data;
49 m_Data = other.m_Data;
47 }
50 }
48
51
49 /**
52 /**
53 * @return the data at a specified index
54 * @remarks index must be a valid position
55 * @remarks this method is only available for a unidimensional ArrayData
56 */
57 template <int D = Dim, typename = std::enable_if_t<D == 1> >
58 double at(int index) const noexcept
59 {
60 QReadLocker locker{&m_Lock};
61 return m_Data[0].at(index);
62 }
63
64 /**
50 * Sets a data at a specified index. The index has to be valid to be effective
65 * Sets a data at a specified index. The index has to be valid to be effective
51 * @param index the index to which the data will be set
66 * @param index the index to which the data will be set
52 * @param data the data to set
67 * @param data the data to set
53 * @remarks this method is only available for a unidimensional ArrayData
68 * @remarks this method is only available for a unidimensional ArrayData
54 */
69 */
55 template <int D = Dim, typename = std::enable_if_t<D == 1> >
70 template <int D = Dim, typename = std::enable_if_t<D == 1> >
56 void setData(int index, double data) noexcept
71 void setData(int index, double data) noexcept
57 {
72 {
58 QWriteLocker locker{&m_Lock};
73 QWriteLocker locker{&m_Lock};
59 if (index >= 0 && index < m_Data.at(0).size()) {
74 if (index >= 0 && index < m_Data.at(0).size()) {
60 m_Data[0].replace(index, data);
75 m_Data[0].replace(index, data);
61 }
76 }
62 }
77 }
63
78
64 /**
79 /**
65 * @return the data as a vector
80 * @return the data as a vector
66 * @remarks this method is only available for a unidimensional ArrayData
81 * @remarks this method is only available for a unidimensional ArrayData
67 */
82 */
68 template <int D = Dim, typename = std::enable_if_t<D == 1> >
83 template <int D = Dim, typename = std::enable_if_t<D == 1> >
69 QVector<double> data() const noexcept
84 QVector<double> data() const noexcept
70 {
85 {
71 QReadLocker locker{&m_Lock};
86 QReadLocker locker{&m_Lock};
72 return m_Data[0];
87 return m_Data[0];
73 }
88 }
74
89
75 /**
90 /**
76 * @return the data as a vector, as a const reference
91 * @return the data as a vector, as a const reference
77 * @remarks this method is only available for a unidimensional ArrayData
92 * @remarks this method is only available for a unidimensional ArrayData
78 */
93 */
79 template <int D = Dim, typename = std::enable_if_t<D == 1> >
94 template <int D = Dim, typename = std::enable_if_t<D == 1> >
80 const QVector<double> &cdata() const noexcept
95 const QVector<double> &cdata() const noexcept
81 {
96 {
82 QReadLocker locker{&m_Lock};
97 QReadLocker locker{&m_Lock};
83 return m_Data.at(0);
98 return m_Data.at(0);
84 }
99 }
85
100
86 // TODO Comment
101 // TODO Comment
87 template <int D = Dim, typename = std::enable_if_t<D == 1> >
102 template <int D = Dim, typename = std::enable_if_t<D == 1> >
88 void merge(const ArrayData<1> &arrayData)
103 void merge(const ArrayData<1> &arrayData)
89 {
104 {
90 QWriteLocker locker{&m_Lock};
105 QWriteLocker locker{&m_Lock};
91 if (!m_Data.empty()) {
106 if (!m_Data.empty()) {
92 QReadLocker otherLocker{&arrayData.m_Lock};
107 QReadLocker otherLocker{&arrayData.m_Lock};
93 m_Data[0] += arrayData.data();
108 m_Data[0] += arrayData.data();
94 }
109 }
95 }
110 }
96
111
97 template <int D = Dim, typename = std::enable_if_t<D == 1> >
112 template <int D = Dim, typename = std::enable_if_t<D == 1> >
98 int size() const
113 int size() const
99 {
114 {
100 QReadLocker locker{&m_Lock};
115 QReadLocker locker{&m_Lock};
101 return m_Data[0].size();
116 return m_Data[0].size();
102 }
117 }
103
118
119 template <int D = Dim, typename = std::enable_if_t<D == 1> >
120 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> sortPermutation)
121 {
122 QReadLocker locker{&m_Lock};
123
124 const auto &data = m_Data.at(0);
125
126 // Inits result
127 auto sortedData = QVector<double>{};
128 sortedData.resize(data.size());
note

Do the resize at the construction

129
130 std::transform(sortPermutation.cbegin(), sortPermutation.cend(), sortedData.begin(),
131 [&data](int i) { return data[i]; });
132
133 return std::make_shared<ArrayData<Dim> >(std::move(sortedData));
134 }
104 void clear()
135 void clear()
105 {
136 {
106 QWriteLocker locker{&m_Lock};
137 QWriteLocker locker{&m_Lock};
107 m_Data.clear();
138 m_Data.clear();
108 }
139 }
109
140
110
141
111 private:
142 private:
112 QVector<QVector<double> > m_Data;
143 QVector<QVector<double> > m_Data;
113 mutable QReadWriteLock m_Lock;
144 mutable QReadWriteLock m_Lock;
114 };
145 };
115
146
116 #endif // SCIQLOP_ARRAYDATA_H
147 #endif // SCIQLOP_ARRAYDATA_H
@@ -1,130 +1,134
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>
5
4 #include <Data/ArrayData.h>
6 #include <Data/ArrayData.h>
5 #include <Data/IDataSeries.h>
7 #include <Data/IDataSeries.h>
6
8
7 #include <QLoggingCategory>
9 #include <QLoggingCategory>
8
10
9 #include <QReadLocker>
11 #include <QReadLocker>
10 #include <QReadWriteLock>
12 #include <QReadWriteLock>
11 #include <memory>
13 #include <memory>
12
14
13 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
14 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
16 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
15
17
16
18
17 /**
19 /**
18 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
20 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
19 *
21 *
20 * It proposes to set a dimension for the values ​​data.
22 * It proposes to set a dimension for the values ​​data.
21 *
23 *
22 * A DataSeries is always sorted on its x-axis data.
24 * A DataSeries is always sorted on its x-axis data.
23 *
25 *
24 * @tparam Dim The dimension of the values data
26 * @tparam Dim The dimension of the values data
25 *
27 *
26 */
28 */
27 template <int Dim>
29 template <int Dim>
28 class DataSeries : public IDataSeries {
30 class DataSeries : public IDataSeries {
29 public:
31 public:
30 /// @sa IDataSeries::xAxisData()
32 /// @sa IDataSeries::xAxisData()
31 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
33 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
32 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
34 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
33
35
34 /// @sa IDataSeries::xAxisUnit()
36 /// @sa IDataSeries::xAxisUnit()
35 Unit xAxisUnit() const override { return m_XAxisUnit; }
37 Unit xAxisUnit() const override { return m_XAxisUnit; }
36
38
37 /// @return the values dataset
39 /// @return the values dataset
38 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
40 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
39 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
41 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
40
42
41 /// @sa IDataSeries::valuesUnit()
43 /// @sa IDataSeries::valuesUnit()
42 Unit valuesUnit() const override { return m_ValuesUnit; }
44 Unit valuesUnit() const override { return m_ValuesUnit; }
43
45
44 void clear()
46 void clear()
45 {
47 {
46 m_XAxisData->clear();
48 m_XAxisData->clear();
47 m_ValuesData->clear();
49 m_ValuesData->clear();
48 }
50 }
49
51
50 /// @sa IDataSeries::merge()
52 /// @sa IDataSeries::merge()
51 void merge(IDataSeries *dataSeries) override
53 void merge(IDataSeries *dataSeries) override
52 {
54 {
53 if (auto dimDataSeries = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
55 if (auto dimDataSeries = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
54 m_XAxisData->merge(*dimDataSeries->xAxisData());
56 m_XAxisData->merge(*dimDataSeries->xAxisData());
55 m_ValuesData->merge(*dimDataSeries->valuesData());
57 m_ValuesData->merge(*dimDataSeries->valuesData());
56 dimDataSeries->clear();
58 dimDataSeries->clear();
57 }
59 }
58 else {
60 else {
59 qCWarning(LOG_DataSeries())
61 qCWarning(LOG_DataSeries())
60 << QObject::tr("Dection of a type of IDataSeries we cannot merge with !");
62 << QObject::tr("Dection of a type of IDataSeries we cannot merge with !");
61 }
63 }
62 }
64 }
63
65
64 virtual void lockRead() { m_Lock.lockForRead(); }
66 virtual void lockRead() { m_Lock.lockForRead(); }
65 virtual void lockWrite() { m_Lock.lockForWrite(); }
67 virtual void lockWrite() { m_Lock.lockForWrite(); }
66 virtual void unlock() { m_Lock.unlock(); }
68 virtual void unlock() { m_Lock.unlock(); }
67
69
68 protected:
70 protected:
69 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
71 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
70 /// DataSeries with no values will be created.
72 /// DataSeries with no values will be created.
71 /// @remarks data series is automatically sorted on its x-axis data
73 /// @remarks data series is automatically sorted on its x-axis data
72 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
74 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
73 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
75 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
74 : m_XAxisData{xAxisData},
76 : m_XAxisData{xAxisData},
75 m_XAxisUnit{xAxisUnit},
77 m_XAxisUnit{xAxisUnit},
76 m_ValuesData{valuesData},
78 m_ValuesData{valuesData},
77 m_ValuesUnit{valuesUnit}
79 m_ValuesUnit{valuesUnit}
78 {
80 {
79 if (m_XAxisData->size() != m_ValuesData->size()) {
81 if (m_XAxisData->size() != m_ValuesData->size()) {
80 clear();
82 clear();
81 }
83 }
82
84
83 // Sorts data if it's not the case
85 // Sorts data if it's not the case
84 const auto &xAxisCData = m_XAxisData->cdata();
86 const auto &xAxisCData = m_XAxisData->cdata();
85 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
87 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
86 sort();
88 sort();
87 }
89 }
88 }
90 }
89
91
90 /// Copy ctor
92 /// Copy ctor
91 explicit DataSeries(const DataSeries<Dim> &other)
93 explicit DataSeries(const DataSeries<Dim> &other)
92 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
94 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
93 m_XAxisUnit{other.m_XAxisUnit},
95 m_XAxisUnit{other.m_XAxisUnit},
94 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
96 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
95 m_ValuesUnit{other.m_ValuesUnit}
97 m_ValuesUnit{other.m_ValuesUnit}
96 {
98 {
97 // Since a series is ordered from its construction and is always ordered, it is not
99 // Since a series is ordered from its construction and is always ordered, it is not
98 // necessary to call the sort method here ('other' is sorted)
100 // necessary to call the sort method here ('other' is sorted)
99 }
101 }
100
102
101 /// Assignment operator
103 /// Assignment operator
102 template <int D>
104 template <int D>
103 DataSeries &operator=(DataSeries<D> other)
105 DataSeries &operator=(DataSeries<D> other)
104 {
106 {
105 std::swap(m_XAxisData, other.m_XAxisData);
107 std::swap(m_XAxisData, other.m_XAxisData);
106 std::swap(m_XAxisUnit, other.m_XAxisUnit);
108 std::swap(m_XAxisUnit, other.m_XAxisUnit);
107 std::swap(m_ValuesData, other.m_ValuesData);
109 std::swap(m_ValuesData, other.m_ValuesData);
108 std::swap(m_ValuesUnit, other.m_ValuesUnit);
110 std::swap(m_ValuesUnit, other.m_ValuesUnit);
109
111
110 return *this;
112 return *this;
111 }
113 }
112
114
113 private:
115 private:
114 /**
116 /**
115 * Sorts data series on its x-axis data
117 * Sorts data series on its x-axis data
116 */
118 */
117 void sort() noexcept
119 void sort() noexcept
118 {
120 {
119 /// @todo ALX
121 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
122 m_XAxisData = m_XAxisData->sort(permutation);
123 m_ValuesData = m_ValuesData->sort(permutation);
120 }
124 }
121
125
122 std::shared_ptr<ArrayData<1> > m_XAxisData;
126 std::shared_ptr<ArrayData<1> > m_XAxisData;
123 Unit m_XAxisUnit;
127 Unit m_XAxisUnit;
124 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
128 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
125 Unit m_ValuesUnit;
129 Unit m_ValuesUnit;
126
130
127 QReadWriteLock m_Lock;
131 QReadWriteLock m_Lock;
128 };
132 };
129
133
130 #endif // SCIQLOP_DATASERIES_H
134 #endif // SCIQLOP_DATASERIES_H
General Comments 0
You need to be logged in to leave comments. Login now