]> mj.ucw.cz Git - libucw.git/blob - ucw/gary.c
Conf: Dynamic arrays re-implemented as gary's
[libucw.git] / ucw / gary.c
1 /*
2  *      UCW Library -- A simple growing array of an arbitrary type
3  *
4  *      (c) 2010--2014 Martin Mares <mj@ucw.cz>
5  */
6
7 #undef LOCAL_DEBUG
8
9 #include <ucw/lib.h>
10 #include <ucw/gary.h>
11
12 #include <string.h>
13
14 struct gary_hdr gary_empty_hdr;
15
16 void *
17 gary_init(size_t elt_size, size_t num_elts, struct gary_allocator *allocator)
18 {
19   DBG("GARY: Init to %zd elements", num_elts);
20   struct gary_hdr *h = allocator->alloc(allocator, GARY_HDR_SIZE + elt_size * num_elts);
21   h->num_elts = h->have_space = num_elts;
22   h->elt_size = elt_size;
23   h->allocator = allocator;
24   return GARY_BODY(h);
25 }
26
27 static struct gary_hdr *
28 gary_realloc(struct gary_hdr *h, size_t n)
29 {
30   size_t old_size = h->have_space;
31   if (n > 2*h->have_space)
32     h->have_space = n;
33   else
34     h->have_space *= 2;
35   DBG("GARY: Resize from %zd to %zd elements (need %zd)", old_size, h->have_space, n);
36   return h->allocator->realloc(h->allocator, h, GARY_HDR_SIZE + old_size * h->elt_size, GARY_HDR_SIZE + h->have_space * h->elt_size);
37 }
38
39 void *
40 gary_set_size(void *array, size_t n)
41 {
42   struct gary_hdr *h = GARY_HDR(array);
43   h->num_elts = n;
44   if (n <= h->have_space)
45     return array;
46
47   h = gary_realloc(h, n);
48   return GARY_BODY(h);
49 }
50
51 void *
52 gary_push_helper(void *array, size_t n, byte **cptr)
53 {
54   struct gary_hdr *h = GARY_HDR(array);
55   h = gary_realloc(h, h->num_elts);
56   *cptr = GARY_BODY(h) + (h->num_elts - n) * h->elt_size;
57   return GARY_BODY(h);
58 }
59
60 void *
61 gary_fix(void *array)
62 {
63   struct gary_hdr *h = GARY_HDR(array);
64   if (h->num_elts != h->have_space)
65     {
66       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);
67       h->have_space = h->num_elts;
68     }
69   return GARY_BODY(h);
70 }
71
72 /* Default allocator */
73
74 static void *gary_default_alloc(struct gary_allocator *a UNUSED, size_t size)
75 {
76   return xmalloc(size);
77 }
78
79 static void *gary_default_realloc(struct gary_allocator *a UNUSED, void *ptr, size_t old_size UNUSED, size_t new_size)
80 {
81   return xrealloc(ptr, new_size);
82 }
83
84 static void gary_default_free(struct gary_allocator *a UNUSED, void *ptr)
85 {
86   xfree(ptr);
87 }
88
89 struct gary_allocator gary_allocator_default = {
90   .alloc = gary_default_alloc,
91   .realloc = gary_default_realloc,
92   .free = gary_default_free,
93 };
94
95 /* Zeroing allocator */
96
97 static void *gary_zeroed_alloc(struct gary_allocator *a UNUSED, size_t size)
98 {
99   return xmalloc_zero(size);
100 }
101
102 static void *gary_zeroed_realloc(struct gary_allocator *a UNUSED, void *ptr, size_t old_size, size_t new_size)
103 {
104   ptr = xrealloc(ptr, new_size);
105   if (old_size < new_size)
106     bzero((byte *) ptr + old_size, new_size - old_size);
107   return ptr;
108 }
109
110 struct gary_allocator gary_allocator_zeroed = {
111   .alloc = gary_zeroed_alloc,
112   .realloc = gary_zeroed_realloc,
113   .free = gary_default_free,
114 };
115
116 #ifdef TEST
117
118 #include <stdio.h>
119
120 int main(void)
121 {
122   int *a;
123   GARY_INIT_ZERO(a, 5);
124
125   for (int i=0; i<5; i++)
126     {
127       ASSERT(!a[i]);
128       a[i] = i+1;
129     }
130
131   GARY_PUSH(a);
132   *GARY_PUSH(a) = 10;
133   *GARY_PUSH(a) = 20;
134   *GARY_PUSH(a) = 30;
135   GARY_POP(a);
136   GARY_FIX(a);
137
138   for (int i=0; i<(int)GARY_SIZE(a); i++)
139     printf("%d\n", a[i]);
140
141   GARY_FREE(a);
142   return 0;
143 }
144
145 #endif