tree.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2011-2018 K. Lange
  5. *
  6. * General-purpose tree implementation
  7. */
  8. #ifdef _KERNEL_
  9. # include <kernel/system.h>
  10. #else
  11. # include <stddef.h>
  12. # include <stdlib.h>
  13. #endif
  14. #include <toaru/tree.h>
  15. tree_t * tree_create(void) {
  16. /* Create a new tree */
  17. tree_t * out = malloc(sizeof(tree_t));
  18. out->nodes = 0;
  19. out->root = NULL;
  20. return out;
  21. }
  22. void tree_set_root(tree_t * tree, void * value) {
  23. /* Set the root node for a new tree. */
  24. tree_node_t * root = tree_node_create(value);
  25. tree->root = root;
  26. tree->nodes = 1;
  27. }
  28. void tree_node_destroy(tree_node_t * node) {
  29. /* Free the contents of a node and its children, but not the nodes themselves */
  30. foreach(child, node->children) {
  31. tree_node_destroy((tree_node_t *)child->value);
  32. }
  33. free(node->value);
  34. }
  35. void tree_destroy(tree_t * tree) {
  36. /* Free the contents of a tree, but not the nodes */
  37. if (tree->root) {
  38. tree_node_destroy(tree->root);
  39. }
  40. }
  41. void tree_node_free(tree_node_t * node) {
  42. /* Free a node and its children, but not their contents */
  43. if (!node) return;
  44. foreach(child, node->children) {
  45. tree_node_free(child->value);
  46. }
  47. free(node);
  48. }
  49. void tree_free(tree_t * tree) {
  50. /* Free all of the nodes in a tree, but not their contents */
  51. tree_node_free(tree->root);
  52. }
  53. tree_node_t * tree_node_create(void * value) {
  54. /* Create a new tree node pointing to the given value */
  55. tree_node_t * out = malloc(sizeof(tree_node_t));
  56. out->value = value;
  57. out->children = list_create();
  58. out->parent = NULL;
  59. return out;
  60. }
  61. void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node) {
  62. /* Insert a node as a child of parent */
  63. list_insert(parent->children, node);
  64. node->parent = parent;
  65. tree->nodes++;
  66. }
  67. tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value) {
  68. /* Insert a (fresh) node as a child of parent */
  69. tree_node_t * out = tree_node_create(value);
  70. tree_node_insert_child_node(tree, parent, out);
  71. return out;
  72. }
  73. tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle) {
  74. /* Recursive node part of tree_find_parent */
  75. tree_node_t * found = NULL;
  76. foreach(child, haystack->children) {
  77. if (child->value == needle) {
  78. return haystack;
  79. }
  80. found = tree_node_find_parent((tree_node_t *)child->value, needle);
  81. if (found) {
  82. break;
  83. }
  84. }
  85. return found;
  86. }
  87. tree_node_t * tree_find_parent(tree_t * tree, tree_node_t * node) {
  88. /* Return the parent of a node, inefficiently. */
  89. if (!tree->root) return NULL;
  90. return tree_node_find_parent(tree->root, node);
  91. }
  92. size_t tree_count_children(tree_node_t * node) {
  93. /* return the number of children this node has */
  94. if (!node) return 0;
  95. if (!node->children) return 0;
  96. size_t out = node->children->length;
  97. foreach(child, node->children) {
  98. out += tree_count_children((tree_node_t *)child->value);
  99. }
  100. return out;
  101. }
  102. void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node) {
  103. /* remove a node when we know its parent; update node counts for the tree */
  104. tree->nodes -= tree_count_children(node) + 1;
  105. list_delete(parent->children, list_find(parent->children, node));
  106. tree_node_free(node);
  107. }
  108. void tree_node_remove(tree_t * tree, tree_node_t * node) {
  109. /* remove an entire branch given its root */
  110. tree_node_t * parent = node->parent;
  111. if (!parent) {
  112. if (node == tree->root) {
  113. tree->nodes = 0;
  114. tree->root = NULL;
  115. tree_node_free(node);
  116. }
  117. }
  118. tree_node_parent_remove(tree, parent, node);
  119. }
  120. void tree_remove(tree_t * tree, tree_node_t * node) {
  121. /* Remove this node and move its children into its parent's list of children */
  122. tree_node_t * parent = node->parent;
  123. /* This is something we just can't do. We don't know how to merge our
  124. * children into our "parent" because then we'd have more than one root node.
  125. * A good way to think about this is actually what this tree struct
  126. * primarily exists for: processes. Trying to remove the root is equivalent
  127. * to trying to kill init! Which is bad. We immediately fault on such
  128. * a case anyway ("Tried to kill init, shutting down!").
  129. */
  130. if (!parent) return;
  131. tree->nodes--;
  132. list_delete(parent->children, list_find(parent->children, node));
  133. foreach(child, node->children) {
  134. /* Reassign the parents */
  135. ((tree_node_t *)child->value)->parent = parent;
  136. }
  137. list_merge(parent->children, node->children);
  138. free(node);
  139. }
  140. void tree_remove_reparent_root(tree_t * tree, tree_node_t * node) {
  141. /* Remove this node and move its children into the root children */
  142. tree_node_t * parent = node->parent;
  143. if (!parent) return;
  144. tree->nodes--;
  145. list_delete(parent->children, list_find(parent->children, node));
  146. foreach(child, node->children) {
  147. /* Reassign the parents */
  148. ((tree_node_t *)child->value)->parent = tree->root;
  149. }
  150. list_merge(tree->root->children, node->children);
  151. free(node);
  152. }
  153. void tree_break_off(tree_t * tree, tree_node_t * node) {
  154. tree_node_t * parent = node->parent;
  155. if (!parent) return;
  156. list_delete(parent->children, list_find(parent->children, node));
  157. }
  158. tree_node_t * tree_node_find(tree_node_t * node, void * search, tree_comparator_t comparator) {
  159. if (comparator(node->value,search)) {
  160. return node;
  161. }
  162. tree_node_t * found;
  163. foreach(child, node->children) {
  164. found = tree_node_find((tree_node_t *)child->value, search, comparator);
  165. if (found) return found;
  166. }
  167. return NULL;
  168. }
  169. tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator) {
  170. return tree_node_find(tree->root, value, comparator);
  171. }