refactor(tree): better testing code
							parent
							
								
									3fb027715c
								
							
						
					
					
						commit
						06fca6f5ae
					
				|  | @ -16,7 +16,7 @@ vieter_tree_error vieter_tree_insert(vieter_tree *tree, uint64_t key, | |||
|     tree->root = vieter_tree_node_init(); | ||||
|     tree->root->key = key; | ||||
|     tree->root->data = data; | ||||
|     vieter_tree_node_set(tree->root, vieter_node_black); | ||||
|     vieter_tree_node_set(tree->root, vieter_tree_node_black); | ||||
|     tree->size = 1; | ||||
| 
 | ||||
|     return vieter_tree_ok; | ||||
|  | @ -99,9 +99,9 @@ end: | |||
|   free(tree); | ||||
| } | ||||
| 
 | ||||
| int vieter_tree_validate(vieter_tree *tree) { | ||||
| bool vieter_tree_validate(vieter_tree *tree) { | ||||
|   if (tree->size == 0) { | ||||
|     return 0; | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   // DFS to get expected black nodes
 | ||||
|  | @ -109,12 +109,13 @@ int vieter_tree_validate(vieter_tree *tree) { | |||
|   vieter_tree_node *node = tree->root; | ||||
| 
 | ||||
|   while (node != NULL) { | ||||
|     if (vieter_tree_node_get(node, vieter_node_black)) { | ||||
|     if (vieter_tree_node_get(node, vieter_tree_node_black)) { | ||||
|       expected_black_nodes++; | ||||
|     } | ||||
| 
 | ||||
|     node = node->left; | ||||
|   } | ||||
| 
 | ||||
|   return vieter_tree_node_validate(tree->root, 0, expected_black_nodes); | ||||
|   return vieter_tree_node_get(tree->root, vieter_tree_node_black) && | ||||
|          vieter_tree_node_validate(tree->root, 0, expected_black_nodes); | ||||
| } | ||||
|  |  | |||
|  | @ -1,41 +1,31 @@ | |||
| #include "vieter_tree_balancing.h" | ||||
| 
 | ||||
| int vieter_tree_node_validate(vieter_tree_node *node, | ||||
|                               uint64_t passed_black_nodes, | ||||
|                               uint64_t expected_black_nodes) { | ||||
|   if (vieter_tree_node_get(node, vieter_node_black)) { | ||||
| bool vieter_tree_node_validate(vieter_tree_node *node, | ||||
|                                uint64_t passed_black_nodes, | ||||
|                                uint64_t expected_black_nodes) { | ||||
|   // Path to NULL children should contain the same amount of black nodes
 | ||||
|   if (node == NULL) { | ||||
|     return passed_black_nodes == expected_black_nodes; | ||||
|   } | ||||
| 
 | ||||
|   if (vieter_tree_node_get(node, vieter_tree_node_black)) { | ||||
|     passed_black_nodes++; | ||||
|   } else { | ||||
|     // A red node should have black child nodes
 | ||||
|     if ((node->left != NULL && | ||||
|          !vieter_tree_node_get(node->left, vieter_node_black)) || | ||||
|         (node->right != NULL && | ||||
|          !vieter_tree_node_get(node->right, vieter_node_black))) { | ||||
|       return 1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // All paths to a NULL child should have the same amount of black nodes
 | ||||
|   if ((node->left == NULL || node->right == NULL) && | ||||
|       passed_black_nodes != expected_black_nodes) { | ||||
|     return 1; | ||||
|   } | ||||
|   // Either the node itself is black, or its children are both either NULL or
 | ||||
|   // black.
 | ||||
|   bool correctly_colored_children = | ||||
|       vieter_tree_node_get(node, vieter_tree_node_black) || | ||||
|       ((node->left == NULL || | ||||
|         vieter_tree_node_get(node->left, vieter_tree_node_black)) && | ||||
|        (node->right == NULL || | ||||
|         vieter_tree_node_get(node->right, vieter_tree_node_black))); | ||||
| 
 | ||||
|   if (node->left != NULL) { | ||||
|     if (vieter_tree_node_validate(node->left, passed_black_nodes, | ||||
|                                   expected_black_nodes) != 0) { | ||||
|       return 1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (node->right != NULL) { | ||||
|     if (vieter_tree_node_validate(node->right, passed_black_nodes, | ||||
|                                   expected_black_nodes) != 0) { | ||||
|       return 1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
|   return correctly_colored_children && | ||||
|          vieter_tree_node_validate(node->left, passed_black_nodes, | ||||
|                                    expected_black_nodes) && | ||||
|          vieter_tree_node_validate(node->right, passed_black_nodes, | ||||
|                                    expected_black_nodes); | ||||
| } | ||||
| 
 | ||||
| vieter_tree_node *vieter_tree_node_balance(vieter_tree_node *node) { | ||||
|  | @ -106,9 +96,9 @@ vieter_tree_node *vieter_tree_node_balance(vieter_tree_node *node) { | |||
|     children[3] = node->right; | ||||
|   } | ||||
| 
 | ||||
|   vieter_tree_node_set(left, vieter_node_black); | ||||
|   vieter_tree_node_set(right, vieter_node_black); | ||||
|   vieter_tree_node_unset(root, vieter_node_black); | ||||
|   vieter_tree_node_set(left, vieter_tree_node_black); | ||||
|   vieter_tree_node_set(right, vieter_tree_node_black); | ||||
|   vieter_tree_node_unset(root, vieter_tree_node_black); | ||||
| 
 | ||||
|   left->left = children[0]; | ||||
|   left->right = children[1]; | ||||
|  | @ -137,14 +127,16 @@ vieter_tree_node *vieter_tree_node_balance(vieter_tree_node *node) { | |||
| } | ||||
| 
 | ||||
| void vieter_tree_node_balance_after_insert(vieter_tree_node *node) { | ||||
|   while (!vieter_tree_node_get(node, vieter_node_black) && | ||||
|   while (!vieter_tree_node_get(node, vieter_tree_node_black) && | ||||
|          node->parent != NULL && | ||||
|          !vieter_tree_node_get(node->parent, vieter_node_black)) { | ||||
|          !vieter_tree_node_get(node->parent, vieter_tree_node_black)) { | ||||
|     node = vieter_tree_node_balance(node); | ||||
|   } | ||||
| 
 | ||||
|   // The root must always be black
 | ||||
|   if (node->parent == NULL) { | ||||
|     vieter_tree_node_set(node, vieter_node_black); | ||||
|     vieter_tree_node_set(node, vieter_tree_node_black); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void vieter_tree_node_remove_balanced(vieter_tree_node *node) {} | ||||
|  |  | |||
|  | @ -3,6 +3,17 @@ | |||
| 
 | ||||
| #include "vieter_tree_node.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * Ensure the tree remains a valid red-black tree after having inserting the | ||||
|  * node. | ||||
|  */ | ||||
| void vieter_tree_node_balance_after_insert(vieter_tree_node *node); | ||||
| 
 | ||||
| /*
 | ||||
|  * Remove the given node, ensuring the tree remains a valid red-black tree. | ||||
|  * | ||||
|  * @param node node to remove. This node should have at least one NULL child. | ||||
|  */ | ||||
| void vieter_tree_node_remove_balanced(vieter_tree_node *node); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -1,8 +1,10 @@ | |||
| #include "vieter_tree.h" | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Inspect whether the tree is still a valid red-black-tree. | ||||
|  * | ||||
|  * @return 0 if correct, 1 if not. | ||||
|  * @return true if valid, false otherwise. | ||||
|  */ | ||||
| int vieter_tree_validate(vieter_tree *tree); | ||||
| bool vieter_tree_validate(vieter_tree *tree); | ||||
|  |  | |||
|  | @ -153,14 +153,15 @@ vieter_tree_error vieter_tree_node_remove(void **out, vieter_tree_node *root, | |||
|   return vieter_tree_ok; | ||||
| } | ||||
| 
 | ||||
| void vieter_tree_node_set(vieter_tree_node *node, vieter_node_flag flag) { | ||||
| void vieter_tree_node_set(vieter_tree_node *node, vieter_tree_node_flag flag) { | ||||
|   node->flags |= flag; | ||||
| } | ||||
| 
 | ||||
| void vieter_tree_node_unset(vieter_tree_node *node, vieter_node_flag flag) { | ||||
| void vieter_tree_node_unset(vieter_tree_node *node, | ||||
|                             vieter_tree_node_flag flag) { | ||||
|   node->flags &= ~flag; | ||||
| } | ||||
| 
 | ||||
| bool vieter_tree_node_get(vieter_tree_node *node, vieter_node_flag flag) { | ||||
| bool vieter_tree_node_get(vieter_tree_node *node, vieter_tree_node_flag flag) { | ||||
|   return (node->flags & flag) != 0; | ||||
| } | ||||
|  |  | |||
|  | @ -5,11 +5,9 @@ | |||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #define VIETER_NODE_BLACK ((uint8_t)1) | ||||
| 
 | ||||
| typedef enum vieter_node_flag { | ||||
|     vieter_node_black = ((uint8_t)1) << 0 | ||||
| } vieter_node_flag; | ||||
| typedef enum vieter_tree_node_flag { | ||||
|     vieter_tree_node_black = ((uint8_t)1) << 0 | ||||
| } vieter_tree_node_flag; | ||||
| 
 | ||||
| typedef struct vieter_tree_node { | ||||
|     uint64_t key; | ||||
|  | @ -26,20 +24,24 @@ void vieter_tree_node_free(vieter_tree_node *node); | |||
| 
 | ||||
| vieter_tree_error vieter_tree_node_insert(vieter_tree_node *root, uint64_t key, void *data); | ||||
| 
 | ||||
| /*
 | ||||
|  * Return the node representing the requested value. | ||||
|  */ | ||||
| vieter_tree_error vieter_tree_node_search_node(vieter_tree_node **out, vieter_tree_node *root, uint64_t key); | ||||
| 
 | ||||
| vieter_tree_error vieter_tree_node_search(void **out, vieter_tree_node *root, uint64_t key); | ||||
| 
 | ||||
| vieter_tree_error vieter_tree_node_remove(void **out, vieter_tree_node *root, uint64_t key); | ||||
| 
 | ||||
| void vieter_tree_node_replace(vieter_tree_node *to_replace, vieter_tree_node *replacement); | ||||
| void vieter_tree_node_replace_with_child(vieter_tree_node *to_replace, vieter_tree_node *replacement); | ||||
| 
 | ||||
| void vieter_tree_node_set(vieter_tree_node *node, vieter_node_flag flag); | ||||
| void vieter_tree_node_unset(vieter_tree_node *node, vieter_node_flag flag); | ||||
| bool vieter_tree_node_get(vieter_tree_node *node, vieter_node_flag flag); | ||||
| void vieter_tree_node_set(vieter_tree_node *node, vieter_tree_node_flag flag); | ||||
| void vieter_tree_node_unset(vieter_tree_node *node, vieter_tree_node_flag flag); | ||||
| bool vieter_tree_node_get(vieter_tree_node *node, vieter_tree_node_flag flag); | ||||
| 
 | ||||
| void vieter_tree_node_add_child(vieter_tree_node *parent, uint64_t key, | ||||
|                                 vieter_tree_node *child); | ||||
| 
 | ||||
| int vieter_tree_node_validate(vieter_tree_node *node, uint64_t passed_black_nodes, uint64_t expected_black_nodes); | ||||
| bool vieter_tree_node_validate(vieter_tree_node *node, uint64_t passed_black_nodes, uint64_t expected_black_nodes); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ void test_insert() { | |||
|     for (uint64_t i = 0; i < 250; i++) { | ||||
|         TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok); | ||||
|         TEST_SIZE(tree, i + 1); | ||||
|         TEST_CHECK(vieter_tree_validate(tree) == 0); | ||||
|         TEST_CHECK(vieter_tree_validate(tree)); | ||||
|     } | ||||
| 
 | ||||
|     void *out; | ||||
|  | @ -37,7 +37,7 @@ void test_remove() { | |||
| 
 | ||||
|     for (uint64_t i = 0; i < 250; i++) { | ||||
|         TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok); | ||||
|         TEST_CHECK(vieter_tree_validate(tree) == 0); | ||||
|         TEST_CHECK(vieter_tree_validate(tree)); | ||||
|     } | ||||
| 
 | ||||
|     void *out; | ||||
|  | @ -45,7 +45,7 @@ void test_remove() { | |||
|     for (uint64_t i = 0; i < 25; i++) { | ||||
|         TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok); | ||||
|         TEST_CHECK(vieter_tree_remove(&out, tree, i) == vieter_tree_ok); | ||||
|         TEST_CHECK(vieter_tree_validate(tree) == 0); | ||||
|         TEST_CHECK(vieter_tree_validate(tree)); | ||||
|         TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_not_present); | ||||
|         TEST_SIZE(tree, 250 - i - 1); | ||||
|     } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue