Changeset - 9ce163ba1b88
[Not reviewed]
stream
0 3 0
Hasan Yavuz ÖZDERYA - 8 years ago 2018-04-03 15:37:27
hy@ozderya.net
added method for disconnecting all sinks
3 files changed with 31 insertions and 1 deletions:
0 comments (0 inline, 0 general)
src/source.cpp
Show inline comments
 
/*
 
  Copyright © 2018 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 <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include <QtGlobal>
 

	
 
#include "source.h"
 

	
 
Source::~Source()
 
{
 
    for (auto sink : sinks)
 
    {
 
        sink->setSource(NULL);
 
    }
 
}
 

	
 
void Source::connect(Sink* sink)
 
{
 
    Q_ASSERT(!sinks.contains(sink));
 
    Q_ASSERT(sink->connectedSource() == NULL);
 

	
 
    sinks.append(sink);
 
    sink->setSource(this);
 
    sink->setNumChannels(numChannels(), hasX());
 
}
 

	
 
void Source::disconnect(Sink* sink)
 
{
 
    Q_ASSERT(sinks.contains(sink));
 
    Q_ASSERT(sink->connectedSource() == this);
 

	
 
    sink->setSource(NULL);
 
    sinks.removeOne(sink);
 
}
 

	
 
void Source::disconnectSinks()
 
{
 
    while (!sinks.isEmpty())
 
    {
 
        auto sink = sinks.takeFirst();
 
        sink->setSource(NULL);
 
    }
 
}
 

	
 
void Source::feedOut(const SamplePack& data) const
 
{
 
    for (auto sink : sinks)
 
    {
 
        sink->feedIn(data);
 
    }
 
}
 

	
 
void Source::updateNumChannels() const
 
{
 
    for (auto sink : sinks)
 
    {
 
        sink->setNumChannels(numChannels(), hasX());
 
    }
 
}
src/source.h
Show inline comments
 
/*
 
  Copyright © 2018 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 <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef SOURCE_H
 
#define SOURCE_H
 

	
 
#include <QList>
 

	
 
#include "sink.h"
 
#include "samplepack.h"
 

	
 
class Source
 
{
 
public:
 
    /// Virtual destructor. Must be called by implementors to notify sinks.
 
    virtual ~Source();
 

	
 
    /// Returns true if source has X data
 
    virtual bool hasX() const = 0;
 

	
 
    /// Returns number of channels
 
    virtual unsigned numChannels() const = 0;
 

	
 
    /// Connects a sink to this source. Trying to connect an already
 
    /// connected sink is an error.
 
    void connect(Sink* sink);
 

	
 
    /// Disconnects an already connected sink. Trying to disconnect an
 
    /// unconnected sink is an error.
 
    void disconnect(Sink* sink);
 

	
 
    /// Disconnects all connected sinks.
 
    void disconnectSinks();
 

	
 
protected:
 
    /// Feeds "in" given data to connected sinks
 
    void feedOut(const SamplePack& data) const;
 
    virtual void feedOut(const SamplePack& data) const;
 

	
 
    /// Updates "number of channels" of connected sinks. Must be
 
    /// called when num. channels or hasX changes.
 
    void updateNumChannels() const;
 

	
 
private:
 
    QList<Sink*> sinks;
 
};
 

	
 
#endif // SOURCE_H
tests/test.cpp
Show inline comments
 
@@ -34,192 +34,210 @@ TEST_CASE("samplepack with no X", "[memo
 
    SamplePack pack(100, 3, false);
 

	
 
    REQUIRE_FALSE(pack.hasX());
 
    REQUIRE(pack.numChannels() == 3);
 
    REQUIRE(pack.numSamples() == 100);
 

	
 
    double* chan0 = pack.data(0);
 
    double* chan1 = pack.data(1);
 
    double* chan2 = pack.data(2);
 

	
 
    REQUIRE(chan0 == chan1 - 100);
 
    REQUIRE(chan1 == chan2 - 100);
 
}
 

	
 
TEST_CASE("samplepack with X", "[memory]")
 
{
 
    SamplePack pack(100, 3, true);
 

	
 
    REQUIRE(pack.hasX());
 
    REQUIRE(pack.numChannels() == 3);
 
    REQUIRE(pack.numSamples() == 100);
 
    REQUIRE(pack.xData() != nullptr);
 
}
 

	
 
TEST_CASE("sink", "[memory, stream]")
 
{
 
    TestSink sink;
 
    SamplePack pack(100, 3, false);
 

	
 
    sink.setNumChannels(3, false);
 
    REQUIRE(sink.numChannels() == 3);
 

	
 
    sink.feedIn(pack);
 
    REQUIRE(sink.totalFed == 100);
 
    sink.feedIn(pack);
 
    REQUIRE(sink.totalFed == 200);
 

	
 
    TestSink follower;
 

	
 
    sink.connectFollower(&follower);
 
    REQUIRE(follower.numChannels() == 3);
 
    REQUIRE(follower.hasX() == false);
 

	
 
    sink.feedIn(pack);
 
    REQUIRE(sink.totalFed == 300);
 
    REQUIRE(follower.totalFed == 100);
 

	
 
    sink.setNumChannels(2, true);
 
    REQUIRE(follower.numChannels() == 2);
 
    REQUIRE(follower.hasX() == true);
 
}
 

	
 
TEST_CASE("sink must be created unconnected", "[memory, stream]")
 
{
 
    TestSink sink;
 
    REQUIRE(sink.connectedSource() == NULL);
 
}
 

	
 
TEST_CASE("source", "[memory, stream]")
 
{
 
    TestSink sink;
 

	
 
    TestSource source(3, false);
 

	
 
    REQUIRE(source.numChannels() == 3);
 
    REQUIRE(source.hasX() == false);
 

	
 
    source.connect(&sink);
 
    REQUIRE(sink.numChannels() == 3);
 
    REQUIRE(sink.hasX() == false);
 

	
 
    source._setNumChannels(5, true);
 
    REQUIRE(sink.numChannels() == 5);
 
    REQUIRE(sink.hasX() == true);
 

	
 
    SamplePack pack(100, 5, true);
 
    source._feed(pack);
 
    REQUIRE(sink.totalFed == 100);
 

	
 
    source.disconnect(&sink);
 
    source._feed(pack);
 
    REQUIRE(sink.totalFed == 100);
 
}
 

	
 
TEST_CASE("source must set/unset sink 'source'", "[memory, stream]")
 
{
 
    TestSink sink;
 
    TestSource source(3, false);
 

	
 
    source.connect(&sink);
 
    REQUIRE(sink.connectedSource() == &source);
 

	
 
    source.disconnect(&sink);
 
    REQUIRE(sink.connectedSource() == NULL);
 
}
 

	
 
TEST_CASE("source disconnect all sinks", "[memory, stream]")
 
{
 
    TestSink sinks[3];
 
    TestSource source(3, false);
 

	
 
    // connect sinks
 
    for (int i = 0; i < 3; i++)
 
    {
 
        source.connect(&sinks[i]);
 
    }
 

	
 
    source.disconnectSinks();
 
    for (int i = 0; i < 3; i++)
 
    {
 
        REQUIRE(sinks[i].connectedSource() == NULL);
 
    }
 
}
 

	
 
TEST_CASE("IndexBuffer", "[memory, buffer]")
 
{
 
    IndexBuffer buf(10);
 

	
 
    REQUIRE(buf.size() == 10);
 
    for (unsigned i = 0; i < 10; i++)
 
    {
 
        REQUIRE(buf.sample(i) == i);
 
    }
 
    auto l = buf.limits();
 
    REQUIRE(l.start == 0);
 
    REQUIRE(l.end == 9);
 

	
 
    buf.resize(20);
 
    REQUIRE(buf.size() == 20);
 
    REQUIRE(buf.sample(15) == 15);
 
    l = buf.limits();
 
    REQUIRE(l.start == 0);
 
    REQUIRE(l.end == 19);
 
}
 

	
 
TEST_CASE("LinIndexBuffer", "[memory, buffer]")
 
{
 
    LinIndexBuffer buf(10, 0., 3.0);
 

	
 
    REQUIRE(buf.size() == 10);
 
    REQUIRE(buf.sample(0) == 0.);
 
    REQUIRE(buf.sample(9) == 3.0);
 
    REQUIRE(buf.sample(4) == Approx(1+1/3.));
 

	
 
    auto l = buf.limits();
 
    REQUIRE(l.start == 0.);
 
    REQUIRE(l.end == 3.);
 

	
 
    buf.resize(20);
 
    REQUIRE(buf.size() == 20);
 
    REQUIRE(buf.sample(0) == 0.);
 
    REQUIRE(buf.sample(9) == Approx(9.*3./19.));
 
    REQUIRE(buf.sample(4) == Approx(4.*3./19.));
 
    REQUIRE(buf.sample(19) == 3.0);
 

	
 
    l = buf.limits();
 
    REQUIRE(l.start == 0.);
 
    REQUIRE(l.end == 3.0);
 

	
 
    buf.setLimits({-5., 5.});
 
    l = buf.limits();
 
    REQUIRE(l.start == -5.0);
 
    REQUIRE(l.end == 5.0);
 

	
 
    REQUIRE(buf.sample(0) == -5.0);
 
    REQUIRE(buf.sample(19) == 5.0);
 
}
 

	
 
TEST_CASE("RingBuffer sizing", "[memory, buffer]")
 
{
 
    RingBuffer buf(10);
 

	
 
    REQUIRE(buf.size() == 10);
 

	
 
    buf.resize(5);
 
    REQUIRE(buf.size() == 5);
 

	
 
    buf.resize(15);
 
    REQUIRE(buf.size() == 15);
 
}
 

	
 
TEST_CASE("RingBuffer initial values should be 0", "[memory, buffer]")
 
{
 
    RingBuffer buf(10);
 

	
 
    for (unsigned i = 0; i < 10; i++)
 
    {
 
        REQUIRE(buf.sample(i) == 0.);
 
    }
 
}
 

	
 
TEST_CASE("RingBuffer data access", "[memory, buffer]")
 
{
 
    RingBuffer buf(10);
 
    double values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
 

	
 
    buf.addSamples(values, 10);
 

	
 
    REQUIRE(buf.size() == 10);
 
    for (unsigned i = 0; i < 10; i++)
 
    {
 
        REQUIRE(buf.sample(i) == values[i]);
 
    }
 

	
 
    buf.addSamples(values, 5);
 

	
 
    REQUIRE(buf.size() == 10);
 
    for (unsigned i = 0; i < 5; i++)
 
    {
 
        REQUIRE(buf.sample(i) == values[i+5]);
0 comments (0 inline, 0 general)