Add DBuf , buffer API
This commit is contained in:
@@ -0,0 +1,121 @@
|
|||||||
|
#ifndef dbuf_H_
|
||||||
|
#define dbuf_H_
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dbuf is a generic buffer that will grow automatically.
|
||||||
|
* call buf_ensure() to reserve space, and don't write more data
|
||||||
|
* than you told buf_ensure() to reserve.
|
||||||
|
*
|
||||||
|
* You write data to buf->end
|
||||||
|
* When finished writing data
|
||||||
|
* you call dbuf_added/( with the no. of bytes you've added.
|
||||||
|
*
|
||||||
|
* You read data from buf->start, the buffer has dbuf_len() bytes of data
|
||||||
|
* When you've read and processed the data, call dbuf_take()
|
||||||
|
* to indicate you're done with the data.
|
||||||
|
*
|
||||||
|
* typically(but add error checking)
|
||||||
|
* DBuf buf;
|
||||||
|
* dbuf_init(&buf,4096);
|
||||||
|
* for(;;) {
|
||||||
|
* dbuf_ensure(buf,4096);
|
||||||
|
* size_t len = fread(buf,4096,1,f);
|
||||||
|
* dbuf_added(&buf,len);
|
||||||
|
* char *end;
|
||||||
|
* while((end = memchr(buf.start,'\n',dbuf_len(&dbuf))) != NULL) { //look for a newline
|
||||||
|
* ++end;
|
||||||
|
* int linelen = end - buf.start;
|
||||||
|
* process_line(buf.start,linelen);
|
||||||
|
* dbuf_take(&dbuf,linelen);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
typedef struct DBuf DBuf;
|
||||||
|
struct DBuf {
|
||||||
|
/** Start of user data */
|
||||||
|
unsigned char *start;
|
||||||
|
/** end of user data */
|
||||||
|
unsigned char *end;
|
||||||
|
/** Start of underlying buffer. Internal use.*/
|
||||||
|
unsigned char *bufstart;
|
||||||
|
/** end of underlying buffer. Internal use.*/
|
||||||
|
unsigned char *bufend;
|
||||||
|
};
|
||||||
|
/** free the internals of a DBuf, does not free buf itself.
|
||||||
|
* Does nothing if buf == NULL
|
||||||
|
* @param buf buffer to free
|
||||||
|
*/
|
||||||
|
void uc_dbuf_free(DBuf *buf);
|
||||||
|
|
||||||
|
/** Initialixe a dbuf.
|
||||||
|
*
|
||||||
|
* @param buf buffer to initialize
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
int uc_dbuf_init(DBuf *buf,size_t initlen);
|
||||||
|
|
||||||
|
/** Get length of user data in the buffer
|
||||||
|
*
|
||||||
|
* @param buf buffer to get length of
|
||||||
|
* @return length of the user data
|
||||||
|
*/
|
||||||
|
size_t uc_dbuf_len(DBuf *buf);
|
||||||
|
|
||||||
|
/** Allocated size of the buffer
|
||||||
|
*
|
||||||
|
* @buf buffer to get allocated length of
|
||||||
|
* @return allocated length of the underlying buffer
|
||||||
|
*/
|
||||||
|
size_t uc_dbuf_buflen(DBuf *buf);
|
||||||
|
|
||||||
|
/** Get remaining space in the buffer
|
||||||
|
* @param buf buffer
|
||||||
|
* @return remaining space (after buf->end) in the buffer
|
||||||
|
*/
|
||||||
|
size_t uc_dbuf_remaining(DBuf *buf);
|
||||||
|
|
||||||
|
/** ensure the buffer can hold 'capacity' no of bytes,
|
||||||
|
*
|
||||||
|
* @param buffer
|
||||||
|
* @param capacity ensure there is room for capacity bytes after buf->end
|
||||||
|
* @retun 0 on success
|
||||||
|
*/
|
||||||
|
int uc_dbuf_ensure(DBuf *buf,size_t capacity);
|
||||||
|
|
||||||
|
/** trim the buffer to hold no more space than needed.
|
||||||
|
* @param buf buffer to trum
|
||||||
|
*/
|
||||||
|
void uc_dbuf_trim(DBuf *buf);
|
||||||
|
|
||||||
|
/** Indicate you've taken 'len' bytes out of the buffer.
|
||||||
|
* Advances buf->start by len bytes
|
||||||
|
* This may re-set buf->start and buf->end if e.g. all data
|
||||||
|
* is taken out of the buffer.
|
||||||
|
*
|
||||||
|
* @param buf buffer
|
||||||
|
* @param len length that was taken out of the buffer
|
||||||
|
* @return 0 on success. Non-zero if @len is larger than the bufer capacity
|
||||||
|
*/
|
||||||
|
int uc_dbuf_take(DBuf *buf,size_t len);
|
||||||
|
|
||||||
|
/** indicate you've added 'len' bytes to the buffer
|
||||||
|
* Advances buf->end by @len bytes
|
||||||
|
* User must always make sure (e.g. by using uc_dbuf_ensure)
|
||||||
|
* that the buffer has the capacity to add @len bytes
|
||||||
|
*
|
||||||
|
* @param buf buffer
|
||||||
|
* @param len length that was added to the buffer.
|
||||||
|
*/
|
||||||
|
void uc_dbuf_added(DBuf *buf,size_t len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "ucore/dbuf.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_dbuf_free(DBuf *buf)
|
||||||
|
{
|
||||||
|
if(buf != NULL)
|
||||||
|
free(buf->bufstart);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_dbuf_init(DBuf *buf,size_t initlen)
|
||||||
|
{
|
||||||
|
unsigned char *tmp = malloc(initlen);
|
||||||
|
if(tmp == NULL)
|
||||||
|
return -1;
|
||||||
|
buf->start = buf->bufstart = buf->end = tmp;
|
||||||
|
buf->bufend = tmp + initlen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_dbuf_len(DBuf *buf)
|
||||||
|
{
|
||||||
|
return buf->end - buf->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_dbuf_buflen(DBuf *buf)
|
||||||
|
{
|
||||||
|
return buf->bufend - buf->bufstart;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_dbuf_remaining(DBuf *buf)
|
||||||
|
{
|
||||||
|
return buf->bufend - buf->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_dbuf_ensure(DBuf *buf,size_t capacity)
|
||||||
|
{
|
||||||
|
size_t sz,remaining,len;
|
||||||
|
|
||||||
|
remaining = uc_dbuf_remaining(buf);
|
||||||
|
if(remaining >= capacity)
|
||||||
|
return 0;
|
||||||
|
len = uc_dbuf_len(buf);
|
||||||
|
sz = buf->start - buf->bufstart;
|
||||||
|
memmove(buf->bufstart,buf->start,len);
|
||||||
|
if(sz + remaining < capacity) {
|
||||||
|
size_t newlen = uc_dbuf_buflen(buf) + capacity;
|
||||||
|
void *tmp = realloc(buf->bufstart,newlen);
|
||||||
|
if(tmp == NULL)
|
||||||
|
return 1;
|
||||||
|
buf->bufstart = tmp;
|
||||||
|
buf->bufend = buf->bufstart + newlen;
|
||||||
|
|
||||||
|
}
|
||||||
|
buf->start = buf->bufstart;
|
||||||
|
buf->end = buf->start + len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_dbuf_trim(DBuf *buf)
|
||||||
|
{
|
||||||
|
size_t len = uc_dbuf_len(buf);
|
||||||
|
void *tmp;
|
||||||
|
|
||||||
|
if(len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memmove(buf->bufstart,buf->start,len);
|
||||||
|
|
||||||
|
tmp = realloc(buf->bufstart,len);
|
||||||
|
if(tmp != NULL)
|
||||||
|
buf->bufstart = tmp;
|
||||||
|
|
||||||
|
buf->start = buf->bufstart;
|
||||||
|
buf->bufend = buf->end = buf->bufstart + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_dbuf_take(DBuf *buf,size_t len)
|
||||||
|
{
|
||||||
|
size_t buflen = uc_dbuf_len(buf);
|
||||||
|
|
||||||
|
if(len == buflen) {
|
||||||
|
buf->start = buf->end = buf->bufstart;
|
||||||
|
} else if (len < buflen) {
|
||||||
|
buf->start = buf->start + len;
|
||||||
|
} else {
|
||||||
|
//should maybe assert. This is a serious offence
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_dbuf_added(DBuf *buf,size_t len)
|
||||||
|
{
|
||||||
|
assert(len <= uc_dbuf_remaining(buf));
|
||||||
|
buf->end +=len;
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ucore/dbuf.h>
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_dbuf)
|
||||||
|
DBuf buf;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_dbuf_init(&buf, 10);
|
||||||
|
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 10);
|
||||||
|
|
||||||
|
strcpy((char *)buf.end, "12345679");
|
||||||
|
uc_dbuf_added(&buf, 10);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 0);
|
||||||
|
|
||||||
|
rc = uc_dbuf_ensure(&buf, 110);
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 110);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 120);
|
||||||
|
|
||||||
|
rc = uc_dbuf_ensure(&buf, 5);
|
||||||
|
fail_if(rc != 0);
|
||||||
|
strcpy((char *)buf.end, "ABCD");
|
||||||
|
uc_dbuf_added(&buf, 5);
|
||||||
|
uc_dbuf_take(&buf, 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 105);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 5);
|
||||||
|
ck_assert_str_eq((char *)buf.start, "ABCD");
|
||||||
|
|
||||||
|
uc_dbuf_take(&buf, 5);
|
||||||
|
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 120);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 120);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 0);
|
||||||
|
|
||||||
|
strcpy((char *)buf.end, "EFGH");
|
||||||
|
uc_dbuf_added(&buf, 5);
|
||||||
|
uc_dbuf_trim(&buf);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 5);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 5);
|
||||||
|
|
||||||
|
uc_dbuf_free(&buf);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_dbuf_take_fail)
|
||||||
|
DBuf buf;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_dbuf_init(&buf, 10);
|
||||||
|
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 10);
|
||||||
|
|
||||||
|
strcpy((char *)buf.end, "12345679");
|
||||||
|
uc_dbuf_added(&buf, 10);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 0);
|
||||||
|
|
||||||
|
rc = uc_dbuf_take(&buf, 11);
|
||||||
|
fail_if(rc == 0);
|
||||||
|
|
||||||
|
uc_dbuf_free(&buf);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Suite *dbuf_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("dbuf");
|
||||||
|
TCase *tc = tcase_create("dbuf tests");
|
||||||
|
tcase_add_test(tc, test_dbuf);
|
||||||
|
tcase_add_test(tc, test_dbuf_take_fail);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
+3
-1
@@ -21,6 +21,7 @@ extern Suite *sat_math_suite(void);
|
|||||||
extern Suite *timers_suite(void);
|
extern Suite *timers_suite(void);
|
||||||
extern Suite *mbuf_suite(void);
|
extern Suite *mbuf_suite(void);
|
||||||
extern Suite *human_bytesz_suite(void);
|
extern Suite *human_bytesz_suite(void);
|
||||||
|
extern Suite *dbuf_suite(void);
|
||||||
|
|
||||||
static suite_func suites[] = {
|
static suite_func suites[] = {
|
||||||
bitvec_suite,
|
bitvec_suite,
|
||||||
@@ -37,7 +38,8 @@ static suite_func suites[] = {
|
|||||||
sat_math_suite,
|
sat_math_suite,
|
||||||
timers_suite,
|
timers_suite,
|
||||||
mbuf_suite,
|
mbuf_suite,
|
||||||
human_bytesz_suite
|
human_bytesz_suite,
|
||||||
|
dbuf_suite
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
Reference in New Issue
Block a user