2 * Graph data structure.
5 * Copyright (C) 2016 Cumulus Networks, Inc.
7 * This file is part of GNU Zebra.
9 * GNU Zebra is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2, or (at your option) any
14 * GNU Zebra is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 DEFINE_MTYPE_STATIC(LIB
, GRAPH
, "Graph");
29 DEFINE_MTYPE_STATIC(LIB
, GRAPH_NODE
, "Graph Node");
30 struct graph
*graph_new(void)
32 struct graph
*graph
= XCALLOC(MTYPE_GRAPH
, sizeof(struct graph
));
33 graph
->nodes
= vector_init(VECTOR_MIN_SIZE
);
38 void graph_delete_graph(struct graph
*graph
)
40 for (unsigned int i
= vector_active(graph
->nodes
); i
--; /**/)
41 graph_delete_node(graph
, vector_slot(graph
->nodes
, i
));
43 vector_free(graph
->nodes
);
44 XFREE(MTYPE_GRAPH
, graph
);
47 struct graph_node
*graph_new_node(struct graph
*graph
, void *data
,
50 struct graph_node
*node
=
51 XCALLOC(MTYPE_GRAPH_NODE
, sizeof(struct graph_node
));
53 node
->from
= vector_init(VECTOR_MIN_SIZE
);
54 node
->to
= vector_init(VECTOR_MIN_SIZE
);
58 vector_set(graph
->nodes
, node
);
63 static void graph_vector_remove(vector v
, unsigned int ix
)
68 /* v->active is guaranteed >= 1 because ix can't be lower than 0
69 * and v->active is > ix. */
71 /* if ix == v->active--, we set the item to itself, then to NULL...
72 * still correct, no check necessary. */
73 v
->index
[ix
] = v
->index
[v
->active
];
74 v
->index
[v
->active
] = NULL
;
77 void graph_delete_node(struct graph
*graph
, struct graph_node
*node
)
83 struct graph_node
*adj
;
85 // remove all edges from other nodes to us
86 for (unsigned int i
= vector_active(node
->from
); i
--; /**/) {
87 adj
= vector_slot(node
->from
, i
);
88 graph_remove_edge(adj
, node
);
91 // remove all edges from us to other nodes
92 for (unsigned int i
= vector_active(node
->to
); i
--; /**/) {
93 adj
= vector_slot(node
->to
, i
);
94 graph_remove_edge(node
, adj
);
97 // if there is a deletion callback, call it
98 if (node
->del
&& node
->data
)
99 (*node
->del
)(node
->data
);
101 // free adjacency lists
102 vector_free(node
->to
);
103 vector_free(node
->from
);
105 // remove node from graph->nodes
106 for (unsigned int i
= vector_active(graph
->nodes
); i
--; /**/)
107 if (vector_slot(graph
->nodes
, i
) == node
) {
108 graph_vector_remove(graph
->nodes
, i
);
112 // free the node itself
113 XFREE(MTYPE_GRAPH_NODE
, node
);
116 struct graph_node
*graph_add_edge(struct graph_node
*from
,
117 struct graph_node
*to
)
119 vector_set(from
->to
, to
);
120 vector_set(to
->from
, from
);
124 void graph_remove_edge(struct graph_node
*from
, struct graph_node
*to
)
126 // remove from from to->from
127 for (unsigned int i
= vector_active(to
->from
); i
--; /**/)
128 if (vector_slot(to
->from
, i
) == from
) {
129 graph_vector_remove(to
->from
, i
);
132 // remove to from from->to
133 for (unsigned int i
= vector_active(from
->to
); i
--; /**/)
134 if (vector_slot(from
->to
, i
) == to
) {
135 graph_vector_remove(from
->to
, i
);
140 struct graph_node
*graph_find_node(struct graph
*graph
, void *data
)
142 struct graph_node
*g
;
144 for (unsigned int i
= vector_active(graph
->nodes
); i
--; /**/) {
145 g
= vector_slot(graph
->nodes
, i
);
153 bool graph_has_edge(struct graph_node
*from
, struct graph_node
*to
)
155 for (unsigned int i
= vector_active(from
->to
); i
--; /**/)
156 if (vector_slot(from
->to
, i
) == to
)
162 static void _graph_dfs(struct graph
*graph
, struct graph_node
*start
,
164 void (*dfs_cb
)(struct graph_node
*, void *), void *arg
)
166 /* check that we have not visited this node */
167 for (unsigned int i
= 0; i
< vector_active(visited
); i
++) {
168 if (start
== vector_slot(visited
, i
))
172 /* put this node in visited stack */
173 vector_ensure(visited
, vector_active(visited
));
174 vector_set_index(visited
, vector_active(visited
), start
);
179 /* recurse into children */
180 for (unsigned int i
= vector_active(start
->to
); i
--; /**/) {
181 struct graph_node
*c
= vector_slot(start
->to
, i
);
183 _graph_dfs(graph
, c
, visited
, dfs_cb
, arg
);
187 void graph_dfs(struct graph
*graph
, struct graph_node
*start
,
188 void (*dfs_cb
)(struct graph_node
*, void *), void *arg
)
190 vector visited
= vector_init(VECTOR_MIN_SIZE
);
192 _graph_dfs(graph
, start
, visited
, dfs_cb
, arg
);
193 vector_free(visited
);
196 #ifndef BUILDING_CLIPPY
198 void graph_dump_dot_default_print_cb(struct graph_node
*gn
, struct buffer
*buf
)
202 for (unsigned int i
= 0; i
< vector_active(gn
->to
); i
++) {
203 struct graph_node
*adj
= vector_slot(gn
->to
, i
);
205 snprintf(nbuf
, sizeof(nbuf
), " n%p -> n%p;\n", gn
, adj
);
206 buffer_putstr(buf
, nbuf
);
210 char *graph_dump_dot(struct graph
*graph
, struct graph_node
*start
,
211 void (*pcb
)(struct graph_node
*, struct buffer
*))
213 struct buffer
*buf
= buffer_new(0);
216 pcb
= (pcb
) ? pcb
: graph_dump_dot_default_print_cb
;
217 buffer_putstr(buf
, "digraph {\n");
219 graph_dfs(graph
, start
, (void (*)(struct graph_node
*, void *))pcb
,
222 buffer_putstr(buf
, "}\n");
224 ret
= buffer_getstr(buf
);
230 #endif /* BUILDING_CLIPPY */