/* Copyright (C) 2015 * swift Project Community / Contributors * * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, * including this file, may be copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE file. */ //! \cond PRIVATE #include "blackmisc/aviation/aircraftsituationlist.h" #include "blackmisc/aviation/aircraftpartslist.h" #include "blackmisc/aviation/aircraftsituationchangelist.h" #include "blackmisc/aviation/liverylist.h" #include "blackmisc/aviation/aircrafticaocodelist.h" #include "blackmisc/aviation/airlineicaocodelist.h" #include "blackmisc/aviation/airportlist.h" #include "blackmisc/db/dbinfolist.h" #include "blackmisc/db/artifactlist.h" #include "blackmisc/db/distributionlist.h" #include "blackmisc/network/textmessagelist.h" #include "blackmisc/network/rawfsdmessagelist.h" #include "blackmisc/network/urlloglist.h" #include "blackmisc/simulation/distributorlist.h" #include "blackmisc/simulation/aircraftmodellist.h" #include "blackmisc/simulation/distributorlist.h" #include "blackmisc/simulation/matchingstatistics.h" #include "blackmisc/statusmessagelist.h" #include "blackmisc/timestampobjectlist.h" #include "blackmisc/predicates.h" #include "blackmisc/identifierlist.h" #include "blackmisc/countrylist.h" #include "blackmisc/verify.h" #include "blackconfig/buildconfig.h" #include #include #include #include #include #include using namespace BlackConfig; namespace BlackMisc { template ITimestampObjectList::ITimestampObjectList() { static_assert(std::is_base_of::value, "OBJ needs to implement ITimestampBased"); } template const CONTAINER &ITimestampObjectList::container() const { return static_cast(*this); } template CONTAINER &ITimestampObjectList::container() { return static_cast(*this); } template CONTAINER ITimestampObjectList::findBefore(qint64 msSinceEpoch) const { return this->container().findBy([&](const OBJ & obj) { return obj.isOlderThan(msSinceEpoch); }); } template OBJ ITimestampObjectList::findObjectBeforeOrDefault(qint64 msSinceEpoch) const { const CONTAINER before = this->findBefore(msSinceEpoch); if (before.isEmpty()) { return OBJ(); } return before.latestObject(); } template CONTAINER ITimestampObjectList::findBeforeAndRemove(qint64 msSinceEpoch) { CONTAINER result(findBefore(msSinceEpoch)); this->removeBefore(msSinceEpoch); return result; } template CONTAINER ITimestampObjectList::findBeforeNowMinusOffset(qint64 msOffset) const { return this->findBefore(QDateTime::currentMSecsSinceEpoch() - msOffset); } template CONTAINER ITimestampObjectList::findBefore(const QDateTime &dateTime) const { return this->findBefore(dateTime.toMSecsSinceEpoch()); } template CONTAINER ITimestampObjectList::findAfter(qint64 msSinceEpoc) const { return this->container().findBy([&](const OBJ & obj) { return obj.isNewerThan(msSinceEpoc); }); } template CONTAINER ITimestampObjectList::findAfterNowMinusOffset(qint64 msOffset) const { return this->findAfter(QDateTime::currentMSecsSinceEpoch() - msOffset); } template OBJ ITimestampObjectList::findObjectAfterOrDefault(qint64 msSinceEpoch) const { const CONTAINER after = this->findAfter(msSinceEpoch); if (after.isEmpty()) { return OBJ(); } return after.oldestObject(); } template CONTAINER ITimestampObjectList::findInvalidTimestamps() const { return this->container().findBy([&](const OBJ & obj) { return !obj.hasValidTimestamp(); }); } template OBJ ITimestampObjectList::findClosestTimeDistance(qint64 msSinceEpoch) const { if (this->container().isEmpty()) { return OBJ(); } const auto closest = std::min_element(this->container().cbegin(), this->container().cend(), [ = ](const ITimestampBased & a, const ITimestampBased & b) { return qAbs(a.getTimeDifferenceMs(msSinceEpoch)) < qAbs(b.getTimeDifferenceMs(msSinceEpoch)); }); return *closest; } template bool ITimestampObjectList::hasInvalidTimestamps() const { return this->container().contains(&OBJ::hasValidTimestamp, false); } template void ITimestampObjectList::setCurrentUtcTime() { for (ITimestampBased &tsObj : this->container()) { tsObj.setCurrentUtcTime(); } } template void ITimestampObjectList::setUtcTime(qint64 msSinceEpoch) { for (ITimestampBased &tsObj : this->container()) { tsObj.setMSecsSinceEpoch(msSinceEpoch); } } template void ITimestampObjectList::setInvalidTimestampsToCurrentUtcTime() { for (ITimestampBased &tsObj : this->container()) { if (tsObj.hasValidTimestamp()) { continue; } tsObj.setCurrentUtcTime(); } } template QDateTime ITimestampObjectList::latestTimestamp() const { if (this->container().isEmpty()) { return QDateTime(); } return this->latestObject().getUtcTimestamp(); } template qint64 ITimestampObjectList::latestTimestampMsecsSinceEpoch() const { const QDateTime dt(latestTimestamp()); return dt.isValid() ? dt.toMSecsSinceEpoch() : -1; } template QDateTime ITimestampObjectList::oldestTimestamp() const { if (this->container().isEmpty()) { return QDateTime(); } return this->oldestObject().getUtcTimestamp(); } template qint64 ITimestampObjectList::oldestTimestampMsecsSinceEpoch() const { const QDateTime dt(oldestTimestamp()); return dt.isValid() ? dt.toMSecsSinceEpoch() : -1; } template OBJ ITimestampObjectList::latestObject() const { if (this->container().isEmpty()) { return OBJ(); } const auto latest = std::max_element(this->container().begin(), this->container().end(), [](const OBJ & a, const OBJ & b) { return a.getMSecsSinceEpoch() < b.getMSecsSinceEpoch(); }); return *latest; } template OBJ ITimestampObjectList::oldestObject() const { if (this->container().isEmpty()) { return OBJ(); } const auto oldest = std::min_element(this->container().begin(), this->container().end(), [](const OBJ & a, const OBJ & b) { return a.getMSecsSinceEpoch() < b.getMSecsSinceEpoch(); }); return *oldest; } template CONTAINER ITimestampObjectList::findAfter(const QDateTime &dateTime) const { return this->findAfter(dateTime.toMSecsSinceEpoch()); } template int ITimestampObjectList::removeBefore(const QDateTime &dateTime) { return this->removeBefore(dateTime.toMSecsSinceEpoch()); } template int ITimestampObjectList::removeBefore(qint64 msSinceEpoc) { return this->container().removeIf([&](const OBJ & obj) { return obj.isOlderThan(msSinceEpoc); }); } template int ITimestampObjectList::removeOlderThanNowMinusOffset(qint64 offsetMs) { const qint64 epoch = QDateTime::currentMSecsSinceEpoch() - offsetMs; return this->container().removeIf([&](const OBJ & obj) { return obj.isOlderThan(epoch); }); } template void ITimestampObjectList::sortLatestFirst() { this->container().sortOldestFirst(); this->container().reverse(); } template void ITimestampObjectList::sortOldestFirst() { this->container().sort(Predicates::MemberLess(&OBJ::getMSecsSinceEpoch)); } template void ITimestampObjectList::push_frontKeepLatestFirst(const OBJ &value, bool replaceSameTimestamp, int maxElements) { Q_ASSERT_X(maxElements < 0 || maxElements > 1, Q_FUNC_INFO, "Max.value wrong range"); CONTAINER &c = this->container(); if (replaceSameTimestamp && !c.isEmpty() && c[0].getMSecsSinceEpoch() == value.getMSecsSinceEpoch()) { c[0] = value; if (maxElements > 0) { c.truncate(maxElements); } return; } if (maxElements > 0) { c.truncate(maxElements - 1); } const bool needSort = !c.isEmpty() && value.isOlderThan(c.front()); c.push_front(value); if (needSort) { ITimestampObjectList::sortLatestFirst(); } } template int ITimestampObjectList::replaceIfSameTimestamp(const OBJ &newObject) { int c = 0; for (OBJ &obj : this->container()) { if (obj.getMSecsSinceEpoch() == newObject.getMSecsSinceEpoch()) { obj = newObject; c++; } } return c; } template bool ITimestampObjectList::isSortedLatestLast() const { if (this->container().size() < 2) { return true; } qint64 max = -1; for (const ITimestampBased &obj : this->container()) { if (!obj.hasValidTimestamp()) { return false; } if (obj.getMSecsSinceEpoch() < max) { return false; } max = obj.getMSecsSinceEpoch(); } return true; } template bool ITimestampObjectList::isSortedLatestFirst() const { if (this->container().size() < 2) { return true; } qint64 min = std::numeric_limits ::max(); for (const ITimestampBased &obj : this->container()) { if (!obj.hasValidTimestamp()) { return false; } if (obj.getMSecsSinceEpoch() > min) { return false; } min = obj.getMSecsSinceEpoch(); } return true; } template void ITimestampObjectList::addMsecs(qint64 msToAdd) { if (msToAdd == 0) { return; } for (ITimestampBased &obj : this->container()) { obj.addMsecs(msToAdd); } } template MillisecondsMinMaxMean ITimestampObjectList::getTimestampDifferenceMinMaxMean() const { MillisecondsMinMaxMean mmm; mmm.reset(); if (this->container().size() < 2) { return mmm; } if (m_tsSortHint == NoTimestampSortHint) { CONTAINER copy(this->container()); copy.sortLatestFirst(); copy.m_tsSortHint = TimestampLatestFirst; return copy.getTimestampDifferenceMinMaxMean(); } mmm.max = std::numeric_limits::min(); mmm.min = std::numeric_limits::max(); qint64 mean = 0; int c = 0; OBJ last; for (const OBJ &object : this->container()) { c++; last = object; if (c < 2) { continue; } const ITimestampBased &l = last; const ITimestampBased &o = object; const qint64 diff = l.getAbsTimeDifferenceMs(o); if (diff > mmm.max) { mmm.max = diff; } if (diff < mmm.min) { mmm.min = diff; } mean += diff; } mmm.mean = mean / c; return mmm; } template void ITimestampWithOffsetObjectList::sortAdjustedLatestFirst() { this->container().sortAdjustedOldestFirst(); this->container().reverse(); } template CONTAINER ITimestampWithOffsetObjectList::getSortedAdjustedLatestFirst() const { CONTAINER copy(this->container()); copy.sortAdjustedLatestFirst(); return copy; } template CONTAINER ITimestampWithOffsetObjectList::getLatestAdjustedTwoObjects(bool alreadySortedLatestFirst) const { if (this->container().size() < 2) { return CONTAINER(); } CONTAINER copy(alreadySortedLatestFirst ? this->container() : this->container().getSortedAdjustedLatestFirst()); copy.truncate(2); return copy; } template void ITimestampWithOffsetObjectList::sortAdjustedOldestFirst() { this->container().sort(Predicates::MemberLess(&OBJ::getAdjustedMSecsSinceEpoch)); } template bool ITimestampWithOffsetObjectList::containsZeroOrNegativeOffsetTime() const { for (const ITimestampWithOffsetBased &obj : this->container()) { if (obj.getTimeOffsetMs() <= 0) { return true; } } return false; } template bool ITimestampWithOffsetObjectList::containsNegativeOffsetTime() const { for (const ITimestampWithOffsetBased &obj : this->container()) { if (obj.getTimeOffsetMs() < 0) { return true; } } return false; } template void ITimestampWithOffsetObjectList::addMsecsToOffset(qint64 msToAdd) { for (ITimestampWithOffsetBased &obj : this->container()) { obj.addMsecsToOffsetTime(msToAdd); } } template ITimestampWithOffsetObjectList::ITimestampWithOffsetObjectList() : ITimestampObjectList() { static_assert(std::is_base_of::value, "OBJ needs to implement ITimestampBased"); } template void ITimestampWithOffsetObjectList::push_frontKeepLatestAdjustedFirst(const OBJ &value, bool replaceSameTimestamp, int maxElements) { Q_ASSERT_X(maxElements < 0 || maxElements > 1, Q_FUNC_INFO, "Max.value wrong range"); CONTAINER &c = this->container(); if (replaceSameTimestamp && !c.isEmpty() && c[0].getMSecsSinceEpoch() == value.getMSecsSinceEpoch()) { c[0] = value; if (maxElements > 0) { c.truncate(maxElements); } return; } if (maxElements > 0) { c.truncate(maxElements - 1); } const bool needSort = !c.isEmpty() && value.isOlderThanAdjusted(c.front()); c.push_front(value); if (needSort) { ITimestampWithOffsetObjectList::sortAdjustedLatestFirst(); } } template void ITimestampWithOffsetObjectList::push_frontKeepLatestFirstAdjustOffset(const OBJ &value, bool replaceSameTimestamp, int maxElements) { ITimestampWithOffsetObjectList::push_frontKeepLatestAdjustedFirst(value, replaceSameTimestamp, maxElements); // now sorted by timestamp // this reflects normally the incoming order // ts // 8: os 2 adj 10 // 6: os 2 adj 8 // 5: os 5 adj 10 => max os 3 // 0: os 5 adj 5 CONTAINER &c = this->container(); if (c.size() < 2) { return; } const ITimestampWithOffsetBased &front = c.front(); ITimestampWithOffsetBased &second = c[1]; if (front.isNewerThanAdjusted(second)) { return; } const qint64 diffOs = front.getAdjustedMSecsSinceEpoch() - second.getMSecsSinceEpoch() - 1; const qint64 avgOs = (diffOs + qMin(front.getTimeOffsetMs(), diffOs)) / 2; second.setTimeOffsetMs(avgOs); if (CBuildConfig::isLocalDeveloperDebugBuild()) { Q_ASSERT_X(front.isNewerThanAdjusted(second), Q_FUNC_INFO, "Front/second timestamp"); Q_ASSERT_X(this->isSortedAdjustedLatestFirst(), Q_FUNC_INFO, "Wrong sort order"); } } template void ITimestampWithOffsetObjectList::prefillLatestAdjustedFirst(const OBJ &value, int elements, qint64 deltaTimeMs) { this->container().clear(); const qint64 osTime = value.getTimeOffsetMs(); const qint64 os = -1 * qAbs(deltaTimeMs < 0 ? osTime : deltaTimeMs); if (CBuildConfig::isLocalDeveloperDebugBuild()) { BLACK_VERIFY_X(os < 0, Q_FUNC_INFO, "Need negative offset time to prefill time"); } this->container().push_front(value); for (int i = 1; i < elements; i++) { OBJ copy(value); copy.addMsecs(os * i); this->container().push_back(copy); } this->setAdjustedSortHint(ITimestampWithOffsetObjectList::AdjustedTimestampLatestFirst); } template bool ITimestampWithOffsetObjectList::isSortedAdjustedLatestLast() const { if (this->container().isEmpty()) { return false; } if (this->container().size() < 2) { return true; } qint64 max = -1; for (const ITimestampWithOffsetBased &obj : this->container()) { if (!obj.hasValidTimestamp()) { return false; } if (obj.getAdjustedMSecsSinceEpoch() < max) { return false; } max = obj.getAdjustedMSecsSinceEpoch(); } return true; } template bool ITimestampWithOffsetObjectList::isSortedAdjustedLatestFirst() const { if (this->container().isEmpty()) { return false; } if (this->container().size() < 2) { return true; } qint64 min = std::numeric_limits ::max(); for (const ITimestampWithOffsetBased &obj : this->container()) { if (!obj.hasValidTimestamp()) { return false; } if (obj.getAdjustedMSecsSinceEpoch() > min) { return false; } min = obj.getAdjustedMSecsSinceEpoch(); } return true; } template CONTAINER ITimestampWithOffsetObjectList::findAfterAdjusted(qint64 msSinceEpoch) const { return this->container().findBy([&](const ITimestampWithOffsetBased & obj) { return obj.isNewerThanAdjusted(msSinceEpoch); }); } template OBJ ITimestampWithOffsetObjectList::findObjectAfterAdjustedOrDefault(qint64 msSinceEpoch) const { const CONTAINER after = this->findAfterAdjusted(msSinceEpoch); if (after.isEmpty()) { return OBJ(); } return after.oldestAdjustedObject(); } template CONTAINER ITimestampWithOffsetObjectList::findBeforeAdjusted(qint64 msSinceEpoch) const { return this->container().findBy([&](const ITimestampWithOffsetBased & obj) { return obj.isOlderThanAdjusted(msSinceEpoch); }); } template OBJ ITimestampWithOffsetObjectList::findObjectBeforeAdjustedOrDefault(qint64 msSinceEpoch) const { const CONTAINER before = this->findBeforeAdjusted(msSinceEpoch); if (before.isEmpty()) { return OBJ(); } return before.latestAdjustedObject(); } template OBJ ITimestampWithOffsetObjectList::findClosestTimeDistanceAdjusted(qint64 msSinceEpoch) const { if (this->container().isEmpty()) { return OBJ(); } const auto closest = std::min_element(this->container().cbegin(), this->container().cend(), [ = ](const ITimestampWithOffsetBased & a, const ITimestampWithOffsetBased & b) { return qAbs(a.getAdjustedTimeDifferenceMs(msSinceEpoch)) < qAbs(b.getAdjustedTimeDifferenceMs(msSinceEpoch)); }); return *closest; } template OBJ ITimestampWithOffsetObjectList::latestAdjustedObject() const { if (this->container().isEmpty()) { return OBJ(); } if (m_tsAdjustedSortHint == AdjustedTimestampLatestFirst) { return this->container().front(); } const auto latest = std::max_element(this->container().begin(), this->container().end(), [](const OBJ & a, const OBJ & b) { return a.getAdjustedMSecsSinceEpoch() < b.getAdjustedMSecsSinceEpoch(); }); return *latest; } template OBJ ITimestampWithOffsetObjectList::oldestAdjustedObject() const { if (this->container().isEmpty()) { return OBJ(); } if (m_tsAdjustedSortHint == AdjustedTimestampLatestFirst) { return this->container().back(); } const auto oldest = std::min_element(this->container().begin(), this->container().end(), [](const OBJ & a, const OBJ & b) { return a.getAdjustedMSecsSinceEpoch() < b.getAdjustedMSecsSinceEpoch(); }); return *oldest; } template QDateTime ITimestampWithOffsetObjectList::latestAdjustedTimestamp() const { if (this->container().isEmpty()) { return QDateTime(); } return this->latestAdjustedObject().getUtcTimestamp(); } template qint64 ITimestampWithOffsetObjectList::latestAdjustedTimestampMsecsSinceEpoch() const { if (this->container().isEmpty()) { return -1; } const QDateTime dt(this->latestAdjustedTimestamp()); return dt.isValid() ? dt.toMSecsSinceEpoch() : -1; } template QDateTime ITimestampWithOffsetObjectList::oldestAdjustedTimestamp() const { if (this->container().isEmpty()) { return QDateTime(); } return this->oldestAdjustedObject().getUtcTimestamp(); } template qint64 ITimestampWithOffsetObjectList::oldestAdjustedTimestampMsecsSinceEpoch() const { if (this->container().isEmpty()) { return -1; } const QDateTime dt(oldestAdjustedTimestamp()); return dt.isValid() ? dt.toMSecsSinceEpoch() : -1; } template void ITimestampWithOffsetObjectList::setAdjustedSortHint(HintAdjustedTimestampSort hint) { m_tsAdjustedSortHint = hint; } // see here for the reason of thess forward instantiations // https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampWithOffsetObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampWithOffsetObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE ITimestampWithOffsetObjectList; } // namespace //! \endcond