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