]> mj.ucw.cz Git - libucw.git/commitdiff
Implemented a new growing array module
authorMartin Mares <mj@ucw.cz>
Thu, 22 Jul 2010 14:56:12 +0000 (16:56 +0200)
committerMartin Mares <mj@ucw.cz>
Wed, 18 Aug 2010 16:11:31 +0000 (18:11 +0200)
Instead of gbuf/bbuf, it supports arbitrary types without having
to instantiate the data structure for every type.

Will add some documentation later.

ucw/Makefile
ucw/gary.c [new file with mode: 0644]
ucw/gary.h [new file with mode: 0644]
ucw/gary.t [new file with mode: 0644]

index 327581ef92269d2c2fd0a702500bf41ba0d49ce6..bfb039a5c316bd5a5f1d044e8bf2acedf073b842 100644 (file)
@@ -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 (file)
index 0000000..801981a
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *     UCW Library -- A simple growing array of an arbitrary type
+ *
+ *     (c) 2010 Martin Mares <mj@ucw.cz>
+ */
+
+#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 <stdio.h>
+
+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 (file)
index 0000000..386dd76
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *     UCW Library -- A simple growing array of an arbitrary type
+ *
+ *     (c) 2010 Martin Mares <mj@ucw.cz>
+ */
+
+#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 (file)
index 0000000..660e649
--- /dev/null
@@ -0,0 +1,10 @@
+# Tests for gary module
+
+Run:   ../obj/ucw/gary-t -e
+Output:        1
+       2
+       3
+       4
+       5
+       10
+       20