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
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
18 typedef struct Node Node
;
20 struct Map
{ /* struct holding either an item with value v and key u.s or an internal node */
25 void *v
; /* value stored in the map, if non NULL u.s holds the corresponding key */
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. */
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
];
53 void *map_get(const Map
*map
, const char *key
)
57 Map
*n
= closest((Map
*)map
, key
);
58 if (strcmp(key
, n
->u
.s
) == 0)
64 void *map_closest(const Map
*map
, const char *prefix
)
67 void *v
= map_get(map
, prefix
);
70 const Map
*m
= map_prefix(map
, prefix
);
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
;
88 uint8_t bit_num
, new_dir
;
96 if (!(key
= strdup(k
))) {
104 map
->v
= (void *)value
;
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') {
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
));
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! */
144 uint8_t direction
= 0;
146 if (n
->u
.n
->byte_num
> byte_num
)
148 /* Subtle: bit numbers are "backwards" for comparison */
149 if (n
->u
.n
->byte_num
== byte_num
&& n
->u
.n
->bit_num
< bit_num
)
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
;
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
;
179 /* Find closest, but keep track of parent. */
181 /* Anything with NULL value is a node. */
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;
192 n
= &n
->u
.n
->child
[direction
];
195 /* Did we find it? */
196 if (strcmp(key
, n
->u
.s
)) {
205 /* We deleted last node. */
208 Node
*old
= parent
->u
.n
;
209 /* Raise other node to parent. */
210 *parent
= old
->child
[!direction
];
217 static bool iterate(Map n
, bool (*handle
)(const char *, void *, void *), const void *data
)
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
)
232 iterate(*map
, handle
, data
);
240 static bool first(const char *key
, void *value
, void *data
)
248 void *map_first(const Map
*map
, const char **key
)
251 map_iterate(map
, first
, &kv
);
257 const Map
*map_prefix(const Map
*map
, const char *prefix
)
260 size_t len
= strlen(prefix
);
261 const uint8_t *bytes
= (const uint8_t *)prefix
;
263 /* Empty map -> return empty map. */
269 /* We walk to find the top, but keep going to check prefix matches. */
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
];
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
;
291 static void clear(Map n
)
294 clear(n
.u
.n
->child
[0]);
295 clear(n
.u
.n
->child
[1]);
302 void map_clear(Map
*map
)
310 static bool copy(Map
*dest
, Map n
)
313 return copy(dest
, n
.u
.n
->child
[0]) &&
314 copy(dest
, n
.u
.n
->child
[1]);
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
);
324 bool map_copy(Map
*dest
, Map
*src
)
326 if (!src
|| !src
->u
.n
)
329 return copy(dest
, *src
);
332 bool map_empty(const Map
*map
)
334 return map
->u
.n
== NULL
;
339 return calloc(1, sizeof(Map
));
342 void map_free(Map
*map
)
350 static bool free_elem(const char *key
, void *value
, void *data
)
356 void map_free_full(Map
*map
)
360 map_iterate(map
, free_elem
, NULL
);