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
);
235 const Map
*map_prefix(const Map
*map
, const char *prefix
)
238 size_t len
= strlen(prefix
);
239 const uint8_t *bytes
= (const uint8_t *)prefix
;
241 /* Empty map -> return empty map. */
247 /* We walk to find the top, but keep going to check prefix matches. */
249 uint8_t c
= 0, direction
;
251 if (n
->u
.n
->byte_num
< len
)
252 c
= bytes
[n
->u
.n
->byte_num
];
254 direction
= (c
>> n
->u
.n
->bit_num
) & 1;
255 n
= &n
->u
.n
->child
[direction
];
260 if (strncmp(n
->u
.s
, prefix
, len
)) {
261 /* Convenient return for prefixes which do not appear in map. */
262 static const Map empty_map
;
269 static void clear(Map n
)
272 clear(n
.u
.n
->child
[0]);
273 clear(n
.u
.n
->child
[1]);
280 void map_clear(Map
*map
)
288 static bool copy(Map
*dest
, Map n
)
291 return copy(dest
, n
.u
.n
->child
[0]) &&
292 copy(dest
, n
.u
.n
->child
[1]);
294 if (!map_put(dest
, n
.u
.s
, n
.v
) && map_get(dest
, n
.u
.s
) != n
.v
) {
295 map_delete(dest
, n
.u
.s
);
296 return map_put(dest
, n
.u
.s
, n
.v
);
302 bool map_copy(Map
*dest
, Map
*src
)
304 if (!src
|| !src
->u
.n
)
307 return copy(dest
, *src
);
310 bool map_empty(const Map
*map
)
312 return map
->u
.n
== NULL
;
317 return calloc(1, sizeof(Map
));
320 void map_free(Map
*map
)