diff --git a/core/include/Data/ArrayData.h b/core/include/Data/ArrayData.h index d676c70..a07dc93 100644 --- a/core/include/Data/ArrayData.h +++ b/core/include/Data/ArrayData.h @@ -256,16 +256,7 @@ public: return; } - if (prepend) { - auto otherDataSize = other.m_Data.size(); - m_Data.insert(m_Data.begin(), otherDataSize, 0.); - for (auto i = 0; i < otherDataSize; ++i) { - m_Data.replace(i, other.m_Data.at(i)); - } - } - else { - m_Data.append(other.m_Data); - } + insert(other.cbegin(), other.cend(), prepend); } void clear() @@ -332,16 +323,16 @@ public: } } - /// 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 - /// components of the array data - /// @param values the values to insert - /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter - void push_back(const QVector &values) + void insert(ArrayDataIterator first, ArrayDataIterator last, bool prepend = false) { - Q_ASSERT(values.size() % m_NbComponents == 0); - m_Data.append(values); + auto firstImpl = dynamic_cast *>(first->impl()); + auto lastImpl = dynamic_cast *>(last->impl()); + + if (firstImpl && lastImpl) { + auto insertIt = prepend ? m_Data.begin() : m_Data.end(); + + m_Data.insert(insertIt, firstImpl->m_It, lastImpl->m_It); + } } /** diff --git a/core/include/Data/DataSeries.h b/core/include/Data/DataSeries.h index 9fa5b0f..7e4f998 100644 --- a/core/include/Data/DataSeries.h +++ b/core/include/Data/DataSeries.h @@ -134,10 +134,6 @@ class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries { friend class DataSeriesMergeHelper; public: - /// Tag needed to define the push_back() method - /// @sa push_back() - using value_type = DataSeriesIteratorValue; - /// @sa IDataSeries::xAxisData() std::shared_ptr > xAxisData() override { return m_XAxisData; } const std::shared_ptr > xAxisData() const { return m_XAxisData; } @@ -254,6 +250,17 @@ public: } } + void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false) + { + auto firstImpl = dynamic_cast *>(first->impl()); + auto lastImpl = dynamic_cast *>(last->impl()); + + if (firstImpl && lastImpl) { + m_XAxisData->insert(firstImpl->m_XIt, lastImpl->m_XIt, prepend); + m_ValuesData->insert(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt, prepend); + } + } + /// @sa IDataSeries::minXAxisData() DataSeriesIterator minXAxisData(double minXAxisData) const override { @@ -287,7 +294,7 @@ public: begin, end, minXAxisData, [](const auto &itValue, const auto &value) { return itValue.x() < value; }); auto upperIt = std::upper_bound( - begin, end, maxXAxisData, + lowerIt, end, maxXAxisData, [](const auto &value, const auto &itValue) { return value < itValue.x(); }); return std::make_pair(lowerIt, upperIt); @@ -327,22 +334,6 @@ public: virtual void lockWrite() { m_Lock.lockForWrite(); } virtual void unlock() { m_Lock.unlock(); } - // ///// // - // Other // - // ///// // - - /// Inserts at the end of the data series the value of the iterator passed as a parameter. This - /// method is intended to be used in the context of generating a back insert iterator - /// @param iteratorValue the iterator value containing the values to insert - /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter - /// @sa merge() - /// @sa value_type - void push_back(const value_type &iteratorValue) - { - m_XAxisData->push_back(QVector{iteratorValue.x()}); - m_ValuesData->push_back(iteratorValue.values()); - } - protected: /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a /// DataSeries with no values will be created. diff --git a/core/include/Data/DataSeriesMergeHelper.h b/core/include/Data/DataSeriesMergeHelper.h index 0f45a02..90d7c26 100644 --- a/core/include/Data/DataSeriesMergeHelper.h +++ b/core/include/Data/DataSeriesMergeHelper.h @@ -27,45 +27,6 @@ MergeScope scope(FEnd end) return MergeScope{end}; } -/** - * Enum used to position a data series relative to another during a merge operation - */ -enum class MergePosition { LOWER_THAN, GREATER_THAN, EQUAL, OVERLAP }; - -/** - * Computes the position of the first data series relative to the second data series - * @param lhs the first data series - * @param rhs the second data series - * @return the merge position computed - * @remarks the data series must not be empty - */ -template -MergePosition mergePosition(DataSeries &lhs, DataSeries &rhs) -{ - Q_ASSERT(!lhs.isEmpty() && !rhs.isEmpty()); - - // Case lhs < rhs - auto lhsLast = --lhs.cend(); - auto rhsFirst = rhs.cbegin(); - if (lhsLast->x() < rhsFirst->x()) { - return MergePosition::LOWER_THAN; - } - - // Case lhs > rhs - auto lhsFirst = lhs.cbegin(); - auto rhsLast = --rhs.cend(); - if (lhsFirst->x() > rhsLast->x()) { - return MergePosition::GREATER_THAN; - } - - // Other cases - auto equal = std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), - [](const auto &it1, const auto &it2) { - return it1.x() == it2.x() && it1.values() == it2.values(); - }); - return equal ? MergePosition::EQUAL : MergePosition::OVERLAP; -} - } // namespace detail @@ -92,40 +53,30 @@ struct DataSeriesMergeHelper { return; } - // Gets the position of the source in relation to the destination - auto sourcePosition = detail::mergePosition(source, dest); + auto destMin = dest.cbegin()->x(); + auto destMax = (--dest.cend())->x(); + + auto sourceBegin = source.cbegin(); + auto sourceEnd = source.cend(); + auto sourceMin = sourceBegin->x(); + auto sourceMax = (--source.cend())->x(); - switch (sourcePosition) { - case detail::MergePosition::LOWER_THAN: - case detail::MergePosition::GREATER_THAN: { - auto prepend = sourcePosition == detail::MergePosition::LOWER_THAN; - dest.m_XAxisData->add(*source.m_XAxisData, prepend); - dest.m_ValuesData->add(*source.m_ValuesData, prepend); - break; - } - case detail::MergePosition::EQUAL: - // the data series equal each other : no merge made - break; - case detail::MergePosition::OVERLAP: { - // the two data series overlap : merge is made - auto temp = dest.clone(); - if (auto tempSeries = dynamic_cast *>(temp.get())) { - // Makes the merge : - // - Data are sorted by x-axis values - // - If two entries are in the source range and the other range, only one entry - // is retained as result - // - The results are stored directly in the data series - dest.clear(); - std::set_union( - tempSeries->cbegin(), tempSeries->cend(), source.cbegin(), source.cend(), - std::back_inserter(dest), - [](const auto &it1, const auto &it2) { return it1.x() < it2.x(); }); - } - break; - } - default: - Q_ASSERT(false); + // Case : source bounds are inside dest bounds -> no merge is made + if (sourceMin >= destMin && sourceMax <= destMax) { + return; } + + // Default case : + // - prepend to dest the values of source that are lower than min value of dest + // - append to dest the values of source that are greater than max value of dest + auto lowerIt + = std::lower_bound(sourceBegin, sourceEnd, destMin, + [](const auto &it, const auto &val) { return it.x() < val; }); + auto upperIt + = std::upper_bound(lowerIt, sourceEnd, destMax, + [](const auto &val, const auto &it) { return val < it.x(); }); + dest.insert(sourceBegin, lowerIt, true); + dest.insert(upperIt, sourceEnd); } };