1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
// SPDX-FileCopyrightText: 2021 Quotient contributors
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "eventstats.h"
using namespace Quotient;
EventStats EventStats::fromRange(const Room* room, const Room::rev_iter_t& from,
const Room::rev_iter_t& to,
const EventStats& init)
{
Q_ASSERT(to <= room->historyEdge());
Q_ASSERT(from >= Room::rev_iter_t(room->syncEdge()));
Q_ASSERT(from <= to);
QElapsedTimer et;
et.start();
const auto result =
accumulate(from, to, init,
[room](EventStats acc, const TimelineItem& ti) {
acc.notableCount += room->isEventNotable(ti);
acc.highlightCount += room->notificationFor(ti).type
== Notification::Highlight;
return acc;
});
if (et.nsecsElapsed() > profilerMinNsecs() / 10)
qCDebug(PROFILER).nospace()
<< "Event statistics collection over index range [" << from->index()
<< "," << (to - 1)->index() << "] took " << et;
return result;
}
EventStats EventStats::fromMarker(const Room* room,
const EventStats::marker_t& marker)
{
const auto s = fromRange(room, marker_t(room->syncEdge()), marker,
{ 0, 0, marker == room->historyEdge() });
Q_ASSERT(s.isValidFor(room, marker));
return s;
}
EventStats EventStats::fromCachedCounters(Omittable<int> notableCount,
Omittable<int> highlightCount)
{
const auto hCount = std::max(0, highlightCount.value_or(0));
if (!notableCount.has_value())
return { 0, hCount, true };
auto nCount = notableCount.value_or(0);
return { std::max(0, nCount), hCount, nCount != -1 };
}
bool EventStats::updateOnMarkerMove(const Room* room, const marker_t& oldMarker,
const marker_t& newMarker)
{
if (newMarker == oldMarker)
return false;
// Double-check consistency between the old marker and the old stats
Q_ASSERT(isValidFor(room, oldMarker));
Q_ASSERT(oldMarker > newMarker);
// A bit of optimisation: only calculate the difference if the marker moved
// less than half the remaining timeline ahead; otherwise, recalculation
// over the remaining timeline will very likely be faster.
if (oldMarker != room->historyEdge()
&& oldMarker - newMarker < newMarker - marker_t(room->syncEdge())) {
const auto removedStats = fromRange(room, newMarker, oldMarker);
Q_ASSERT(notableCount >= removedStats.notableCount
&& highlightCount >= removedStats.highlightCount);
notableCount -= removedStats.notableCount;
highlightCount -= removedStats.highlightCount;
return removedStats.notableCount > 0 || removedStats.highlightCount > 0;
}
const auto newStats = EventStats::fromMarker(room, newMarker);
if (!isEstimate && newStats == *this)
return false;
*this = newStats;
return true;
}
bool EventStats::isValidFor(const Room* room, const marker_t& marker) const
{
const auto markerAtHistoryEdge = marker == room->historyEdge();
// Either markerAtHistoryEdge and isEstimate are in the same state, or it's
// a special case of no notable events and the marker at history edge
// (then isEstimate can assume any value).
return markerAtHistoryEdge == isEstimate
|| (markerAtHistoryEdge && notableCount == 0);
}
QDebug Quotient::operator<<(QDebug dbg, const EventStats& es)
{
QDebugStateSaver _(dbg);
dbg.nospace() << es.notableCount << '/' << es.highlightCount;
if (es.isEstimate)
dbg << " (estimated)";
return dbg;
}
|