# HG changeset patch # User Olaf Wintermann # Date 1354277458 -3600 # Node ID 655020a30e774c3b40c7a9a8d4337f4e77e2c9be # Parent 990734f548efa6100e1a602f6d42bfe3c9880704 fixed buffer diff -r 990734f548ef -r 655020a30e77 test/buffer_tests.c --- a/test/buffer_tests.c Sun Nov 04 20:50:12 2012 +0100 +++ b/test/buffer_tests.c Fri Nov 30 13:10:58 2012 +0100 @@ -5,11 +5,8 @@ #include "buffer_tests.h" UCX_TEST_IMPLEMENT(test_ucx_buffer_seektell) { - char *buffer = (char*) malloc(16); - memset(buffer, 32, 7); - buffer[7] = 0; - - UcxBuffer *b = ucx_buffer_new(buffer, 16, UCX_BUFFER_DEFAULT); + UcxBuffer *b = ucx_buffer_new(NULL, 32, UCX_BUFFER_DEFAULT); + b->size = 16; // less than capacity int r; UCX_TEST_BEGIN @@ -34,17 +31,16 @@ r = ucx_buffer_seek(b, -5, SEEK_END); UCX_TEST_ASSERT(r == 0, "seek END-5 failed"); - UCX_TEST_ASSERT(b->pos == 2, "seek END-5 set wrong position"); + UCX_TEST_ASSERT(b->pos == 11, "seek END-5 set wrong position"); - r = ucx_buffer_seek(b, -10, SEEK_END); + r = ucx_buffer_seek(b, -20, SEEK_END); UCX_TEST_ASSERT(r != 0, "seek END beyond bounds shall fail"); - UCX_TEST_ASSERT(b->pos == 2, + UCX_TEST_ASSERT(b->pos == 11, "failed seek shall leave pos unchanged"); UCX_TEST_END ucx_buffer_free(b); - free(buffer); } UCX_TEST_IMPLEMENT(test_ucx_buffer_putc) { @@ -52,19 +48,34 @@ memset(buffer, 32, 16); UcxBuffer *b = ucx_buffer_new(buffer, 16, UCX_BUFFER_DEFAULT); + b->size = b->capacity; int r; UCX_TEST_BEGIN - ucx_buffer_putc(b, 48); ucx_buffer_putc(b, 48); ucx_buffer_putc(b, 48); + ucx_buffer_putc(b, '0'); + ucx_buffer_putc(b, '0'); + ucx_buffer_putc(b, '0'); + UCX_TEST_ASSERT(b->pos == 3, "pos wrong after first 3 puts"); ucx_buffer_seek(b, 10, SEEK_CUR); - ucx_buffer_putc(b, 48); ucx_buffer_putc(b, 48); ucx_buffer_putc(b, 48); + + ucx_buffer_putc(b, '0'); + ucx_buffer_putc(b, '0'); + ucx_buffer_putc(b, '0'); + UCX_TEST_ASSERT(b->pos == 16, "pos wrong after last 3 puts"); UCX_TEST_ASSERT(ucx_buffer_eof(b), "eof not set"); UCX_TEST_ASSERT(ucx_buffer_putc(b, 48) == EOF, "put shall return EOF when buffer is full"); - UCX_TEST_ASSERT(memcmp(buffer, "000 000", 16) == 0, + + ucx_buffer_seek(b, 3, SEEK_SET); + ucx_buffer_putc(b, 'a'); + ucx_buffer_putc(b, 'b'); + ucx_buffer_putc(b, 'c'); + + UCX_TEST_ASSERT(b->size == 16, "wrong size after seek and puts"); + UCX_TEST_ASSERT(memcmp(buffer, "000abc 000", 16) == 0, "buffer contains incorrect content"); UCX_TEST_END @@ -73,6 +84,30 @@ free(buffer); } +UCX_TEST_IMPLEMENT(test_ucx_buffer_putc_ax) { + UcxBuffer *b = ucx_buffer_new(NULL, 2, UCX_BUFFER_AUTOEXTEND); + + UCX_TEST_BEGIN + + ucx_buffer_putc(b, '0'); + ucx_buffer_putc(b, '1'); + + UCX_TEST_ASSERT(b->pos == 2, "pos wrong after first 2 puts"); + UCX_TEST_ASSERT(b->capacity == 2, "buffer erroneously extended"); + + ucx_buffer_putc(b, 'a'); + + UCX_TEST_ASSERT(b->pos == 3, "pos wrong after 1 put"); + UCX_TEST_ASSERT(b->capacity == 4, "buffer not properly extended"); + UCX_TEST_ASSERT(b->size == 3, "wrong buffer size"); + + UCX_TEST_ASSERT(b->space[2] == 'a', "wrong content"); + + UCX_TEST_END + + +} + UCX_TEST_IMPLEMENT(test_ucx_buffer_getc) { char *buffer = (char*) malloc(16); memset(buffer, 32, 8); @@ -81,6 +116,7 @@ } UcxBuffer *b = ucx_buffer_new(buffer, 16, UCX_BUFFER_DEFAULT); + b->size = b->capacity; int r; UCX_TEST_BEGIN @@ -132,7 +168,7 @@ memset(buffer, 49, 16); ucx_buffer_seek(b, 0, SEEK_SET); r = ucx_buffer_write((void*)threebytestring, 3, 6, b); - UCX_TEST_ASSERT(r == 15, "three byte string not correctly trimed"); + UCX_TEST_ASSERT(r == 5, "three byte string not correctly trimed"); UCX_TEST_ASSERT(b->pos == 15, "position after write of three byte string incorrect"); UCX_TEST_ASSERT(!ucx_buffer_eof(b), "eof shall not be set"); @@ -146,7 +182,7 @@ } UCX_TEST_IMPLEMENT(test_ucx_buffer_write_ax) { - char *buffer = (char*) malloc(4); + char *buffer = (char*) malloc(16); UcxBuffer *b = ucx_buffer_new(buffer, 16, UCX_BUFFER_AUTOEXTEND | UCX_BUFFER_AUTOFREE); @@ -158,7 +194,7 @@ r = ucx_buffer_write((void*)teststring, 1, 20, b); buffer = (char*) b->space; /*autoextend enabled, we MUST retrieve pointer*/ UCX_TEST_ASSERT(r == 20, "not all characters written"); - UCX_TEST_ASSERT(b->size == 32, "buffer not properly extended"); + UCX_TEST_ASSERT(b->capacity == 32, "buffer not properly extended"); UCX_TEST_ASSERT(b->pos == 20, "position incorrect"); UCX_TEST_ASSERT(memcmp(buffer, "this is way too much\0\0\0\0\0\0\0\0\0\0\0\0", 32) == 0, @@ -170,54 +206,53 @@ } UCX_TEST_IMPLEMENT(test_ucx_buffer_read) { - char *buffer = (char*) malloc(16); - memset(buffer, 56, 8); - for (int i = 8; i < 16 ; i++) { - buffer[i] = 40+i; - } - - UcxBuffer *b = ucx_buffer_new(buffer, 16, UCX_BUFFER_DEFAULT); + UcxBuffer *b = ucx_buffer_new(NULL, 8, UCX_BUFFER_AUTOFREE); + + char buf[32]; + memset(buf, 'X', 32); int r; - + UCX_TEST_BEGIN - - char rb[16]; - memset(rb, 32, 16); - - ucx_buffer_seek(b, 8, SEEK_SET); - r = ucx_buffer_read(rb, 1, 16, b); - UCX_TEST_ASSERT(r == 8, "read did not stop at buffer end"); - UCX_TEST_ASSERT(memcmp(rb, "01234567 ", 16) == 0, + + ucx_buffer_write("01234567", 1, 8, b); + UCX_TEST_ASSERT(b->pos == 8, "buffer not correctly filled"); + b->pos = 0; + + r = ucx_buffer_read(buf, 1, 2, b); + UCX_TEST_ASSERT(r == 2, "wrong number of bytes read"); + UCX_TEST_ASSERT(buf[0] == '0' && buf[1] == '1' && buf[2] == 'X', "buffer incorrect after first read"); - UCX_TEST_ASSERT(ucx_buffer_eof(b), "eof shall be set"); - - ucx_buffer_seek(b, 0, SEEK_SET); - r = ucx_buffer_read(rb+8, 1, 8, b); - UCX_TEST_ASSERT(r == 8, "read did not read the specified amount of bytes"); - UCX_TEST_ASSERT(memcmp(rb, "0123456788888888", 16) == 0, - "buffer incorrect after second read"); - + + r = ucx_buffer_read(buf + 2, 1, 8, b); + UCX_TEST_ASSERT(r == 6, "wrong number of bytes read(2)"); + UCX_TEST_ASSERT(memcmp(buf, "01234567XX", 10) == 0, + "buffer incorrect after second read"); + + memset(buf, 'X', 32); ucx_buffer_seek(b, 0, SEEK_SET); - r = ucx_buffer_read(rb, 3, 6, b); - UCX_TEST_ASSERT(r == 15, - "three byte read did not read the desired amount of bytes"); - UCX_TEST_ASSERT(memcmp(rb, "8888888801234568", 16) == 0, - "buffer incorrect after three byte read"); - + r = ucx_buffer_read(buf, 3, 3, b); + + UCX_TEST_ASSERT(r == 2, "wrong number of blocks read"); + UCX_TEST_ASSERT(memcmp(buf, "012345XX", 8) == 0, + "buffer incorrect after three byte read"); + + UCX_TEST_END - - ucx_buffer_free(b); - free(buffer); + + } UCX_TEST_IMPLEMENT(test_ucx_buffer_extract) { char *buffer = (char*) malloc(16); strcpy(buffer, "this is a test!"); - UcxBuffer *src = ucx_buffer_new(buffer, 16, UCX_BUFFER_AUTOFREE), - *dst = ucx_buffer_extract(src, 5, 5, UCX_BUFFER_DEFAULT); + UcxBuffer *src = ucx_buffer_new(buffer, 16, UCX_BUFFER_AUTOFREE); + src->size = 15; + UcxBuffer *dst = ucx_buffer_extract(src, 5, 5, UCX_BUFFER_DEFAULT); UCX_TEST_BEGIN + UCX_TEST_ASSERT(dst != NULL, "ucx_buffer_extract returned NULL"); + UCX_TEST_ASSERT((dst->flags & UCX_BUFFER_AUTOFREE) == UCX_BUFFER_AUTOFREE, "autofree flag shall be enforced"); UCX_TEST_ASSERT(dst->size == 5, "wrong size for new buffer"); @@ -234,3 +269,48 @@ ucx_buffer_free(dst); ucx_buffer_free(src); } + +UCX_TEST_IMPLEMENT(test_ucx_buffer_generic_copy) { + UcxBuffer *b1 = ucx_buffer_new(NULL, 64, UCX_BUFFER_DEFAULT); + UcxBuffer *b2 = ucx_buffer_new(NULL, 2, UCX_BUFFER_AUTOEXTEND); + + UCX_TEST_BEGIN + + ucx_buffer_write("01234567", 1, 8, b1); + ucx_buffer_write("abcdefgh", 1, 8, b1); + UCX_TEST_ASSERT(b1->size == 16, "failed to fill buffer b1"); + ucx_buffer_seek(b1, 0, SEEK_SET); + + size_t ncp = ucx_buffer_copy(b1, b2, ucx_buffer_read, ucx_buffer_write); + UCX_TEST_ASSERT(ncp == 16, "wrong number of copied bytes"); + UCX_TEST_ASSERT(b2->size == 16, "b2 has wrong size"); + UCX_TEST_ASSERT(memcmp(b1->space, b2->space, 16) == 0, + "b1 and b2 have not the same content"); + + memset(b2->space, 0, b2->capacity); + b2->pos = 0; + b2->size = 0; + ucx_buffer_seek(b1, 0, SEEK_SET); + + FILE *file = tmpfile(); + UCX_TEST_ASSERT(file, "test file cannot be opened, test aborted"); + + ncp = ucx_buffer_copy(b1, file, ucx_buffer_read, fwrite); + UCX_TEST_ASSERT(ncp == 16, "copied wrong number of bytes to file"); + + fseek(file, 0, SEEK_SET); + + ncp = ucx_buffer_copy(file, b2, fread, ucx_buffer_write); + UCX_TEST_ASSERT(ncp == 16, "copied wrong number of bytes from file"); + + UCX_TEST_ASSERT(memcmp(b1->space, b2->space, 16) == 0, + "b1 and b2 content mismatch"); + + fclose(file); + + + UCX_TEST_END + + ucx_buffer_free(b1); + ucx_buffer_free(b2); +} diff -r 990734f548ef -r 655020a30e77 test/buffer_tests.h --- a/test/buffer_tests.h Sun Nov 04 20:50:12 2012 +0100 +++ b/test/buffer_tests.h Fri Nov 30 13:10:58 2012 +0100 @@ -16,11 +16,13 @@ UCX_TEST_DECLARE(test_ucx_buffer_seektell); UCX_TEST_DECLARE(test_ucx_buffer_putc); +UCX_TEST_DECLARE(test_ucx_buffer_putc_ax); UCX_TEST_DECLARE(test_ucx_buffer_getc); UCX_TEST_DECLARE(test_ucx_buffer_write); UCX_TEST_DECLARE(test_ucx_buffer_write_ax); UCX_TEST_DECLARE(test_ucx_buffer_read); UCX_TEST_DECLARE(test_ucx_buffer_extract); +UCX_TEST_DECLARE(test_ucx_buffer_generic_copy); #ifdef __cplusplus } diff -r 990734f548ef -r 655020a30e77 test/main.c --- a/test/main.c Sun Nov 04 20:50:12 2012 +0100 +++ b/test/main.c Fri Nov 30 13:10:58 2012 +0100 @@ -166,11 +166,13 @@ /* UcxMemstream Tests */ ucx_test_register(suite, test_ucx_buffer_seektell); ucx_test_register(suite, test_ucx_buffer_putc); + ucx_test_register(suite, test_ucx_buffer_putc_ax); ucx_test_register(suite, test_ucx_buffer_getc); ucx_test_register(suite, test_ucx_buffer_write); ucx_test_register(suite, test_ucx_buffer_write_ax); ucx_test_register(suite, test_ucx_buffer_read); ucx_test_register(suite, test_ucx_buffer_extract); + ucx_test_register(suite, test_ucx_buffer_generic_copy); ucx_test_run(suite, stdout); fflush(stdout); diff -r 990734f548ef -r 655020a30e77 test/map_tests.c --- a/test/map_tests.c Sun Nov 04 20:50:12 2012 +0100 +++ b/test/map_tests.c Fri Nov 30 13:10:58 2012 +0100 @@ -266,7 +266,7 @@ UCX_TEST_BEGIN FILE *f = tmpfile(); - UCX_TEST_ASSERT(f, "test file cannot be opened, test aborted") + UCX_TEST_ASSERT(f, "test file cannot be opened, test aborted"); int r; r = ucx_map_store_enc(map, f, NULL, NULL); ucx_map_free(map); diff -r 990734f548ef -r 655020a30e77 ucx/buffer.c --- a/ucx/buffer.c Sun Nov 04 20:50:12 2012 +0100 +++ b/ucx/buffer.c Fri Nov 30 13:10:58 2012 +0100 @@ -3,22 +3,23 @@ #include #include -UcxBuffer *ucx_buffer_new(void *space, size_t length, int flags) { +UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags) { UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer)); if (buffer) { buffer->flags = flags; if (!space) { - buffer->space = malloc(length); + buffer->space = malloc(size); if (!buffer->space) { free(buffer); return NULL; } - memset(buffer->space, 0, length); + memset(buffer->space, 0, size); buffer->flags |= UCX_BUFFER_AUTOFREE; } else { buffer->space = space; } - buffer->size = length; + buffer->capacity = size; + buffer->size = 0; buffer->pos = 0; } @@ -33,8 +34,11 @@ free(buffer); } -UcxBuffer *restrict ucx_buffer_extract( - UcxBuffer *restrict src, size_t start, size_t length, int flags) { +UcxBuffer* ucx_buffer_extract( + UcxBuffer *src, size_t start, size_t length, int flags) { + if(src->size == 0) { + return NULL; + } if (length == 0) { length = src->size - start; } @@ -42,17 +46,18 @@ return NULL; } - UcxBuffer *restrict dst = (UcxBuffer*) malloc(sizeof(UcxBuffer)); + UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer)); if (dst) { dst->space = malloc(length); if (!dst->space) { free(dst); return NULL; } + dst->capacity = length; dst->size = length; dst->flags = flags | UCX_BUFFER_AUTOFREE; dst->pos = 0; - memcpy(dst->space, (char*)src->space+start, length); + memcpy(dst->space, src->space+start, length); } return dst; } @@ -67,12 +72,12 @@ npos = buffer->pos; break; case SEEK_END: - npos = strlen((const char*) buffer->space); + npos = buffer->size; break; } npos += offset; - + if (npos < 0 || npos > buffer->size) { return -1; } else { @@ -86,57 +91,114 @@ return buffer->pos >= buffer->size; } -size_t ucx_bufio(void* d, size_t s, size_t n, UcxBuffer *b, _Bool read) { - size_t len = s*n; - if (b->pos + len > b->size) { - if ((b->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { - size_t newsize = b->size; - while (b->pos + len > newsize) newsize <<= 1; - void *newspace = realloc(b->space, newsize); - if (newspace) { - memset((char*)newspace+b->size, 0, newsize-b->size); - b->space = newspace; - b->size = newsize; - } else { - len = -1; +int ucx_buffer_extend(UcxBuffer *buffer, size_t len) { + size_t newcap = buffer->capacity; + while (buffer->pos + len > newcap) newcap <<= 1; + + char *newspace = realloc(buffer->space, newcap); + if (newspace) { + memset(newspace+buffer->size, 0, newcap-buffer->size); + buffer->space = newspace; + buffer->capacity = newcap; + } else { + return -1; + } + + return 0; +} + +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer) { + size_t len = size * nitems; + if (buffer->pos + len > buffer->capacity) { + if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { + if(ucx_buffer_extend(buffer, len)) { + return -1; } } else { - len = b->size - b->pos; - if (s > 1) len -= len%s; + len = buffer->capacity - buffer->pos; + if (size > 1) len -= len%size; } } - + if (len <= 0) { return len; } + + memcpy(buffer->space + buffer->pos, ptr, len); + buffer->pos += len; + if(buffer->pos > buffer->size) { + buffer->size = buffer->pos; + } + + return len / size; +} - if (read) { - memcpy(d, (char*)b->space+b->pos, len); - } else { - memcpy((char*)b->space+b->pos, d, len); +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer) { + size_t len = size * nitems; + if (buffer->pos + len > buffer->size) { + len = buffer->size - buffer->pos; + if (size > 1) len -= len%size; } - b->pos += len; - - return len; + + if (len <= 0) { + return len; + } + + memcpy(ptr, buffer->space + buffer->pos, len); + buffer->pos += len; + + return len / size; } int ucx_buffer_putc(UcxBuffer *buffer, int c) { - if (ucx_buffer_eof(buffer)) { - return EOF; - } else { - c &= 0xFF; - ((char*)(buffer->space))[buffer->pos] = (char) c; - buffer->pos++; - return c; + if(buffer->pos >= buffer->capacity) { + if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { + if(ucx_buffer_extend(buffer, 1)) { + return EOF; + } + } else { + return EOF; + } } + + c &= 0xFF; + buffer->space[buffer->pos] = (char) c; + buffer->pos++; + if(buffer->pos > buffer->size) { + buffer->size = buffer->pos; + } + return c; } int ucx_buffer_getc(UcxBuffer *buffer) { if (ucx_buffer_eof(buffer)) { return EOF; } else { - int c = ((char*)(buffer->space))[buffer->pos]; + int c = buffer->space[buffer->pos]; buffer->pos++; return c; } } + +size_t ucx_buffer_generic_copy(void *s1, void *s2, + read_func readfnc, write_func writefnc, size_t bufsize) { + size_t ncp = 0; + char *buf = malloc(bufsize); + if(buf == NULL) { + return 0; + } + + size_t r; + while((r = readfnc(buf, 1, bufsize, s1)) != 0) { + r = writefnc(buf, 1, r, s2); + ncp += r; + if(r == 0) { + break; + } + } + + free(buf); + return ncp; +} diff -r 990734f548ef -r 655020a30e77 ucx/buffer.h --- a/ucx/buffer.h Sun Nov 04 20:50:12 2012 +0100 +++ b/ucx/buffer.h Fri Nov 30 13:10:58 2012 +0100 @@ -16,14 +16,15 @@ /* the user shall not modify values, but may get the latest pointer */ typedef struct { - void *space; + char *space; size_t pos; + size_t capacity; size_t size; int flags; } UcxBuffer; /* if space is NULL, new space is allocated and the autofree flag is enforced */ -UcxBuffer *ucx_buffer_new(void *space, size_t length, int flags); +UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags); void ucx_buffer_free(UcxBuffer* buffer); /* @@ -31,7 +32,7 @@ * if length is zero, the whole remaining buffer shall be extracted * the position of the new buffer is set to zero */ -UcxBuffer *restrict ucx_buffer_extract(UcxBuffer *restrict src, +UcxBuffer* ucx_buffer_extract(UcxBuffer *src, size_t start, size_t length, int flags); #define ucx_buffer_clone(src,flags) \ ucx_buffer_extract(src, 0, 0, flags) @@ -51,21 +52,46 @@ int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence); /* - * returns non-zero, iff the current buffer position has exceeded the last + * returns non-zero, if the current buffer position has exceeded the last * available byte of the underlying buffer * */ int ucx_buffer_eof(UcxBuffer *buffer); -size_t ucx_bufio(void *d, size_t s, size_t n, UcxBuffer* b, _Bool read); + +int ucx_buffere_extend(UcxBuffer *buffer, size_t len); + +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + /* when autoextend is enabled, ensure you get the latest pointer to the data */ -#define ucx_buffer_write(data, itemsize, nitems, buffer) \ - ucx_bufio(data, itemsize, nitems, buffer, 0) -#define ucx_buffer_read(data, itemsize, nitems, buffer) \ - ucx_bufio(data, itemsize, nitems, buffer, 1) +//define ucx_buffer_write(data, itemsize, nitems, buffer) \ +// ucx_bufio(data, itemsize, nitems, buffer, 0) +//define ucx_buffer_read(data, itemsize, nitems, buffer) \ +// ucx_bufio(data, itemsize, nitems, buffer, 1) int ucx_buffer_putc(UcxBuffer *b, int c); int ucx_buffer_getc(UcxBuffer *b); + +/* + * copies all bytes from s1 to s2 + * uses the read function r to read from s1 und writes the data using the + * write function w to s2 + * returns the number of bytes copied + */ +size_t ucx_buffer_generic_copy(void *s1, void *s2, read_func r, write_func w, + size_t bufsize); + + +#define UCX_DEFAULT_BUFFER_SIZE 0x4000000 + +#define ucx_buffer_copy(s1,s2,r,w) \ + ucx_buffer_generic_copy(s1, s2, (read_func)r, (write_func)w, \ + UCX_DEFAULT_BUFFER_SIZE) + #ifdef __cplusplus } #endif diff -r 990734f548ef -r 655020a30e77 ucx/ucx.h --- a/ucx/ucx.h Sun Nov 04 20:50:12 2012 +0100 +++ b/ucx/ucx.h Fri Nov 30 13:10:58 2012 +0100 @@ -37,6 +37,12 @@ /* element,custom data -> copy of element */ typedef void*(*copy_func)(void*,void*); +/* buffer, element size, element count, stream */ +typedef size_t(*write_func)(const void*, size_t, size_t, void*); + +/* buffer, element size, element count, stream */ +typedef size_t(*read_func)(void*, size_t, size_t, void*); + #ifdef __cplusplus } #endif