# HG changeset patch # User Hasan Yavuz ÖZDERYA # Date 2017-12-12 03:29:00 # Node ID b2f0d61c350726719401bc7b13b3641e380b5e38 # Parent 41cf55d3a08c96eeae17d178f24d3021d4051d3d added read only buffer for use with snapshots diff --git a/src/readonlybuffer.cpp b/src/readonlybuffer.cpp new file mode 100644 --- /dev/null +++ b/src/readonlybuffer.cpp @@ -0,0 +1,86 @@ +/* + 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 "readonlybuffer.h" + +ReadOnlyBuffer::ReadOnlyBuffer(const FrameBuffer* source) : + ReadOnlyBuffer(source, 0, source->size()) +{ + // empty +} + +ReadOnlyBuffer::ReadOnlyBuffer(const FrameBuffer* source, unsigned start, unsigned n) +{ + Q_ASSERT(source->size() > 0); + Q_ASSERT(start + n <= source->size()); + + _size = n; + data = new double[_size]; + + for (unsigned i = 0; i < n; i++) + { + data[i] = source->sample(start + i); + } + + /// if not exact copy of source re-calculate limits + if (start == 0 && n == source->size()) + { + _limits = source->limits(); + } + else + { + // TODO: code duplication with RingBuffer::updateLimits, consider reuse + _limits.start = data[0]; + _limits.end = data[0]; + + for (unsigned i = 0; i < _size; i++) + { + if (data[i] > _limits.end) + { + _limits.end = data[i]; + } + else if (data[i] < _limits.start) + { + _limits.start = data[i]; + } + } + } +} + +ReadOnlyBuffer::~ReadOnlyBuffer() +{ + delete[] data; +} + +unsigned ReadOnlyBuffer::size() const +{ + return _size; +} + +double ReadOnlyBuffer::sample(unsigned i) const +{ + return data[i]; +} + +Range ReadOnlyBuffer::limits() const +{ + return _limits; +} diff --git a/src/readonlybuffer.h b/src/readonlybuffer.h new file mode 100644 --- /dev/null +++ b/src/readonlybuffer.h @@ -0,0 +1,57 @@ +/* + 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 . +*/ + +#ifndef READONLYBUFFER_H +#define READONLYBUFFER_H + +// IMPORTANT TODO: rename to "framebuffer.h" when stream work is done. +#include "framebuffer2.h" + +/// A read only frame buffer used for storing snapshot data. Main advantage of +/// this compared to `RingBuffer` is that reading data should be somewhat +/// faster. +class ReadOnlyBuffer : public FrameBuffer +{ +public: + /// Creates a buffer with data copied from `source`. Source buffer cannot be + /// empty. + ReadOnlyBuffer(const FrameBuffer* source); + + /// Creates a buffer from a slice of the `source`. + /// + /// @param start start of the slice + /// @param n number of samples + /// + /// @important (start + n) should be smaller or equal than `source->size()`, + /// otherwise it's an error. + ReadOnlyBuffer(const FrameBuffer* source, unsigned start, unsigned n); + + ~ReadOnlyBuffer(); + + virtual unsigned size() const; + virtual double sample(unsigned i) const; + virtual Range limits() const; + +private: + double* data; ///< data storage + unsigned _size; ///< data size + Range _limits; ///< limits cache +}; + +#endif // READONLYBUFFER_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(Test EXCLUDE_FROM_ALL ../src/indexbuffer.cpp ../src/linindexbuffer.cpp ../src/ringbuffer.cpp + ../src/readonlybuffer.cpp ) add_test(NAME test1 COMMAND Test) qt5_use_modules(Test Widgets) diff --git a/tests/test.cpp b/tests/test.cpp --- a/tests/test.cpp +++ b/tests/test.cpp @@ -25,6 +25,7 @@ #include "indexbuffer.h" #include "linindexbuffer.h" #include "ringbuffer.h" +#include "readonlybuffer.h" TEST_CASE("samplepack with no X", "[memory]") { @@ -364,3 +365,35 @@ TEST_CASE("RingBuffer clear", "[memory, REQUIRE(lim.start == 0.); REQUIRE(lim.end == 0.); } + +TEST_CASE("ReadOnlyBuffer", "[memory, buffer]") +{ + IndexBuffer source(10); + + ReadOnlyBuffer buf(&source); + + REQUIRE(buf.size() == 10); + auto lim = buf.limits(); + REQUIRE(lim.start == 0.); + REQUIRE(lim.end == 9.); + for (unsigned i = 0; i < 10; i++) + { + REQUIRE(buf.sample(i) == i); + } +} + +TEST_CASE("ReadOnlyBuffer sliced constructor", "[memory, buffer]") +{ + IndexBuffer source(10); + + ReadOnlyBuffer buf(&source, 5, 4); + + REQUIRE(buf.size() == 4); + auto lim = buf.limits(); + REQUIRE(lim.start == 5.); + REQUIRE(lim.end == 8.); + for (unsigned i = 0; i < 4; i++) + { + REQUIRE(buf.sample(i) == (i + 5)); + } +}