Ref T243, adjust offset for timestamp based objects when keeping the order

This commit is contained in:
Klaus Basan
2018-02-06 00:42:28 +01:00
parent 23cd247bd8
commit 5d155fb59c
4 changed files with 81 additions and 26 deletions

View File

@@ -1288,7 +1288,7 @@ namespace BlackCore
// list from new to old // list from new to old
QWriteLocker lock(&m_lockSituations); QWriteLocker lock(&m_lockSituations);
CAircraftSituationList &situationList = m_situationsByCallsign[callsign]; CAircraftSituationList &situationList = m_situationsByCallsign[callsign];
situationList.push_frontMaxElements(situation, IRemoteAircraftProvider::MaxSituationsPerCallsign); situationList.push_frontKeepLatestFirstAdjustOffset(situation, IRemoteAircraftProvider::MaxSituationsPerCallsign);
// check sort order // check sort order
Q_ASSERT_X(situationList.isSortedAdjustedLatestFirst(), Q_FUNC_INFO, "wrong sort order"); Q_ASSERT_X(situationList.isSortedAdjustedLatestFirst(), Q_FUNC_INFO, "wrong sort order");
@@ -1303,7 +1303,7 @@ namespace BlackCore
// list sorted from new to old // list sorted from new to old
QWriteLocker lock(&m_lockParts); QWriteLocker lock(&m_lockParts);
CAircraftPartsList &partsList = m_partsByCallsign[callsign]; CAircraftPartsList &partsList = m_partsByCallsign[callsign];
partsList.push_frontKeepLatestAdjustedFirst(parts, IRemoteAircraftProvider::MaxPartsPerCallsign); partsList.push_frontKeepLatestFirstAdjustOffset(parts, IRemoteAircraftProvider::MaxPartsPerCallsign);
// remove outdated parts (but never remove the most recent one) // remove outdated parts (but never remove the most recent one)
IRemoteAircraftProvider::removeOutdatedParts(partsList); IRemoteAircraftProvider::removeOutdatedParts(partsList);

View File

@@ -238,11 +238,7 @@ namespace BlackMisc
return emptyParts; return emptyParts;
} }
// with the latest updates of T243 the order and the offsets are supposed to be correct // Ref T243, KB 2018-02, can be removed in future, we verify parts when we add parts
// so even mixing fast/slow updates shall work
Q_ASSERT_X(m_aircraftParts.isSortedAdjustedLatestFirst(), Q_FUNC_INFO, "Wrong sort order");
// Ref T243, KB 2018-02, can be removed in future, we verify parts above
// Parts are supposed to be in correct order // Parts are supposed to be in correct order
// const auto end = std::is_sorted_until(m_aircraftParts.begin(), m_aircraftParts.end(), [](auto && a, auto && b) { return b.getAdjustedMSecsSinceEpoch() < a.getAdjustedMSecsSinceEpoch(); }); // const auto end = std::is_sorted_until(m_aircraftParts.begin(), m_aircraftParts.end(), [](auto && a, auto && b) { return b.getAdjustedMSecsSinceEpoch() < a.getAdjustedMSecsSinceEpoch(); });
// const auto validParts = makeRange(m_aircraftParts.begin(), end); // const auto validParts = makeRange(m_aircraftParts.begin(), end);
@@ -328,36 +324,54 @@ namespace BlackMisc
} }
// we add new situations at front and keep the latest values (real time) first // we add new situations at front and keep the latest values (real time) first
m_aircraftSituations.push_frontKeepLatestFirst(situation, IRemoteAircraftProvider::MaxSituationsPerCallsign); m_aircraftSituations.push_frontKeepLatestFirstAdjustOffset(situation, IRemoteAircraftProvider::MaxSituationsPerCallsign);
// with the latest updates of T243 the order and the offsets are supposed to be correct
// so even mixing fast/slow updates shall work
Q_ASSERT_X(!m_aircraftSituations.containsZeroOrNegativeOffsetTime(), Q_FUNC_INFO, "Missing offset time");
Q_ASSERT_X(m_aircraftSituations.isSortedAdjustedLatestFirst(), Q_FUNC_INFO, "Wrong sort order");
} }
template <typename Derived> template <typename Derived>
void CInterpolator<Derived>::addAircraftParts(const CAircraftParts &parts) void CInterpolator<Derived>::addAircraftParts(const CAircraftParts &parts)
{ {
const bool hasOffset = parts.hasOffsetTime(); const bool hasOffset = parts.hasOffsetTime();
const qint64 offset = if (!hasOffset)
hasOffset ? {
parts.getTimeOffsetMs() : const qint64 offset =
m_aircraftSituations.isEmpty() ? IRemoteAircraftProvider::DefaultOffsetTimeMs : m_aircraftSituations.front().getTimeOffsetMs(); hasOffset ?
parts.getTimeOffsetMs() :
m_aircraftSituations.isEmpty() ? IRemoteAircraftProvider::DefaultOffsetTimeMs : m_aircraftSituations.front().getTimeOffsetMs();
CAircraftParts copy(parts);
copy.setTimeOffsetMs(offset);
CInterpolator<Derived>::addAircraftParts(copy);
return;
}
// here we have an offset
Q_ASSERT_X(parts.hasOffsetTime(), Q_FUNC_INFO, "Missing parts offset");
if (m_aircraftParts.isEmpty()) if (m_aircraftParts.isEmpty())
{ {
// make sure we have enough parts to do start interpolating immediately without waiting for more updates // make sure we have enough parts to do start interpolating immediately without waiting for more updates
// the offsets here (addMSecs) do not really matter // the offsets here (addMSecs) do not really matter
CAircraftParts copy(parts); CAircraftParts copy(parts);
copy.setTimeOffsetMs(offset); copy.addMsecs(-2 * parts.getTimeOffsetMs());
copy.addMsecs(-2 * offset);
m_aircraftParts.push_frontKeepLatestFirst(copy); m_aircraftParts.push_frontKeepLatestFirst(copy);
copy.addMsecs(offset); copy.addMsecs(parts.getTimeOffsetMs());
m_aircraftParts.push_frontKeepLatestFirst(copy); m_aircraftParts.push_frontKeepLatestFirst(copy);
} }
// we add new situations at front and keep the latest values (real time) first // we add new situations at front and keep the latest values (real time) first
m_aircraftParts.push_frontKeepLatestFirst(parts, IRemoteAircraftProvider::MaxSituationsPerCallsign); m_aircraftParts.push_frontKeepLatestFirstAdjustOffset(parts, IRemoteAircraftProvider::MaxSituationsPerCallsign);
if (!hasOffset) { m_aircraftParts.front().setTimeOffsetMs(offset); }
// force remote provider to cleanup // force remote provider to cleanup
IRemoteAircraftProvider::removeOutdatedParts(m_aircraftParts); IRemoteAircraftProvider::removeOutdatedParts(m_aircraftParts);
// with the latest updates of T243 the order and the offsets are supposed to be correct
// so even mixing fast/slow updates shall work
Q_ASSERT_X(!m_aircraftParts.containsZeroOrNegativeOffsetTime(), Q_FUNC_INFO, "Missing offset time");
Q_ASSERT_X(m_aircraftParts.isSortedAdjustedLatestFirst(), Q_FUNC_INFO, "Wrong sort order");
} }
template<typename Derived> template<typename Derived>

View File

@@ -232,17 +232,18 @@ namespace BlackMisc
{ {
c.truncate(maxElements - 1); c.truncate(maxElements - 1);
} }
if (!c.isEmpty() && value.isOlderThan(c.front())) const bool needSort = !c.isEmpty() && value.isOlderThan(c.front());
c.push_front(value);
if (needSort)
{ {
ITimestampObjectList::sortLatestFirst(); ITimestampObjectList::sortLatestFirst();
} }
c.push_front(value);
} }
template<class OBJ, class CONTAINER> template<class OBJ, class CONTAINER>
bool ITimestampObjectList<OBJ, CONTAINER>::isSortedLatestLast() const bool ITimestampObjectList<OBJ, CONTAINER>::isSortedLatestLast() const
{ {
if (this->container().isEmpty()) { return true; } if (this->container().size() < 2) { return true; }
qint64 max = -1; qint64 max = -1;
for (const ITimestampBased &obj : this->container()) for (const ITimestampBased &obj : this->container())
{ {
@@ -257,7 +258,7 @@ namespace BlackMisc
template<class OBJ, class CONTAINER> template<class OBJ, class CONTAINER>
bool ITimestampObjectList<OBJ, CONTAINER>::isSortedLatestFirst() const bool ITimestampObjectList<OBJ, CONTAINER>::isSortedLatestFirst() const
{ {
if (this->container().isEmpty()) { return true; } if (this->container().size() < 2) { return true; }
qint64 min = std::numeric_limits <qint64>::max(); qint64 min = std::numeric_limits <qint64>::max();
for (const ITimestampBased &obj : this->container()) for (const ITimestampBased &obj : this->container())
{ {
@@ -282,6 +283,16 @@ namespace BlackMisc
this->container().sort(Predicates::MemberLess(&OBJ::getAdjustedMSecsSinceEpoch)); this->container().sort(Predicates::MemberLess(&OBJ::getAdjustedMSecsSinceEpoch));
} }
template<class OBJ, class CONTAINER>
bool ITimestampWithOffsetObjectList<OBJ, CONTAINER>::containsZeroOrNegativeOffsetTime() const
{
for (const ITimestampWithOffsetBased &obj : this->container())
{
if (obj.getTimeOffsetMs() <= 0) { return true; }
}
return false;
}
template<class OBJ, class CONTAINER> template<class OBJ, class CONTAINER>
ITimestampWithOffsetObjectList<OBJ, CONTAINER>::ITimestampWithOffsetObjectList() : ITimestampObjectList<OBJ, CONTAINER>() ITimestampWithOffsetObjectList<OBJ, CONTAINER>::ITimestampWithOffsetObjectList() : ITimestampObjectList<OBJ, CONTAINER>()
{ {
@@ -297,17 +308,41 @@ namespace BlackMisc
{ {
c.truncate(maxElements - 1); c.truncate(maxElements - 1);
} }
if (!c.isEmpty() && value.isOlderThanAdjusted(c.front())) const bool needSort = !c.isEmpty() && value.isOlderThanAdjusted(c.front());
c.push_front(value);
if (needSort)
{ {
ITimestampWithOffsetObjectList::sortAdjustedLatestFirst(); ITimestampWithOffsetObjectList::sortAdjustedLatestFirst();
} }
c.push_front(value); }
template<class OBJ, class CONTAINER>
void ITimestampWithOffsetObjectList<OBJ, CONTAINER>::push_frontKeepLatestFirstAdjustOffset(const OBJ &value, int maxElements)
{
ITimestampObjectList<OBJ, CONTAINER>::push_frontKeepLatestFirst(value, maxElements);
// now sorted by timestamp
// this reflects normally the incoming order
CONTAINER &c = this->container();
if (c.size() < 2) { return; }
const ITimestampWithOffsetBased &front = c.front();
ITimestampWithOffsetBased &second = c[1];
if (!front.isOlderThanAdjusted(second)) { return; }
const qint64 maxOs = front.getAdjustedMSecsSinceEpoch() - second.getMSecsSinceEpoch();
const qint64 avgOs = (maxOs + qMax(front.getTimeOffsetMs(), maxOs)) / 2;
second.setTimeOffsetMs(avgOs);
// ts
// 8: os 2 adj 10
// 6: os 2 adj 8
// 5: os 5 adj 10 => max os 3
// 0: os 5 adj 5
} }
template<class OBJ, class CONTAINER> template<class OBJ, class CONTAINER>
bool ITimestampWithOffsetObjectList<OBJ, CONTAINER>::isSortedAdjustedLatestLast() const bool ITimestampWithOffsetObjectList<OBJ, CONTAINER>::isSortedAdjustedLatestLast() const
{ {
if (this->container().isEmpty()) { return true; } if (this->container().size() < 2) { return true; }
qint64 max = -1; qint64 max = -1;
for (const ITimestampWithOffsetBased &obj : this->container()) for (const ITimestampWithOffsetBased &obj : this->container())
{ {
@@ -321,14 +356,13 @@ namespace BlackMisc
template<class OBJ, class CONTAINER> template<class OBJ, class CONTAINER>
bool ITimestampWithOffsetObjectList<OBJ, CONTAINER>::isSortedAdjustedLatestFirst() const bool ITimestampWithOffsetObjectList<OBJ, CONTAINER>::isSortedAdjustedLatestFirst() const
{ {
if (this->container().isEmpty()) { return true; } if (this->container().size() < 2) { return true; }
qint64 min = std::numeric_limits <qint64>::max(); qint64 min = std::numeric_limits <qint64>::max();
for (const ITimestampWithOffsetBased &obj : this->container()) for (const ITimestampWithOffsetBased &obj : this->container())
{ {
if (!obj.hasValidTimestamp()) { return false; } if (!obj.hasValidTimestamp()) { return false; }
if (obj.getAdjustedMSecsSinceEpoch() > min) { return false; } if (obj.getAdjustedMSecsSinceEpoch() > min) { return false; }
min = obj.getAdjustedMSecsSinceEpoch(); min = obj.getAdjustedMSecsSinceEpoch();
continue;
} }
return true; return true;
} }

View File

@@ -125,9 +125,16 @@ namespace BlackMisc
//! Sort by adjusted timestamp //! Sort by adjusted timestamp
void sortAdjustedOldestFirst(); void sortAdjustedOldestFirst();
//! Any negative or zero offset time?
bool containsZeroOrNegativeOffsetTime() const;
//! Insert as first element by keeping maxElements and the latest first //! Insert as first element by keeping maxElements and the latest first
void push_frontKeepLatestAdjustedFirst(const OBJ &value, int maxElements = -1); void push_frontKeepLatestAdjustedFirst(const OBJ &value, int maxElements = -1);
//! Insert as first element by keeping maxElements and the latest first
//! \remark adjust offset so adjusted values are sorted
void push_frontKeepLatestFirstAdjustOffset(const OBJ &value, int maxElements = -1);
//! Is completely sorted: latest last //! Is completely sorted: latest last
//! \remark all object must have a valid timestamp //! \remark all object must have a valid timestamp
bool isSortedAdjustedLatestLast() const; bool isSortedAdjustedLatestLast() const;