VariableCacheController.cpp
225 lines
| 9.2 KiB
| text/x-c
|
CppLexer
r225 | #include "Variable/VariableCacheController.h" | |||
#include "Variable/Variable.h" | ||||
#include <unordered_map> | ||||
r364 | #include <QThread> | |||
r293 | Q_LOGGING_CATEGORY(LOG_VariableCacheController, "VariableCacheController") | |||
r225 | struct VariableCacheController::VariableCacheControllerPrivate { | |||
r512 | std::unordered_map<std::shared_ptr<Variable>, QVector<SqpRange> > m_VariableToSqpRangeListMap; | |||
r229 | ||||
r512 | void addInCacheDataByEnd(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, | |||
QVector<SqpRange> ¬InCache, int cacheIndex, double currentTStart); | ||||
r229 | ||||
r512 | void addInCacheDataByStart(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, | |||
QVector<SqpRange> ¬InCache, int cacheIndex, double currentTStart); | ||||
r230 | ||||
r512 | void addDateTimeRecurse(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, | |||
r230 | int cacheIndex); | |||
r225 | }; | |||
VariableCacheController::VariableCacheController(QObject *parent) | ||||
r243 | : QObject{parent}, impl{spimpl::make_unique_impl<VariableCacheControllerPrivate>()} | |||
r225 | { | |||
} | ||||
void VariableCacheController::addDateTime(std::shared_ptr<Variable> variable, | ||||
r512 | const SqpRange &dateTime) | |||
r225 | { | |||
|
r960 | qCDebug(LOG_VariableCacheController()) | ||
<< "VariableCacheController::addDateTime" << QThread::currentThread()->objectName(); | ||||
r225 | if (variable) { | |||
r512 | auto findVariableIte = impl->m_VariableToSqpRangeListMap.find(variable); | |||
if (findVariableIte == impl->m_VariableToSqpRangeListMap.end()) { | ||||
impl->m_VariableToSqpRangeListMap[variable].push_back(dateTime); | ||||
r230 | } | |||
else { | ||||
r512 | // addDateTime modify the list<SqpRange> of the variable in a way to ensure | |||
r230 | // that the list is ordered : l(0) < l(1). We assume also a < b | |||
r512 | // (with a & b of type SqpRange) means ts(b) > te(a) | |||
r230 | ||||
// The algorithm will try the merge of two interval: | ||||
// - dateTime will be compare with the first interval of the list: | ||||
// A: if it is inferior, it will be inserted and it's finished. | ||||
// B: if it is in intersection, it will be merge then the merged one | ||||
// will be compared to the next interval. The old one is remove from the list | ||||
// C: if it is superior, we do the same with the next interval of the list | ||||
r300 | try { | |||
r512 | impl->addDateTimeRecurse(dateTime, impl->m_VariableToSqpRangeListMap.at(variable), | |||
0); | ||||
r300 | } | |||
catch (const std::out_of_range &e) { | ||||
r319 | qCWarning(LOG_VariableCacheController()) << "addDateTime" << e.what(); | |||
r300 | } | |||
r230 | } | |||
r225 | } | |||
} | ||||
r229 | ||||
|
r331 | void VariableCacheController::clear(std::shared_ptr<Variable> variable) noexcept | ||
{ | ||||
if (!variable) { | ||||
qCCritical(LOG_VariableCacheController()) << "Can't clear variable cache: variable is null"; | ||||
return; | ||||
} | ||||
r512 | auto nbEntries = impl->m_VariableToSqpRangeListMap.erase(variable); | |||
|
r331 | |||
auto clearCacheMessage | ||||
= (nbEntries != 0) | ||||
? tr("Variable cache cleared for variable %1").arg(variable->name()) | ||||
: tr("No deletion of variable cache: no cache was associated with the variable"); | ||||
qCDebug(LOG_VariableCacheController()) << clearCacheMessage; | ||||
} | ||||
r512 | QVector<SqpRange> | |||
r229 | VariableCacheController::provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable, | |||
r512 | const SqpRange &dateTime) | |||
r229 | { | |||
r367 | qCDebug(LOG_VariableCacheController()) | |||
r364 | << "VariableCacheController::provideNotInCacheDateTimeList" | |||
<< QThread::currentThread()->objectName(); | ||||
r512 | auto notInCache = QVector<SqpRange>{}; | |||
r229 | ||||
// This algorithm is recursif. The idea is to localise the start time then the end time in the | ||||
// list of date time request associated to the variable | ||||
// We assume that the list is ordered in a way that l(0) < l(1). We assume also a < b | ||||
r512 | // (with a & b of type SqpRange) means ts(b) > te(a) | |||
auto it = impl->m_VariableToSqpRangeListMap.find(variable); | ||||
if (it != impl->m_VariableToSqpRangeListMap.end()) { | ||||
r319 | impl->addInCacheDataByStart(dateTime, it->second, notInCache, 0, dateTime.m_TStart); | |||
r300 | } | |||
r319 | else { | |||
notInCache << dateTime; | ||||
r300 | } | |||
r229 | ||||
return notInCache; | ||||
} | ||||
r512 | QVector<SqpRange> | |||
r230 | VariableCacheController::dateCacheList(std::shared_ptr<Variable> variable) const noexcept | |||
{ | ||||
|
r960 | qCDebug(LOG_VariableCacheController()) | ||
<< "VariableCacheController::dateCacheList" << QThread::currentThread()->objectName(); | ||||
r300 | try { | |||
r512 | return impl->m_VariableToSqpRangeListMap.at(variable); | |||
r300 | } | |||
catch (const std::out_of_range &e) { | ||||
r303 | qCWarning(LOG_VariableCacheController()) << e.what(); | |||
r512 | return QVector<SqpRange>{}; | |||
r300 | } | |||
r230 | } | |||
void VariableCacheController::VariableCacheControllerPrivate::addDateTimeRecurse( | ||||
r512 | const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, int cacheIndex) | |||
r230 | { | |||
const auto dateTimeListSize = dateTimeList.count(); | ||||
if (cacheIndex >= dateTimeListSize) { | ||||
dateTimeList.push_back(dateTime); | ||||
// there is no anymore interval to compore, we can just push_back it | ||||
return; | ||||
} | ||||
auto currentDateTime = dateTimeList[cacheIndex]; | ||||
if (dateTime.m_TEnd < currentDateTime.m_TStart) { | ||||
// The compared one is < to current one compared, we can insert it | ||||
dateTimeList.insert(cacheIndex, dateTime); | ||||
} | ||||
else if (dateTime.m_TStart > currentDateTime.m_TEnd) { | ||||
// The compared one is > to current one compared we can comparet if to the next one | ||||
addDateTimeRecurse(dateTime, dateTimeList, ++cacheIndex); | ||||
} | ||||
else { | ||||
// Merge cases: we need to merge the two interval, remove the old one from the list then | ||||
// rerun the algo from this index with the merged interval | ||||
auto mTStart = std::min(dateTime.m_TStart, currentDateTime.m_TStart); | ||||
auto mTEnd = std::max(dateTime.m_TEnd, currentDateTime.m_TEnd); | ||||
r512 | auto mergeDateTime = SqpRange{mTStart, mTEnd}; | |||
r230 | ||||
dateTimeList.remove(cacheIndex); | ||||
addDateTimeRecurse(mergeDateTime, dateTimeList, cacheIndex); | ||||
} | ||||
} | ||||
r229 | ||||
void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByEnd( | ||||
r512 | const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, QVector<SqpRange> ¬InCache, | |||
int cacheIndex, double currentTStart) | ||||
r229 | { | |||
const auto dateTimeListSize = dateTimeList.count(); | ||||
if (cacheIndex >= dateTimeListSize) { | ||||
if (currentTStart < dateTime.m_TEnd) { | ||||
// te localised after all other interval: The last interval is [currentTsart, te] | ||||
r512 | notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd}); | |||
r229 | } | |||
return; | ||||
} | ||||
auto currentDateTimeJ = dateTimeList[cacheIndex]; | ||||
if (dateTime.m_TEnd <= currentDateTimeJ.m_TStart) { | ||||
// te localised between to interval: The last interval is [currentTsart, te] | ||||
r512 | notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd}); | |||
r229 | } | |||
else { | ||||
r512 | notInCache.push_back(SqpRange{currentTStart, currentDateTimeJ.m_TStart}); | |||
r229 | if (dateTime.m_TEnd > currentDateTimeJ.m_TEnd) { | |||
// te not localised before the current interval: we need to look at the next interval | ||||
addInCacheDataByEnd(dateTime, dateTimeList, notInCache, ++cacheIndex, | ||||
currentDateTimeJ.m_TEnd); | ||||
} | ||||
} | ||||
} | ||||
void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByStart( | ||||
r512 | const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, QVector<SqpRange> ¬InCache, | |||
int cacheIndex, double currentTStart) | ||||
r229 | { | |||
const auto dateTimeListSize = dateTimeList.count(); | ||||
if (cacheIndex >= dateTimeListSize) { | ||||
// ts localised after all other interval: The last interval is [ts, te] | ||||
r512 | notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd}); | |||
r229 | return; | |||
} | ||||
auto currentDateTimeI = dateTimeList[cacheIndex]; | ||||
if (currentTStart < currentDateTimeI.m_TStart) { | ||||
// ts localised between to interval: let's localized te | ||||
r243 | addInCacheDataByEnd(dateTime, dateTimeList, notInCache, cacheIndex, currentTStart); | |||
r229 | } | |||
r293 | else if (currentTStart < currentDateTimeI.m_TEnd) { | |||
if (dateTime.m_TEnd > currentDateTimeI.m_TEnd) { | ||||
// ts not localised before the current interval: we need to look at the next interval | ||||
// We can assume now current tstart is the last interval tend, because data between them | ||||
// are | ||||
// in the cache | ||||
addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex, | ||||
currentDateTimeI.m_TEnd); | ||||
} | ||||
r229 | } | |||
else { | ||||
// ts not localised before the current interval: we need to look at the next interval | ||||
addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex, currentTStart); | ||||
} | ||||
} | ||||
r293 | ||||
r300 | void VariableCacheController::displayCache(std::shared_ptr<Variable> variable) const | |||
r293 | { | |||
r512 | auto variableDateTimeList = impl->m_VariableToSqpRangeListMap.find(variable); | |||
if (variableDateTimeList != impl->m_VariableToSqpRangeListMap.end()) { | ||||
|
r960 | qCInfo(LOG_VariableCacheController()) | ||
<< tr("VariableCacheController::displayCache") << variableDateTimeList->second; | ||||
r300 | } | |||
else { | ||||
qCWarning(LOG_VariableCacheController()) | ||||
<< tr("Cannot display a variable that is not in the cache"); | ||||
} | ||||
r293 | } | |||