From: Mike D. Lowis Date: Mon, 10 Dec 2012 21:28:03 +0000 (-0500) Subject: Finished implementation of circular buffer X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=0956be282f74ad0728a0993c0cef1c58cbc06b7e;p=projs%2Flibcds.git Finished implementation of circular buffer --- diff --git a/source/buffer/buf.c b/source/buffer/buf.c new file mode 100644 index 0000000..c210b9a --- /dev/null +++ b/source/buffer/buf.c @@ -0,0 +1,93 @@ +/** + @file buf.c + @brief See header for details + $Revision$ + $HeadURL$ +*/ +#include +#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; +} + diff --git a/source/buffer/buf.h b/source/buffer/buf.h index e69de29..165795d 100644 --- a/source/buffer/buf.h +++ b/source/buffer/buf.h @@ -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 index 0000000..c22f52a --- /dev/null +++ b/tests/test_buf.cpp @@ -0,0 +1,181 @@ +// Unit Test Framework Includes +#include "UnitTest++.h" +#include +#include + +// 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) ); + } +}