]> git.mdlowis.com Git - projs/libcds.git/commitdiff
Finished implementation of circular buffer circular-buffer
authorMike D. Lowis <mike@mdlowis.com>
Mon, 10 Dec 2012 21:28:03 +0000 (16:28 -0500)
committerMike D. Lowis <mike@mdlowis.com>
Mon, 10 Dec 2012 21:28:03 +0000 (16:28 -0500)
source/buffer/buf.c [new file with mode: 0644]
source/buffer/buf.h
tests/test_buf.cpp [new file with mode: 0644]

diff --git a/source/buffer/buf.c b/source/buffer/buf.c
new file mode 100644 (file)
index 0000000..c210b9a
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+    @file buf.c
+    @brief See header for details
+    $Revision$
+    $HeadURL$
+*/
+#include <stdlib.h>
+#include "buf.h"
+
+buf_t* buf_new(size_t size)
+{
+    buf_t* buf = NULL;
+    if (size > 0)
+    {
+        buf         = (buf_t*) malloc( sizeof(buf_t) );
+        buf->buffer = (void**) malloc( sizeof(void*) * size );
+        buf->size   = size;
+        buf->reads  = 0;
+        buf->writes = 0;
+    }
+    return buf;
+}
+
+void buf_free(buf_t* buf, int free_contents)
+{
+    if (NULL != buf)
+    {
+        buf_clear(buf,free_contents);
+        free( buf->buffer );
+        free( buf );
+    }
+}
+
+size_t buf_size(buf_t* buf)
+{
+    return (NULL == buf) ? (size_t)0 : (size_t)buf->size;
+}
+
+int buf_empty(buf_t* buf)
+{
+    return (NULL == buf) ? 1 : (buf->reads == buf->writes);
+}
+
+int buf_full(buf_t* buf)
+{
+    int full = 1;
+    if (NULL != buf)
+    {
+        full  = !buf_empty(buf);
+        full &= ((buf->reads % buf->size) == (buf->writes % buf->size));
+    }
+    return full;
+}
+
+void buf_clear(buf_t* buf, int free_contents)
+{
+    if (NULL != buf)
+    {
+        if (free_contents)
+        {
+            while ( !buf_empty(buf) )
+            {
+                free( buf_read(buf) );
+            }
+        }
+        buf->reads  = 0;
+        buf->writes = 0;
+    }
+}
+
+void* buf_read(buf_t* buf)
+{
+    void* data = NULL;
+    if ((NULL != buf) && !buf_empty(buf))
+    {
+        data = buf->buffer[ buf->reads % buf->size ];
+        buf->reads++;
+    }
+    return data;
+}
+
+int buf_write(buf_t* buf, void* data)
+{
+    int success = 0;
+    if ((NULL != buf) && !buf_full(buf))
+    {
+        buf->buffer[ buf->writes % buf->size ] = data;
+        buf->writes++;
+        success = 1;
+    }
+    return success;
+}
+
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..165795d4c508e51e393a48f27ec42c33cbbb3343 100644 (file)
@@ -0,0 +1,97 @@
+/**
+    @file buf.h
+    @brief Implementation of a circular buffer.
+    $Revision$
+    $HeadURL$
+*/
+#ifndef BUF_H
+#define BUF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** A structure defining a circular buffer */
+typedef struct {
+    void** buffer; /**< Pointer to the buffer */
+    size_t size    /**< Size of the allocated buffer */;
+    size_t reads   /**< Total number of reads that have occurred */;
+    size_t writes  /**< Total number of writes that have occrurred */;
+} buf_t;
+
+/**
+ * @brief Creates a new buffer.
+ *
+ * @param size The fixed size of the new buffer.
+ *
+ * @return Pointer to the new buffer.
+ */
+buf_t* buf_new(size_t size);
+
+/**
+ * @brief Frees the provided buffer and optionally any unread contents.
+ *
+ * @param buf           The buffer to free.
+ * @param free_contents Whether unread contents should also be freed.
+ */
+void buf_free(buf_t* buf, int free_contents);
+
+/**
+ * @brief Returns the size of the provided buffer.
+ *
+ * @param buf The buffer on which to operate.
+ *
+ * @return The size of the buffer.
+ */
+size_t buf_size(buf_t* buf);
+
+/**
+ * @brief Returns whether the buffer is empty.
+ *
+ * @param buf The buffer on which to operate.
+ *
+ * @return 1 if the buffer is empty 0 otherwise.
+ */
+int buf_empty(buf_t* buf);
+
+/**
+ * @brief Returns whether the buffer is full.
+ *
+ * @param buf The buffer on which to operate.
+ *
+ * @return 1 if the buffer is full 0 otherwise.
+ */
+int buf_full(buf_t* buf);
+
+/**
+ * @brief Clears all unread data from the provided buffer.
+ *
+ * @param buf           The buffer to clear.
+ * @param free_contents Whether the unread contents should also be freed.
+ */
+void buf_clear(buf_t* buf, int free_contents);
+
+/**
+ * @brief Reads an item from the provided buffer.
+ *
+ * @param buf The buffer to read from.
+ *
+ * @return Pointer to the data read from the buffer. NULL If no data was read.
+ */
+void* buf_read(buf_t* buf);
+
+/**
+ * @brief Writes data to the provided buffer.
+ *
+ * @param buf  The buffer to write to.
+ * @param data The data to write.
+ *
+ * @return 1 on successful write 0 otherwise.
+ */
+int buf_write(buf_t* buf, void* data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BUF_H */
diff --git a/tests/test_buf.cpp b/tests/test_buf.cpp
new file mode 100644 (file)
index 0000000..c22f52a
--- /dev/null
@@ -0,0 +1,181 @@
+// Unit Test Framework Includes
+#include "UnitTest++.h"
+#include <cstdlib>
+#include <iostream>
+
+// File To Test
+#include "buf.h"
+
+using namespace UnitTest;
+
+//-----------------------------------------------------------------------------
+// Begin Unit Tests
+//-----------------------------------------------------------------------------
+namespace {
+    //-------------------------------------------------------------------------
+    // Test buf_new function
+    //-------------------------------------------------------------------------
+    TEST(Verify_buf_new_returns_a_new_buffer_of_the_desired_size)
+    {
+        buf_t* buf = buf_new(5);
+        CHECK( NULL != buf );
+        CHECK( NULL != buf->buffer );
+        CHECK( 5 == buf->size );
+        CHECK( 0 == buf->reads );
+        CHECK( 0 == buf->writes );
+        free( buf->buffer );
+        free( buf );
+    }
+
+    TEST(Verify_buf_new_returns_null_if_passed_a_size_of_0)
+    {
+        CHECK( NULL == buf_new(0) );
+    }
+
+    //-------------------------------------------------------------------------
+    // Test buf_free function
+    //-------------------------------------------------------------------------
+    TEST(Verify_buf_free_does_nothing_when_pointer_is_NULL)
+    {
+        buf_free( NULL, 0 );
+    }
+
+    TEST(Verify_buf_free_frees_the_buffer)
+    {
+        buf_free( buf_new(5), 0 );
+    }
+
+    //-------------------------------------------------------------------------
+    // Test buf_size function
+    //-------------------------------------------------------------------------
+    TEST(Verify_buf_size_should_return_0_when_passed_NULL)
+    {
+        CHECK( 0 == buf_size(NULL) );
+    }
+
+    TEST(Verify_buf_size_should_return_the_size_of_the_buffer)
+    {
+        buf_t* buf = buf_new(5);
+        CHECK( 5 == buf_size( buf ) );
+        buf_free(buf,0);
+    }
+
+    //-------------------------------------------------------------------------
+    // Test buf_empty function
+    //-------------------------------------------------------------------------
+    TEST(Verify_buf_empty_returns_1_when_passed_NULL)
+    {
+        CHECK( 1 == buf_empty( NULL ) );
+    }
+
+    TEST(Verify_buf_empty_returns_1_when_buffer_is_empty)
+    {
+        buf_t buf = { NULL, 5, 1, 1 };
+        CHECK( 1 == buf_empty( &buf ) );
+    }
+
+    TEST(Verify_buf_empty_returns_0_when_buffer_is_empty)
+    {
+        buf_t buf = { NULL, 5, 1, 2 };
+        CHECK( 0 == buf_empty( &buf ) );
+    }
+
+    //-------------------------------------------------------------------------
+    // Test buf_full function
+    //-------------------------------------------------------------------------
+    TEST(Verify_buf_full_returns_1_if_passed_null)
+    {
+        CHECK( 1 == buf_full(NULL) );
+    }
+
+    TEST(Verify_buf_full_returns_1_if_buffer_is_full)
+    {
+        buf_t buf = { NULL, 5, 1, 6 };
+        CHECK( 1 == buf_full( &buf ) );
+    }
+
+    TEST(Verify_buf_full_returns_0_if_buffer_empty)
+    {
+        buf_t buf = { NULL, 5, 1, 1 };
+        CHECK( 0 == buf_full( &buf ) );
+    }
+
+    TEST(Verify_buf_full_returns_0_if_buffer_not_full)
+    {
+        buf_t buf = { NULL, 5, 1, 5 };
+        CHECK( 0 == buf_full( &buf ) );
+    }
+
+    //-------------------------------------------------------------------------
+    // Test buf_clear function
+    //-------------------------------------------------------------------------
+    TEST(Verify_buf_clear_does_nothing_when_passed_null)
+    {
+        buf_clear(NULL,0);
+    }
+
+    TEST(Verify_buf_clears_the_buffer)
+    {
+        buf_t buf = { NULL, 5, 1, 5 };
+        buf_clear( &buf, 0 );
+        CHECK( buf.reads == 0 );
+        CHECK( buf.writes == 0 );
+    }
+
+    TEST(Verify_buf_clears_the_buffer_and_frees_the_contents)
+    {
+        buf_t* buf = buf_new(3);
+        buf_write( buf, (void*)malloc(sizeof(int)) );
+        buf_write( buf, (void*)malloc(sizeof(int)) );
+        buf_write( buf, (void*)malloc(sizeof(int)) );
+        buf_clear( buf, 1 );
+        CHECK( buf->reads == 0 );
+        CHECK( buf->writes == 0 );
+    }
+
+    //-------------------------------------------------------------------------
+    // Test buf_read function
+    //-------------------------------------------------------------------------
+    TEST(Verify_buf_read_should_return_NULL_if_passed_NULL)
+    {
+        CHECK( NULL == buf_read(NULL) );
+    }
+
+    TEST(Verify_buf_read_should_return_NULL_if_buffer_is_empty)
+    {
+        buf_t* buf = buf_new(3);
+        CHECK( NULL == buf_read( buf ) );
+        buf_free(buf,0);
+    }
+
+    TEST(Verify_buf_read_should_return_the_next_piece_of_data_from_the_buffer)
+    {
+        void* data[] = { (void*)0x1234, (void*)0x4321, (void*)0x1221 };
+        buf_t buf = { data, sizeof(data), 0, 3 };
+        CHECK( (void*)0x1234 == buf_read(&buf) );
+        CHECK( (void*)0x4321 == buf_read(&buf) );
+        CHECK( (void*)0x1221 == buf_read(&buf) );
+        CHECK( (void*)NULL == buf_read(&buf) );
+    }
+
+    //-------------------------------------------------------------------------
+    // Test buf_write function
+    //-------------------------------------------------------------------------
+    TEST(Verify_buf_write_should_return_0_if_passed_NULL)
+    {
+        CHECK( 0 == buf_write(NULL,(void*)0x1234) );
+    }
+
+    TEST(Verify_buf_write_should_return_0_if_buffer_is_full)
+    {
+        buf_t buf = { NULL, 3, 0, 3 };
+        CHECK( 0 == buf_write(&buf,(void*)0x1234) );
+    }
+
+    TEST(Verify_buf_write_should_return_1_if_data_successfully_wrote)
+    {
+        void* data[] = { (void*)0x1234, (void*)0x4321, (void*)0x1221 };
+        buf_t buf = { data, sizeof(data), 0, 2 };
+        CHECK( 1 == buf_write(&buf,(void*)0x1234) );
+    }
+}