6 #ifndef SWIFT_MISC_TIMESTAMPOBJECTLIST_H
7 #define SWIFT_MISC_TIMESTAMPOBJECTLIST_H
42 return QStringLiteral(
"Min: %1ms Max: %2ms Mean: %3ms").arg(
min).arg(
max).arg(
mean, 0,
'f', 2);
48 template <
class OBJ,
class CONTAINER>
51 static_assert(std::is_base_of_v<ITimestampBased, OBJ>,
"OBJ needs to implement ITimestampBased");
63 CONTAINER
findBefore(
const QDateTime &dateTime)
const {
return this->
findBefore(dateTime.toMSecsSinceEpoch()); }
68 return this->
container().findBy([&](
const OBJ &obj) {
return obj.isOlderThan(msSinceEpoch); });
74 const CONTAINER before = this->
findBefore(msSinceEpoch);
75 if (before.isEmpty()) {
return OBJ(); }
76 return before.latestObject();
90 return this->
findBefore(QDateTime::currentMSecsSinceEpoch() - msOffset);
94 CONTAINER
findAfter(
const QDateTime &dateTime)
const {
return this->
findAfter(dateTime.toMSecsSinceEpoch()); }
99 return this->
container().findBy([&](
const OBJ &obj) {
return obj.isNewerThan(msSinceEpoch); });
105 return this->
findAfter(QDateTime::currentMSecsSinceEpoch() - msOffset);
111 const CONTAINER after = this->
findAfter(msSinceEpoch);
112 if (after.isEmpty()) {
return OBJ(); }
113 return after.oldestObject();
119 return this->
container().findBy([&](
const OBJ &obj) {
return !obj.hasValidTimestamp(); });
125 if (this->
container().isEmpty()) {
return OBJ(); }
126 const auto closest = std::min_element(this->
container().cbegin(), this->
container().cend(),
154 if (tsObj.hasValidTimestamp()) {
continue; }
155 tsObj.setCurrentUtcTime();
162 if (this->
container().isEmpty()) {
return {}; }
170 return dt.isValid() ? dt.toMSecsSinceEpoch() : -1;
176 if (this->
container().isEmpty()) {
return QDateTime(); }
184 return dt.isValid() ? dt.toMSecsSinceEpoch() : -1;
190 if (this->
container().isEmpty()) {
return OBJ(); }
193 return a.getMSecsSinceEpoch() < b.getMSecsSinceEpoch();
201 if (this->
container().isEmpty()) {
return OBJ(); }
204 return a.getMSecsSinceEpoch() < b.getMSecsSinceEpoch();
215 return this->
container().removeIf([&](
const OBJ &obj) {
return obj.isOlderThan(msSinceEpoch); });
221 const qint64 epoch = QDateTime::currentMSecsSinceEpoch() - offsetMs;
222 return this->
container().removeIf([&](
const OBJ &obj) {
return obj.isOlderThan(epoch); });
238 Q_ASSERT_X(maxElements < 0 || maxElements > 1, Q_FUNC_INFO,
"Max.value wrong range");
240 if (replaceSameTimestamp && !c.isEmpty() && c[0].getMSecsSinceEpoch() == value.getMSecsSinceEpoch())
243 if (maxElements > 0) { c.truncate(maxElements); }
247 if (maxElements > 0) { c.truncate(maxElements - 1); }
248 const bool needSort = !c.isEmpty() && value.isOlderThan(c.front());
269 const qint64 newMs = newObject.getMSecsSinceEpoch();
270 const qint64 oldMs = this->
container().back().getMSecsSinceEpoch();
282 OBJ newObjectCopy(newObject);
283 newObjectCopy.setMSecsSinceEpoch(newTsMsSinceEpoch);
284 this->
container().push_back(newObjectCopy);
290 if (this->
container().isEmpty()) {
return; }
291 qint64 currentMs = startTimeStampMs;
294 it->setMSecsSinceEpoch(currentMs);
295 currentMs += deltaTimeMs;
305 if (obj.getMSecsSinceEpoch() == newObject.getMSecsSinceEpoch())
318 if (this->
container().size() < 2) {
return true; }
322 if (!obj.hasValidTimestamp()) {
return false; }
323 if (obj.getMSecsSinceEpoch() < max) {
return false; }
324 max = obj.getMSecsSinceEpoch();
333 if (this->
container().size() < 2) {
return true; }
334 qint64 min = std::numeric_limits<qint64>::max();
337 if (!obj.hasValidTimestamp()) {
return false; }
338 if (obj.getMSecsSinceEpoch() > min) {
return false; }
339 min = obj.getMSecsSinceEpoch();
347 if (msToAdd == 0) {
return; }
361 if (container.size() < 2) {
return mmm; }
364 if (
container.m_tsSortHint == NoTimestampSortHint)
367 copy.sortLatestFirst();
368 copy.m_tsSortHint = TimestampLatestFirst;
369 return copy.getTimestampDifferenceMinMaxMean();
372 mmm.
max = std::numeric_limits<qint64>::min();
373 mmm.
min = std::numeric_limits<qint64>::max();
385 if (diff > mmm.
max) { mmm.
max = diff; }
386 if (diff < mmm.
min) { mmm.
min = diff; }
402 const CONTAINER &
container()
const {
return static_cast<const CONTAINER &
>(*this); }
405 CONTAINER &
container() {
return static_cast<CONTAINER &
>(*this); }
412 template <
class OBJ,
class CONTAINER>
415 static_assert(std::is_base_of_v<ITimestampWithOffsetBased, OBJ>,
"OBJ needs to implement ITimestampBased");
421 NoAdjustedTimestampSortHint,
422 AdjustedTimestampLatestFirst
428 this->
container().sortAdjustedOldestFirst();
436 copy.sortAdjustedLatestFirst();
443 if (this->
container().size() < 2) {
return CONTAINER(); }
444 CONTAINER copy(alreadySortedLatestFirst ? this->
container() :
461 if (obj.getTimeOffsetMs() <= 0) {
return true; }
471 if (obj.getTimeOffsetMs() < 0) {
return true; }
485 Q_ASSERT_X(maxElements < 0 || maxElements > 1, Q_FUNC_INFO,
"Max.value wrong range");
487 if (replaceSameTimestamp && !c.isEmpty() && c[0].getMSecsSinceEpoch() == value.getMSecsSinceEpoch())
490 if (maxElements > 0) { c.truncate(maxElements); }
494 if (maxElements > 0) { c.truncate(maxElements - 1); }
495 const bool needSort = !c.isEmpty() && value.isOlderThanAdjusted(c.front());
503 int maxElements = -1)
516 if (c.size() < 2) {
return; }
522 const qint64 minReqOs =
525 const qint64 os = qMax(minReqOs + 1, avgOs);
538 int maxElements = -1)
554 const qint64 osTime = value.getTimeOffsetMs();
555 const qint64 os = -1 * qAbs(deltaTimeMs < 0 ? osTime : deltaTimeMs);
558 SWIFT_VERIFY_X(os < 0, Q_FUNC_INFO,
"Need negative offset time to prefill time");
561 for (
int i = 1; i < elements; i++)
564 copy.addMsecs(os * i);
574 if (this->
container().isEmpty()) {
return false; }
575 if (this->
container().size() < 2) {
return true; }
579 if (!obj.hasValidTimestamp()) {
return false; }
580 if (obj.getAdjustedMSecsSinceEpoch() < max) {
return false; }
581 max = obj.getAdjustedMSecsSinceEpoch();
590 if (this->
container().size() < 2) {
return true; }
591 qint64 min = std::numeric_limits<qint64>::max();
594 if (!obj.hasValidTimestamp()) {
return false; }
595 if (obj.getAdjustedMSecsSinceEpoch() > min) {
return false; }
596 min = obj.getAdjustedMSecsSinceEpoch();
612 if (after.isEmpty()) {
return OBJ(); }
613 return after.oldestAdjustedObject();
627 if (before.isEmpty()) {
return OBJ(); }
628 return before.latestAdjustedObject();
634 if (this->
container().isEmpty()) {
return OBJ(); }
647 if (this->
container().isEmpty()) {
return OBJ(); }
654 return a.getAdjustedMSecsSinceEpoch() < b.getAdjustedMSecsSinceEpoch();
662 if (this->
container().isEmpty()) {
return OBJ(); }
669 return a.getAdjustedMSecsSinceEpoch() < b.getAdjustedMSecsSinceEpoch();
677 if (this->
container().isEmpty()) {
return QDateTime(); }
684 if (this->
container().isEmpty()) {
return QDateTime(); }
691 if (this->
container().isEmpty()) {
return -1; }
693 return dt.isValid() ? dt.toMSecsSinceEpoch() : -1;
699 if (this->
container().isEmpty()) {
return -1; }
701 return dt.isValid() ? dt.toMSecsSinceEpoch() : -1;
714 if (container.size() < 1) {
return mmm; }
716 mmm.
max = std::numeric_limits<qint64>::min();
717 mmm.
min = std::numeric_limits<qint64>::max();
723 if (!
object.hasNonZeroOffsetTime()) {
continue; }
724 const qint64 os =
object.getTimeOffsetMs();
725 if (os > mmm.
max) { mmm.
max = os; }
726 if (os < mmm.
min) { mmm.
min = os; }
731 if (c > 0) { mmm.
mean = mean / c; }
static bool isLocalDeveloperDebugBuild()
Local build for developers.
qint64 getMSecsSinceEpoch() const
Timestamp as ms value.
qint64 getTimeDifferenceMs(qint64 compareTime) const
Time difference in ms.
qint64 getAbsTimeDifferenceMs(qint64 compareTime) const
Time difference in ms.
List of objects with timestamp. Such objects should implement.
OBJ findObjectBeforeOrDefault(qint64 msSinceEpoch) const
Object before timestamp or default (older)
qint64 latestTimestampMsecsSinceEpoch() const
Latest timestamp.
QDateTime latestTimestamp() const
Latest timestamp.
void push_backOverrideTimestamp(const OBJ &newObject, qint64 newTsMsSinceEpoch)
Push back, but set new timestamp.
void setSortHint(HintTimestampSort hint)
Set the hint.
HintTimestampSort m_tsSortHint
sort hint
void sortOldestFirst()
Sort by timestamp.
OBJ oldestObject() const
Latest object.
int removeBefore(qint64 msSinceEpoch)
Remove objects with timestamp before dateTime.
CONTAINER findBeforeNowMinusOffset(qint64 msOffset) const
List of objects before now - offset.
int replaceIfSameTimestamp(const OBJ &newObject)
Replace if an object has the same timestamp.
CONTAINER findAfter(const QDateTime &dateTime) const
List of objects after dateTime (newer)
void addMsecs(qint64 msToAdd)
Adds a time to all values.
const CONTAINER & container() const
Container.
qint64 oldestTimestampMsecsSinceEpoch() const
Oldest timestamp.
CONTAINER findBeforeAndRemove(qint64 msSinceEpoch)
Get objects before msSinceEpoch and remove those.
MillisecondsMinMaxMean getTimestampDifferenceMinMaxMean() const
Difference of timestamp values.
CONTAINER findAfter(qint64 msSinceEpoch) const
List of objects after msSinceEpoch (newer)
ITimestampObjectList()=default
Constructor.
void setCurrentUtcTime()
Set all timestamps to now.
OBJ findObjectAfterOrDefault(qint64 msSinceEpoch) const
List of objects after msSinceEpoch (newer)
void setInvalidTimestampsToCurrentUtcTime()
Set invalid timestamps to now.
OBJ latestObject() const
Latest object.
void sortLatestFirst()
Sort by timestamp.
HintTimestampSort
Hint if the list is sorted.
void push_backIncreaseTimestamp(const OBJ &newObject)
Push back and increase the timestamp at least by +1ms if equal to last element.
int removeBefore(const QDateTime &dateTime)
Remove objects with timestamp before dateTime.
int removeOlderThanNowMinusOffset(qint64 offsetMs)
Remove objects older than seconds.
bool isSortedLatestLast() const
Is completely sorted: latest last.
CONTAINER & container()
Container.
void push_frontKeepLatestFirst(const OBJ &value, bool replaceSameTimestamp=true, int maxElements=-1)
Insert as first element by keeping maxElements and the latest first.
QDateTime oldestTimestamp() const
Oldest timestamp.
CONTAINER findBefore(const QDateTime &dateTime) const
List of objects before dateTime (older)
CONTAINER findBefore(qint64 msSinceEpoch) const
List of objects before msSinceEpoch (older)
bool hasInvalidTimestamps() const
Has invalid timestamp.
void setUtcTime(qint64 msSinceEpoch)
Set all timestamps to given time.
CONTAINER findInvalidTimestamps() const
Objects without valid timestamp.
bool isSortedLatestFirst() const
Is completely sorted: latest last.
void setNewTimestampStartingLast(qint64 startTimeStampMs, qint64 deltaTimeMs)
Set new timestamps starting with the last element.
CONTAINER findAfterNowMinusOffset(qint64 msOffset) const
List of objects before now - offset.
OBJ findClosestTimeDistance(qint64 msSinceEpoch) const
Find closest (or default)
qint64 getAdjustedMSecsSinceEpoch() const
Timestamp with offset added for interpolation.
qint64 getTimeOffsetMs() const
Milliseconds to add to timestamp for interpolation.
bool isNewerThanAdjusted(const ITimestampWithOffsetBased &otherTimestampObj) const
Is this newer than other?
bool isOlderThanAdjusted(const ITimestampWithOffsetBased &otherTimestampObj) const
Is this older than other?
qint64 getAdjustedTimeDifferenceMs(qint64 compareTime) const
Time difference in ms (this -> compare)
void setTimeOffsetMs(qint64 offset)
Milliseconds to add to timestamp for interpolation.
List of objects with timestamp and offset. Such objects should implement.
OBJ findClosestTimeDistanceAdjusted(qint64 msSinceEpoch) const
Closest adjusted time difference.
bool containsZeroOrNegativeOffsetTime() const
Any negative or zero offset time?
CONTAINER getLatestAdjustedTwoObjects(bool alreadySortedLatestFirst=false) const
Get the latest 2 values.
HintAdjustedTimestampSort
Hint if the list is sorted.
QDateTime oldestAdjustedTimestamp() const
Oldest adjusted timestamp.
bool isSortedAdjustedLatestFirst() const
Is completely sorted: latest last.
OBJ findObjectBeforeAdjustedOrDefault(qint64 msSinceEpoch) const
Object before timestamp (older)
void setAdjustedSortHint(HintAdjustedTimestampSort hint)
Set the hint.
CONTAINER findBeforeAdjusted(qint64 msSinceEpoch) const
List of objects before msSinceEpoch (older)
OBJ latestAdjustedObject() const
Latest adjusted object.
bool isSortedAdjustedLatestLast() const
Is completely sorted: latest last.
MillisecondsMinMaxMean getOffsetMinMaxMean() const
Difference of timestamp values.
void addMsecsToOffset(qint64 msToAdd)
Adds a time to all offset values.
void push_frontKeepLatestAdjustedFirst(const OBJ &value, bool replaceSameTimestamp=true, int maxElements=-1)
Insert as first element by keeping maxElements and the latest first.
qint64 oldestAdjustedTimestampMsecsSinceEpoch() const
Oldest adjusted timestamp.
void sortAdjustedLatestFirst()
Sort by adjusted timestamp.
bool containsNegativeOffsetTime() const
Any negative offset time?
CONTAINER getSortedAdjustedLatestFirst() const
As sorted copy.
void prefillLatestAdjustedFirst(const OBJ &value, int elements, qint64 deltaTimeMs=-1)
Prefill with elements.
QDateTime latestAdjustedTimestamp() const
Latest adjusted timestamp.
OBJ oldestAdjustedObject() const
Oldest adjusted object.
void push_frontKeepLatestFirstAdjustOffset(const OBJ &value, bool replaceSameTimestamp=true, int maxElements=-1)
Insert as first element by keeping maxElements and the latest first.
HintAdjustedTimestampSort m_tsAdjustedSortHint
sort hint
void push_frontKeepLatestFirstIgnoreOverlapping(const OBJ &value, bool replaceSameTimestamp=true, int maxElements=-1)
Add value, but ignore overlapping (past) values.
qint64 latestAdjustedTimestampMsecsSinceEpoch() const
Latest adjusted timestamp.
CONTAINER findAfterAdjusted(qint64 msSinceEpoch) const
List of objects after msSinceEpoch (newer)
OBJ findObjectAfterAdjustedOrDefault(qint64 msSinceEpoch) const
List of objects after msSinceEpoch (newer)
ITimestampWithOffsetObjectList()=default
Constructor.
void sortAdjustedOldestFirst()
Sort by adjusted timestamp.
auto MemberLess(Ts... vs)
Predicate which compares the return values of some member functions of two objects.
Free functions in swift::misc.
T::const_iterator begin(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
T::const_iterator end(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
Milliseconds minimum/maximum/mean.
bool isValid() const
Valid?
void reset()
Reset the values.
double mean
Mean (average)
QString asString() const
As string.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.