summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2016-09-18 20:31:20 +0000
committerQuentin Young <qlyoung@cumulusnetworks.com>2016-09-18 20:31:20 +0000
commitba06a3a0dec8b132f3ad81c62f7ec98f95430f11 (patch)
tree7e3b367f3fcc3ffbca3d5148152088de1a717e0f
parent535ef5569adb011209ad4f852da75d4a8fa06c1d (diff)
lib: Add edge removal to graph data structure
Ability to remove directed edge between two nodes. Also ensures that adjacency vectors have no null entries. Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
-rw-r--r--lib/graph.c51
-rw-r--r--lib/graph.h11
2 files changed, 46 insertions, 16 deletions
diff --git a/lib/graph.c b/lib/graph.c
index 18f32b8ca2..7c59fe95b5 100644
--- a/lib/graph.c
+++ b/lib/graph.c
@@ -50,6 +50,16 @@ graph_new_node (struct graph *graph, void *data, void (*del) (void*))
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)
{
@@ -58,25 +68,23 @@ graph_delete_node (struct graph *graph, struct graph_node *node)
// an adjacent node
struct graph_node *adj;
- // for all nodes that have an edge to us, remove us from their ->to
- for (unsigned int i = 0; i < vector_active (node->from); i++)
+ // 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 (node->from, i);
- if (!adj) continue;
- for (unsigned int j = 0; j < vector_active (adj->to); j++)
- if (vector_slot (adj->to, j) == node)
- vector_unset (adj->to, j);
+ adj = vector_slot (edges, i);
+ graph_remove_edge (adj, node);
}
+ vector_free (edges);
- // for all nodes that we have an edge to, remove us from their ->from
- for (unsigned int i = 0; i < vector_active (node->to); i++)
+ // 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 (node->to, i);
- if (!adj) continue;
- for (unsigned int j = 0; j < vector_active (adj->from); j++)
- if (vector_slot (adj->from, j) == node)
- vector_unset (adj->from, j);
+ 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)
@@ -89,7 +97,7 @@ graph_delete_node (struct graph *graph, struct graph_node *node)
// remove node from graph->nodes
for (unsigned int i = 0; i < vector_active (graph->nodes); i++)
if (vector_slot (graph->nodes, i) == node)
- vector_unset (graph->nodes, i);
+ vector_remove (graph->nodes, i);
// free the node itself
XFREE (MTYPE_GRAPH_NODE, node);
@@ -104,6 +112,19 @@ graph_add_edge (struct graph_node *from, struct graph_node *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
diff --git a/lib/graph.h b/lib/graph.h
index b6a03b938a..8d8aa3823b 100644
--- a/lib/graph.h
+++ b/lib/graph.h
@@ -64,6 +64,7 @@ graph_new_node (struct graph *graph, void *data, void (*del) (void*));
* If *data and *del are non-null, the following call is made:
* (*node->del) (node->data);
*
+ * @param[in] graph the graph this node belongs to
* @param[out] node pointer to node to delete
*/
void
@@ -80,8 +81,16 @@ struct graph_node *
graph_add_edge (struct graph_node *from, struct graph_node *to);
/**
- * Deletes a graph.
+ * Removes a directed edge between two nodes.
*
+ * @param[in] from
+ * @param[in] to
+ */
+void
+graph_remove_edge (struct graph_node *from, struct graph_node *to);
+
+/**
+ * Deletes a graph.
* Calls graph_delete_node on each node before freeing the graph struct itself.
*
* @param graph the graph to delete