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') {
120 /* Find which bit differs */
121 uint8_t diff
= (uint8_t)n
->u
.s
[byte_num
] ^ bytes
[byte_num
];
122 /* TODO: bit_num = 31 - __builtin_clz(diff); ? */
123 for (bit_num
= 0; diff
>>= 1; bit_num
++);
125 /* Which direction do we go at this bit? */
126 new_dir
= ((bytes
[byte_num
]) >> bit_num
) & 1;
128 /* Allocate new node. */
129 newn
= malloc(sizeof(*newn
));
135 newn
->byte_num
= byte_num
;
136 newn
->bit_num
= bit_num
;
137 newn
->child
[new_dir
].v
= (void *)value
;
138 newn
->child
[new_dir
].u
.s
= key
;
140 /* Find where to insert: not closest, but first which differs! */
143 uint8_t direction
= 0;
145 if (n
->u
.n
->byte_num
> byte_num
)
147 /* Subtle: bit numbers are "backwards" for comparison */
148 if (n
->u
.n
->byte_num
== byte_num
&& n
->u
.n
->bit_num
< bit_num
)
151 if (n
->u
.n
->byte_num
< len
) {
152 uint8_t c
= bytes
[n
->u
.n
->byte_num
];
153 direction
= (c
>> n
->u
.n
->bit_num
) & 1;
155 n
= &n
->u
.n
->child
[direction
];
158 newn
->child
[!new_dir
] = *n
;
164 void *map_delete(Map
*map
, const char *key
)
166 size_t len
= strlen(key
);
167 const uint8_t *bytes
= (const uint8_t *)key
;
168 Map
*parent
= NULL
, *n
;
178 /* Find closest, but keep track of parent. */
180 /* Anything with NULL value is a node. */
185 if (n
->u
.n
->byte_num
< len
) {
186 c
= bytes
[n
->u
.n
->byte_num
];
187 direction
= (c
>> n
->u
.n
->bit_num
) & 1;
191 n
= &n
->u
.n
->child
[direction
];
194 /* Did we find it? */
195 if (strcmp(key
, n
->u
.s
)) {
204 /* We deleted last node. */
207 Node
*old
= parent
->u
.n
;
208 /* Raise other node to parent. */
209 *parent
= old
->child
[!direction
];
216 static bool iterate(Map n
, bool (*handle
)(const char *, void *, void *), const void *data
)
219 return handle(n
.u
.s
, n
.v
, (void *)data
);
221 return iterate(n
.u
.n
->child
[0], handle
, data
)
222 && iterate(n
.u
.n
->child
[1], handle
, data
);
225 void map_iterate(const Map
*map
, bool (*handle
)(const char *, void *, void *), const void *data
)
231 iterate(*map
, handle
, data
);
234 const Map
*map_prefix(const Map
*map
, const char *prefix
)
237 size_t len
= strlen(prefix
);
238 const uint8_t *bytes
= (const uint8_t *)prefix
;
240 /* Empty map -> return empty map. */
246 /* We walk to find the top, but keep going to check prefix matches. */
248 uint8_t c
= 0, direction
;
250 if (n
->u
.n
->byte_num
< len
)
251 c
= bytes
[n
->u
.n
->byte_num
];
253 direction
= (c
>> n
->u
.n
->bit_num
) & 1;
254 n
= &n
->u
.n
->child
[direction
];
259 if (strncmp(n
->u
.s
, prefix
, len
)) {
260 /* Convenient return for prefixes which do not appear in map. */
261 static const Map empty_map
;
268 static void clear(Map n
)
271 clear(n
.u
.n
->child
[0]);
272 clear(n
.u
.n
->child
[1]);
279 void map_clear(Map
*map
)
287 static bool copy(Map
*dest
, Map n
)
290 return copy(dest
, n
.u
.n
->child
[0]) &&
291 copy(dest
, n
.u
.n
->child
[1]);
293 if (!map_put(dest
, n
.u
.s
, n
.v
) && map_get(dest
, n
.u
.s
) != n
.v
) {
294 map_delete(dest
, n
.u
.s
);
295 return map_put(dest
, n
.u
.s
, n
.v
);
301 bool map_copy(Map
*dest
, Map
*src
)
303 if (!src
|| !src
->u
.n
)
306 return copy(dest
, *src
);
309 bool map_empty(const Map
*map
)
311 return map
->u
.n
== NULL
;
316 return calloc(1, sizeof(Map
));
319 void map_free(Map
*map
)