1 /*
2 * critbit89 - A crit-bit tree implementation for strings in C89
3 * Written by Jonas Gehring <jonas@jgehring.net>
4 */
5
6
7 #define _POSIX_C_SOURCE 200112L /* For posix_memalign */
8
9 #include <errno.h>
10 #include <string.h>
11 #include <stdlib.h>
12
13 #include "critbit.h"
14
15 #ifdef _MSC_VER /* MSVC */
16 typedef unsigned __int8 uint8_t;
17 typedef unsigned __int32 uint32_t;
18 #ifdef _WIN64
19 typedef signed __int64 intptr_t;
20 #else
21 typedef _W64 signed int intptr_t;
22 #endif
23 #else /* Not MSVC */
24 #include <stdint.h>
25 #endif
26
27
28 typedef struct {
29 void *child[2];
30 uint32_t byte;
31 uint8_t otherbits;
32 } cb_node_t;
33
34
35 /* Standard memory allocation functions */
malloc_align_std(size_t alignment,size_t size,void * baton)36 static void *malloc_align_std(size_t alignment, size_t size, void *baton) {
37 void *ptr;
38 (void)baton; /* Prevent compiler warnigns */
39
40 #ifdef _MSC_VER /* MSVC */
41 if ((ptr = _aligned_malloc(size, alignment)) == NULL) {
42 return NULL;
43 }
44 #else
45 if (posix_memalign(&ptr, alignment, size) != 0) {
46 return NULL;
47 }
48 #endif
49 return ptr;
50 }
51
free_std(void * ptr,void * baton)52 static void free_std(void *ptr, void *baton) {
53 (void)baton; /* Prevent compiler warnigns */
54 #ifdef _MSC_VER /* MSVC */
55 _aligned_free(ptr);
56 #else
57 free(ptr);
58 #endif
59 }
60
61 /* Static helper functions */
cbt_traverse_delete(cb_tree_t * tree,void * top)62 static void cbt_traverse_delete(cb_tree_t *tree, void *top)
63 {
64 uint8_t *p = top;
65 if (1 & (intptr_t)p) {
66 cb_node_t *q = (void *)(p - 1);
67 cbt_traverse_delete(tree, q->child[0]);
68 cbt_traverse_delete(tree, q->child[1]);
69 (tree->free)(q, tree->baton);
70 } else {
71 (tree->free)(p, tree->baton);
72 }
73 }
74
cbt_traverse_prefixed(uint8_t * top,int (* callback)(const char *,void *),void * baton)75 static int cbt_traverse_prefixed(uint8_t *top,
76 int (*callback)(const char *, void *), void *baton)
77 {
78 if (1 & (intptr_t)top) {
79 cb_node_t *q = (void *)(top - 1);
80 int ret = 0;
81
82 ret = cbt_traverse_prefixed(q->child[0], callback, baton);
83 if (ret != 0) {
84 return ret;
85 }
86 ret = cbt_traverse_prefixed(q->child[1], callback, baton);
87 if (ret != 0) {
88 return ret;
89 }
90 return 0;
91 }
92
93 return (callback)((const char *)top, baton);
94 }
95
96
97 /*! Creates an new, empty critbit tree */
cb_tree_make()98 cb_tree_t cb_tree_make()
99 {
100 cb_tree_t tree;
101 tree.root = NULL;
102 tree.malloc_align = &malloc_align_std;
103 tree.free = &free_std;
104 tree.baton = NULL;
105 return tree;
106 }
107
108 /*! Returns non-zero if tree contains str */
cb_tree_contains(cb_tree_t * tree,const char * str)109 int cb_tree_contains(cb_tree_t *tree, const char *str)
110 {
111 const uint8_t *ubytes = (void *)str;
112 const size_t ulen = strlen(str);
113 uint8_t *p = tree->root;
114
115 if (p == NULL) {
116 return 0;
117 }
118
119 while (1 & (intptr_t)p) {
120 cb_node_t *q = (void *)(p - 1);
121 uint8_t c = 0;
122 int direction;
123
124 if (q->byte < ulen) {
125 c = ubytes[q->byte];
126 }
127 direction = (1 + (q->otherbits | c)) >> 8;
128
129 p = q->child[direction];
130 }
131
132 return (strcmp(str, (const char *)p) == 0);
133 }
134
135 /*! Inserts str into tree, returns 0 on suceess */
cb_tree_insert(cb_tree_t * tree,const char * str)136 int cb_tree_insert(cb_tree_t *tree, const char *str)
137 {
138 const uint8_t *const ubytes = (void *)str;
139 const size_t ulen = strlen(str);
140 uint8_t *p = tree->root;
141 uint8_t c, *x;
142 uint32_t newbyte;
143 uint32_t newotherbits;
144 int direction, newdirection;
145 cb_node_t *newnode;
146 void **wherep;
147
148 if (p == NULL) {
149 x = (tree->malloc_align)(sizeof(void *), ulen + 1, tree->baton);
150 if (x == NULL) {
151 return ENOMEM;
152 }
153 memcpy(x, str, ulen + 1);
154 tree->root = x;
155 return 0;
156 }
157
158 while (1 & (intptr_t)p) {
159 cb_node_t *q = (void *)(p - 1);
160 c = 0;
161 if (q->byte < ulen) {
162 c = ubytes[q->byte];
163 }
164 direction = (1 + (q->otherbits | c)) >> 8;
165
166 p = q->child[direction];
167 }
168
169 for (newbyte = 0; newbyte < ulen; ++newbyte) {
170 if (p[newbyte] != ubytes[newbyte]) {
171 newotherbits = p[newbyte] ^ ubytes[newbyte];
172 goto different_byte_found;
173 }
174 }
175
176 if (p[newbyte] != 0) {
177 newotherbits = p[newbyte];
178 goto different_byte_found;
179 }
180 return 1;
181
182 different_byte_found:
183 newotherbits |= newotherbits >> 1;
184 newotherbits |= newotherbits >> 2;
185 newotherbits |= newotherbits >> 4;
186 newotherbits = (newotherbits & ~(newotherbits >> 1)) ^ 255;
187 c = p[newbyte];
188 newdirection = (1 + (newotherbits | c)) >> 8;
189
190 newnode =
191 (tree->malloc_align)(sizeof(void *), sizeof(cb_node_t), tree->baton);
192 if (newnode == NULL) {
193 return ENOMEM;
194 }
195
196 x = (tree->malloc_align)(sizeof(void *), ulen + 1, tree->baton);
197 if (x == NULL) {
198 (tree->free)(newnode, tree->baton);
199 return ENOMEM;
200 }
201
202 memcpy(x, ubytes, ulen + 1);
203 newnode->byte = newbyte;
204 newnode->otherbits = newotherbits;
205 newnode->child[1 - newdirection] = x;
206
207 /* Insert intro tree */
208 wherep = &tree->root;
209 for (;;) {
210 cb_node_t *q;
211 p = *wherep;
212 if (!(1 & (intptr_t)p)) {
213 break;
214 }
215
216 q = (void *)(p - 1);
217 if (q->byte > newbyte) {
218 break;
219 }
220 if (q->byte == newbyte && q->otherbits > newotherbits) {
221 break;
222 }
223
224 c = 0;
225 if (q->byte < ulen) {
226 c = ubytes[q->byte];
227 }
228 direction = (1 + (q->otherbits | c)) >> 8;
229 wherep = q->child + direction;
230 }
231
232 newnode->child[newdirection] = *wherep;
233 *wherep = (void *)(1 + (char *)newnode);
234 return 0;
235 }
236
237 /*! Deletes str from the tree, returns 0 on suceess */
cb_tree_delete(cb_tree_t * tree,const char * str)238 int cb_tree_delete(cb_tree_t *tree, const char *str)
239 {
240 const uint8_t *ubytes = (void *)str;
241 const size_t ulen = strlen(str);
242 uint8_t *p = tree->root;
243 void **wherep = 0, **whereq = 0;
244 cb_node_t *q = 0;
245 int direction = 0;
246
247 if (tree->root == NULL) {
248 return 1;
249 }
250 wherep = &tree->root;
251
252 while (1 & (intptr_t)p) {
253 uint8_t c = 0;
254 whereq = wherep;
255 q = (void *)(p - 1);
256
257 if (q->byte < ulen) {
258 c = ubytes[q->byte];
259 }
260 direction = (1 + (q->otherbits | c)) >> 8;
261 wherep = q->child + direction;
262 p = *wherep;
263 }
264
265 if (strcmp(str, (const char *)p) != 0) {
266 return 1;
267 }
268 (tree->free)(p, tree->baton);
269
270 if (!whereq) {
271 tree->root = NULL;
272 return 0;
273 }
274
275 *whereq = q->child[1 - direction];
276 (tree->free)(q, tree->baton);
277 return 0;
278 }
279
280 /*! Clears the given tree */
cb_tree_clear(cb_tree_t * tree)281 void cb_tree_clear(cb_tree_t *tree)
282 {
283 if (tree->root) {
284 cbt_traverse_delete(tree, tree->root);
285 }
286 tree->root = NULL;
287 }
288
289 /*! Calls callback for all strings in tree with the given prefix */
cb_tree_walk_prefixed(cb_tree_t * tree,const char * prefix,int (* callback)(const char *,void *),void * baton)290 int cb_tree_walk_prefixed(cb_tree_t *tree, const char *prefix,
291 int (*callback)(const char *, void *), void *baton)
292 {
293 const uint8_t *ubytes = (void *)prefix;
294 const size_t ulen = strlen(prefix);
295 uint8_t *p = tree->root;
296 uint8_t *top = p;
297
298 if (p == NULL) {
299 return 0;
300 }
301
302 while (1 & (intptr_t)p) {
303 cb_node_t *q = (void *)(p - 1);
304 uint8_t c = 0;
305 int direction;
306
307 if (q->byte < ulen) {
308 c = ubytes[q->byte];
309 }
310 direction = (1 + (q->otherbits | c)) >> 8;
311
312 p = q->child[direction];
313 if (q->byte < ulen) {
314 top = p;
315 }
316 }
317
318 return cbt_traverse_prefixed(top, callback, baton);
319 }
320