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