123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- /* vim: tabstop=4 shiftwidth=4 noexpandtab
- * This file is part of ToaruOS and is released under the terms
- * of the NCSA / University of Illinois License - see LICENSE.md
- * Copyright (C) 2011-2018 K. Lange
- *
- * General-purpose tree implementation
- */
- #ifdef _KERNEL_
- # include <kernel/system.h>
- #else
- # include <stddef.h>
- # include <stdlib.h>
- #endif
- #include <toaru/tree.h>
- tree_t * tree_create(void) {
- /* Create a new tree */
- tree_t * out = malloc(sizeof(tree_t));
- out->nodes = 0;
- out->root = NULL;
- return out;
- }
- void tree_set_root(tree_t * tree, void * value) {
- /* Set the root node for a new tree. */
- tree_node_t * root = tree_node_create(value);
- tree->root = root;
- tree->nodes = 1;
- }
- void tree_node_destroy(tree_node_t * node) {
- /* Free the contents of a node and its children, but not the nodes themselves */
- foreach(child, node->children) {
- tree_node_destroy((tree_node_t *)child->value);
- }
- free(node->value);
- }
- void tree_destroy(tree_t * tree) {
- /* Free the contents of a tree, but not the nodes */
- if (tree->root) {
- tree_node_destroy(tree->root);
- }
- }
- void tree_node_free(tree_node_t * node) {
- /* Free a node and its children, but not their contents */
- if (!node) return;
- foreach(child, node->children) {
- tree_node_free(child->value);
- }
- free(node);
- }
- void tree_free(tree_t * tree) {
- /* Free all of the nodes in a tree, but not their contents */
- tree_node_free(tree->root);
- }
- tree_node_t * tree_node_create(void * value) {
- /* Create a new tree node pointing to the given value */
- tree_node_t * out = malloc(sizeof(tree_node_t));
- out->value = value;
- out->children = list_create();
- out->parent = NULL;
- return out;
- }
- void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node) {
- /* Insert a node as a child of parent */
- list_insert(parent->children, node);
- node->parent = parent;
- tree->nodes++;
- }
- tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value) {
- /* Insert a (fresh) node as a child of parent */
- tree_node_t * out = tree_node_create(value);
- tree_node_insert_child_node(tree, parent, out);
- return out;
- }
- tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle) {
- /* Recursive node part of tree_find_parent */
- tree_node_t * found = NULL;
- foreach(child, haystack->children) {
- if (child->value == needle) {
- return haystack;
- }
- found = tree_node_find_parent((tree_node_t *)child->value, needle);
- if (found) {
- break;
- }
- }
- return found;
- }
- tree_node_t * tree_find_parent(tree_t * tree, tree_node_t * node) {
- /* Return the parent of a node, inefficiently. */
- if (!tree->root) return NULL;
- return tree_node_find_parent(tree->root, node);
- }
- size_t tree_count_children(tree_node_t * node) {
- /* return the number of children this node has */
- if (!node) return 0;
- if (!node->children) return 0;
- size_t out = node->children->length;
- foreach(child, node->children) {
- out += tree_count_children((tree_node_t *)child->value);
- }
- return out;
- }
- void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node) {
- /* remove a node when we know its parent; update node counts for the tree */
- tree->nodes -= tree_count_children(node) + 1;
- list_delete(parent->children, list_find(parent->children, node));
- tree_node_free(node);
- }
- void tree_node_remove(tree_t * tree, tree_node_t * node) {
- /* remove an entire branch given its root */
- tree_node_t * parent = node->parent;
- if (!parent) {
- if (node == tree->root) {
- tree->nodes = 0;
- tree->root = NULL;
- tree_node_free(node);
- }
- }
- tree_node_parent_remove(tree, parent, node);
- }
- void tree_remove(tree_t * tree, tree_node_t * node) {
- /* Remove this node and move its children into its parent's list of children */
- tree_node_t * parent = node->parent;
- /* This is something we just can't do. We don't know how to merge our
- * children into our "parent" because then we'd have more than one root node.
- * A good way to think about this is actually what this tree struct
- * primarily exists for: processes. Trying to remove the root is equivalent
- * to trying to kill init! Which is bad. We immediately fault on such
- * a case anyway ("Tried to kill init, shutting down!").
- */
- if (!parent) return;
- tree->nodes--;
- list_delete(parent->children, list_find(parent->children, node));
- foreach(child, node->children) {
- /* Reassign the parents */
- ((tree_node_t *)child->value)->parent = parent;
- }
- list_merge(parent->children, node->children);
- free(node);
- }
- void tree_remove_reparent_root(tree_t * tree, tree_node_t * node) {
- /* Remove this node and move its children into the root children */
- tree_node_t * parent = node->parent;
- if (!parent) return;
- tree->nodes--;
- list_delete(parent->children, list_find(parent->children, node));
- foreach(child, node->children) {
- /* Reassign the parents */
- ((tree_node_t *)child->value)->parent = tree->root;
- }
- list_merge(tree->root->children, node->children);
- free(node);
- }
- void tree_break_off(tree_t * tree, tree_node_t * node) {
- tree_node_t * parent = node->parent;
- if (!parent) return;
- list_delete(parent->children, list_find(parent->children, node));
- }
- tree_node_t * tree_node_find(tree_node_t * node, void * search, tree_comparator_t comparator) {
- if (comparator(node->value,search)) {
- return node;
- }
- tree_node_t * found;
- foreach(child, node->children) {
- found = tree_node_find((tree_node_t *)child->value, search, comparator);
- if (found) return found;
- }
- return NULL;
- }
- tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator) {
- return tree_node_find(tree->root, value, comparator);
- }
|