radix-tree函数功能实现
1 #include "radix-tree.h"
2
3 /**
4 * calloc radix_tree_node
5 *
6 * return Pointer
7 */
8
9 static Pradix_tree_node radix_tree_node_alloc()
10 {
11 Pradix_tree_node ret;
12 ret = (Pradix_tree_node)calloc(1, sizeof(radix_tree_node));
13 if(!ret)
14 {
15 printf("calloc radix_tree_node failed\n");
16 }
17 return ret;
18 }
19
20 static void radix_tree_node_free(Pradix_tree_node node)
21 {
22 free(node);
23 }
24
25 /**
26 * Return the maximum key which can store a radix tree with height HEIGHT
27 */
28 static unsigned int radix_tree_maxindex(Pradix_tree_head head)
29 {
30 return head->height_to_maxindex[head->height];
31 }
32
33 static unsigned int __maxindex(unsigned int height)
34 {
35 unsigned int tmp = height * RADIX_TREE_MAP_SHIFT;
36 /* following strange? one day, you'll konw it, learn more.....
37 * ~0U not ~0, that's different
38 */
39 unsigned int index = (~0U >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1;
40
41 if(tmp >= RADIX_TREE_INDEX_BITS)
42 {
43 index = ~0;
44 }
45 return index;
46 }
47
48 static void radix_tree_init_maxindex(Pradix_tree_head head)
49 {
50 unsigned int i;
51 for(i = 0; i < RADIX_TREE_MAX_PATH ; i++)
52 {
53 head->height_to_maxindex[i] = __maxindex(i);
54 }
55 }
56 static int radix_tree_extend(Pradix_tree_head head, unsigned int index)
57 {
58 Pradix_tree_node node;
59 unsigned int height;
60
61 /* Figure out what the height should be */
62 height = head->height + 1;
63 //bug: while(index > radix_tree_maxindex(head))
64 while(index > head->height_to_maxindex[height])
65 {
66 height++;
67 if(height > RADIX_TREE_MAX_PATH)
68 {
69 printf("index are out of the capacity of radix tree\n");
70 }
71 }
72
73 if(head->rnode)
74 {
75 do
76 {
77 if(!(node = radix_tree_node_alloc()))
78 {
79 return 1;
80 //return -ENOMEM;
81 }
82 node->slots[0] = head->rnode;
83 /* boys, what is count? how many slots have been occupied */
84 node->count = 1;
85 head->rnode = node;
86 head->height++;
87 }while(height > head->height);
88 }
89 else
90 {
91 head->height = height;
92 }
93 return 0;
94 }
95
96 /**
97 * insert into a radix tree
98 * @head: radix tree head
99 * @index: index key
100 * @item: item to insert
101 *
102 * Insert an item into the radix tree at position @index
103 */
104 int radix_tree_insert(Pradix_tree_head head, unsigned int index, void *item)
105 {
106 Pradix_tree_node node = NULL, tmp;
107 PPradix_tree_node slot;
108 unsigned int height, shift;
109 int error;
110
111 /* Make sure tree is high enough */
112 if((index > radix_tree_maxindex(head)) || (!radix_tree_maxindex(head)))
113 {
114 error = radix_tree_extend(head, index);
115 if(error)
116 {
117 return error;
118 }
119 }
120 slot = &head->rnode;
121 height = head->height;
122 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
123
124 while(height > 0)
125 {
126 if(*slot == NULL)
127 {
128 /* Have to add a child node */
129 if(!(tmp = radix_tree_node_alloc()))
130 {
131 return 1;
132 // return -ENOMEM;
133 }
134 *slot = tmp;
135 if(node)
136 {
137 node->count++;
138 }
139 }
140
141 /* Go a level down */
142 node = *slot;
143 slot = (PPradix_tree_node)(node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
144 shift -= RADIX_TREE_MAP_SHIFT;
145 height--;
146 }
147 if(*slot != NULL)
148 {
149 printf("slot have been occupied\n");
150 return 1;
151 //return -EEXIST;
152 }
153 if(node)
154 {
155 node->count++;
156 }
157
158 insert_succeed:
159 *slot = item;
160 return 0;
161 }
162
163 /** Perform lookup operation on a radix tree
164 * @head: radix tree head
165 * @index: index key
166 *
167 * lookup the item at the position @index in the radix tree @head
168 */
169
170 void *radix_tree_lookup(Pradix_tree_head head, unsigned int index)
171 {
172 unsigned int height, shift;
173 PPradix_tree_node slot;
174
175 height = head->height;
176 /* Make sure tree is high enough */
177 if(index > radix_tree_maxindex(head))
178 {
179 printf("index are out of range\n");
180 return NULL;
181 }
182 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
183 slot = &head->rnode;
184
185 while(height > 0)
186 {
187 if(*slot == NULL)
188 {
189 printf("index does not exist, it's empty\n");
190 return NULL;
191 }
192 slot = (PPradix_tree_node)((*slot)->slots +((index >> shift) & RADIX_TREE_MAP_MASK));
193 shift -= RADIX_TREE_MAP_SHIFT;
194 height--;
195 }
196 return (void*)(*slot);
197 }
198
199 static unsigned int __lookup(Pradix_tree_head head, void **results, unsigned int first_index,
200 unsigned int max_items, unsigned int *next_index)
201 {
202 unsigned int nr_found = 0, index = first_index;
203 unsigned int shift;
204 unsigned int height = head->height;
205 Pradix_tree_node slot;
206
207 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
208 slot = head->rnode;
209
210 while(height > 0)
211 {
212 unsigned int i = (index >> shift) & RADIX_TREE_MAP_MASK;
213 height--;
214 if(height && !slot->slots[i])
215 {
216 printf("bug, please check!!!\n");
217 //abort();
218 }
219 if(height == 0)
220 {
221 unsigned int j = index & RADIX_TREE_MAP_MASK;
222 for(; j < RADIX_TREE_MAP_SIZE; j++)
223 {
224 index++;
225 if(slot->slots[j])
226 {
227 results[nr_found++] = slot->slots[j];
228 if(nr_found == max_items)
229 {
230 index = 0;
231 goto out;
232 }
233 }
234 }
235 }
236 shift -= RADIX_TREE_MAP_SHIFT;
237 slot = slot->slots[i];
238 }
239 out:
240 *next_index = index;
241 return nr_found;
242 }
243
244 /**
245 * Perform multiple lookup on a radix tree
246 * @head: radix tree head
247 * @results: where the results of the lookup are placed
248 * @first_index: start the lookup from this key
249 * @max_items: palce up to this many items at *results
250 *
251 * Performs an index-ascending scan of the tree for present items. Places
252 * them at *@results and returns the number of items which were placed at
253 * *@results
254 *
255 * The implementation is naive
256 */
257 unsigned int radix_tree_gang_lookup(Pradix_tree_head head, void **results,
258 unsigned int first_index, unsigned int max_items)
259 {
260 const unsigned int max_index = radix_tree_maxindex(head);
261 unsigned int cur_index = first_index;
262 unsigned int ret = 0;
263
264 if((head->rnode == NULL) || (max_index == 0))
265 {
266 goto out;
267 }
268 while(ret < max_items)
269 {
270 unsigned int nr_found, next_index;
271 if(cur_index > max_index)
272 {
273 break;
274 }
275 nr_found = __lookup(head, results + ret, cur_index, max_items - ret, &next_index);
276 ret += nr_found;
277 if(next_index == 0)
278 {
279 break;
280 }
281 cur_index = next_index;
282 }
283 out:
284 return ret;
285 }
286
287 /**
288 * radix_tree_delete delete an item from a radix tree
289 * @head: radix tree head
290 * @index: index key
291 *
292 * Remove the item at @index from the radix tree @head
293 *
294 * Return the address of the deleted item, or NULL if it was not present
295 */
296 void *radix_tree_delete(Pradix_tree_head head, unsigned int index)
297 {
298 radix_tree_path path[RADIX_TREE_MAX_PATH];
299 Pradix_tree_path pathp = path;
300 unsigned int height, shift;
301 void *ret = NULL;
302
303 height = head->height;
304 /* Make sure tree is high enough */
305 if(index > radix_tree_maxindex(head))
306 {
307 goto out;
308 }
309 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
310 pathp->node = NULL;
311 pathp->slot = &head->rnode;
312
313 while(height)
314 {
315 if(*pathp->slot == NULL)
316 {
317 printf("bug, please check your input\n");
318 goto out;
319 }
320 pathp[1].node = *pathp[0].slot;
321 pathp[1].slot = (PPradix_tree_node) (pathp[1].node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
322
323 pathp++;
324 shift -= RADIX_TREE_MAP_SHIFT;
325 height--;
326 }
327
328 ret = *pathp[0].slot;
329 if(ret == NULL)
330 {
331 printf("bug, please check your input\n");
332 goto out;
333 }
334
335 *pathp[0].slot = NULL;
336 while((pathp[0].node) && (--(pathp[0].node->count) == 0))
337 {
338 pathp--;
339 *pathp[0].slot = NULL;
340 radix_tree_node_free(pathp[1].node);
341 }
342 if(head->rnode == NULL)
343 {
344 printf("radix tree emtpy now\n");
345 head->height = 0;
346 }
347 out:
348 return ret;
349 }
350
351 Pradix_tree_head radix_tree_head_new(void)
352 {
353 Pradix_tree_head head = (Pradix_tree_head)calloc(1, sizeof(radix_tree_head));
354 if(!head)
355 {
356 printf("calloc radix_tree_node failed\n");
357 }
358 return head;
359 }
360
361 void radix_tree_initial(Pradix_tree_head head)
362 {
363 radix_tree_init_maxindex(head);
364 }
365
366 int radix_tree_destroy(Pradix_tree_head head)
367 {
368 printf("why I should write this function?\n, is it useful?!!!!\n");
369 return 0;
370 }
测试文件test.c
1 #include "radix_tree.h"
2
3 int main(void)
4 {
5 char *test[] = {"abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz0",
6 "123", "456", "789", "zyx", "wvu", "tsr", "qpo", "nml", "kji"};
7 int i = 0;
8 int num = sizeof(test)/sizeof(*test);
9 printf("num : %d\n", num);
10 Pradix_tree_head head = radix_tree_head_new();
11 radix_tree_initial(head);
12 if(!head)
13 {
14 printf("alloc head failed\n");
15 }
16
17 for(i = 0; i < num; i++)
18 {
19 radix_tree_insert(head, i, test[i]);
20 }
21
22 for(i = 0; i < num; i++)
23 {
24 printf("%s\n",(char*) radix_tree_lookup(head, i));
25 }
26 for(i = 0; i < num; i++)
27 {
28 radix_tree_delete(head, i);
29 }
30
31 return 0;
32 }