feat(tree): add tree iterator
							parent
							
								
									ef5037f941
								
							
						
					
					
						commit
						a6ed89d8cd
					
				|  | @ -9,7 +9,8 @@ typedef struct vieter_tree vieter_tree; | |||
| typedef enum vieter_tree_error { | ||||
|   vieter_tree_ok = 0, | ||||
|   vieter_tree_already_present = 1, | ||||
|   vieter_tree_not_present = 2 | ||||
|   vieter_tree_not_present = 2, | ||||
|   vieter_tree_iterator_done = 3 | ||||
| } vieter_tree_error; | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -45,4 +46,25 @@ vieter_tree_error vieter_tree_remove(void **out, vieter_tree *tree, | |||
|  */ | ||||
| uint64_t vieter_tree_size(vieter_tree *tree); | ||||
| 
 | ||||
| /*
 | ||||
|  * An iterator that can be used to traverse a tree in-order. | ||||
|  */ | ||||
| typedef struct vieter_tree_iterator vieter_tree_iterator; | ||||
| 
 | ||||
| /*
 | ||||
|  * Allocate and initialize a new iterator from the given tree. | ||||
|  */ | ||||
| vieter_tree_iterator *vieter_tree_iterator_from(vieter_tree *tree); | ||||
| 
 | ||||
| /*
 | ||||
|  * Free an iterator. | ||||
|  */ | ||||
| void vieter_tree_iterator_free(vieter_tree_iterator **ptp); | ||||
| 
 | ||||
| /*
 | ||||
|  * Return the iterator's next element. | ||||
|  */ | ||||
| vieter_tree_error vieter_tree_iterator_next(void **out, | ||||
|                                             vieter_tree_iterator *iter); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -1,11 +1,5 @@ | |||
| #include "vieter_tree_internal.h" | ||||
| #include "vieter_tree_node.h" | ||||
| #include "vieter_tree_balancing.h" | ||||
| 
 | ||||
| struct vieter_tree { | ||||
|   uint64_t size; | ||||
|   vieter_tree_node *root; | ||||
| }; | ||||
| #include "vieter_tree_internal.h" | ||||
| 
 | ||||
| vieter_tree *vieter_tree_init() { return calloc(1, sizeof(vieter_tree)); } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,10 +1,22 @@ | |||
| #include "vieter_tree.h" | ||||
| #include "vieter_tree_node.h" | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| struct vieter_tree { | ||||
|   uint64_t size; | ||||
|   vieter_tree_node *root; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Inspect whether the tree is still a valid red-black-tree. | ||||
|  * | ||||
|  * @return true if valid, false otherwise. | ||||
|  */ | ||||
| bool vieter_tree_validate(vieter_tree *tree); | ||||
| 
 | ||||
| struct vieter_tree_iterator { | ||||
|     vieter_tree_node *current_node; | ||||
|     bool started; | ||||
|     bool done; | ||||
| }; | ||||
|  |  | |||
|  | @ -0,0 +1,49 @@ | |||
| #include "vieter_tree.h" | ||||
| #include "vieter_tree_internal.h" | ||||
| 
 | ||||
| vieter_tree_iterator *vieter_tree_iterator_from(vieter_tree *tree) { | ||||
|   vieter_tree_iterator *iter = calloc(1, sizeof(vieter_tree_iterator)); | ||||
| 
 | ||||
|   // An empty tree's iterator will be done immediately
 | ||||
|   if (tree->size == 0) { | ||||
|     iter->started = true; | ||||
|     iter->done = true; | ||||
| 
 | ||||
|     return iter; | ||||
|   } | ||||
| 
 | ||||
|   iter->current_node = tree->root; | ||||
| 
 | ||||
|   return iter; | ||||
| } | ||||
| 
 | ||||
| vieter_tree_error vieter_tree_iterator_next(void **out, | ||||
|                                             vieter_tree_iterator *iter) { | ||||
|   if (iter->done) { | ||||
|     return vieter_tree_iterator_done; | ||||
|   } | ||||
| 
 | ||||
|   if (!iter->started) { | ||||
|     while (iter->current_node->children[0] != NULL) { | ||||
|       iter->current_node = iter->current_node->children[0]; | ||||
|     } | ||||
| 
 | ||||
|     iter->started = true; | ||||
|   } | ||||
| 
 | ||||
|   *out = iter->current_node->data; | ||||
| 
 | ||||
|   iter->current_node = vieter_tree_node_next(iter->current_node); | ||||
| 
 | ||||
|   if (iter->current_node == NULL) { | ||||
|     iter->done = true; | ||||
|   } | ||||
| 
 | ||||
|   return vieter_tree_ok; | ||||
| } | ||||
| 
 | ||||
| void vieter_tree_iterator_free(vieter_tree_iterator **ptp) { | ||||
|   free(*ptp); | ||||
| 
 | ||||
|   *ptp = NULL; | ||||
| } | ||||
|  | @ -150,3 +150,22 @@ void vieter_tree_node_set(vieter_tree_node *node, vieter_tree_node_flag flag, | |||
| bool vieter_tree_node_get(vieter_tree_node *node, vieter_tree_node_flag flag) { | ||||
|   return (node->flags & flag) != 0; | ||||
| } | ||||
| 
 | ||||
| vieter_tree_node *vieter_tree_node_next(vieter_tree_node *node) { | ||||
|   if (node->children[1] != NULL) { | ||||
|     node = node->children[1]; | ||||
| 
 | ||||
|     while (node->children[0] != NULL) { | ||||
|       node = node->children[0]; | ||||
|     } | ||||
| 
 | ||||
|     return node; | ||||
|   } | ||||
| 
 | ||||
|   while (node->parent != NULL && | ||||
|          vieter_tree_node_get(node, vieter_tree_node_right)) { | ||||
|     node = node->parent; | ||||
|   } | ||||
| 
 | ||||
|   return node->parent; | ||||
| } | ||||
|  |  | |||
|  | @ -77,4 +77,10 @@ void vieter_tree_node_set_children(vieter_tree_node *parent, vieter_tree_node ** | |||
|  */ | ||||
| void vieter_tree_node_set_child(vieter_tree_node *parent, vieter_tree_node *child, bool right); | ||||
| 
 | ||||
| /*
 | ||||
|  * Return the in-order successor of the given node, or NULL if it's the last | ||||
|  * node in the tree. | ||||
|  */ | ||||
| vieter_tree_node *vieter_tree_node_next(vieter_tree_node *node); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -16,19 +16,30 @@ void test_insert() { | |||
|     vieter_tree *tree = vieter_tree_init(); | ||||
| 
 | ||||
|     for (uint64_t i = 0; i < 250; i++) { | ||||
|         TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok); | ||||
|         TEST_CHECK(vieter_tree_insert(tree, i, (void *)i) == vieter_tree_ok); | ||||
|         TEST_SIZE(tree, i + 1); | ||||
|         TEST_CHECK(vieter_tree_validate(tree)); | ||||
|     } | ||||
| 
 | ||||
|     void *out; | ||||
|     vieter_tree_iterator *iter = vieter_tree_iterator_from(tree); | ||||
| 
 | ||||
|     void *out = NULL; | ||||
| 
 | ||||
|     for (uint64_t i = 0; i < 250; i++) { | ||||
|         TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok); | ||||
|         TEST_CHECK(out == (void *)i); | ||||
|         TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_already_present); | ||||
|         TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok); | ||||
| 
 | ||||
|         out = NULL; | ||||
| 
 | ||||
|         TEST_CHECK(vieter_tree_iterator_next(&out, iter) == vieter_tree_ok); | ||||
|         TEST_CHECK(out == (void *)i); | ||||
|     } | ||||
| 
 | ||||
|     TEST_CHECK(vieter_tree_iterator_next(&out, iter) == vieter_tree_iterator_done); | ||||
| 
 | ||||
|     vieter_tree_iterator_free(&iter); | ||||
|     vieter_tree_free(tree); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue