vp8_pick_inter_mode code cleanup
[libvpx.git] / nestegg / halloc / src / halloc.c
blob38fd6c11a4cba006ef8260011b3a177982da55da
1 /*
2 * Copyright (c) 2004i-2010 Alex Pankratov. All rights reserved.
4 * Hierarchical memory allocator, 1.2.1
5 * http://swapped.cc/halloc
6 */
8 /*
9 * The program is distributed under terms of BSD license.
10 * You can obtain the copy of the license by visiting:
12 * http://www.opensource.org/licenses/bsd-license.php
15 #include <stdlib.h> /* realloc */
16 #include <string.h> /* memset & co */
18 #include "../halloc.h"
19 #include "align.h"
20 #include "hlist.h"
23 * block control header
25 typedef struct hblock
27 #ifndef NDEBUG
28 #define HH_MAGIC 0x20040518L
29 long magic;
30 #endif
31 hlist_item_t siblings; /* 2 pointers */
32 hlist_head_t children; /* 1 pointer */
33 max_align_t data[1]; /* not allocated, see below */
35 } hblock_t;
37 #define sizeof_hblock offsetof(hblock_t, data)
42 realloc_t halloc_allocator = NULL;
44 #define allocator halloc_allocator
47 * static methods
49 static void _set_allocator(void);
50 static void * _realloc(void * ptr, size_t n);
52 static int _relate(hblock_t * b, hblock_t * p);
53 static void _free_children(hblock_t * p);
56 * Core API
58 void * halloc(void * ptr, size_t len)
60 hblock_t * p;
62 /* set up default allocator */
63 if (! allocator)
65 _set_allocator();
66 assert(allocator);
69 /* calloc */
70 if (! ptr)
72 if (! len)
73 return NULL;
75 p = allocator(0, len + sizeof_hblock);
76 if (! p)
77 return NULL;
78 #ifndef NDEBUG
79 p->magic = HH_MAGIC;
80 #endif
81 hlist_init(&p->children);
82 hlist_init_item(&p->siblings);
84 return p->data;
87 p = structof(ptr, hblock_t, data);
88 assert(p->magic == HH_MAGIC);
90 /* realloc */
91 if (len)
93 p = allocator(p, len + sizeof_hblock);
94 if (! p)
95 return NULL;
97 hlist_relink(&p->siblings);
98 hlist_relink_head(&p->children);
100 return p->data;
103 /* free */
104 _free_children(p);
105 hlist_del(&p->siblings);
106 allocator(p, 0);
108 return NULL;
111 void hattach(void * block, void * parent)
113 hblock_t * b, * p;
115 if (! block)
117 assert(! parent);
118 return;
121 /* detach */
122 b = structof(block, hblock_t, data);
123 assert(b->magic == HH_MAGIC);
125 hlist_del(&b->siblings);
127 if (! parent)
128 return;
130 /* attach */
131 p = structof(parent, hblock_t, data);
132 assert(p->magic == HH_MAGIC);
134 /* sanity checks */
135 assert(b != p); /* trivial */
136 assert(! _relate(p, b)); /* heavy ! */
138 hlist_add(&p->children, &b->siblings);
142 * malloc/free api
144 void * h_malloc(size_t len)
146 return halloc(0, len);
149 void * h_calloc(size_t n, size_t len)
151 void * ptr = halloc(0, len*=n);
152 return ptr ? memset(ptr, 0, len) : NULL;
155 void * h_realloc(void * ptr, size_t len)
157 return halloc(ptr, len);
160 void h_free(void * ptr)
162 halloc(ptr, 0);
165 char * h_strdup(const char * str)
167 size_t len = strlen(str);
168 char * ptr = halloc(0, len + 1);
169 return ptr ? (ptr[len] = 0, memcpy(ptr, str, len)) : NULL;
173 * static stuff
175 static void _set_allocator(void)
177 void * p;
178 assert(! allocator);
181 * the purpose of the test below is to check the behaviour
182 * of realloc(ptr, 0), which is defined in the standard
183 * as an implementation-specific. if it returns zero,
184 * then it's equivalent to free(). it can however return
185 * non-zero, in which case it cannot be used for freeing
186 * memory blocks and we'll need to supply our own version
188 * Thanks to Stan Tobias for pointing this tricky part out.
190 allocator = realloc;
191 if (! (p = malloc(1)))
192 /* hmm */
193 return;
195 if ((p = realloc(p, 0)))
197 /* realloc cannot be used as free() */
198 allocator = _realloc;
199 free(p);
203 static void * _realloc(void * ptr, size_t n)
206 * free'ing realloc()
208 if (n)
209 return realloc(ptr, n);
210 free(ptr);
211 return NULL;
214 static int _relate(hblock_t * b, hblock_t * p)
216 hlist_item_t * i;
218 if (!b || !p)
219 return 0;
222 * since there is no 'parent' pointer, which would've allowed
223 * O(log(n)) upward traversal, the check must use O(n) downward
224 * iteration of the entire hierarchy; and this can be VERY SLOW
226 hlist_for_each(i, &p->children)
228 hblock_t * q = structof(i, hblock_t, siblings);
229 if (q == b || _relate(b, q))
230 return 1;
232 return 0;
235 static void _free_children(hblock_t * p)
237 hlist_item_t * i, * tmp;
239 #ifndef NDEBUG
241 * this catches loops in hierarchy with almost zero
242 * overhead (compared to _relate() running time)
244 assert(p && p->magic == HH_MAGIC);
245 p->magic = 0;
246 #endif
247 hlist_for_each_safe(i, tmp, &p->children)
249 hblock_t * q = structof(i, hblock_t, siblings);
250 _free_children(q);
251 allocator(q, 0);