mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 23:05:36 +08:00
Ref T261, timestamp utility functions
This commit is contained in:
committed by
Roland Winklmeier
parent
d390116666
commit
d1f5635bd1
@@ -335,7 +335,7 @@ namespace BlackMisc
|
||||
switch (i)
|
||||
{
|
||||
case IndexOffsetMs: { return QVariant::fromValue(m_timeOffsetMs); }
|
||||
case IndexAdjustedMisWithOffset: { return QVariant::fromValue(this->getAdjustedMSecsSinceEpoch()); }
|
||||
case IndexAdjustedMsWithOffset: { return QVariant::fromValue(this->getAdjustedMSecsSinceEpoch()); }
|
||||
case IndexOffsetWithUnit: { return QVariant::fromValue(this->getTimeOffsetWithUnit()); }
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace BlackMisc
|
||||
enum ColumnIndex
|
||||
{
|
||||
IndexOffsetMs = CPropertyIndex::GlobalIndexITimestampBased + ITimestampBased::IndexMSecsSinceEpoch + 1,
|
||||
IndexAdjustedMisWithOffset,
|
||||
IndexAdjustedMsWithOffset,
|
||||
IndexOffsetWithUnit // keep this as last item
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "blackmisc/predicates.h"
|
||||
#include "blackmisc/identifierlist.h"
|
||||
#include "blackmisc/countrylist.h"
|
||||
#include "blackmisc/verify.h"
|
||||
#include "blackconfig/buildconfig.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <algorithm>
|
||||
@@ -35,6 +37,8 @@
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
using namespace BlackConfig;
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
template <class OBJ, class CONTAINER>
|
||||
@@ -64,6 +68,14 @@ namespace BlackMisc
|
||||
});
|
||||
}
|
||||
|
||||
template<class OBJ, class CONTAINER>
|
||||
OBJ ITimestampObjectList<OBJ, CONTAINER>::findObjectBeforeOrDefault(qint64 msSinceEpoch) const
|
||||
{
|
||||
const CONTAINER before = this->findBefore(msSinceEpoch);
|
||||
if (before.isEmpty()) { return OBJ(); }
|
||||
return before.latestObject();
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
CONTAINER ITimestampObjectList<OBJ, CONTAINER>::findBeforeAndRemove(qint64 msSinceEpoch)
|
||||
{
|
||||
@@ -93,6 +105,14 @@ namespace BlackMisc
|
||||
});
|
||||
}
|
||||
|
||||
template<class OBJ, class CONTAINER>
|
||||
OBJ ITimestampObjectList<OBJ, CONTAINER>::findObjectAfterOrDefault(qint64 msSinceEpoch) const
|
||||
{
|
||||
const CONTAINER after = this->findAfter(msSinceEpoch);
|
||||
if (after.isEmpty()) { return OBJ(); }
|
||||
return after.oldestObject();
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
CONTAINER ITimestampObjectList<OBJ, CONTAINER>::findInvalidTimestamps() const
|
||||
{
|
||||
@@ -179,7 +199,7 @@ namespace BlackMisc
|
||||
OBJ ITimestampObjectList<OBJ, CONTAINER>::latestObject() const
|
||||
{
|
||||
if (this->container().isEmpty()) { return OBJ(); }
|
||||
const auto latest = std::max_element(container().begin(), container().end(), [](const OBJ & a, const OBJ & b) { return a.getMSecsSinceEpoch() < b.getMSecsSinceEpoch(); });
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -187,7 +207,7 @@ namespace BlackMisc
|
||||
OBJ ITimestampObjectList<OBJ, CONTAINER>::oldestObject() const
|
||||
{
|
||||
if (this->container().isEmpty()) { return OBJ(); }
|
||||
const auto oldest = std::min_element(container().begin(), container().end(), [](const OBJ & a, const OBJ & b) { return a.getMSecsSinceEpoch() < b.getMSecsSinceEpoch(); });
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -238,11 +258,9 @@ namespace BlackMisc
|
||||
template<class OBJ, class CONTAINER>
|
||||
void ITimestampObjectList<OBJ, CONTAINER>::push_frontKeepLatestFirst(const OBJ &value, int maxElements)
|
||||
{
|
||||
Q_ASSERT_X(maxElements < 0 || maxElements > 1, Q_FUNC_INFO, "Max.value wrong range");
|
||||
CONTAINER &c = this->container();
|
||||
if (maxElements > 0 && c.size() >= maxElements)
|
||||
{
|
||||
c.truncate(maxElements - 1);
|
||||
}
|
||||
if (maxElements > 0) { c.truncate(maxElements - 1); }
|
||||
const bool needSort = !c.isEmpty() && value.isOlderThan(c.front());
|
||||
c.push_front(value);
|
||||
if (needSort)
|
||||
@@ -296,6 +314,23 @@ namespace BlackMisc
|
||||
this->container().reverse();
|
||||
}
|
||||
|
||||
template<class OBJ, class CONTAINER>
|
||||
CONTAINER ITimestampWithOffsetObjectList<OBJ, CONTAINER>::getSortedAdjustedLatestFirst() const
|
||||
{
|
||||
CONTAINER copy(this->container());
|
||||
copy.sortAdjustedLatestFirst();
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<class OBJ, class CONTAINER>
|
||||
CONTAINER ITimestampWithOffsetObjectList<OBJ, CONTAINER>::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<class OBJ, class CONTAINER>
|
||||
void ITimestampWithOffsetObjectList<OBJ, CONTAINER>::sortAdjustedOldestFirst()
|
||||
{
|
||||
@@ -342,10 +377,7 @@ namespace BlackMisc
|
||||
{
|
||||
Q_ASSERT_X(maxElements < 0 || maxElements > 1, Q_FUNC_INFO, "Max.value wrong range");
|
||||
CONTAINER &c = this->container();
|
||||
if (maxElements > 0 && c.size() >= maxElements)
|
||||
{
|
||||
c.truncate(maxElements - 1);
|
||||
}
|
||||
if (maxElements > 0) { c.truncate(maxElements - 1); }
|
||||
const bool needSort = !c.isEmpty() && value.isOlderThanAdjusted(c.front());
|
||||
c.push_front(value);
|
||||
if (needSort)
|
||||
@@ -361,27 +393,37 @@ namespace BlackMisc
|
||||
|
||||
// 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
|
||||
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<class OBJ, class CONTAINER>
|
||||
void ITimestampWithOffsetObjectList<OBJ, CONTAINER>::prefillLatestAdjustedFirst(const OBJ &value, int elements, qint64 deltaTimeMs)
|
||||
{
|
||||
this->container().clear();
|
||||
const qint64 os = -1 * qAbs(deltaTimeMs < 0 ? value.getTimeOffsetMs() : deltaTimeMs);
|
||||
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++)
|
||||
{
|
||||
@@ -394,6 +436,7 @@ namespace BlackMisc
|
||||
template<class OBJ, class CONTAINER>
|
||||
bool ITimestampWithOffsetObjectList<OBJ, CONTAINER>::isSortedAdjustedLatestLast() const
|
||||
{
|
||||
if (this->container().isEmpty()) { return false; }
|
||||
if (this->container().size() < 2) { return true; }
|
||||
qint64 max = -1;
|
||||
for (const ITimestampWithOffsetBased &obj : this->container())
|
||||
@@ -408,6 +451,7 @@ namespace BlackMisc
|
||||
template<class OBJ, class CONTAINER>
|
||||
bool ITimestampWithOffsetObjectList<OBJ, CONTAINER>::isSortedAdjustedLatestFirst() const
|
||||
{
|
||||
if (this->container().isEmpty()) { return false; }
|
||||
if (this->container().size() < 2) { return true; }
|
||||
qint64 min = std::numeric_limits <qint64>::max();
|
||||
for (const ITimestampWithOffsetBased &obj : this->container())
|
||||
@@ -419,6 +463,40 @@ namespace BlackMisc
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class OBJ, class CONTAINER>
|
||||
CONTAINER ITimestampWithOffsetObjectList<OBJ, CONTAINER>::findAfterAdjusted(qint64 msSinceEpoch) const
|
||||
{
|
||||
return this->container().findBy([&](const ITimestampWithOffsetBased & obj)
|
||||
{
|
||||
return obj.isNewerThanAdjusted(msSinceEpoch);
|
||||
});
|
||||
}
|
||||
|
||||
template<class OBJ, class CONTAINER>
|
||||
OBJ ITimestampWithOffsetObjectList<OBJ, CONTAINER>::findObjectAfterAdjustedOrDefault(qint64 msSinceEpoch) const
|
||||
{
|
||||
const CONTAINER after = this->findAfterAdjusted(msSinceEpoch);
|
||||
if (after.isEmpty()) { return OBJ(); }
|
||||
return after.oldestAdjustedObject();
|
||||
}
|
||||
|
||||
template<class OBJ, class CONTAINER>
|
||||
CONTAINER ITimestampWithOffsetObjectList<OBJ, CONTAINER>::findBeforeAdjusted(qint64 msSinceEpoch) const
|
||||
{
|
||||
return this->container().findBy([&](const ITimestampWithOffsetBased & obj)
|
||||
{
|
||||
return obj.isOlderThanAdjusted(msSinceEpoch);
|
||||
});
|
||||
}
|
||||
|
||||
template<class OBJ, class CONTAINER>
|
||||
OBJ ITimestampWithOffsetObjectList<OBJ, CONTAINER>::findObjectBeforeAdjustedOrDefault(qint64 msSinceEpoch) const
|
||||
{
|
||||
const CONTAINER before = this->findBeforeAdjusted(msSinceEpoch);
|
||||
if (before.isEmpty()) { return OBJ(); }
|
||||
return before.latestAdjustedObject();
|
||||
}
|
||||
|
||||
template<class OBJ, class CONTAINER>
|
||||
OBJ ITimestampWithOffsetObjectList<OBJ, CONTAINER>::findClosestTimeDistanceAdjusted(qint64 msSinceEpoch) const
|
||||
{
|
||||
@@ -430,6 +508,50 @@ namespace BlackMisc
|
||||
return *closest;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
OBJ ITimestampWithOffsetObjectList<OBJ, CONTAINER>::latestAdjustedObject() 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.getAdjustedMSecsSinceEpoch() < b.getAdjustedMSecsSinceEpoch(); });
|
||||
return *latest;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
OBJ ITimestampWithOffsetObjectList<OBJ, CONTAINER>::oldestAdjustedObject() 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.getAdjustedMSecsSinceEpoch() < b.getAdjustedMSecsSinceEpoch(); });
|
||||
return *oldest;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
QDateTime ITimestampWithOffsetObjectList<OBJ, CONTAINER>::latestAdjustedTimestamp() const
|
||||
{
|
||||
if (this->container().isEmpty()) { return QDateTime(); }
|
||||
return this->latestAdjustedObject().getUtcTimestamp();
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
qint64 ITimestampWithOffsetObjectList<OBJ, CONTAINER>::latestAdjustedTimestampMsecsSinceEpoch() const
|
||||
{
|
||||
const QDateTime dt(this->latestTimestamp());
|
||||
return dt.isValid() ? dt.toMSecsSinceEpoch() : -1;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
QDateTime ITimestampWithOffsetObjectList<OBJ, CONTAINER>::oldestAdjustedTimestamp() const
|
||||
{
|
||||
if (this->container().isEmpty()) { return QDateTime(); }
|
||||
return this->oldestAdjustedObject().getUtcTimestamp();
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
qint64 ITimestampWithOffsetObjectList<OBJ, CONTAINER>::oldestAdjustedTimestampMsecsSinceEpoch() const
|
||||
{
|
||||
const QDateTime dt(oldestAdjustedTimestamp());
|
||||
return dt.isValid() ? dt.toMSecsSinceEpoch() : -1;
|
||||
}
|
||||
|
||||
// see here for the reason of thess forward instantiations
|
||||
// https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl
|
||||
//! \cond PRIVATE
|
||||
|
||||
@@ -26,24 +26,30 @@ namespace BlackMisc
|
||||
template<class OBJ, class CONTAINER> class ITimestampObjectList
|
||||
{
|
||||
public:
|
||||
//! List of objects before dateTime
|
||||
//! List of objects before dateTime (older)
|
||||
CONTAINER findBefore(const QDateTime &dateTime) const;
|
||||
|
||||
//! List of objects before msSinceEpoch
|
||||
//! List of objects before msSinceEpoch (older)
|
||||
CONTAINER findBefore(qint64 msSinceEpoch) const;
|
||||
|
||||
//! Object before timestamp or default (older)
|
||||
OBJ findObjectBeforeOrDefault(qint64 msSinceEpoch) const;
|
||||
|
||||
//! Get objects before msSinceEpoch and remove those
|
||||
CONTAINER findBeforeAndRemove(qint64 msSinceEpoch);
|
||||
|
||||
//! List of objects before now - offset
|
||||
CONTAINER findBeforeNowMinusOffset(qint64 msOffset) const;
|
||||
|
||||
//! List of objects after dateTime
|
||||
//! List of objects after dateTime (newer)
|
||||
CONTAINER findAfter(const QDateTime &dateTime) const;
|
||||
|
||||
//! List of objects after msSinceEpoch
|
||||
//! List of objects after msSinceEpoch (newer)
|
||||
CONTAINER findAfter(qint64 msSinceEpoch) const;
|
||||
|
||||
//! List of objects after msSinceEpoch (newer)
|
||||
OBJ findObjectAfterOrDefault(qint64 msSinceEpoch) const;
|
||||
|
||||
//! Objects without valid timestamp
|
||||
CONTAINER findInvalidTimestamps() const;
|
||||
|
||||
@@ -74,10 +80,10 @@ namespace BlackMisc
|
||||
//! Oldest timestamp
|
||||
qint64 oldestTimestampMsecsSinceEpoch() const;
|
||||
|
||||
//! Latest value
|
||||
//! Latest object
|
||||
OBJ latestObject() const;
|
||||
|
||||
//! Latest value
|
||||
//! Latest object
|
||||
OBJ oldestObject() const;
|
||||
|
||||
//! Remove objects with timestamp before dateTime
|
||||
@@ -128,6 +134,12 @@ namespace BlackMisc
|
||||
//! Sort by adjusted timestamp
|
||||
void sortAdjustedLatestFirst();
|
||||
|
||||
//! As sorted copy
|
||||
CONTAINER getSortedAdjustedLatestFirst() const;
|
||||
|
||||
//! Get the latest 2 values
|
||||
CONTAINER getLatestAdjustedTwoObjects(bool alreadySortedLatestFirst = false) const;
|
||||
|
||||
//! Sort by adjusted timestamp
|
||||
void sortAdjustedOldestFirst();
|
||||
|
||||
@@ -158,9 +170,39 @@ namespace BlackMisc
|
||||
//! \remark all object must have a valid timestamp
|
||||
bool isSortedAdjustedLatestFirst() const;
|
||||
|
||||
//! List of objects after msSinceEpoch (newer)
|
||||
CONTAINER findAfterAdjusted(qint64 msSinceEpoch) const;
|
||||
|
||||
//! List of objects after msSinceEpoch (newer)
|
||||
OBJ findObjectAfterAdjustedOrDefault(qint64 msSinceEpoch) const;
|
||||
|
||||
//! List of objects before msSinceEpoch (older)
|
||||
CONTAINER findBeforeAdjusted(qint64 msSinceEpoch) const;
|
||||
|
||||
//! Object before timestamp (older)
|
||||
OBJ findObjectBeforeAdjustedOrDefault(qint64 msSinceEpoch) const;
|
||||
|
||||
//! Closest adjusted time difference
|
||||
OBJ findClosestTimeDistanceAdjusted(qint64 msSinceEpoch) const;
|
||||
|
||||
//! Latest adjusted object
|
||||
OBJ latestAdjustedObject() const;
|
||||
|
||||
//! Oldest adjusted object
|
||||
OBJ oldestAdjustedObject() const;
|
||||
|
||||
//! Latest adjusted timestamp
|
||||
QDateTime latestAdjustedTimestamp() const;
|
||||
|
||||
//! Oldest adjusted timestamp
|
||||
QDateTime oldestAdjustedTimestamp() const;
|
||||
|
||||
//! Latest adjusted timestamp
|
||||
qint64 latestAdjustedTimestampMsecsSinceEpoch() const;
|
||||
|
||||
//! Oldest adjusted timestamp
|
||||
qint64 oldestAdjustedTimestampMsecsSinceEpoch() const;
|
||||
|
||||
protected:
|
||||
//! Constructor
|
||||
ITimestampWithOffsetObjectList();
|
||||
|
||||
Reference in New Issue
Block a user