]> mj.ucw.cz Git - libucw.git/commitdiff
Gary: Gary now works over a general allocator
authorMartin Mares <mj@ucw.cz>
Tue, 28 Jan 2014 15:51:26 +0000 (16:51 +0100)
committerMartin Mares <mj@ucw.cz>
Tue, 28 Jan 2014 15:51:26 +0000 (16:51 +0100)
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
ucw/gary.h

index 10b73288d57f250e6a1d1a7f7668e0cd637c001b..5f62f9932051c8c5365ef73675d5adab4ec74482 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     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);
 }
 
@@ -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 <stdio.h>
index 0da8f690fe95da61e96925d45b8cbeda194528b9..30613f9a5c52c50221bd687b0f33efd9f56bf0a5 100644 (file)
@@ -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