From e899bacb01d97a49a4323fa4706d9469d317f670 2017-08-31 10:29:15 From: Alexandre Leroux Date: 2017-08-31 10:29:15 Subject: [PATCH] Merge branch 'feature/PurgeDataSeries' into develop --- diff --git a/core/include/Data/ArrayData.h b/core/include/Data/ArrayData.h index 6a149e2..5125f6b 100644 --- a/core/include/Data/ArrayData.h +++ b/core/include/Data/ArrayData.h @@ -39,19 +39,58 @@ struct Sort<1> { } }; +template +class IteratorValue; + +template +struct IteratorValueBuilder { +}; + +template +struct IteratorValueBuilder { + using DataContainerIterator = DataContainer::const_iterator; + + static void swap(IteratorValue &o1, IteratorValue &o2) {} +}; + template +struct IteratorValueBuilder { + using DataContainerIterator = DataContainer::iterator; + + static void swap(IteratorValue &o1, IteratorValue &o2) + { + for (auto i = 0; i < o1.m_NbComponents; ++i) { + std::iter_swap(o1.m_It + i, o2.m_It + i); + } + } +}; + +template class IteratorValue : public ArrayDataIteratorValue::Impl { public: + friend class ArrayData; + friend class IteratorValueBuilder; + + using DataContainerIterator = + typename IteratorValueBuilder::DataContainerIterator; + + template > explicit IteratorValue(const DataContainer &container, int nbComponents, bool begin) : m_It{begin ? container.cbegin() : container.cend()}, m_NbComponents{nbComponents} { } + template > + explicit IteratorValue(DataContainer &container, int nbComponents, bool begin) + : m_It{begin ? container.begin() : container.end()}, m_NbComponents{nbComponents} + { + } + IteratorValue(const IteratorValue &other) = default; std::unique_ptr clone() const override { - return std::make_unique >(*this); + return std::make_unique >(*this); } bool equals(const ArrayDataIteratorValue::Impl &other) const override try { @@ -97,8 +136,14 @@ public: return result; } + void swap(ArrayDataIteratorValue::Impl &other) override + { + auto &otherImpl = dynamic_cast(other); + IteratorValueBuilder::swap(*this, otherImpl); + } + private: - DataContainer::const_iterator m_It; + DataContainerIterator m_It; int m_NbComponents; }; @@ -223,18 +268,44 @@ public: // Iterators // // ///////// // + ArrayDataIterator begin() + { + return ArrayDataIterator{ + ArrayDataIteratorValue{std::make_unique >( + m_Data, m_NbComponents, true)}}; + } + + ArrayDataIterator end() + { + return ArrayDataIterator{ + ArrayDataIteratorValue{std::make_unique >( + m_Data, m_NbComponents, false)}}; + } + ArrayDataIterator cbegin() const { - return ArrayDataIterator{ArrayDataIteratorValue{ - std::make_unique >(m_Data, m_NbComponents, true)}}; + return ArrayDataIterator{ + ArrayDataIteratorValue{std::make_unique >( + m_Data, m_NbComponents, true)}}; } + ArrayDataIterator cend() const { return ArrayDataIterator{ - ArrayDataIteratorValue{std::make_unique >( + ArrayDataIteratorValue{std::make_unique >( m_Data, m_NbComponents, false)}}; } + void erase(ArrayDataIterator first, ArrayDataIterator last) + { + auto firstImpl = dynamic_cast *>(first->impl()); + auto lastImpl = dynamic_cast *>(last->impl()); + + if (firstImpl && lastImpl) { + m_Data.erase(firstImpl->m_It, lastImpl->m_It); + } + } + /// Inserts at the end of the array data the values passed as a parameter. This /// method is intended to be used in the context of generating a back insert iterator, or only /// if it's ensured that the total size of the vector is consistent with the number of diff --git a/core/include/Data/ArrayDataIterator.h b/core/include/Data/ArrayDataIterator.h index fa86409..791b473 100644 --- a/core/include/Data/ArrayDataIterator.h +++ b/core/include/Data/ArrayDataIterator.h @@ -27,11 +27,12 @@ public: virtual double min() const = 0; virtual double max() const = 0; virtual QVector values() const = 0; + + virtual void swap(Impl &other) = 0; }; explicit ArrayDataIteratorValue(std::unique_ptr impl); ArrayDataIteratorValue(const ArrayDataIteratorValue &other); - ArrayDataIteratorValue(ArrayDataIteratorValue &&other) = default; ArrayDataIteratorValue &operator=(ArrayDataIteratorValue other); bool equals(const ArrayDataIteratorValue &other) const; @@ -51,6 +52,13 @@ public: /// Gets all values QVector values() const; + Impl *impl(); + + friend void swap(ArrayDataIteratorValue &lhs, ArrayDataIteratorValue &rhs) + { + std::swap(lhs.m_Impl, rhs.m_Impl); + } + private: std::unique_ptr m_Impl; }; diff --git a/core/include/Data/DataSeries.h b/core/include/Data/DataSeries.h index bfa12c9..ea2d962 100644 --- a/core/include/Data/DataSeries.h +++ b/core/include/Data/DataSeries.h @@ -27,20 +27,31 @@ class DataSeries; namespace dataseries_detail { -template +template class IteratorValue : public DataSeriesIteratorValue::Impl { public: + friend class DataSeries; + + template > + explicit IteratorValue(DataSeries &dataSeries, bool begin) + : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()), + m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end()) + { + } + + template > explicit IteratorValue(const DataSeries &dataSeries, bool begin) : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()), m_ValuesIt(begin ? dataSeries.valuesData()->cbegin() : dataSeries.valuesData()->cend()) { } + IteratorValue(const IteratorValue &other) = default; std::unique_ptr clone() const override { - return std::make_unique >(*this); + return std::make_unique >(*this); } bool equals(const DataSeriesIteratorValue::Impl &other) const override try { @@ -70,6 +81,13 @@ public: double maxValue() const override { return m_ValuesIt->max(); } QVector values() const override { return m_ValuesIt->values(); } + void swap(DataSeriesIteratorValue::Impl &other) override + { + auto &otherImpl = dynamic_cast(other); + m_XIt->impl()->swap(*otherImpl.m_XIt->impl()); + m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl()); + } + private: ArrayDataIterator m_XIt; ArrayDataIterator m_ValuesIt; @@ -145,20 +163,59 @@ public: dataSeries->unlock(); } + void purge(double min, double max) override + { + if (min > max) { + std::swap(min, max); + } + + lockWrite(); + + auto it = std::remove_if( + begin(), end(), [min, max](const auto &it) { return it.x() < min || it.x() > max; }); + erase(it, end()); + + unlock(); + } + // ///////// // // Iterators // // ///////// // + DataSeriesIterator begin() override + { + return DataSeriesIterator{DataSeriesIteratorValue{ + std::make_unique >(*this, true)}}; + } + + DataSeriesIterator end() override + { + return DataSeriesIterator{DataSeriesIteratorValue{ + std::make_unique >(*this, false)}}; + } + DataSeriesIterator cbegin() const override { return DataSeriesIterator{DataSeriesIteratorValue{ - std::make_unique >(*this, true)}}; + std::make_unique >(*this, true)}}; } DataSeriesIterator cend() const override { return DataSeriesIterator{DataSeriesIteratorValue{ - std::make_unique >(*this, false)}}; + std::make_unique >(*this, false)}}; + } + + void erase(DataSeriesIterator first, DataSeriesIterator last) + { + auto firstImpl + = dynamic_cast *>(first->impl()); + auto lastImpl = dynamic_cast *>(last->impl()); + + if (firstImpl && lastImpl) { + m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt); + m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt); + } } /// @sa IDataSeries::minXAxisData() diff --git a/core/include/Data/DataSeriesIterator.h b/core/include/Data/DataSeriesIterator.h index fd859bb..be513b0 100644 --- a/core/include/Data/DataSeriesIterator.h +++ b/core/include/Data/DataSeriesIterator.h @@ -29,11 +29,12 @@ public: virtual double minValue() const = 0; virtual double maxValue() const = 0; virtual QVector values() const = 0; + + virtual void swap(Impl &other) = 0; }; explicit DataSeriesIteratorValue(std::unique_ptr impl); DataSeriesIteratorValue(const DataSeriesIteratorValue &other); - DataSeriesIteratorValue(DataSeriesIteratorValue &&other) = default; DataSeriesIteratorValue &operator=(DataSeriesIteratorValue other); bool equals(const DataSeriesIteratorValue &other) const; @@ -55,6 +56,13 @@ public: /// Gets all values data QVector values() const; + Impl *impl(); + + friend void swap(DataSeriesIteratorValue &lhs, DataSeriesIteratorValue &rhs) + { + std::swap(lhs.m_Impl, rhs.m_Impl); + } + private: std::unique_ptr m_Impl; }; diff --git a/core/include/Data/IDataSeries.h b/core/include/Data/IDataSeries.h index 33fc095..aea7206 100644 --- a/core/include/Data/IDataSeries.h +++ b/core/include/Data/IDataSeries.h @@ -57,6 +57,9 @@ public: virtual Unit valuesUnit() const = 0; virtual void merge(IDataSeries *dataSeries) = 0; + /// Removes from data series all entries whose value on the x-axis is not between min and max + virtual void purge(double min, double max) = 0; + /// @todo Review the name and signature of this method virtual std::shared_ptr subDataSeries(const SqpRange &range) = 0; @@ -69,6 +72,8 @@ public: virtual DataSeriesIterator cbegin() const = 0; virtual DataSeriesIterator cend() const = 0; + virtual DataSeriesIterator begin() = 0; + virtual DataSeriesIterator end() = 0; /// @return the iterator to the first entry of the data series whose x-axis data is greater than /// or equal to the value passed in parameter, or the end iterator if there is no matching value diff --git a/core/include/Data/SqpIterator.h b/core/include/Data/SqpIterator.h index 8b51389..be7e79f 100644 --- a/core/include/Data/SqpIterator.h +++ b/core/include/Data/SqpIterator.h @@ -22,9 +22,7 @@ public: virtual ~SqpIterator() noexcept = default; SqpIterator(const SqpIterator &) = default; - SqpIterator(SqpIterator &&) = default; - SqpIterator &operator=(const SqpIterator &) = default; - SqpIterator &operator=(SqpIterator &&) = default; + SqpIterator &operator=(SqpIterator other) { swap(m_CurrentValue, other.m_CurrentValue); } SqpIterator &operator++() { @@ -38,8 +36,10 @@ public: return *this; } - pointer operator->() const { return &m_CurrentValue; } - reference operator*() const { return m_CurrentValue; } + const T *operator->() const { return &m_CurrentValue; } + const T &operator*() const { return m_CurrentValue; } + T *operator->() { return &m_CurrentValue; } + T &operator*() { return m_CurrentValue; } bool operator==(const SqpIterator &other) const { diff --git a/core/include/Variable/Variable.h b/core/include/Variable/Variable.h index 8c1d0bb..117dd08 100644 --- a/core/include/Variable/Variable.h +++ b/core/include/Variable/Variable.h @@ -57,7 +57,6 @@ public: QVector provideNotInCacheRangeList(const SqpRange &range) const noexcept; QVector provideInCacheRangeList(const SqpRange &range) const noexcept; - void setDataSeries(std::shared_ptr dataSeries) noexcept; void mergeDataSeries(std::shared_ptr dataSeries) noexcept; signals: diff --git a/core/src/Data/ArrayDataIterator.cpp b/core/src/Data/ArrayDataIterator.cpp index cd397c4..c7e7a9b 100644 --- a/core/src/Data/ArrayDataIterator.cpp +++ b/core/src/Data/ArrayDataIterator.cpp @@ -12,7 +12,7 @@ ArrayDataIteratorValue::ArrayDataIteratorValue(const ArrayDataIteratorValue &oth ArrayDataIteratorValue &ArrayDataIteratorValue::operator=(ArrayDataIteratorValue other) { - std::swap(m_Impl, other.m_Impl); + m_Impl->swap(*other.m_Impl); return *this; } @@ -55,3 +55,8 @@ QVector ArrayDataIteratorValue::values() const { return m_Impl->values(); } + +ArrayDataIteratorValue::Impl *ArrayDataIteratorValue::impl() +{ + return m_Impl.get(); +} diff --git a/core/src/Data/DataSeriesIterator.cpp b/core/src/Data/DataSeriesIterator.cpp index d492b32..62e33b9 100644 --- a/core/src/Data/DataSeriesIterator.cpp +++ b/core/src/Data/DataSeriesIterator.cpp @@ -13,7 +13,7 @@ DataSeriesIteratorValue::DataSeriesIteratorValue(const DataSeriesIteratorValue & DataSeriesIteratorValue &DataSeriesIteratorValue::operator=(DataSeriesIteratorValue other) { - std::swap(m_Impl, other.m_Impl); + m_Impl->swap(*other.m_Impl); return *this; } @@ -61,3 +61,8 @@ QVector DataSeriesIteratorValue::values() const { return m_Impl->values(); } + +DataSeriesIteratorValue::Impl *DataSeriesIteratorValue::impl() +{ + return m_Impl.get(); +} diff --git a/core/src/Variable/Variable.cpp b/core/src/Variable/Variable.cpp index 554dcf3..960b3bf 100644 --- a/core/src/Variable/Variable.cpp +++ b/core/src/Variable/Variable.cpp @@ -24,6 +24,14 @@ struct Variable::VariablePrivate { void lockWrite() { m_Lock.lockForWrite(); } void unlock() { m_Lock.unlock(); } + void purgeDataSeries() + { + if (m_DataSeries) { + m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd); + } + updateRealRange(); + } + /// Updates real range according to current variable range and data series void updateRealRange() { @@ -94,7 +102,10 @@ SqpRange Variable::cacheRange() const noexcept void Variable::setCacheRange(const SqpRange &cacheRange) noexcept { impl->lockWrite(); - impl->m_CacheRange = cacheRange; + if (cacheRange != impl->m_CacheRange) { + impl->m_CacheRange = cacheRange; + impl->purgeDataSeries(); + } impl->unlock(); } @@ -103,20 +114,6 @@ SqpRange Variable::realRange() const noexcept return impl->m_RealRange; } -void Variable::setDataSeries(std::shared_ptr dataSeries) noexcept -{ - qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries" - << QThread::currentThread()->objectName(); - if (!dataSeries) { - /// @todo ALX : log - return; - } - impl->lockWrite(); - impl->m_DataSeries = dataSeries->clone(); - impl->updateRealRange(); - impl->unlock(); -} - void Variable::mergeDataSeries(std::shared_ptr dataSeries) noexcept { qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries" @@ -127,7 +124,6 @@ void Variable::mergeDataSeries(std::shared_ptr dataSeries) noexcept } // Add or merge the data - // Inits the data series of the variable impl->lockWrite(); if (!impl->m_DataSeries) { impl->m_DataSeries = dataSeries->clone(); @@ -135,13 +131,8 @@ void Variable::mergeDataSeries(std::shared_ptr dataSeries) noexcept else { impl->m_DataSeries->merge(dataSeries.get()); } + impl->purgeDataSeries(); impl->unlock(); - - // sub the data - auto subData = this->dataSeries()->subDataSeries(this->cacheRange()); - qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range(); - this->setDataSeries(subData); - qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries set" << this->dataSeries()->range(); } std::shared_ptr Variable::dataSeries() const noexcept diff --git a/core/tests/Data/TestDataSeries.cpp b/core/tests/Data/TestDataSeries.cpp index adb30f6..0a9fa4c 100644 --- a/core/tests/Data/TestDataSeries.cpp +++ b/core/tests/Data/TestDataSeries.cpp @@ -22,6 +22,20 @@ void validateRange(DataSeriesIterator first, DataSeriesIterator last, const QVec [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; })); } +void validateRange(DataSeriesIterator first, DataSeriesIterator last, const QVector &xData, + const QVector > &valuesData) +{ + QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(), + [](const auto &it, const auto &expectedX) { return it.x() == expectedX; })); + for (auto i = 0; i < valuesData.size(); ++i) { + auto componentData = valuesData.at(i); + + QVERIFY(std::equal( + first, last, componentData.cbegin(), componentData.cend(), + [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; })); + } +} + } // namespace class TestDataSeries : public QObject { @@ -75,7 +89,42 @@ private: } } + template + void testPurgeStructure() + { + // ////////////// // + // Test structure // + // ////////////// // + + // Data series to purge + QTest::addColumn >("dataSeries"); + QTest::addColumn("min"); + QTest::addColumn("max"); + + // Expected values after purge + QTest::addColumn >("expectedXAxisData"); + QTest::addColumn > >("expectedValuesData"); + } + + template + void testPurge() + { + QFETCH(std::shared_ptr, dataSeries); + QFETCH(double, min); + QFETCH(double, max); + + dataSeries->purge(min, max); + + // Validates results + QFETCH(QVector, expectedXAxisData); + QFETCH(QVector >, expectedValuesData); + + validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, + expectedValuesData); + } + private slots: + /// Input test data /// @sa testCtor() void testCtor_data(); @@ -91,6 +140,20 @@ private slots: void testMerge(); /// Input test data + /// @sa testPurgeScalar() + void testPurgeScalar_data(); + + /// Tests purge of a scalar series + void testPurgeScalar(); + + /// Input test data + /// @sa testPurgeVector() + void testPurgeVector_data(); + + /// Tests purge of a vector series + void testPurgeVector(); + + /// Input test data /// @sa testMinXAxisData() void testMinXAxisData_data(); @@ -261,6 +324,62 @@ void TestDataSeries::testMerge() validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData); } +void TestDataSeries::testPurgeScalar_data() +{ + testPurgeStructure(); + + // ////////// // + // Test cases // + // ////////// // + + QTest::newRow("purgeScalar") << createScalarSeries({1., 2., 3., 4., 5.}, + {100., 200., 300., 400., 500.}) + << 2. << 4. << QVector{2., 3., 4.} + << QVector >{{200., 300., 400.}}; + QTest::newRow("purgeScalar2") << createScalarSeries({1., 2., 3., 4., 5.}, + {100., 200., 300., 400., 500.}) + << 0. << 2.5 << QVector{1., 2.} + << QVector >{{100., 200.}}; + QTest::newRow("purgeScalar3") << createScalarSeries({1., 2., 3., 4., 5.}, + {100., 200., 300., 400., 500.}) + << 3.5 << 7. << QVector{4., 5.} + << QVector >{{400., 500.}}; + QTest::newRow("purgeScalar4") << createScalarSeries({1., 2., 3., 4., 5.}, + {100., 200., 300., 400., 500.}) + << 0. << 7. << QVector{1., 2., 3., 4., 5.} + << QVector >{{100., 200., 300., 400., 500.}}; + QTest::newRow("purgeScalar5") << createScalarSeries({1., 2., 3., 4., 5.}, + {100., 200., 300., 400., 500.}) + << 5.5 << 7. << QVector{} + << QVector >{{}}; +} + +void TestDataSeries::testPurgeScalar() +{ + testPurge(); +} + +void TestDataSeries::testPurgeVector_data() +{ + testPurgeStructure(); + + // ////////// // + // Test cases // + // ////////// // + + QTest::newRow("purgeVector") << createVectorSeries({1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, + {11., 12., 13., 14., 15.}, + {16., 17., 18., 19., 20.}) + << 2. << 4. << QVector{2., 3., 4.} + << QVector >{ + {7., 8., 9.}, {12., 13., 14.}, {17., 18., 19.}}; +} + +void TestDataSeries::testPurgeVector() +{ + testPurge(); +} + void TestDataSeries::testMinXAxisData_data() { // ////////////// // diff --git a/core/vera-exclusions/exclusions.txt b/core/vera-exclusions/exclusions.txt index 5c6690c..6b91bba 100644 --- a/core/vera-exclusions/exclusions.txt +++ b/core/vera-exclusions/exclusions.txt @@ -11,10 +11,14 @@ DataSeriesMergeHelper\.h:\d+:.*IPSIS_S01.* # Ignore false positive relative to a template class ArrayData\.h:\d+:.*IPSIS_S04_METHOD.*found: push_back +ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (const_iterator) ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (D) +ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (IC) ArrayData\.h:\d+:.*IPSIS_S04_NAMESPACE.*found: (arraydata_detail) ArrayData\.h:\d+:.*IPSIS_S06.*found: (D) ArrayData\.h:\d+:.*IPSIS_S06.*found: (Dim) +ArrayData\.h:\d+:.*IPSIS_S06.*found: (IC) +ArrayData\.h:\d+:.*IPSIS_S06.*found: (IsConst) DataSeries\.h:\d+:.*IPSIS_S04_METHOD.*found: LOG_DataSeries DataSeries\.h:\d+:.*IPSIS_S04_METHOD.*found: push_back DataSeries\.h:\d+:.*IPSIS_S04_VARIABLE.* @@ -22,6 +26,9 @@ DataSeries\.h:\d+:.*IPSIS_S04_NAMESPACE.*found: (dataseries_detail) DataSeries\.h:\d+:.*IPSIS_S05.* DataSeries\.h:\d+:.*IPSIS_S06.*found: (value_type) DataSeries\.h:\d+:.*IPSIS_S06.*found: (DataSeriesIteratorValue) +DataSeries\.h:\d+:.*IPSIS_S06.*found: (Dim) +DataSeries\.h:\d+:.*IPSIS_S06.*found: (IC) +DataSeries\.h:\d+:.*IPSIS_S06.*found: (IsConst) # Ignore false positive relative to iterators SqpIterator\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (forward_iterator_tag)