/*
* UCW Library -- A simple growing array of an arbitrary type
*
- * (c) 2010--2012 Martin Mares <mj@ucw.cz>
+ * (c) 2010--2014 Martin Mares <mj@ucw.cz>
*/
#undef LOCAL_DEBUG
#include <string.h>
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);
}
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 *
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 <stdio.h>
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)
#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