summaryrefslogtreecommitdiff
path: root/lib/graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/graph.c')
-rw-r--r--lib/graph.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/lib/graph.c b/lib/graph.c
new file mode 100644
index 0000000000..891ecc33c0
--- /dev/null
+++ b/lib/graph.c
@@ -0,0 +1,138 @@
+/*
+ * Graph data structure.
+ *
+ * --
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+#include "graph.h"
+#include "memory.h"
+
+DEFINE_MTYPE_STATIC(LIB, GRAPH, "Graph")
+DEFINE_MTYPE_STATIC(LIB, GRAPH_NODE, "Graph Node")
+struct graph *
+graph_new ()
+{
+ struct graph *graph = XCALLOC (MTYPE_GRAPH, sizeof(struct graph));
+ graph->nodes = vector_init (VECTOR_MIN_SIZE);
+
+ return graph;
+}
+
+struct graph_node *
+graph_new_node (struct graph *graph, void *data, void (*del) (void*))
+{
+ struct graph_node *node =
+ XCALLOC(MTYPE_GRAPH_NODE, sizeof(struct graph_node));
+
+ node->from = vector_init (VECTOR_MIN_SIZE);
+ node->to = vector_init (VECTOR_MIN_SIZE);
+ node->data = data;
+ node->del = del;
+
+ vector_set (graph->nodes, node);
+
+ return node;
+}
+
+static void
+vector_remove (vector v, unsigned int ix)
+{
+ vector_unset (v, ix);
+ if (ix == vector_active (v)) return;
+ for (; ix < vector_active (v) - 1; ix++)
+ v->index[ix] = v->index[ix+1];
+ v->active--;
+}
+
+void
+graph_delete_node (struct graph *graph, struct graph_node *node)
+{
+ if (!node) return;
+
+ // an adjacent node
+ struct graph_node *adj;
+
+ // remove all edges from other nodes to us
+ vector edges = vector_copy (node->from);
+ for (unsigned int i = 0; i < vector_active (edges); i++)
+ {
+ adj = vector_slot (edges, i);
+ graph_remove_edge (adj, node);
+ }
+ vector_free (edges);
+
+ // remove all edges from us to other nodes
+ edges = vector_copy (node->to);
+ for (unsigned int i = 0; i < vector_active (edges); i++)
+ {
+ adj = vector_slot (edges, i);
+ graph_remove_edge (node, adj);
+ }
+ vector_free (edges);
+
+ // if there is a deletion callback, call it
+ if (node->del && node->data)
+ (*node->del) (node->data);
+
+ // free adjacency lists
+ vector_free (node->to);
+ vector_free (node->from);
+
+ // remove node from graph->nodes
+ for (unsigned int i = 0; i < vector_active (graph->nodes); i++)
+ if (vector_slot (graph->nodes, i) == node)
+ vector_remove (graph->nodes, i);
+
+ // free the node itself
+ XFREE (MTYPE_GRAPH_NODE, node);
+}
+
+struct graph_node *
+graph_add_edge (struct graph_node *from, struct graph_node *to)
+{
+ vector_set (from->to, to);
+ vector_set (to->from, from);
+ return to;
+}
+
+void
+graph_remove_edge (struct graph_node *from, struct graph_node *to)
+{
+ // remove from from to->from
+ for (unsigned int i = 0; i < vector_active (to->from); i++)
+ if (vector_slot (to->from, i) == from)
+ vector_remove (to->from, i);
+ // remove to from from->to
+ for (unsigned int i = 0; i < vector_active (from->to); i++)
+ if (vector_slot (from->to, i) == to)
+ vector_remove (from->to, i);
+}
+
+void
+graph_delete_graph (struct graph *graph)
+{
+ // delete each node in the graph
+ for (unsigned int i = 0; i < vector_active (graph->nodes); i++)
+ graph_delete_node (graph, vector_slot (graph->nodes, i));
+
+ vector_free (graph->nodes);
+ XFREE (MTYPE_GRAPH, graph);
+}