Ref T275, Ref T280 hint for timestamp based list if they are already sorted

This commit is contained in:
Klaus Basan
2018-06-13 16:36:30 +02:00
parent e7cfae4fcc
commit 978fe5eea2
6 changed files with 116 additions and 12 deletions

View File

@@ -219,7 +219,8 @@ namespace BlackMisc
else
{
situationList.front().transferGroundElevation(situationCorrected); // transfer last situation if possible
situationList.push_frontKeepLatestFirstAdjustOffset(situationCorrected, IRemoteAircraftProvider::MaxSituationsPerCallsign);
situationList.push_frontKeepLatestFirstAdjustOffset(situationCorrected, true, IRemoteAircraftProvider::MaxSituationsPerCallsign);
situationList.setAdjustedSortHint(CAircraftSituationList::AdjustedTimestampLatestFirst);
// unify all inbound ground information
if (situation.hasInboundGroundDetails())
@@ -252,7 +253,8 @@ namespace BlackMisc
m_partsAdded++;
m_partsLastModified[callsign] = ts;
CAircraftPartsList &partsList = m_partsByCallsign[callsign];
partsList.push_frontKeepLatestFirstAdjustOffset(parts, IRemoteAircraftProvider::MaxPartsPerCallsign);
partsList.push_frontKeepLatestFirstAdjustOffset(parts, true, IRemoteAircraftProvider::MaxPartsPerCallsign);
partsList.setAdjustedSortHint(CAircraftPartsList::AdjustedTimestampLatestFirst);
// remove outdated parts (but never remove the most recent one)
if (removeOutdated) { IRemoteAircraftProvider::removeOutdatedParts(partsList); }

View File

@@ -253,14 +253,21 @@ namespace BlackMisc
template <class OBJ, class CONTAINER>
void ITimestampObjectList<OBJ, CONTAINER>::sortOldestFirst()
{
this->container().sort(BlackMisc::Predicates::MemberLess(&OBJ::getMSecsSinceEpoch));
this->container().sort(Predicates::MemberLess(&OBJ::getMSecsSinceEpoch));
}
template<class OBJ, class CONTAINER>
void ITimestampObjectList<OBJ, CONTAINER>::push_frontKeepLatestFirst(const OBJ &value, int maxElements)
void ITimestampObjectList<OBJ, CONTAINER>::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);
@@ -270,6 +277,21 @@ namespace BlackMisc
}
}
template<class OBJ, class CONTAINER>
int ITimestampObjectList<OBJ, CONTAINER>::replaceIfSameTimestamp(const OBJ &newObject)
{
int c = 0;
for (OBJ &obj : this->container())
{
if (obj.getMSecsSinceEpoch() == newObject.getMSecsSinceEpoch())
{
obj = newObject;
c++;
}
}
return c;
}
template<class OBJ, class CONTAINER>
bool ITimestampObjectList<OBJ, CONTAINER>::isSortedLatestLast() const
{
@@ -374,10 +396,17 @@ namespace BlackMisc
}
template<class OBJ, class CONTAINER>
void ITimestampWithOffsetObjectList<OBJ, CONTAINER>::push_frontKeepLatestAdjustedFirst(const OBJ &value, int maxElements)
void ITimestampWithOffsetObjectList<OBJ, CONTAINER>::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);
@@ -388,9 +417,9 @@ namespace BlackMisc
}
template<class OBJ, class CONTAINER>
void ITimestampWithOffsetObjectList<OBJ, CONTAINER>::push_frontKeepLatestFirstAdjustOffset(const OBJ &value, int maxElements)
void ITimestampWithOffsetObjectList<OBJ, CONTAINER>::push_frontKeepLatestFirstAdjustOffset(const OBJ &value, bool replaceSameTimestamp, int maxElements)
{
ITimestampObjectList<OBJ, CONTAINER>::push_frontKeepLatestFirst(value, maxElements);
ITimestampWithOffsetObjectList<OBJ, CONTAINER>::push_frontKeepLatestAdjustedFirst(value, replaceSameTimestamp, maxElements);
// now sorted by timestamp
// this reflects normally the incoming order
@@ -432,6 +461,7 @@ namespace BlackMisc
copy.addMsecs(os * i);
this->container().push_back(copy);
}
this->setAdjustedSortHint(ITimestampWithOffsetObjectList::AdjustedTimestampLatestFirst);
}
template<class OBJ, class CONTAINER>
@@ -513,6 +543,10 @@ namespace BlackMisc
OBJ ITimestampWithOffsetObjectList<OBJ, CONTAINER>::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;
}
@@ -521,6 +555,10 @@ namespace BlackMisc
OBJ ITimestampWithOffsetObjectList<OBJ, CONTAINER>::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;
}
@@ -535,7 +573,8 @@ namespace BlackMisc
template <class OBJ, class CONTAINER>
qint64 ITimestampWithOffsetObjectList<OBJ, CONTAINER>::latestAdjustedTimestampMsecsSinceEpoch() const
{
const QDateTime dt(this->latestTimestamp());
if (this->container().isEmpty()) { return -1; }
const QDateTime dt(this->latestAdjustedTimestamp());
return dt.isValid() ? dt.toMSecsSinceEpoch() : -1;
}
@@ -549,6 +588,7 @@ namespace BlackMisc
template <class OBJ, class CONTAINER>
qint64 ITimestampWithOffsetObjectList<OBJ, CONTAINER>::oldestAdjustedTimestampMsecsSinceEpoch() const
{
if (this->container().isEmpty()) { return -1; }
const QDateTime dt(oldestAdjustedTimestamp());
return dt.isValid() ? dt.toMSecsSinceEpoch() : -1;
}

View File

@@ -26,6 +26,13 @@ namespace BlackMisc
template<class OBJ, class CONTAINER> class ITimestampObjectList
{
public:
//! Hint if the list is sorted
enum HintTimestampSort
{
NoTimestampSortHint,
TimestampLatestFirst
};
//! List of objects before dateTime (older)
CONTAINER findBefore(const QDateTime &dateTime) const;
@@ -102,7 +109,10 @@ namespace BlackMisc
void sortOldestFirst();
//! Insert as first element by keeping maxElements and the latest first
void push_frontKeepLatestFirst(const OBJ &value, int maxElements = -1);
void push_frontKeepLatestFirst(const OBJ &value, bool replaceSameTimestamp = true, int maxElements = -1);
//! Replace if an object has the same timestamp
int replaceIfSameTimestamp(const OBJ &newObject);
//! Is completely sorted: latest last
//! \remark all object must have a valid timestamp
@@ -115,6 +125,9 @@ namespace BlackMisc
//! Adds a time to all values
void addMsecs(qint64 msToAdd);
//! Set the hint
void setSortHint(HintTimestampSort hint) { m_tsSortHint = hint; }
protected:
//! Constructor
ITimestampObjectList();
@@ -124,6 +137,8 @@ namespace BlackMisc
//! Container
CONTAINER &container();
HintTimestampSort m_tsSortHint = NoTimestampSortHint; //!< sort hint
};
//! List of objects with timestamp and offset.
@@ -131,6 +146,13 @@ namespace BlackMisc
template<class OBJ, class CONTAINER> class ITimestampWithOffsetObjectList : public ITimestampObjectList<OBJ, CONTAINER>
{
public:
//! Hint if the list is sorted
enum HintAdjustedTimestampSort
{
NoAdjustedTimestampSortHint,
AdjustedTimestampLatestFirst
};
//! Sort by adjusted timestamp
void sortAdjustedLatestFirst();
@@ -153,11 +175,11 @@ namespace BlackMisc
void addMsecsToOffset(qint64 msToAdd);
//! 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, bool replaceSameTimestamp = true, int maxElements = -1);
//! Insert as first element by keeping maxElements and the latest first
//! \remark adjust offset to average offset of two adjacent elements so adjusted values are sorted
void push_frontKeepLatestFirstAdjustOffset(const OBJ &value, int maxElements = -1);
void push_frontKeepLatestFirstAdjustOffset(const OBJ &value, bool replaceSameTimestamp = true, int maxElements = -1);
//! Prefill with elements
void prefillLatestAdjustedFirst(const OBJ &value, int elements, qint64 deltaTimeMs = -1);
@@ -203,9 +225,14 @@ namespace BlackMisc
//! Oldest adjusted timestamp
qint64 oldestAdjustedTimestampMsecsSinceEpoch() const;
//! Set the hint
void setAdjustedSortHint(HintAdjustedTimestampSort hint) { m_tsAdjustedSortHint = hint; }
protected:
//! Constructor
ITimestampWithOffsetObjectList();
HintAdjustedTimestampSort m_tsAdjustedSortHint = NoAdjustedTimestampSortHint; //!< sort hint
};
//! \cond PRIVATE

View File

@@ -20,7 +20,9 @@
#include "blackmisc/math/mathutils.h"
#include <QTest>
#include <QTimer>
#include <QDateTime>
#include <QDebug>
using namespace BlackMisc::Aviation;
using namespace BlackMisc::PhysicalQuantities;
@@ -184,6 +186,36 @@ namespace BlackMiscTest
QVERIFY2(corAlt == (ep.getAltitude() + cg), "Expect correction by CG");
}
void CTestAircraftSituation::sortHint()
{
CAircraftSituationList situations = testSituations();
situations.sortAdjustedLatestFirst();
constexpr int Max = 500000;
QTime time;
time.start();
for (int i = 0; i < Max; ++i)
{
CAircraftSituation s1 = situations.oldestAdjustedObject();
CAircraftSituation s2 = situations.latestAdjustedObject();
QVERIFY(s1.getAdjustedMSecsSinceEpoch() < s2.getAdjustedMSecsSinceEpoch());
}
const int noHint = time.elapsed();
situations.setAdjustedSortHint(CAircraftSituationList::AdjustedTimestampLatestFirst);
time.start();
for (int i = 0; i < Max; ++i)
{
CAircraftSituation s1 = situations.oldestAdjustedObject();
CAircraftSituation s2 = situations.latestAdjustedObject();
QVERIFY(s1.getAdjustedMSecsSinceEpoch() < s2.getAdjustedMSecsSinceEpoch());
}
const int hint = time.elapsed();
qDebug() << "Access without hint" << noHint << "ms";
qDebug() << "Access with hint" << hint << "ms";
QVERIFY2(hint < noHint, "Expected hinted sort being faster");
}
CAircraftSituationList CTestAircraftSituation::testSituations()
{
// "Kugaaruk Airport","Pelly Bay","Canada","YBB","CYBB",68.534401,-89.808098,56,-7,"A","America/Edmonton","airport","OurAirports"

View File

@@ -55,6 +55,9 @@ namespace BlackMiscTest
//! Altitude correction
void altitudeCorrection();
//! Using sort hint
void sortHint();
private:
//! Test situations (ascending)
static BlackMisc::Aviation::CAircraftSituationList testSituations();

View File

@@ -329,7 +329,7 @@ namespace BlackMiscTest
}
ts += dt;
situations.push_frontKeepLatestFirstAdjustOffset(s, max);
situations.push_frontKeepLatestFirstAdjustOffset(s, true, max);
QVERIFY2(situations.size() <= max, "Wrong size");
QVERIFY2(situations.isSortedAdjustedLatestFirstWithoutNullPositions(), "Wrong sort order");