[Sheepdog] [PATCH 03/18] add common tree utilities
MORITA Kazutaka
morita.kazutaka at lab.ntt.co.jp
Thu Mar 11 07:48:02 CET 2010
This utilities will be used by cluster startup, vdi deletion, and other
tree manipulations.
Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
include/tree.h | 48 +++++++++++++
lib/tree.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 251 insertions(+), 0 deletions(-)
create mode 100644 include/tree.h
create mode 100644 lib/tree.c
diff --git a/include/tree.h b/include/tree.h
new file mode 100644
index 0000000..b005f32
--- /dev/null
+++ b/include/tree.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __TREE_H__
+#define __TREE_H__
+
+#include <stdint.h>
+
+#include "list.h"
+
+struct tree_vertex {
+ uint64_t id;
+ uint64_t parent_id;
+ struct tree_vertex *parent;
+ struct list_head children;
+ struct list_head siblings;
+};
+
+typedef int (*tree_vertex_func_t)(struct tree_vertex *vertex, int depth,
+ void *data);
+typedef int (*tree_str_func_t)(struct tree_vertex *vertex, char *buf, int len);
+
+
+
+void INIT_TREE_VERTEX(struct tree_vertex *tree, uint64_t id, uint64_t parent_id);
+int tree_no_children(struct tree_vertex *vertex);
+struct tree_vertex *tree_parent(struct tree_vertex *vertex);
+struct tree_vertex *tree_first_child(struct tree_vertex *vertex);
+struct tree_vertex *tree_last_child(struct tree_vertex *vertex);
+
+int tree_walk(struct tree_vertex *root, tree_vertex_func_t func, void *data);
+void tree_add(struct tree_vertex *new, struct tree_vertex *root);
+void tree_del(struct tree_vertex *vertex);
+struct tree_vertex *tree_find(uint64_t id, struct tree_vertex *root);
+int tree_depth(struct tree_vertex *root);
+void tree_print(struct tree_vertex *root, char *label, tree_str_func_t func);
+
+#define tree_for_each_child(pos, root) \
+ list_for_each_entry(pos, &(root)->children, siblings)
+
+#endif
diff --git a/lib/tree.c b/lib/tree.c
new file mode 100644
index 0000000..af29b41
--- /dev/null
+++ b/lib/tree.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2010 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include "list.h"
+#include "tree.h"
+
+void INIT_TREE_VERTEX(struct tree_vertex *tree, uint64_t id, uint64_t parent_id)
+{
+ tree->id = id;
+ tree->parent_id = parent_id;
+ tree->parent = NULL;
+ INIT_LIST_HEAD(&tree->children);
+ INIT_LIST_HEAD(&tree->siblings);
+}
+
+int tree_no_children(struct tree_vertex *vertex)
+{
+ return list_empty(&vertex->children);
+}
+
+struct tree_vertex *tree_parent(struct tree_vertex *vertex)
+{
+ return vertex->parent;
+}
+
+struct tree_vertex *tree_first_child(struct tree_vertex *vertex)
+{
+ return container_of(vertex->children.next, struct tree_vertex, siblings);
+}
+
+struct tree_vertex *tree_last_child(struct tree_vertex *vertex)
+{
+ return container_of(vertex->children.prev, struct tree_vertex, siblings);
+}
+
+static int __tree_walk(struct tree_vertex *vertex, int depth,
+ tree_vertex_func_t func, void *data)
+{
+ struct tree_vertex *e, *_n;
+
+ if (func(vertex, depth, data))
+ return 1;
+ list_for_each_entry_safe(e, _n, &vertex->children, siblings)
+ if (__tree_walk(e, depth + 1, func, data))
+ return 1;
+ return 0;
+}
+
+int tree_walk(struct tree_vertex *root, tree_vertex_func_t func, void *data)
+{
+ return __tree_walk(root, 0, func, data);
+}
+
+static int __tree_add(struct tree_vertex *vertex, int depth,
+ struct tree_vertex *new)
+{
+ if (vertex->id == new->parent_id) {
+ new->parent = vertex;
+ list_del(&new->siblings);
+ list_add(&new->siblings, &vertex->children);
+ } else if (vertex->parent_id == new->id) {
+ vertex->parent = new;
+ list_del(&vertex->siblings);
+ list_add(&vertex->siblings, &new->children);
+ }
+ return 0;
+}
+
+void tree_add(struct tree_vertex *new, struct tree_vertex *root)
+{
+ tree_walk(root, (tree_vertex_func_t)__tree_add, new);
+ if (!new->parent) {
+ new->parent = root;
+ list_add(&new->siblings, &root->children);
+ }
+}
+
+void tree_del(struct tree_vertex *vertex)
+{
+ vertex->parent = NULL;
+ list_del(&vertex->siblings);
+}
+
+struct tree_find_query {
+ uint64_t id;
+ struct tree_vertex *result;
+};
+
+static int __tree_find(struct tree_vertex *vertex, int depth,
+ struct tree_find_query *query)
+{
+ if (vertex->id == query->id) {
+ query->result = vertex;
+ return 1;
+ }
+ return 0;
+}
+
+struct tree_vertex *tree_find(uint64_t id, struct tree_vertex *root)
+{
+ struct tree_find_query query = { id, NULL };
+
+ tree_walk(root, (tree_vertex_func_t)__tree_find, &query);
+ return query.result;
+}
+
+static int __tree_depth(struct tree_vertex *vertex, int depth,
+ int *max_depth)
+{
+ if (depth > *max_depth)
+ *max_depth = depth;
+ return 0;
+}
+
+int tree_depth(struct tree_vertex *root)
+{
+ int res = 0;
+
+ tree_walk(root, (tree_vertex_func_t)__tree_depth, &res);
+ return res;
+}
+
+#define TREE_MAX_PRINT_DEPTH 1024
+
+static int width[TREE_MAX_PRINT_DEPTH];
+static int more[TREE_MAX_PRINT_DEPTH];
+
+static void spaces(int n)
+{
+ while (n--)
+ putchar(' ');
+}
+
+static void indent(int level, int first, int last)
+{
+ int lvl;
+
+ if (first)
+ printf(last ? "---" : "-+-");
+ else {
+ for (lvl = 0; lvl < level - 1; lvl++) {
+ spaces(width[lvl] + 1);
+ printf(more[lvl + 1] ? "| " : " ");
+ }
+
+ spaces(width[level - 1] + 1);
+ printf(last ? "`-" : "|-");
+ }
+}
+
+static int __tree_print(struct tree_vertex *vertex, int depth,
+ tree_str_func_t print_func)
+{
+ char buf[1024];
+ int first, last;
+ int w;
+
+ if (tree_parent(vertex)) {
+ first = (vertex == tree_first_child(vertex->parent));
+ last = (vertex == tree_last_child(vertex->parent));
+ } else {
+ first = 1;
+ last = 1;
+ }
+
+ indent(depth, first, last);
+
+ w = print_func(vertex, buf, sizeof(buf));
+ printf(buf);
+
+ if (tree_no_children(vertex)) {
+ putchar('\n');
+ return 0;
+ }
+
+ width[depth] = w;
+ more[depth] = !last;
+
+ return 0;
+}
+
+void tree_print(struct tree_vertex *root, char *label, tree_str_func_t func)
+{
+ int depth = tree_depth(root);
+
+ if (depth > TREE_MAX_PRINT_DEPTH)
+ return;
+
+ printf(label);
+ more[0] = 0;
+ width[0] = strlen(label);
+ tree_walk(root, (tree_vertex_func_t)__tree_print, func);
+}
--
1.5.6.5
More information about the sheepdog
mailing list