/*
Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
serialplot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
serialplot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with serialplot. If not, see .
*/
#include
#include "ringbuffer.h"
RingBuffer::RingBuffer(unsigned n)
{
_size = n;
data = new double[_size]();
headIndex = 0;
limInvalid = false;
limCache = {0, 0};
}
RingBuffer::~RingBuffer()
{
delete[] data;
}
unsigned RingBuffer::size() const
{
return _size;
}
double RingBuffer::sample(unsigned i) const
{
unsigned index = headIndex + i;
if (index >= _size) index -= _size;
return data[index];
}
Range RingBuffer::limits() const
{
if (limInvalid) updateLimits();
return limCache;
}
void RingBuffer::resize(unsigned n)
{
Q_ASSERT(n != _size);
int offset = (int) n - (int) _size;
if (offset == 0) return;
double* newData = new double[n];
// move data to new array
int fill_start = offset > 0 ? offset : 0;
for (int i = fill_start; i < int(n); i++)
{
newData[i] = sample(i - offset);
}
// fill the beginning of the new data
if (fill_start > 0)
{
for (int i = 0; i < fill_start; i++)
{
newData[i] = 0;
}
}
// data is ready, clean up and re-point
delete data;
data = newData;
headIndex = 0;
_size = n;
// invalidate bounding rectangle
limInvalid = true;
}
void RingBuffer::addSamples(double* samples, unsigned n)
{
unsigned shift = n;
if (shift < _size)
{
unsigned x = _size - headIndex; // distance of `head` to end
if (shift <= x) // there is enough room at the end of array
{
for (unsigned i = 0; i < shift; i++)
{
data[i+headIndex] = samples[i];
}
if (shift == x) // we used all the room at the end
{
headIndex = 0;
}
else
{
headIndex += shift;
}
}
else // there isn't enough room
{
for (unsigned i = 0; i < x; i++) // fill the end part
{
data[i+headIndex] = samples[i];
}
for (unsigned i = 0; i < (shift-x); i++) // continue from the beginning
{
data[i] = samples[i+x];
}
headIndex = shift-x;
}
}
else // number of new samples equal or bigger than current size (doesn't fit)
{
int x = shift - _size;
for (unsigned i = 0; i < _size; i++)
{
data[i] = samples[i+x];
}
headIndex = 0;
}
// invalidate cache
limInvalid = true;
}
void RingBuffer::clear()
{
for (unsigned i=0; i < _size; i++)
{
data[i] = 0.;
}
limCache = {0, 0};
limInvalid = false;
}
void RingBuffer::updateLimits() const
{
limCache.start = data[0];
limCache.end = data[0];
for (unsigned i = 0; i < _size; i++)
{
if (data[i] > limCache.end)
{
limCache.end = data[i];
}
else if (data[i] < limCache.start)
{
limCache.start = data[i];
}
}
limInvalid = false;
}