diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5761abc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/Makefile b/Makefile index fdb8f2b..38802db 100644 --- a/Makefile +++ b/Makefile @@ -8,4 +8,4 @@ dataflow: bipbuffer/bipbuffer.o .PHONE: clean clean: - rm -rf *.o dataflow + rm -rf *.o dataflow bipbuffer/*.o diff --git a/bipbuffer/bipbuffer.c b/bipbuffer/bipbuffer.c new file mode 100644 index 0000000..89c8ee1 --- /dev/null +++ b/bipbuffer/bipbuffer.c @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2011, Willem-Hendrik Thiart + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * @file + * @author Willem Thiart himself@willemthiart.com + */ + +#include "stdio.h" +#include +#include + +/* for memcpy */ +#include + +#include "bipbuffer.h" + +size_t bipbuf_sizeof(const unsigned int size) +{ + return sizeof(bipbuf_t) + size; +} + +int bipbuf_unused(const bipbuf_t* me) +{ + assert( me->reserved_size == 0 ); + if (1 == me->b_inuse) + /* distance between region B and region A */ + return me->a_start - me->b_end; + else + return me->size - me->a_end; +} + +int bipbuf_size(const bipbuf_t* me) +{ + return me->size; +} + +int bipbuf_used(const bipbuf_t* me) +{ + assert( me->reserved_size == 0 ); + return (me->a_end - me->a_start) + me->b_end; +} + +void bipbuf_init(bipbuf_t* me, const unsigned int size) +{ + me->a_start = me->a_end = me->b_end = 0; + me->size = size; + me->b_inuse = 0; +} + +bipbuf_t *bipbuf_new(const unsigned int size) +{ + bipbuf_t *me = malloc(bipbuf_sizeof(size)); + if (!me) + return NULL; + bipbuf_init(me, size); + return me; +} + +void bipbuf_free(bipbuf_t* me) +{ + free(me); +} + +int bipbuf_is_empty(const bipbuf_t* me) +{ + assert( me->reserved_size == 0 ); + return me->a_start == me->a_end; +} + +/* find out if we should turn on region B + * ie. is the distance from A to buffer's end less than B to A? */ +static void __check_for_switch_to_b(bipbuf_t* me) +{ + assert( me->reserved_size == 0 ); + if (me->size - me->a_end < me->a_start - me->b_end) + me->b_inuse = 1; +} + +int bipbuf_offer(bipbuf_t* me, const unsigned char *data, const int size) +{ + assert( me->reserved_size == 0 ); + /* not enough space */ + if (bipbuf_unused(me) < size) + return 0; + + if (1 == me->b_inuse) + { + memcpy(me->data + me->b_end, data, size); + me->b_end += size; + } + else + { + memcpy(me->data + me->a_end, data, size); + me->a_end += size; + } + + __check_for_switch_to_b(me); + return size; +} + +void *bipbuf_reserve( bipbuf_t* me, const unsigned int size ) { + assert( me->reserved_size == 0 ); + printf("%s %d %d\n", __func__, bipbuf_unused(me), size); + if (bipbuf_unused(me) < size) { + return NULL; + } + void * data = NULL; + if( 1 == me->b_inuse ) { + data = me->data + me->b_end; + me->reserved_size = size; + } else { + data = me->data + me->a_end; + me->reserved_size = size; + } + return data; +} + +void bipbuf_commit( bipbuf_t* me, const unsigned int size ) { + assert( me->reserved_size > 0 ); + assert( me->reserved_size >= size ); + unsigned long int reserved_size = (size < me->reserved_size)?size:me->reserved_size; + if( 1 == me->b_inuse ) { + me->b_end += reserved_size; + } else { + me->a_end += reserved_size; + } + me->reserved_size = 0; + __check_for_switch_to_b(me); +} + + +unsigned char *bipbuf_peek(const bipbuf_t* me, const unsigned int size) +{ + /* make sure we can actually peek at this data */ + if (me->size < me->a_start + size) + return NULL; + + if (bipbuf_is_empty(me)) + return NULL; + + return (unsigned char*)me->data + me->a_start; +} + +unsigned char *bipbuf_poll(bipbuf_t* me, const unsigned int size) +{ + assert( me->reserved_size == 0 ); + if (bipbuf_is_empty(me)) + return NULL; + + /* make sure we can actually poll this data */ + if (me->size < me->a_start + size) + return NULL; + + void *end = me->data + me->a_start; + me->a_start += size; + + /* we seem to be empty.. */ + if (me->a_start == me->a_end) + { + /* replace a with region b */ + if (1 == me->b_inuse) + { + me->a_start = 0; + me->a_end = me->b_end; + me->b_end = me->b_inuse = 0; + } + else + /* safely move cursor back to the start because we are empty */ + me->a_start = me->a_end = 0; + } + + __check_for_switch_to_b(me); + return end; +} diff --git a/bipbuffer/bipbuffer.h b/bipbuffer/bipbuffer.h new file mode 100644 index 0000000..b6d801a --- /dev/null +++ b/bipbuffer/bipbuffer.h @@ -0,0 +1,80 @@ +#ifndef BIPBUFFER_H +#define BIPBUFFER_H + +typedef struct +{ + unsigned long int size; + unsigned long int reserved_size; + + /* region A */ + unsigned int a_start, a_end; + + /* region B */ + unsigned int b_end; + + /* is B inuse? */ + int b_inuse; + + unsigned char data[]; +} bipbuf_t; + +/** + * Create a new bip buffer. + * + * malloc()s space + * + * @param[in] size The size of the buffer */ +bipbuf_t *bipbuf_new(const unsigned int size); + +/** + * Initialise a bip buffer. Use memory provided by user. + * + * No malloc()s are performed. + * + * @param[in] size The size of the array */ +void bipbuf_init(bipbuf_t* me, const unsigned int size); + +/** + * Free the bip buffer */ +void bipbuf_free(bipbuf_t *me); + +/** + * @param[in] data The data to be offered to the buffer + * @param[in] size The size of the data to be offered + * @return number of bytes offered */ +int bipbuf_offer(bipbuf_t *me, const unsigned char *data, const int size); + +void *bipbuf_reserve( bipbuf_t* me, const unsigned int size ); +void bipbuf_commit( bipbuf_t* me, const unsigned int size ); + +/** + * Look at data. Don't move cursor + * + * @param[in] len The length of the data to be peeked + * @return data on success, NULL if we can't peek at this much data */ +unsigned char *bipbuf_peek(const bipbuf_t* me, const unsigned int len); + +/** + * Get pointer to data to read. Move the cursor on. + * + * @param[in] len The length of the data to be polled + * @return pointer to data, NULL if we can't poll this much data */ +unsigned char *bipbuf_poll(bipbuf_t* me, const unsigned int size); + +/** + * @return the size of the bipbuffer */ +int bipbuf_size(const bipbuf_t* me); + +/** + * @return 1 if buffer is empty; 0 otherwise */ +int bipbuf_is_empty(const bipbuf_t* me); + +/** + * @return how much space we have assigned */ +int bipbuf_used(const bipbuf_t* cb); + +/** + * @return bytes of unused space */ +int bipbuf_unused(const bipbuf_t* me); + +#endif /* BIPBUFFER_H */