filetype: Set "groovy" for Jenkinsfile
[vis.git] / map.c
blobf6e5c64e5a8de1a12d932ccb2e2e55dff79bcc45
1 /* Crit-bit tree based map which supports lookups based on unique
2 * prefixes as well as ordered iteration.
4 * Based on public domain code from Rusty Russel, Adam Langley
5 * and D. J. Bernstein.
7 * Further information about the data structure can be found at:
8 * http://cr.yp.to/critbit.html
9 * http://github.com/agl/critbit
10 * http://ccodearchive.net/info/strmap.html
12 #include <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <inttypes.h>
16 #include "map.h"
18 typedef struct Node Node;
20 struct Map { /* struct holding either an item with value v and key u.s or an internal node */
21 union {
22 Node *n;
23 const char *s;
24 } u;
25 void *v; /* value stored in the map, if non NULL u.s holds the corresponding key */
28 struct Node {
29 Map child[2]; /* These point to strings or nodes. */
30 size_t byte_num; /* The byte number where first bit differs. */
31 uint8_t bit_num; /* The bit where these children differ. */
34 /* Closest key to this in a non-empty map. */
35 static Map *closest(Map *n, const char *key)
37 size_t len = strlen(key);
38 const uint8_t *bytes = (const uint8_t *)key;
40 /* Anything with NULL value is an internal node. */
41 while (!n->v) {
42 uint8_t direction = 0;
44 if (n->u.n->byte_num < len) {
45 uint8_t c = bytes[n->u.n->byte_num];
46 direction = (c >> n->u.n->bit_num) & 1;
48 n = &n->u.n->child[direction];
50 return n;
53 void *map_get(const Map *map, const char *key)
55 /* Not empty map? */
56 if (map->u.n) {
57 Map *n = closest((Map *)map, key);
58 if (strcmp(key, n->u.s) == 0)
59 return n->v;
61 return NULL;
64 void *map_closest(const Map *map, const char *prefix)
66 errno = 0;
67 void *v = map_get(map, prefix);
68 if (v)
69 return v;
70 const Map *m = map_prefix(map, prefix);
71 if (map_empty(m))
72 errno = ENOENT;
73 return m->v;
76 bool map_contains(const Map *map, const char *prefix)
78 return !map_empty(map_prefix(map, prefix));
81 bool map_put(Map *map, const char *k, const void *value)
83 size_t len = strlen(k);
84 const uint8_t *bytes = (const uint8_t *)k;
85 Map *n;
86 Node *newn;
87 size_t byte_num;
88 uint8_t bit_num, new_dir;
89 char *key;
91 if (!value) {
92 errno = EINVAL;
93 return false;
96 if (!(key = strdup(k))) {
97 errno = ENOMEM;
98 return false;
101 /* Empty map? */
102 if (!map->u.n) {
103 map->u.s = key;
104 map->v = (void *)value;
105 return true;
108 /* Find closest existing key. */
109 n = closest(map, key);
111 /* Find where they differ. */
112 for (byte_num = 0; n->u.s[byte_num] == key[byte_num]; byte_num++) {
113 if (key[byte_num] == '\0') {
114 /* All identical! */
115 free(key);
116 errno = EEXIST;
117 return false;
121 /* Find which bit differs */
122 uint8_t diff = (uint8_t)n->u.s[byte_num] ^ bytes[byte_num];
123 /* TODO: bit_num = 31 - __builtin_clz(diff); ? */
124 for (bit_num = 0; diff >>= 1; bit_num++);
126 /* Which direction do we go at this bit? */
127 new_dir = ((bytes[byte_num]) >> bit_num) & 1;
129 /* Allocate new node. */
130 newn = malloc(sizeof(*newn));
131 if (!newn) {
132 free(key);
133 errno = ENOMEM;
134 return false;
136 newn->byte_num = byte_num;
137 newn->bit_num = bit_num;
138 newn->child[new_dir].v = (void *)value;
139 newn->child[new_dir].u.s = key;
141 /* Find where to insert: not closest, but first which differs! */
142 n = map;
143 while (!n->v) {
144 uint8_t direction = 0;
146 if (n->u.n->byte_num > byte_num)
147 break;
148 /* Subtle: bit numbers are "backwards" for comparison */
149 if (n->u.n->byte_num == byte_num && n->u.n->bit_num < bit_num)
150 break;
152 if (n->u.n->byte_num < len) {
153 uint8_t c = bytes[n->u.n->byte_num];
154 direction = (c >> n->u.n->bit_num) & 1;
156 n = &n->u.n->child[direction];
159 newn->child[!new_dir] = *n;
160 n->u.n = newn;
161 n->v = NULL;
162 return true;
165 void *map_delete(Map *map, const char *key)
167 size_t len = strlen(key);
168 const uint8_t *bytes = (const uint8_t *)key;
169 Map *parent = NULL, *n;
170 void *value = NULL;
171 uint8_t direction;
173 /* Empty map? */
174 if (!map->u.n) {
175 errno = ENOENT;
176 return NULL;
179 /* Find closest, but keep track of parent. */
180 n = map;
181 /* Anything with NULL value is a node. */
182 while (!n->v) {
183 uint8_t c = 0;
185 parent = n;
186 if (n->u.n->byte_num < len) {
187 c = bytes[n->u.n->byte_num];
188 direction = (c >> n->u.n->bit_num) & 1;
189 } else {
190 direction = 0;
192 n = &n->u.n->child[direction];
195 /* Did we find it? */
196 if (strcmp(key, n->u.s)) {
197 errno = ENOENT;
198 return NULL;
201 free((char*)n->u.s);
202 value = n->v;
204 if (!parent) {
205 /* We deleted last node. */
206 map->u.n = NULL;
207 } else {
208 Node *old = parent->u.n;
209 /* Raise other node to parent. */
210 *parent = old->child[!direction];
211 free(old);
214 return value;
217 static bool iterate(Map n, bool (*handle)(const char *, void *, void *), const void *data)
219 if (n.v)
220 return handle(n.u.s, n.v, (void *)data);
222 return iterate(n.u.n->child[0], handle, data)
223 && iterate(n.u.n->child[1], handle, data);
226 void map_iterate(const Map *map, bool (*handle)(const char *, void *, void *), const void *data)
228 /* Empty map? */
229 if (!map->u.n)
230 return;
232 iterate(*map, handle, data);
235 typedef struct {
236 const char *key;
237 void *value;
238 } KeyValue;
240 static bool first(const char *key, void *value, void *data)
242 KeyValue *kv = data;
243 kv->key = key;
244 kv->value = value;
245 return false;
248 void *map_first(const Map *map, const char **key)
250 KeyValue kv = { 0 };
251 map_iterate(map, first, &kv);
252 if (key && kv.key)
253 *key = kv.key;
254 return kv.value;
257 const Map *map_prefix(const Map *map, const char *prefix)
259 const Map *n, *top;
260 size_t len = strlen(prefix);
261 const uint8_t *bytes = (const uint8_t *)prefix;
263 /* Empty map -> return empty map. */
264 if (!map->u.n)
265 return map;
267 top = n = map;
269 /* We walk to find the top, but keep going to check prefix matches. */
270 while (!n->v) {
271 uint8_t c = 0, direction;
273 if (n->u.n->byte_num < len)
274 c = bytes[n->u.n->byte_num];
276 direction = (c >> n->u.n->bit_num) & 1;
277 n = &n->u.n->child[direction];
278 if (c)
279 top = n;
282 if (strncmp(n->u.s, prefix, len)) {
283 /* Convenient return for prefixes which do not appear in map. */
284 static const Map empty_map;
285 return &empty_map;
288 return top;
291 static void clear(Map n)
293 if (!n.v) {
294 clear(n.u.n->child[0]);
295 clear(n.u.n->child[1]);
296 free(n.u.n);
297 } else {
298 free((char*)n.u.s);
302 void map_clear(Map *map)
304 if (map->u.n)
305 clear(*map);
306 map->u.n = NULL;
307 map->v = NULL;
310 static bool copy(Map *dest, Map n)
312 if (!n.v) {
313 return copy(dest, n.u.n->child[0]) &&
314 copy(dest, n.u.n->child[1]);
315 } else {
316 if (!map_put(dest, n.u.s, n.v) && map_get(dest, n.u.s) != n.v) {
317 map_delete(dest, n.u.s);
318 return map_put(dest, n.u.s, n.v);
320 return true;
324 bool map_copy(Map *dest, Map *src)
326 if (!src || !src->u.n)
327 return true;
329 return copy(dest, *src);
332 bool map_empty(const Map *map)
334 return map->u.n == NULL;
337 Map *map_new(void)
339 return calloc(1, sizeof(Map));
342 void map_free(Map *map)
344 if (!map)
345 return;
346 map_clear(map);
347 free(map);
350 static bool free_elem(const char *key, void *value, void *data)
352 free(value);
353 return true;
356 void map_free_full(Map *map)
358 if (!map)
359 return;
360 map_iterate(map, free_elem, NULL);
361 map_free(map);