diff --git a/src/ringbuffer.cpp b/src/ringbuffer.cpp new file mode 100644 --- /dev/null +++ b/src/ringbuffer.cpp @@ -0,0 +1,172 @@ +/* + 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; +}