mirror of
https://github.com/overte-org/overte.git
synced 2025-07-26 08:15:21 +02:00
184 lines
6.4 KiB
C++
184 lines
6.4 KiB
C++
//
|
|
// LossList.cpp
|
|
// libraries/networking/src/udt
|
|
//
|
|
// Created by Clement on 7/27/15.
|
|
// Copyright 2015 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#include "LossList.h"
|
|
|
|
#include "ControlPacket.h"
|
|
|
|
using namespace udt;
|
|
using namespace std;
|
|
|
|
void LossList::append(SequenceNumber seq) {
|
|
Q_ASSERT_X(_lossList.empty() || (_lossList.back().second < seq), "LossList::append(SequenceNumber)",
|
|
"SequenceNumber appended is not greater than the last SequenceNumber in the list");
|
|
|
|
if (getLength() > 0 && _lossList.back().second + 1 == seq) {
|
|
++_lossList.back().second;
|
|
} else {
|
|
_lossList.push_back(make_pair(seq, seq));
|
|
}
|
|
_length += 1;
|
|
}
|
|
|
|
void LossList::append(SequenceNumber start, SequenceNumber end) {
|
|
Q_ASSERT_X(_lossList.empty() || (_lossList.back().second < start),
|
|
"LossList::append(SequenceNumber, SequenceNumber)",
|
|
"SequenceNumber range appended is not greater than the last SequenceNumber in the list");
|
|
Q_ASSERT_X(start <= end,
|
|
"LossList::append(SequenceNumber, SequenceNumber)", "Range start greater than range end");
|
|
|
|
if (getLength() > 0 && _lossList.back().second + 1 == start) {
|
|
_lossList.back().second = end;
|
|
} else {
|
|
_lossList.push_back(make_pair(start, end));
|
|
}
|
|
_length += seqlen(start, end);
|
|
}
|
|
|
|
void LossList::insert(SequenceNumber start, SequenceNumber end) {
|
|
Q_ASSERT_X(start <= end,
|
|
"LossList::insert(SequenceNumber, SequenceNumber)", "Range start greater than range end");
|
|
|
|
auto it = find_if_not(_lossList.begin(), _lossList.end(), [&start](pair<SequenceNumber, SequenceNumber> pair){
|
|
return pair.second < start;
|
|
});
|
|
|
|
if (it == _lossList.end() || end < it->first) {
|
|
// No overlap, simply insert
|
|
_length += seqlen(start, end);
|
|
_lossList.insert(it, make_pair(start, end));
|
|
} else {
|
|
// If it starts before segment, extend segment
|
|
if (start < it->first) {
|
|
_length += seqlen(start, it->first - 1);
|
|
it->first = start;
|
|
}
|
|
|
|
// If it ends after segment, extend segment
|
|
if (end > it->second) {
|
|
_length += seqlen(it->second + 1, end);
|
|
it->second = end;
|
|
}
|
|
|
|
auto it2 = it;
|
|
++it2;
|
|
// For all ranges touching the current range
|
|
while (it2 != _lossList.end() && it->second >= it2->first - 1) {
|
|
// extend current range if necessary
|
|
if (it->second < it2->second) {
|
|
_length += seqlen(it->second + 1, it2->second);
|
|
it->second = it2->second;
|
|
}
|
|
|
|
// Remove overlapping range
|
|
_length -= seqlen(it2->first, it2->second);
|
|
it2 = _lossList.erase(it2);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool LossList::remove(SequenceNumber seq) {
|
|
auto it = find_if(_lossList.begin(), _lossList.end(), [&seq](pair<SequenceNumber, SequenceNumber> pair) {
|
|
return pair.first <= seq && seq <= pair.second;
|
|
});
|
|
|
|
if (it != end(_lossList)) {
|
|
if (it->first == it->second) {
|
|
_lossList.erase(it);
|
|
} else if (seq == it->first) {
|
|
++it->first;
|
|
} else if (seq == it->second) {
|
|
--it->second;
|
|
} else {
|
|
auto temp = it->second;
|
|
it->second = seq - 1;
|
|
_lossList.insert(++it, make_pair(seq + 1, temp));
|
|
}
|
|
_length -= 1;
|
|
|
|
// this sequence number was found in the loss list, return true
|
|
return true;
|
|
} else {
|
|
// this sequence number was not found in the loss list, return false
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void LossList::remove(SequenceNumber start, SequenceNumber end) {
|
|
Q_ASSERT_X(start <= end,
|
|
"LossList::remove(SequenceNumber, SequenceNumber)", "Range start greater than range end");
|
|
// Find the first segment sharing sequence numbers
|
|
auto it = find_if(_lossList.begin(), _lossList.end(), [&start, &end](pair<SequenceNumber, SequenceNumber> pair) {
|
|
return (pair.first <= start && start <= pair.second) || (start <= pair.first && pair.first <= end);
|
|
});
|
|
|
|
// If we found one
|
|
if (it != _lossList.end()) {
|
|
|
|
// While the end of the current segment is contained, either shorten it (first one only - sometimes)
|
|
// or remove it altogether since it is fully contained it the range
|
|
while (it != _lossList.end() && end >= it->second) {
|
|
if (start <= it->first) {
|
|
// Segment is contained, update new length and erase it.
|
|
_length -= seqlen(it->first, it->second);
|
|
it = _lossList.erase(it);
|
|
} else {
|
|
// Beginning of segment not contained, modify end of segment.
|
|
// Will only occur sometimes one the first loop
|
|
_length -= seqlen(start, it->second);
|
|
it->second = start - 1;
|
|
++it;
|
|
}
|
|
}
|
|
|
|
// There might be more to remove
|
|
if (it != _lossList.end() && it->first <= end) {
|
|
if (start <= it->first) {
|
|
// Truncate beginning of segment
|
|
_length -= seqlen(it->first, end);
|
|
it->first = end + 1;
|
|
} else {
|
|
// Cut it in half if the range we are removing is contained within one segment
|
|
_length -= seqlen(start, end);
|
|
auto temp = it->second;
|
|
it->second = start - 1;
|
|
_lossList.insert(++it, make_pair(end + 1, temp));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SequenceNumber LossList::getFirstSequenceNumber() const {
|
|
Q_ASSERT_X(getLength() > 0, "LossList::getFirstSequenceNumber()", "Trying to get first element of an empty list");
|
|
return _lossList.front().first;
|
|
}
|
|
|
|
SequenceNumber LossList::popFirstSequenceNumber() {
|
|
auto front = getFirstSequenceNumber();
|
|
remove(front);
|
|
return front;
|
|
}
|
|
|
|
void LossList::write(ControlPacket& packet, int maxPairs) {
|
|
int writtenPairs = 0;
|
|
|
|
for (const auto& pair : _lossList) {
|
|
packet.writePrimitive(pair.first);
|
|
packet.writePrimitive(pair.second);
|
|
|
|
++writtenPairs;
|
|
|
|
// check if we've written the maximum number we were told to write
|
|
if (maxPairs != -1 && writtenPairs >= maxPairs) {
|
|
break;
|
|
}
|
|
}
|
|
}
|