From eae0331990f945e32d5c66b232fbd534c9aac8bf Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Tue, 28 Jan 2014 16:51:26 +0100 Subject: [PATCH] Gary: Gary now works over a general allocator Zeroed gary's are no longer a special case. Maybe the same system of allocators could be useful in other parts of the library, too. Let me know if you have an idea. --- ucw/gary.c | 61 ++++++++++++++++++++++++++++++++++++++++++++---------- ucw/gary.h | 31 ++++++++++++++++++++++----- 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/ucw/gary.c b/ucw/gary.c index 10b73288..5f62f993 100644 --- a/ucw/gary.c +++ b/ucw/gary.c @@ -1,7 +1,7 @@ /* * UCW Library -- A simple growing array of an arbitrary type * - * (c) 2010--2012 Martin Mares + * (c) 2010--2014 Martin Mares */ #undef LOCAL_DEBUG @@ -12,15 +12,13 @@ #include void * -gary_init(size_t elt_size, size_t num_elts, int zeroed) +gary_init(size_t elt_size, size_t num_elts, struct gary_allocator *allocator) { DBG("GARY: Init to %zd elements", num_elts); - struct gary_hdr *h = xmalloc(GARY_HDR_SIZE + elt_size * num_elts); + struct gary_hdr *h = allocator->alloc(allocator, GARY_HDR_SIZE + elt_size * num_elts); h->num_elts = h->have_space = num_elts; h->elt_size = elt_size; - h->zeroed = zeroed; - if (zeroed) - bzero(GARY_BODY(h), elt_size * num_elts); + h->allocator = allocator; return GARY_BODY(h); } @@ -33,10 +31,7 @@ gary_realloc(struct gary_hdr *h, size_t n) else h->have_space *= 2; DBG("GARY: Resize from %zd to %zd elements (need %zd)", old_size, h->have_space, n); - h = xrealloc(h, GARY_HDR_SIZE + h->have_space * h->elt_size); - if (h->zeroed) - bzero(GARY_BODY(h) + h->elt_size * old_size, h->elt_size * (h->have_space - old_size)); - return h; + return h->allocator->realloc(h->allocator, h, GARY_HDR_SIZE + old_size * h->elt_size, GARY_HDR_SIZE + h->have_space * h->elt_size); } void * @@ -66,12 +61,56 @@ 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 = h->allocator->realloc(h->allocator, h, GARY_HDR_SIZE + h->have_space * h->elt_size, GARY_HDR_SIZE + h->num_elts * h->elt_size); h->have_space = h->num_elts; } return GARY_BODY(h); } +/* Default allocator */ + +static void *gary_default_alloc(struct gary_allocator *a UNUSED, size_t size) +{ + return xmalloc(size); +} + +static void *gary_default_realloc(struct gary_allocator *a UNUSED, void *ptr, size_t old_size UNUSED, size_t new_size) +{ + return xrealloc(ptr, new_size); +} + +static void gary_default_free(struct gary_allocator *a UNUSED, void *ptr) +{ + xfree(ptr); +} + +struct gary_allocator gary_allocator_default = { + .alloc = gary_default_alloc, + .realloc = gary_default_realloc, + .free = gary_default_free, +}; + +/* Zeroing allocator */ + +static void *gary_zeroed_alloc(struct gary_allocator *a UNUSED, size_t size) +{ + return xmalloc_zero(size); +} + +static void *gary_zeroed_realloc(struct gary_allocator *a UNUSED, void *ptr, size_t old_size, size_t new_size) +{ + ptr = xrealloc(ptr, new_size); + if (old_size < new_size) + bzero((byte *) ptr + old_size, new_size - old_size); + return ptr; +} + +struct gary_allocator gary_allocator_zeroed = { + .alloc = gary_zeroed_alloc, + .realloc = gary_zeroed_realloc, + .free = gary_default_free, +}; + #ifdef TEST #include diff --git a/ucw/gary.h b/ucw/gary.h index 0da8f690..30613f9a 100644 --- a/ucw/gary.h +++ b/ucw/gary.h @@ -18,18 +18,30 @@ struct gary_hdr { size_t num_elts; size_t have_space; size_t elt_size; - int zeroed; + struct gary_allocator *allocator; }; +struct gary_allocator { + void * (*alloc)(struct gary_allocator *alloc, size_t size); + void * (*realloc)(struct gary_allocator *alloc, void *ptr, size_t old_size, size_t new_size); + void (*free)(struct gary_allocator *alloc, void *ptr); + void *data; +}; + +extern struct gary_allocator gary_allocator_default; +extern struct gary_allocator gary_allocator_zeroed; + #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), 0) -#define GARY_INIT_ZERO(ptr, n) (ptr) = gary_init(sizeof(*(ptr)), (n), 1) +#define GARY_INIT(ptr, n) (ptr) = gary_init(sizeof(*(ptr)), (n), &gary_allocator_default) +#define GARY_INIT_ZERO(ptr, n) (ptr) = gary_init(sizeof(*(ptr)), (n), &gary_allocator_zeroed) +#define GARY_INIT_ALLOC(ptr, n, a) (ptr) = gary_init(sizeof(*(ptr)), (n), (a)) #define GARY_INIT_SPACE(ptr, n) do { GARY_INIT(ptr, n); (GARY_HDR(ptr))->num_elts = 0; } while (0) #define GARY_INIT_SPACE_ZERO(ptr, n) do { GARY_INIT_ZERO(ptr, n); (GARY_HDR(ptr))->num_elts = 0; } while (0) -#define GARY_FREE(ptr) do { if (ptr) xfree(GARY_HDR(ptr)); } while (0) +#define GARY_INIT_SPACE_ALLOC(ptr, n, a) do { GARY_INIT_ALLOC(ptr, n, a); (GARY_HDR(ptr))->num_elts = 0; } while (0) +#define GARY_FREE(ptr) gary_free(ptr) #define GARY_SIZE(ptr) (GARY_HDR(ptr)->num_elts) #define GARY_RESIZE(ptr, n) ((ptr) = gary_set_size((ptr), (n))) #define GARY_INIT_OR_RESIZE(ptr, n) (ptr) = (ptr) ? gary_set_size((ptr), (n)) : gary_init(sizeof(*(ptr)), (n), 0) @@ -49,9 +61,18 @@ struct gary_hdr { #define GARY_FIX(ptr) (ptr) = gary_fix((ptr)) /* Internal functions */ -void *gary_init(size_t elt_size, size_t num_elts, int zeroed); +void *gary_init(size_t elt_size, size_t num_elts, struct gary_allocator *allocator); 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); +static inline void gary_free(void *ptr) +{ + if (ptr) + { + struct gary_hdr *h = GARY_HDR(ptr); + h->allocator->free(h->allocator, h); + } +} + #endif -- 2.39.2