|
1 /* |
|
2 * Copyright (c) 2000 - 2001 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <xml/cxml/nw_tinytree.h> |
|
20 #include "cxml_vector.h" |
|
21 |
|
22 NW_TinyTree_t* |
|
23 NW_TinyTree_new(){ |
|
24 NW_TinyTree_t* tree = (NW_TinyTree_t*) NW_Mem_Malloc (sizeof(NW_TinyTree_t)); |
|
25 if (tree != NULL){ |
|
26 tree->tree = NULL; |
|
27 tree->root_index = 0; |
|
28 tree->ebuffer = NULL; |
|
29 tree->context = NULL; |
|
30 } |
|
31 return tree; |
|
32 } |
|
33 |
|
34 NW_Status_t |
|
35 NW_TinyTree_construct(NW_TinyTree_t *tree, |
|
36 CXML_Vector_Metric_t initialNodeCount, |
|
37 void *buffer, |
|
38 NW_TinyTree_Offset_t buffsz, |
|
39 void *context, |
|
40 NW_Bool freeBuff){ |
|
41 |
|
42 NW_ASSERT(tree != NULL); |
|
43 |
|
44 tree->tree = |
|
45 NW_TinyTree_TreeVector_Construct (sizeof(NW_TinyTree_Node_t), |
|
46 initialNodeCount, |
|
47 tree); |
|
48 if(tree->tree == NULL) { |
|
49 return NW_STAT_OUT_OF_MEMORY; |
|
50 } |
|
51 |
|
52 /* Make the supplied buffer the first ebuffer segment */ |
|
53 tree->ebuffer = NW_TinyTree_EBuffer_Construct((NW_Uint8*) buffer, |
|
54 buffsz, |
|
55 NW_TINY_TREE_BLOCK_SIZE_DEFAULT, |
|
56 freeBuff); |
|
57 if(tree->ebuffer == NULL){ |
|
58 NW_TinyTree_TreeVector_Destruct(tree->tree); |
|
59 tree->tree = NULL; |
|
60 return NW_STAT_OUT_OF_MEMORY; |
|
61 } |
|
62 |
|
63 /* Init the rest of the tree */ |
|
64 tree->root_index = 0; |
|
65 tree->context = context; |
|
66 return NW_STAT_SUCCESS; |
|
67 } |
|
68 |
|
69 void |
|
70 NW_TinyTree_destruct(NW_TinyTree_t *tree) |
|
71 { |
|
72 if (tree != NULL){ |
|
73 if (tree->tree != NULL) { |
|
74 NW_TinyTree_TreeVector_Destruct (tree->tree); |
|
75 } |
|
76 if (tree->ebuffer != NULL){ |
|
77 NW_TinyTree_EBuffer_Destruct (tree->ebuffer); |
|
78 } |
|
79 tree->tree = NULL; |
|
80 tree->root_index = 0; |
|
81 tree->ebuffer = NULL; |
|
82 tree->context = NULL; |
|
83 } |
|
84 } |
|
85 |
|
86 static |
|
87 NW_TinyTree_Node_t* |
|
88 NW_TinyTree_appendNodeAt(NW_TinyTree_t *tree, |
|
89 NW_TinyTree_Node_t *node, |
|
90 NW_TinyTree_Index_t index){ |
|
91 NW_TinyTree_TreeNode_t* sentinel; |
|
92 NW_TinyTree_Node_t* retNode = NULL; |
|
93 |
|
94 |
|
95 NW_ASSERT(tree != NULL); |
|
96 NW_ASSERT(tree->tree != NULL); |
|
97 NW_ASSERT(node != NULL); |
|
98 |
|
99 sentinel = (NW_TinyTree_TreeNode_t*) NW_Mem_Malloc(sizeof(NW_TinyTree_TreeNode_t)); |
|
100 if(sentinel == NULL){ |
|
101 return NULL; |
|
102 } |
|
103 sentinel->flags = TNODE_FLAG_TREE; |
|
104 sentinel->tree = tree; |
|
105 |
|
106 /* Add the new element at the specified index */ |
|
107 retNode = (NW_TinyTree_Node_t*) |
|
108 CXML_Vector_InsertAt(tree->tree->vector, (void*)node, index, sentinel); |
|
109 NW_Mem_Free(sentinel); |
|
110 return retNode; |
|
111 } |
|
112 |
|
113 /* Add a node, appending storage to the tree vector. |
|
114 * The appended node is created as an orphan and needs to be attached |
|
115 * to the tree somewhere. |
|
116 */ |
|
117 |
|
118 static |
|
119 NW_TinyTree_Node_t* |
|
120 NW_TinyTree_appendNode(NW_TinyTree_t *tree, |
|
121 NW_TinyTree_Node_t *node){ |
|
122 |
|
123 NW_ASSERT(tree != NULL); |
|
124 NW_ASSERT(node != NULL); |
|
125 |
|
126 /* Add the new element */ |
|
127 |
|
128 return NW_TinyTree_appendNodeAt(tree, node, CXML_Vector_AtEnd); |
|
129 } |
|
130 |
|
131 |
|
132 /* Get the node at a given index */ |
|
133 |
|
134 static |
|
135 NW_TinyTree_Node_t* |
|
136 NW_TinyTree_getNode(NW_TinyTree_t *tree, |
|
137 NW_TinyTree_Index_t index){ |
|
138 |
|
139 NW_ASSERT(tree != NULL); |
|
140 NW_ASSERT(tree->tree != NULL); |
|
141 NW_ASSERT(tree->tree->vector != NULL); |
|
142 NW_ASSERT(index > 0); |
|
143 |
|
144 return (NW_TinyTree_Node_t*) |
|
145 CXML_Vector_ElementAt(tree->tree->vector, (CXML_Vector_Metric_t)index); |
|
146 } |
|
147 |
|
148 /* |
|
149 * Create an unattached node which references the source buffer at offset. |
|
150 */ |
|
151 |
|
152 NW_TinyTree_Node_t* |
|
153 NW_TinyTree_createNode(NW_TinyTree_t* tree, |
|
154 NW_TinyTree_Offset_t offset){ |
|
155 |
|
156 NW_TinyTree_Node_t node; |
|
157 |
|
158 NW_ASSERT(tree != NULL); |
|
159 NW_ASSERT(tree->tree != NULL); |
|
160 /* The root must have been set before creating any new nodes */ |
|
161 NW_ASSERT(tree->root_index == 1); |
|
162 |
|
163 /* Initialize a node on the stack */ |
|
164 node.source_offset = offset; |
|
165 node.flags = 0; |
|
166 node.first_child = 0; |
|
167 node.next_sibling = 0; |
|
168 node.tree = tree; |
|
169 node.token = 0; |
|
170 /* Copy this into the tree */ |
|
171 return NW_TinyTree_appendNode(tree, &node); |
|
172 } |
|
173 |
|
174 /* |
|
175 * Create a root node which references the source buffer at offset. |
|
176 * Returns a pointer to the root node. |
|
177 */ |
|
178 |
|
179 NW_TinyTree_Node_t* |
|
180 NW_TinyTree_setRoot(NW_TinyTree_t *tree, |
|
181 NW_TinyTree_Offset_t offset){ |
|
182 |
|
183 NW_TinyTree_Node_t root_node; |
|
184 |
|
185 NW_ASSERT(tree != NULL); |
|
186 NW_ASSERT(tree->tree != NULL); |
|
187 /* The root must not have set been already */ |
|
188 NW_ASSERT(tree->root_index == 0); |
|
189 |
|
190 tree->root_index = 1; |
|
191 root_node.source_offset = offset; |
|
192 root_node.flags = TNODE_FLAG_ROOT; |
|
193 root_node.first_child = 0; |
|
194 root_node.next_sibling = 0; |
|
195 root_node.tree = tree; |
|
196 root_node.token = 0; |
|
197 /* TODO: make this a dummy element! */ |
|
198 if (NW_TinyTree_appendNodeAt(tree, &root_node, 0) == NULL) { |
|
199 return NULL; |
|
200 } |
|
201 |
|
202 return NW_TinyTree_appendNodeAt(tree, &root_node, tree->root_index); |
|
203 } |
|
204 |
|
205 /* |
|
206 * Get the root node of the tree. |
|
207 */ |
|
208 |
|
209 NW_TinyTree_Node_t* |
|
210 NW_TinyTree_getRoot(NW_TinyTree_t *tree){ |
|
211 |
|
212 NW_ASSERT(tree != NULL); |
|
213 /* Return NULL if not set */ |
|
214 if(tree->root_index == 0) |
|
215 return NULL; |
|
216 return NW_TinyTree_getNode(tree, tree->root_index); |
|
217 } |
|
218 |
|
219 NW_TinyTree_Node_t* |
|
220 NW_TinyTree_findNextSibling(NW_TinyTree_Node_t *node){ |
|
221 |
|
222 NW_ASSERT(node != NULL); |
|
223 |
|
224 if (((node->flags & TNODE_FLAG_LASTSIBLING) == TNODE_FLAG_LASTSIBLING) |
|
225 || (node->next_sibling == 0)) { |
|
226 return NULL; |
|
227 } |
|
228 |
|
229 return node->next_sibling; |
|
230 } |
|
231 |
|
232 /* Find last sibling address */ |
|
233 |
|
234 NW_TinyTree_Node_t* |
|
235 NW_TinyTree_findLastSibling(NW_TinyTree_Node_t *node) |
|
236 { |
|
237 NW_TinyTree_Node_t* sibling = node; |
|
238 |
|
239 NW_ASSERT(node != NULL); |
|
240 |
|
241 while (((sibling->flags & TNODE_FLAG_LASTSIBLING) != TNODE_FLAG_LASTSIBLING) |
|
242 && (sibling->next_sibling != 0)) { |
|
243 sibling = sibling->next_sibling; |
|
244 } |
|
245 |
|
246 /* Because the array always starts with the tree node, no node ever has index 0 */ |
|
247 if(sibling == node) |
|
248 return NULL; |
|
249 |
|
250 return sibling; |
|
251 } |
|
252 |
|
253 NW_TinyTree_Node_t* |
|
254 NW_TinyTree_findFirstChild(NW_TinyTree_Node_t *node) |
|
255 { |
|
256 NW_ASSERT(node != NULL); |
|
257 return node->first_child; |
|
258 } |
|
259 |
|
260 |
|
261 /* |
|
262 * Find a node's last child |
|
263 */ |
|
264 |
|
265 NW_TinyTree_Node_t* |
|
266 NW_TinyTree_findLastChild(NW_TinyTree_Node_t* node){ |
|
267 |
|
268 NW_TinyTree_Node_t* first; |
|
269 NW_TinyTree_Node_t* last; |
|
270 |
|
271 NW_ASSERT(node != NULL); |
|
272 |
|
273 first = NW_TinyTree_findFirstChild(node); |
|
274 |
|
275 if(first == NULL){ |
|
276 return NULL; /* No children */ |
|
277 } |
|
278 |
|
279 last = NW_TinyTree_findLastSibling(first); |
|
280 |
|
281 if(last == NULL){ /* No siblings, only child */ |
|
282 return first; |
|
283 } |
|
284 |
|
285 return last; |
|
286 } |
|
287 |
|
288 /* |
|
289 * Get a node's parent |
|
290 */ |
|
291 |
|
292 NW_TinyTree_Node_t* |
|
293 NW_TinyTree_findParent(NW_TinyTree_Node_t *node) |
|
294 { |
|
295 |
|
296 NW_TinyTree_Node_t *last_sibling; |
|
297 |
|
298 NW_ASSERT(node != NULL); |
|
299 |
|
300 /* Is this the root node ? */ |
|
301 if((node->flags & TNODE_FLAG_ROOT) == TNODE_FLAG_ROOT) |
|
302 return NULL; |
|
303 |
|
304 /* Is next sibling zero ? */ |
|
305 if (node->next_sibling == 0) |
|
306 return NULL; |
|
307 |
|
308 /* The next sibling index of the last sibling points back to parent */ |
|
309 |
|
310 last_sibling = NW_TinyTree_findLastSibling(node); |
|
311 |
|
312 if (last_sibling == NULL){ |
|
313 last_sibling = node; /* No siblings */ |
|
314 } |
|
315 |
|
316 return last_sibling->next_sibling; |
|
317 } |
|
318 |
|
319 |
|
320 /* |
|
321 * Attach a node as a sibling after another node. |
|
322 */ |
|
323 |
|
324 NW_Status_t |
|
325 NW_TinyTree_attachAfter(NW_TinyTree_Node_t *node, |
|
326 NW_TinyTree_Node_t *sibling) |
|
327 { |
|
328 NW_ASSERT(node != NULL); |
|
329 NW_ASSERT(sibling != NULL); |
|
330 |
|
331 if((node->flags & TNODE_FLAG_LASTSIBLING) == TNODE_FLAG_LASTSIBLING){ |
|
332 node->flags &= ~TNODE_FLAG_LASTSIBLING; |
|
333 sibling->flags |= TNODE_FLAG_LASTSIBLING; |
|
334 } |
|
335 |
|
336 sibling->next_sibling = node->next_sibling; |
|
337 node->next_sibling = sibling; |
|
338 return NW_STAT_SUCCESS; |
|
339 } |
|
340 |
|
341 NW_TinyTree_Node_t* |
|
342 NW_TinyTree_findPreviousSibling(NW_TinyTree_Node_t *node){ |
|
343 |
|
344 NW_TinyTree_Node_t *sibling; |
|
345 NW_TinyTree_Node_t *parent; |
|
346 |
|
347 NW_ASSERT(node != NULL); |
|
348 |
|
349 /* First find the parent */ |
|
350 parent = NW_TinyTree_findParent(node); |
|
351 |
|
352 if(parent == NULL) |
|
353 return NULL; |
|
354 |
|
355 /* Then get first child */ |
|
356 sibling = NW_TinyTree_findFirstChild(parent); |
|
357 NW_ASSERT(sibling != NULL); |
|
358 if(sibling == node) |
|
359 return NULL; /* Only child */ |
|
360 |
|
361 /* Find a sibling whose next_sibling points to me */ |
|
362 while(sibling->next_sibling != node){ |
|
363 NW_ASSERT(sibling->next_sibling != NULL); |
|
364 sibling = sibling->next_sibling; |
|
365 } |
|
366 return sibling; |
|
367 } |
|
368 |
|
369 /* |
|
370 * Attach a node as a sibling before another node. |
|
371 */ |
|
372 |
|
373 NW_Status_t |
|
374 NW_TinyTree_attachBefore(NW_TinyTree_Node_t *node, |
|
375 NW_TinyTree_Node_t *sibling) |
|
376 { |
|
377 NW_TinyTree_Node_t *previous = NW_TinyTree_findPreviousSibling(node); |
|
378 |
|
379 NW_ASSERT(node != NULL); |
|
380 NW_ASSERT(sibling != NULL); |
|
381 |
|
382 /* Has a previous sibling, insert after */ |
|
383 if(previous != NULL){ |
|
384 NW_TinyTree_attachAfter(previous, sibling); |
|
385 return NW_STAT_SUCCESS; |
|
386 } |
|
387 |
|
388 /*Otherwise, insert as first child */ |
|
389 previous = NW_TinyTree_findParent(node); |
|
390 if(previous == NULL) |
|
391 return NW_STAT_FAILURE; /* TODO: return a more descriptive error status */ |
|
392 |
|
393 previous->first_child = sibling; |
|
394 /*lint -e{794} Conceivable use of null pointer */ |
|
395 sibling->next_sibling = node; |
|
396 |
|
397 return NW_STAT_SUCCESS; |
|
398 } |
|
399 |
|
400 /* |
|
401 * Attach a child (as last child) to a node |
|
402 */ |
|
403 |
|
404 NW_Status_t |
|
405 NW_TinyTree_attachChild(NW_TinyTree_Node_t *node, |
|
406 NW_TinyTree_Node_t *child) |
|
407 { |
|
408 NW_TinyTree_Node_t *last_child = NW_TinyTree_findLastChild(node); |
|
409 |
|
410 NW_ASSERT(node != NULL); |
|
411 NW_ASSERT(child != NULL); |
|
412 |
|
413 /* If there are no children, attach as first child */ |
|
414 if(last_child == NULL){ |
|
415 node->first_child = child; |
|
416 /* Point child's next_sibling back to parent and set LASTSIBLING flag */ |
|
417 child->next_sibling = node; |
|
418 child->flags |= TNODE_FLAG_LASTSIBLING; |
|
419 return NW_STAT_SUCCESS; |
|
420 } |
|
421 /* Else attach as sibling to last child */ |
|
422 else{ |
|
423 return NW_TinyTree_attachAfter(last_child, child); |
|
424 } |
|
425 } |
|
426 |
|
427 NW_Status_t |
|
428 NW_TinyTree_deleteNode(NW_TinyTree_Node_t *node) |
|
429 { |
|
430 NW_ASSERT(node != NULL); |
|
431 |
|
432 /* If not the root node, then adjust parent or sibling indexes */ |
|
433 if((node->flags & TNODE_FLAG_ROOT)!= TNODE_FLAG_ROOT){ |
|
434 NW_TinyTree_Node_t *previous_sibling; |
|
435 previous_sibling = NW_TinyTree_findPreviousSibling(node); |
|
436 /* If we are first child, modify parent's first_child index */ |
|
437 if(previous_sibling == NULL){ |
|
438 NW_TinyTree_Node_t *parent = NW_TinyTree_findParent(node); |
|
439 NW_ASSERT(parent != NULL); |
|
440 /* If also last child (i.e. only child) */ |
|
441 if((node->flags & TNODE_FLAG_LASTSIBLING) == TNODE_FLAG_LASTSIBLING){ |
|
442 /* Zero the parent's child index */ |
|
443 parent->first_child = 0; |
|
444 } |
|
445 /* Not only child */ |
|
446 else{ |
|
447 /* Move parent child offset to my next sibling */ |
|
448 parent->first_child = node->next_sibling; |
|
449 } |
|
450 } |
|
451 /* Not the first child */ |
|
452 else { |
|
453 /* Adjust previous sibling next_sibling index */ |
|
454 previous_sibling->next_sibling = node->next_sibling; |
|
455 if((node->flags & TNODE_FLAG_LASTSIBLING) == TNODE_FLAG_LASTSIBLING){ |
|
456 previous_sibling->flags |= TNODE_FLAG_LASTSIBLING; |
|
457 } |
|
458 } |
|
459 } |
|
460 |
|
461 /* Note that we don't actually remove the node from the tree vector |
|
462 * since this may cause other nodes to be moved, invalidating any |
|
463 * references to them. |
|
464 */ |
|
465 |
|
466 return NW_STAT_SUCCESS; |
|
467 } |
|
468 |
|
469 NW_Status_t |
|
470 NW_TinyTree_setContext(NW_TinyTree_t *tree, |
|
471 void *context){ |
|
472 NW_ASSERT(tree != NULL); |
|
473 tree->context = context; |
|
474 return NW_STAT_SUCCESS; |
|
475 } |
|
476 |
|
477 void* |
|
478 NW_TinyTree_getContext(NW_TinyTree_t *tree){ |
|
479 NW_ASSERT(tree != NULL); |
|
480 return tree->context; |
|
481 } |
|
482 |
|
483 NW_Uint16 |
|
484 NW_TinyTree_Node_getFlags(NW_TinyTree_Node_t *node){ |
|
485 NW_ASSERT(node != NULL); |
|
486 return node->flags; |
|
487 } |
|
488 |
|
489 NW_Status_t |
|
490 NW_TinyTree_Node_setUserFlags(NW_TinyTree_Node_t *node, |
|
491 NW_Uint16 flags){ |
|
492 NW_ASSERT(node != NULL); |
|
493 node->flags &= ~TNODE_USR_FLAGS; /*Zero user flags */ |
|
494 node->flags |= (flags & TNODE_USR_FLAGS); |
|
495 return NW_STAT_SUCCESS; |
|
496 } |
|
497 |
|
498 NW_TinyTree_Offset_t |
|
499 NW_TinyTree_Node_getSourceOffset(NW_TinyTree_Node_t *node){ |
|
500 NW_ASSERT(node != NULL); |
|
501 |
|
502 return node->source_offset; |
|
503 } |
|
504 |
|
505 void * |
|
506 NW_TinyTree_Node_getSourceAddress(NW_TinyTree_t *tree, |
|
507 NW_TinyTree_Node_t* node){ |
|
508 |
|
509 NW_ASSERT(node != NULL); |
|
510 NW_ASSERT(tree != NULL); |
|
511 |
|
512 /*lint -e{794} Conceivable use of null pointer */ |
|
513 return (void *)(NW_TinyTree_EBuffer_AddressAt(tree->ebuffer, |
|
514 node->source_offset)); |
|
515 } |
|
516 |
|
517 |
|
518 NW_Status_t |
|
519 NW_TinyTree_Node_GetSegmentAndOffset(NW_TinyTree_t* tree, |
|
520 NW_TinyTree_Node_t* node, |
|
521 NW_Uint8** segment, |
|
522 NW_TinyTree_Offset_t* segSize, |
|
523 NW_TinyTree_Offset_t* offset) { |
|
524 NW_ASSERT(tree != NULL); |
|
525 NW_ASSERT(node != NULL); |
|
526 |
|
527 return NW_TinyTree_EBuffer_GetSegmentAndOffset(tree->ebuffer, |
|
528 node->source_offset, |
|
529 segment, |
|
530 segSize, |
|
531 offset); |
|
532 } |
|
533 |
|
534 NW_Status_t |
|
535 NW_TinyTree_GetSourceOffset(NW_TinyTree_t* tree, |
|
536 NW_Uint8* segmentAddr, |
|
537 NW_TinyTree_Offset_t offset, |
|
538 NW_TinyTree_Offset_t* index){ |
|
539 NW_ASSERT(tree != NULL); |
|
540 |
|
541 return NW_TinyTree_EBuffer_GetIndex(tree->ebuffer, segmentAddr, offset, index); |
|
542 } |
|
543 |
|
544 |
|
545 |
|
546 NW_Uint8* |
|
547 NW_TinyTree_GetWritableBlock(NW_TinyTree_t* tree, |
|
548 NW_TinyTree_Offset_t size, |
|
549 NW_TinyTree_Offset_t * source_offset){ /* OUT */ |
|
550 |
|
551 return NW_TinyTree_EBuffer_GetWritableBlock(tree->ebuffer, size, source_offset); |
|
552 |
|
553 } |
|
554 |
|
555 NW_TinyTree_t* |
|
556 NW_TinyTree_Node_findTreeOld(NW_TinyTree_Node_t *node) |
|
557 { |
|
558 NW_TinyTree_Node_t *parent = NW_TinyTree_findParent(node); |
|
559 NW_ASSERT(node != NULL); |
|
560 |
|
561 // find rootNode |
|
562 while (parent != NULL) |
|
563 { |
|
564 node = parent; |
|
565 parent = NW_TinyTree_findParent(parent); |
|
566 } |
|
567 // root node should be next to sentinal tree node |
|
568 while(node != NULL){ |
|
569 if((node->flags & TNODE_FLAG_TREE) == TNODE_FLAG_TREE){ |
|
570 return ((NW_TinyTree_TreeNode_t*)node)->tree; |
|
571 } |
|
572 --node; |
|
573 } |
|
574 // Not reached |
|
575 NW_ASSERT(0); |
|
576 return NULL; |
|
577 } |
|
578 |
|
579 EXPORT_C NW_TinyTree_t* |
|
580 NW_TinyTree_Node_findTree(NW_TinyTree_Node_t *node) |
|
581 { |
|
582 if (!node->tree) |
|
583 { |
|
584 return NW_TinyTree_Node_findTreeOld(node); |
|
585 } |
|
586 else |
|
587 { |
|
588 return node->tree; |
|
589 } |
|
590 |
|
591 } |
|
592 |
|
593 /* |
|
594 * Create a new node as a child of an existing node. The child |
|
595 * references the source buffer at offset. The new child node is |
|
596 * returned. |
|
597 */ |
|
598 |
|
599 NW_TinyTree_Node_t* |
|
600 NW_TinyTree_createChild(NW_TinyTree_t *tree, |
|
601 NW_TinyTree_Node_t *parent, |
|
602 NW_TinyTree_Offset_t offset){ |
|
603 |
|
604 NW_TinyTree_Node_t *child = NW_TinyTree_createNode(tree, offset); |
|
605 |
|
606 if (child != NULL){ |
|
607 NW_TinyTree_attachChild(parent, child); |
|
608 } |
|
609 |
|
610 return child; |
|
611 } |
|
612 |
|
613 /* |
|
614 * Create a new node as an immediate sibling to an existing node. The |
|
615 * child references the source buffer at offset. The new child node is |
|
616 * returned. |
|
617 */ |
|
618 NW_TinyTree_Node_t* |
|
619 NW_TinyTree_createSibling(NW_TinyTree_t *tree, |
|
620 NW_TinyTree_Node_t *node, |
|
621 NW_TinyTree_Offset_t offset) |
|
622 { |
|
623 NW_TinyTree_Node_t *sibling = NW_TinyTree_createNode(tree, offset); |
|
624 NW_TinyTree_attachAfter(node, sibling); |
|
625 return sibling; |
|
626 } |
|
627 |
|
628 void |
|
629 NW_TinyTree_recurse(NW_TinyTree_t* tree, |
|
630 NW_TinyTree_Node_t* start_node, |
|
631 void (*Node_CB) (NW_TinyTree_t*, NW_TinyTree_Node_t *, void *), |
|
632 void * context) |
|
633 { |
|
634 NW_TinyTree_Node_t *child; |
|
635 |
|
636 (*(Node_CB)) (tree, start_node, context); |
|
637 if((child = NW_TinyTree_findFirstChild(start_node)) != 0){ |
|
638 NW_TinyTree_recurse(tree, child, Node_CB, context); |
|
639 while((child = NW_TinyTree_findNextSibling(child)) != 0){ |
|
640 NW_TinyTree_recurse(tree, child, Node_CB, context); |
|
641 } |
|
642 } |
|
643 } |
|
644 |
|
645 /* Initialize a node iterator with a start node */ |
|
646 |
|
647 void |
|
648 NW_TinyTree_NodeIterator_init(NW_TinyTree_Node_t* start_node, |
|
649 NW_TinyTree_NodeIterator_t* iterator) |
|
650 { |
|
651 iterator->start_node = start_node; |
|
652 iterator->traversal_node = NULL; |
|
653 } |
|
654 |
|
655 /* |
|
656 * Iterate through a subtree returning each node exactly once. |
|
657 * The algorithm follows the toplogical ordering of the tree (if there is |
|
658 * an edge from v0 to v1, always visit v0 before v1). It's equivalent to |
|
659 * solving a labyrinth by keeping your right hand on the wall! |
|
660 */ |
|
661 |
|
662 NW_TinyTree_Node_t* |
|
663 NW_TinyTree_NodeIterator_iterate(NW_TinyTree_NodeIterator_t *iterator){ |
|
664 |
|
665 NW_TinyTree_Node_t* node; |
|
666 |
|
667 if(iterator->start_node == NULL) |
|
668 return NULL; |
|
669 |
|
670 if(iterator->traversal_node == NULL){ |
|
671 node = iterator->start_node; |
|
672 if(iterator->start_node->first_child != 0){ |
|
673 iterator->traversal_node = iterator->start_node->first_child; |
|
674 } |
|
675 else{ |
|
676 iterator->start_node = NULL; |
|
677 } |
|
678 return node; |
|
679 } |
|
680 |
|
681 node = iterator->traversal_node; |
|
682 |
|
683 /* First try to move down */ |
|
684 if(iterator->traversal_node->first_child != 0){ |
|
685 iterator->traversal_node = iterator->traversal_node->first_child; |
|
686 return node; |
|
687 } |
|
688 |
|
689 /* If you can't move down, move right */ |
|
690 |
|
691 if((iterator->traversal_node->flags & TNODE_FLAG_LASTSIBLING) != TNODE_FLAG_LASTSIBLING){ |
|
692 iterator->traversal_node = iterator->traversal_node->next_sibling; |
|
693 return node; |
|
694 } |
|
695 |
|
696 /* If you can't move right, move back up */ |
|
697 /* TODO: some other expression here */ |
|
698 while(node != NULL){ |
|
699 iterator->traversal_node = iterator->traversal_node->next_sibling; |
|
700 /* If you reached the start, quit */ |
|
701 if(iterator->traversal_node == iterator->start_node){ |
|
702 iterator->start_node = NULL; |
|
703 return node; |
|
704 } |
|
705 /* Otherwise, try to move right */ |
|
706 if((iterator->traversal_node->flags & TNODE_FLAG_LASTSIBLING) != TNODE_FLAG_LASTSIBLING){ |
|
707 iterator->traversal_node = iterator->traversal_node->next_sibling; |
|
708 return node; |
|
709 } |
|
710 /* Otherwise, continue to move up */ |
|
711 } |
|
712 return NULL; |
|
713 } |
|
714 |
|
715 /* Iterate the siblings of a node */ |
|
716 |
|
717 NW_TinyTree_Node_t* |
|
718 NW_TinyTree_NodeIterator_iterateSiblings(NW_TinyTree_NodeIterator_t *iterator){ |
|
719 if((iterator->start_node->flags & TNODE_FLAG_LASTSIBLING)== TNODE_FLAG_LASTSIBLING) |
|
720 return NULL; |
|
721 else{ |
|
722 iterator->start_node = iterator->start_node->next_sibling; |
|
723 return iterator->start_node; |
|
724 } |
|
725 } |
|
726 |
|
727 |
|
728 |
|
729 |
|
730 |