diff --git a/core/include/Data/ArrayData.h b/core/include/Data/ArrayData.h index 55fb8c5..a66b06f 100644 --- a/core/include/Data/ArrayData.h +++ b/core/include/Data/ArrayData.h @@ -98,14 +98,34 @@ public: return m_Data.at(0); } - // TODO Comment + /** + * Merges into the array data an other array data + * @param other the array data to merge with + * @param prepend if true, the other array data is inserted at the beginning, otherwise it is + * inserted at the end + * @remarks this method is only available for a unidimensional ArrayData + */ template > - void merge(const ArrayData<1> &arrayData) + void add(const ArrayData<1> &other, bool prepend = false) { QWriteLocker locker{&m_Lock}; if (!m_Data.empty()) { - QReadLocker otherLocker{&arrayData.m_Lock}; - m_Data[0] += arrayData.data(); + QReadLocker otherLocker{&other.m_Lock}; + + if (prepend) { + const auto &otherData = other.data(); + const auto otherDataSize = otherData.size(); + + auto &data = m_Data[0]; + data.insert(data.begin(), otherDataSize, 0.); + + for (auto i = 0; i < otherDataSize; ++i) { + data.replace(i, otherData.at(i)); + } + } + else { + m_Data[0] += other.data(); + } } } diff --git a/core/include/Data/DataSeries.h b/core/include/Data/DataSeries.h index 7e22a94..f6cbde5 100644 --- a/core/include/Data/DataSeries.h +++ b/core/include/Data/DataSeries.h @@ -49,18 +49,64 @@ public: m_ValuesData->clear(); } - /// @sa IDataSeries::merge() + /// Merges into the data series an other data series + /// @remarks the data series to merge with is cleared after the operation void merge(IDataSeries *dataSeries) override { - if (auto dimDataSeries = dynamic_cast *>(dataSeries)) { - m_XAxisData->merge(*dimDataSeries->xAxisData()); - m_ValuesData->merge(*dimDataSeries->valuesData()); - dimDataSeries->clear(); + dataSeries->lockWrite(); + lockWrite(); + + if (auto other = dynamic_cast *>(dataSeries)) { + const auto &otherXAxisData = other->xAxisData()->cdata(); + const auto &xAxisData = m_XAxisData->cdata(); + + // As data series are sorted, we can improve performances of merge, by call the sort + // method only if the two data series overlap. + if (!otherXAxisData.empty()) { + auto firstValue = otherXAxisData.front(); + auto lastValue = otherXAxisData.back(); + + auto xAxisDataBegin = xAxisData.cbegin(); + auto xAxisDataEnd = xAxisData.cend(); + + bool prepend; + bool sortNeeded; + + if (std::lower_bound(xAxisDataBegin, xAxisDataEnd, firstValue) == xAxisDataEnd) { + // Other data series if after data series + prepend = false; + sortNeeded = false; + } + else if (std::upper_bound(xAxisDataBegin, xAxisDataEnd, lastValue) + == xAxisDataBegin) { + // Other data series if before data series + prepend = true; + sortNeeded = false; + } + else { + // The two data series overlap + prepend = false; + sortNeeded = true; + } + + // Makes the merge + m_XAxisData->add(*other->xAxisData(), prepend); + m_ValuesData->add(*other->valuesData(), prepend); + + if (sortNeeded) { + sort(); + } + } + + // Clears the other data series + other->clear(); } else { qCWarning(LOG_DataSeries()) - << QObject::tr("Dection of a type of IDataSeries we cannot merge with !"); + << QObject::tr("Detection of a type of IDataSeries we cannot merge with !"); } + unlock(); + dataSeries->unlock(); } virtual void lockRead() { m_Lock.lockForRead(); } diff --git a/core/src/Variable/Variable.cpp b/core/src/Variable/Variable.cpp index 286ef52..c866661 100644 --- a/core/src/Variable/Variable.cpp +++ b/core/src/Variable/Variable.cpp @@ -55,11 +55,7 @@ void Variable::setDataSeries(std::shared_ptr dataSeries) noexcept impl->m_DataSeries = dataSeries->clone(); } else { - dataSeries->lockWrite(); - impl->m_DataSeries->lockWrite(); impl->m_DataSeries->merge(dataSeries.get()); - impl->m_DataSeries->unlock(); - dataSeries->unlock(); // emit updated(); } }