~FIFO();
+ /// Returns the amount of space available for incoming data.
+ /// \return The amount of space, in bytes, available for incoming data.
+ inline std::size_t incoming_available() const {
+ return buffer_end - in + out - buffer;
+ }
+
/// Return the address of an incoming data buffer of the requested size.
/// Throws an error if we run the buffer out of space. Well-behaved code
/// won't allocate a size that can't be drained before it is further
inline char * incoming_buffer(std::size_t io_length) {
const char * io_end = in + io_length;
- if ( io_end >= buffer_end )
+ if ( io_end > buffer_end )
return reorder(io_length);
else
return in;
in += length;
}
- /// Returns the amount of space available for incoming data.
- /// \return The amount of space, in bytes, available for incoming data.
- inline std::size_t incoming_space() const {
- return buffer_end - in + out - buffer;
- }
-
/// Returns the amount of data available to read.
/// \return The amount of data, in bytes, available to read.
inline std::size_t outgoing_available() const {
namespace FreeDV {
FIFO::FIFO(std::size_t size)
- : buffer(new char[size]), buffer_end(buffer + size)
+ : buffer(new char[size]), buffer_end(buffer + size), in(buffer), out(buffer)
{
}
+ FIFO::~FIFO()
+ {
+ delete buffer;
+ }
+
char *
FIFO::reorder(std::size_t size)
{
const std::size_t bytes = in - out;
- if ( bytes > 0 ) {
+ if ( bytes > 0 && out > buffer ) {
// memmove() is specified to handle overlap properly.
memmove(buffer, out, bytes);
--- /dev/null
+// Tests for the Base class.
+#include <drivers.h>
+#include <gtest/gtest.h>
+#include <stdexcept>
+
+using namespace FreeDV;
+
+class FIFOTest : public ::testing::Test {
+protected:
+ FIFO * f;
+
+ FIFOTest()
+ : f(0)
+ {
+ }
+
+ void SetUp() {
+ f = new FIFO(100);
+ }
+
+ void TearDown() {
+ delete f;
+ }
+};
+
+TEST_F(FIFOTest, CanFillAndDrain) {
+ ASSERT_EQ(100, f->incoming_available());
+ memset(f->incoming_buffer(100), 255, 100);
+ ASSERT_EQ(0, f->outgoing_available());
+ f->incoming_done(100);
+ ASSERT_EQ(100, f->outgoing_available());
+ ASSERT_EQ(0, f->incoming_available());
+ EXPECT_THROW(f->incoming_buffer(1), std::runtime_error);
+ ASSERT_EQ(100, f->outgoing_available());
+ ASSERT_NE((char *)0, f->outgoing_buffer(100));
+ f->outgoing_done(100);
+ ASSERT_EQ(0, f->outgoing_available());
+ ASSERT_EQ(100, f->incoming_available());
+ ASSERT_EQ(100, f->incoming_available());
+ memset(f->incoming_buffer(100), 255, 100);
+ ASSERT_EQ(0, f->outgoing_available());
+ f->incoming_done(100);
+ ASSERT_EQ(100, f->outgoing_available());
+ ASSERT_EQ(0, f->incoming_available());
+}
+
+TEST_F(FIFOTest, Reorder) {
+ char * b;
+ const char * r;
+
+ ASSERT_EQ(100, f->incoming_available());
+ ASSERT_NE((char *)0, b = f->incoming_buffer(99));
+ memset(b, 0, 98);
+ b[98] = 'b';
+ f->incoming_done(99);
+ ASSERT_EQ(1, f->incoming_available());
+ ASSERT_EQ(99, f->outgoing_available());
+ ASSERT_NE((char *)0, f->outgoing_buffer(98));
+ f->outgoing_done(98);
+ ASSERT_EQ(1, f->outgoing_available());
+ ASSERT_EQ(99, f->incoming_available());
+ // This should cause reorder().
+ ASSERT_NE((char *)0, b = f->incoming_buffer(2));
+ f->incoming_done(0);
+ ASSERT_EQ(99, f->incoming_available());
+ ASSERT_EQ(1, f->outgoing_available());
+ ASSERT_NE((char *)0, r = f->outgoing_buffer(1));
+ ASSERT_EQ('b', *r);
+ f->outgoing_done(1);
+}