From: Martin Mares Date: Thu, 22 Jul 2010 14:56:12 +0000 (+0200) Subject: Implemented a new growing array module X-Git-Tag: v5.0~150 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=305df0095d05525e1324cbc7c74d764535338b07;p=libucw.git Implemented a new growing array module Instead of gbuf/bbuf, it supports arbitrary types without having to instantiate the data structure for every type. Will add some documentation later. --- diff --git a/ucw/Makefile b/ucw/Makefile index 327581ef..bfb039a5 100644 --- a/ucw/Makefile +++ b/ucw/Makefile @@ -30,7 +30,7 @@ LIBUCW_MODS= \ sync \ qache \ string str-esc str-split str-match str-imatch str-hex \ - bbuf \ + bbuf gary \ getopt \ strtonum @@ -41,7 +41,7 @@ LIBUCW_MAIN_INCLUDES= \ string.h stkstring.h unicode.h chartype.h regex.h \ wildmatch.h \ unaligned.h prefetch.h \ - bbuf.h gbuf.h bitarray.h bitsig.h \ + bbuf.h gbuf.h gary.h bitarray.h bitsig.h \ hashfunc.h hashtable.h \ heap.h binheap.h binheap-node.h \ redblack.h \ @@ -108,7 +108,8 @@ TESTS+=$(addprefix $(o)/ucw/,regex.test unicode.test hash-test.test mempool.test slists.test bbuf.test kmp-test.test getopt.test ff-unicode.test eltpool.test \ fb-socket.test trie-test.test string.test sha1.test asort-test.test binheap-test.test \ redblack-test.test fb-file.test fb-grow.test fb-pool.test fb-atomic.test \ - fb-limfd.test fb-temp.test fb-mem.test fb-buffer.test fb-mmap.test url.test strtonum-test.test) + fb-limfd.test fb-temp.test fb-mem.test fb-buffer.test fb-mmap.test url.test strtonum-test.test \ + gary.test) $(o)/ucw/regex.test: $(o)/ucw/regex-t $(o)/ucw/unicode.test: $(o)/ucw/unicode-t @@ -132,6 +133,7 @@ $(o)/ucw/strtonum-test.test: $(o)/ucw/strtonum-test $(addprefix $(o)/ucw/fb-,file.test grow.test pool.test socket.test atomic.test \ limfd.test temp.test mem.test buffer.test mmap.test): %.test: %-t $(o)/ucw/url.test: $(o)/ucw/url-t +$(o)/ucw/gary.test: $(o)/ucw/gary-t ifdef CONFIG_UCW_THREADS TESTS+=$(addprefix $(o)/ucw/,asio.test) diff --git a/ucw/gary.c b/ucw/gary.c new file mode 100644 index 00000000..801981ae --- /dev/null +++ b/ucw/gary.c @@ -0,0 +1,97 @@ +/* + * UCW Library -- A simple growing array of an arbitrary type + * + * (c) 2010 Martin Mares + */ + +#undef LOCAL_DEBUG + +#include "ucw/lib.h" +#include "ucw/gary.h" + +void * +gary_init(size_t elt_size, size_t num_elts) +{ + DBG("GARY: Init to %zd elements", num_elts); + struct gary_hdr *h = xmalloc(GARY_HDR_SIZE + elt_size * num_elts); + h->num_elts = h->have_space = num_elts; + h->elt_size = elt_size; + return (byte *)h + GARY_HDR_SIZE; +} + +void +gary_free(void *array) +{ + xfree(GARY_HDR(array)); +} + +static struct gary_hdr * +gary_realloc(struct gary_hdr *h, size_t n) +{ + if (n > 2*h->have_space) + h->have_space = n; + else + h->have_space *= 2; + DBG("GARY: Resize to %zd elements (need %zd)", h->have_space, n); + return xrealloc(h, GARY_HDR_SIZE + h->have_space * h->elt_size); +} + +void * +gary_set_size(void *array, size_t n) +{ + struct gary_hdr *h = GARY_HDR(array); + h->num_elts = n; + if (n <= h->have_space) + return array; + + h = gary_realloc(h, n); + return GARY_BODY(h); +} + +void * +gary_push_helper(void *array, size_t n, byte **cptr) +{ + struct gary_hdr *h = GARY_HDR(array); + h = gary_realloc(h, h->num_elts); + *cptr = GARY_BODY(h) + (h->num_elts - n) * h->elt_size; + return GARY_BODY(h); +} + +void * +gary_fix(void *array) +{ + struct gary_hdr *h = GARY_HDR(array); + if (h->num_elts != h->have_space) + { + h = xrealloc(h, GARY_HDR_SIZE + h->num_elts * h->elt_size); + h->have_space = h->num_elts; + } + return GARY_BODY(h); +} + +#ifdef TEST + +#include + +int main(void) +{ + int *a; + GARY_INIT(a, 5); + + for (int i=0; i<5; i++) + a[i] = i+1; + + *GARY_PUSH(a, 1) = 10; + *GARY_PUSH(a, 1) = 20; + *GARY_PUSH(a, 1) = 30; + GARY_POP(a, 1); + GARY_FIX(a); + + for (int i=0; i<(int)GARY_SIZE(a); i++) + printf("%d\n", a[i]); + + GARY_FREE(a); + return 0; +} + +#endif diff --git a/ucw/gary.h b/ucw/gary.h new file mode 100644 index 00000000..386dd765 --- /dev/null +++ b/ucw/gary.h @@ -0,0 +1,44 @@ +/* + * UCW Library -- A simple growing array of an arbitrary type + * + * (c) 2010 Martin Mares + */ + +#ifndef _UCW_GARY_H +#define _UCW_GARY_H + +struct gary_hdr { + size_t num_elts; + size_t have_space; + size_t elt_size; +}; + +#define GARY_HDR_SIZE ALIGN_TO(sizeof(struct gary_hdr), CPU_STRUCT_ALIGN) +#define GARY_HDR(ptr) ((struct gary_hdr *)((byte*)(ptr) - GARY_HDR_SIZE)) +#define GARY_BODY(ptr) ((byte *)(ptr) + GARY_HDR_SIZE) + +#define GARY_INIT(ptr, n) (ptr) = gary_init(sizeof(*(ptr)), (n)) +#define GARY_FREE(ptr) xfree(GARY_HDR(ptr)) +#define GARY_SIZE(ptr) (GARY_HDR(ptr)->num_elts) +#define GARY_SET_SIZE(ptr, n) (ptr) = gary_set_size((ptr), (n)) + +#define GARY_PUSH(ptr, n) ({ \ + struct gary_hdr *_h = GARY_HDR(ptr); \ + typeof(*(ptr)) *_c = &(ptr)[_h->num_elts]; \ + size_t _n = n; \ + _h->num_elts += _n; \ + if (_h->num_elts > _h->have_space) \ + (ptr) = gary_push_helper((ptr), _n, (byte **) &_c); \ + _c; }) + +#define GARY_POP(ptr, n) GARY_HDR(ptr)->num_elts -= (n) +#define GARY_FIX(ptr) (ptr) = gary_fix((ptr)) + +/* Internal functions */ +void *gary_init(size_t elt_size, size_t num_elts); +void gary_free(void *array); +void *gary_set_size(void *array, size_t n); +void *gary_push_helper(void *array, size_t n, byte **cptr); +void *gary_fix(void *array); + +#endif diff --git a/ucw/gary.t b/ucw/gary.t new file mode 100644 index 00000000..660e649b --- /dev/null +++ b/ucw/gary.t @@ -0,0 +1,10 @@ +# Tests for gary module + +Run: ../obj/ucw/gary-t -e +Output: 1 + 2 + 3 + 4 + 5 + 10 + 20