diff options
author | Richard Braun <rbraun@sceen.net> | 2017-07-24 23:11:30 +0200 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2017-07-24 23:11:30 +0200 |
commit | 3f9b2ac2bd9654fa237eed19ce593e2bedb20703 (patch) | |
tree | 9b466aa23f6b526e3828562f39040aa6f2de8789 | |
parent | b4b0028d58aa76e3da39d9978975d672aa5fa809 (diff) |
cbuf: update interface
Rename cbuf_push and cbuf_pop to cbuf_pushb and cbuf_pop respectively,
and add the new cbuf_push and cbuf_pop functions, that provide the same
services as the old functions, on buffers rather than single bytes.
-rw-r--r-- | cbuf.c | 49 | ||||
-rw-r--r-- | cbuf.h | 31 | ||||
-rw-r--r-- | test/test_cbuf.c | 81 |
3 files changed, 149 insertions, 12 deletions
@@ -63,16 +63,59 @@ cbuf_update_start(struct cbuf *cbuf) } } -void -cbuf_push(struct cbuf *cbuf, char byte) +int +cbuf_push(struct cbuf *cbuf, const void *buf, size_t size, bool erase) +{ + size_t free_size; + + if (!erase) { + free_size = cbuf_capacity(cbuf) - cbuf_size(cbuf); + + if (size > free_size) { + return ERR_AGAIN; + } + } + + cbuf_write(cbuf, cbuf_end(cbuf), buf, size); + return 0; +} + +int +cbuf_pop(struct cbuf *cbuf, void *buf, size_t *sizep) +{ + int error; + + if (cbuf_size(cbuf) == 0) { + return ERR_AGAIN; + } + + error = cbuf_read(cbuf, cbuf_start(cbuf), buf, sizep); + assert(!error); + cbuf->start += *sizep; + return 0; +} + +int +cbuf_pushb(struct cbuf *cbuf, char byte, bool erase) { + size_t free_size; + + if (!erase) { + free_size = cbuf_capacity(cbuf) - cbuf_size(cbuf); + + if (free_size == 0) { + return ERR_AGAIN; + } + } + cbuf->buf[cbuf_index(cbuf, cbuf->end)] = byte; cbuf->end++; cbuf_update_start(cbuf); + return 0; } int -cbuf_pop(struct cbuf *cbuf, char *bytep) +cbuf_popb(struct cbuf *cbuf, char *bytep) { if (cbuf_size(cbuf) == 0) { return ERR_AGAIN; @@ -94,12 +94,35 @@ cbuf_range_valid(const struct cbuf *cbuf, size_t start, size_t end) void cbuf_init(struct cbuf *cbuf, char *buf, size_t capacity); /* + * Append a buffer to a circular buffer. + * + * If erasing old data is not allowed, and the circular buffer doesn't have + * enough unused bytes for the new data, ERR_AGAIN is returned. Otherwise, + * the end index is increased by the new data size, possibly erasing old + * data, in which case, the start index is updated accordingly. + */ +int cbuf_push(struct cbuf *cbuf, const void *buf, size_t size, bool erase); + +/* + * Read bytes from a circular buffer. + * + * If the buffer is empty, ERR_AGAIN is returned. Otherwise, the oldest + * bytes are stored into the given buffer. On entry, the sizep argument points + * to the size of the given buffer. On exit, that value is updated to the + * number of bytes actually stored. If successful, the start index is increased + * by the amount of bytes read. + */ +int cbuf_pop(struct cbuf *cbuf, void *buf, size_t *sizep); + +/* * Append a byte to a circular buffer. * - * The end index is incremented. If the buffer is full, the oldest byte - * is overwritten and the start index is updated accordingly. + * If erasing old data is not allowed, and the circular buffer is full, + * ERR_AGAIN is returned. Otherwise, the end index is incremented and, if the + * buffer is full, the oldest byte is overwritten and the start index + * is updated accordingly. */ -void cbuf_push(struct cbuf *cbuf, char byte); +int cbuf_pushb(struct cbuf *cbuf, char byte, bool erase); /* * Read a byte from a circular buffer. @@ -108,7 +131,7 @@ void cbuf_push(struct cbuf *cbuf, char byte); * byte is stored at the bytep address, the start index is incremented, * and 0 is returned. */ -int cbuf_pop(struct cbuf *cbuf, char *bytep); +int cbuf_popb(struct cbuf *cbuf, char *bytep); /* * Write into a circular buffer at a specific location. diff --git a/test/test_cbuf.c b/test/test_cbuf.c index 918597e..15e4d62 100644 --- a/test/test_cbuf.c +++ b/test/test_cbuf.c @@ -42,7 +42,7 @@ test_push(struct cbuf *cbuf, const char *s) len = strlen(s) + 1; for (i = 0; i < len; i++) { - cbuf_push(cbuf, s[i]); + cbuf_pushb(cbuf, s[i], true); } } @@ -258,12 +258,79 @@ test_write_overflow(void) #undef STRING } -int -main(int argc, char *argv[]) +static void +test_push_buf(void) +{ + char cbuf_buf[TEST_BUF_SIZE]; + struct cbuf cbuf; + int error; + + cbuf_init(&cbuf, cbuf_buf, sizeof(cbuf_buf)); + +#define STRING "abcdef" + error = cbuf_push(&cbuf, STRING, STRLEN(STRING) + 1, false); + check(!error); + test_check(&cbuf, cbuf_start(&cbuf), STRING, STRLEN(STRING) + 1); + check(cbuf_size(&cbuf) == (STRLEN(STRING) + 1)); +#undef STRING +} + +static void +test_push_buf_overflow(void) +{ + char cbuf_buf[TEST_BUF_SIZE]; + struct cbuf cbuf; + int error; + + cbuf_init(&cbuf, cbuf_buf, sizeof(cbuf_buf)); + cbuf.start = 0; + cbuf.end = TEST_BUF_SIZE - 1; + +#define STRING "abcdef" + error = cbuf_push(&cbuf, STRING, STRLEN(STRING) + 1, false); + check(error); +#undef STRING +} + +static void +test_pop_buf(void) { - (void)argc; - (void)argv; + char cbuf_buf[TEST_BUF_SIZE]; + struct cbuf cbuf; + size_t size; + int error; + + cbuf_init(&cbuf, cbuf_buf, sizeof(cbuf_buf)); +#define STRING "abcdef" + error = cbuf_push(&cbuf, STRING, STRLEN(STRING) + 1, false); + check(!error); + size = sizeof(cbuf_buf); + error = cbuf_pop(&cbuf, cbuf_buf, &size); + check(!error && (size == (STRLEN(STRING) + 1))); +#undef STRING +} + +static void +test_pop_buf_overflow(void) +{ + char cbuf_buf[TEST_BUF_SIZE]; + struct cbuf cbuf; + size_t size; + int error; + + cbuf_init(&cbuf, cbuf_buf, sizeof(cbuf_buf)); + +#define STRING "abcdef" + size = sizeof(cbuf_buf); + error = cbuf_pop(&cbuf, cbuf_buf, &size); + check(error); +#undef STRING +} + +int +main(void) +{ test_read_0(); test_read_regular(); test_read_overflow(); @@ -274,6 +341,10 @@ main(int argc, char *argv[]) test_append_overwrite(); test_write_regular(); test_write_overflow(); + test_push_buf(); + test_push_buf_overflow(); + test_pop_buf(); + test_pop_buf_overflow(); return 0; } |