#define MS_CLASS "RTC::SeqManager"
#include "RTC/SeqManager.hpp"
#include "Logger.hpp"
#include <iterator>
namespace RTC
{
template<typename T, uint8_t N>
bool SeqManager<T, N>::SeqLowerThan::operator()(const T lhs, const T rhs) const
{
return ((rhs > lhs) && (rhs - lhs <= MaxValue / 2)) ||
((lhs > rhs) && (lhs - rhs > MaxValue / 2));
}
template<typename T, uint8_t N>
bool SeqManager<T, N>::SeqHigherThan::operator()(const T lhs, const T rhs) const
{
return ((lhs > rhs) && (lhs - rhs <= MaxValue / 2)) ||
((rhs > lhs) && (rhs - lhs > MaxValue / 2));
}
template<typename T, uint8_t N>
const typename SeqManager<T, N>::SeqLowerThan SeqManager<T, N>::isSeqLowerThan{};
template<typename T, uint8_t N>
const typename SeqManager<T, N>::SeqHigherThan SeqManager<T, N>::isSeqHigherThan{};
template<typename T, uint8_t N>
bool SeqManager<T, N>::IsSeqLowerThan(const T lhs, const T rhs)
{
return isSeqLowerThan(lhs, rhs);
}
template<typename T, uint8_t N>
bool SeqManager<T, N>::IsSeqHigherThan(const T lhs, const T rhs)
{
return isSeqHigherThan(lhs, rhs);
}
template<typename T, uint8_t N>
void SeqManager<T, N>::Sync(T input)
{
this->base = (this->maxOutput - input) & MaxValue;
this->maxInput = input;
this->dropped.clear();
}
template<typename T, uint8_t N>
void SeqManager<T, N>::Drop(T input)
{
if (SeqManager<T, N>::IsSeqHigherThan(input, this->maxInput))
{
this->maxInput = input;
this->dropped.insert(this->dropped.end(), input);
ClearDropped();
}
}
template<typename T, uint8_t N>
bool SeqManager<T, N>::Input(const T input, T& output)
{
auto base = this->base;
if (this->dropped.empty())
{
goto done;
}
else
{
if (this->started && IsSeqHigherThan(input, this->maxInput))
{
this->maxInput = input;
}
ClearDropped();
base = this->base;
}
if (this->dropped.empty())
{
goto done;
}
else if (this->dropped.find(input) != this->dropped.end())
{
MS_DEBUG_DEV("trying to send a dropped input");
return false;
}
else
{
auto droppedCount = this->dropped.size();
auto it = this->dropped.lower_bound(input);
droppedCount -= std::distance(it, this->dropped.end());
base = (this->base - droppedCount) & MaxValue;
}
done:
output = (input + base) & MaxValue;
if (!this->started)
{
this->started = true;
this->maxInput = input;
this->maxOutput = output;
}
else
{
if (IsSeqHigherThan(input, this->maxInput))
{
this->maxInput = input;
}
if (IsSeqHigherThan(output, this->maxOutput))
{
this->maxOutput = output;
}
}
return true;
}
template<typename T, uint8_t N>
T SeqManager<T, N>::GetMaxInput() const
{
return this->maxInput;
}
template<typename T, uint8_t N>
T SeqManager<T, N>::GetMaxOutput() const
{
return this->maxOutput;
}
template<typename T, uint8_t N>
void SeqManager<T, N>::ClearDropped()
{
if (this->dropped.empty())
{
return;
}
const size_t previousDroppedSize = this->dropped.size();
for (auto it = this->dropped.begin(); it != this->dropped.end();)
{
auto value = *it;
if (isSeqHigherThan(value, this->maxInput))
{
it = this->dropped.erase(it);
}
else
{
break;
}
}
this->base = (this->base - (previousDroppedSize - this->dropped.size())) & MaxValue;
}
template class SeqManager<uint8_t>;
template class SeqManager<uint8_t, 3>; template class SeqManager<uint16_t>;
template class SeqManager<uint16_t, 15>; template class SeqManager<uint32_t>;
}