-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtimeestimator.cpp
69 lines (63 loc) · 2.5 KB
/
timeestimator.cpp
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
#include <cassert>
#include "timeestimator.hpp"
void TimeEstimator::add(const QDateTime& postTime,const QDateTime& replyTime,const bool instantResponse,const QVariant& timeOnServer)
{
assert(postTime.isValid());
if (timeOnServer.isValid()) {
lastTimeOnServer=QDateTime::fromSecsSinceEpoch(timeOnServer.toLongLong()).addMSecs(500);
referenceTime=replyTime;
}
if (instantResponse) {
const auto roundTripTime=postTime.msecsTo(replyTime);
insertSorted(roundTripTimes,roundTripTime);
if (timeOnServer.isValid())
estimatedServerToLocalOffsets.push_back(lastTimeOnServer.msecsTo(replyTime.addMSecs(-roundTripTime/2)));
}
else if (timeOnServer.isValid())
estimatedServerToLocalPlusReplyOffsets.push_back(lastTimeOnServer.msecsTo(replyTime));
}
qint64 TimeEstimator::estimatedRoundTripTime() const
{
if (roundTripTimes.empty())
return 0;
else
return medianSorted(roundTripTimes);
}
qint64 TimeEstimator::estimatedExtraTime() const
{
const auto numEstimates=estimatedServerToLocalOffsets.size()+estimatedServerToLocalPlusReplyOffsets.size();
if (numEstimates==0)
return 0;
std::vector<qint64> allEstimatedServerToLocal;
allEstimatedServerToLocal.reserve(numEstimates);
allEstimatedServerToLocal.insert(allEstimatedServerToLocal.end(),estimatedServerToLocalOffsets.begin(),estimatedServerToLocalOffsets.end());
const auto estimatedReplyTime=estimatedRoundTripTime()/2;
for (const auto& estimatedServerToLocalPlusReplyOffset:estimatedServerToLocalPlusReplyOffsets)
allEstimatedServerToLocal.push_back(estimatedServerToLocalPlusReplyOffset-estimatedReplyTime);
const auto estimatedTurnTime=std::max(referenceTime,lastTimeOnServer.addMSecs(medianUnsorted(allEstimatedServerToLocal)));
return estimatedTurnTime.msecsTo(QDateTime::currentDateTimeUtc());
}
qint64 TimeEstimator::medianSorted(const std::vector<qint64>& multiset)
{
auto iter=next(multiset.begin(),multiset.size()/2);
if (multiset.size()%2==0) {
const auto high=*iter--;
return (high+*iter)/2;
}
else
return *iter;
}
qint64 TimeEstimator::medianUnsorted(std::vector<qint64>& multiset)
{
assert(!multiset.empty());
const auto iter=next(multiset.begin(),multiset.size()/2);
nth_element(multiset.begin(),iter,multiset.end());
if (multiset.size()%2==0)
return (*iter+*max_element(multiset.begin(),iter))/2;
else
return *iter;
}
void TimeEstimator::insertSorted(std::vector<qint64>& vector,const qint64 element)
{
vector.insert(upper_bound(vector.begin(),vector.end(),element),element);
}