]> git.proxmox.com Git - mirror_frr.git/blame - lib/graph.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / lib / graph.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
16d7c050
QY
2/*
3 * Graph data structure.
4 *
5 * --
6 * Copyright (C) 2016 Cumulus Networks, Inc.
16d7c050
QY
7 */
8#include <zebra.h>
1eb5e8dc 9#include "graph.h"
16d7c050 10#include "memory.h"
58f8a9ec 11#include "buffer.h"
16d7c050 12
bf8d3d6a
DL
13DEFINE_MTYPE_STATIC(LIB, GRAPH, "Graph");
14DEFINE_MTYPE_STATIC(LIB, GRAPH_NODE, "Graph Node");
4d762f26 15struct graph *graph_new(void)
1eb5e8dc 16{
d62a17ae 17 struct graph *graph = XCALLOC(MTYPE_GRAPH, sizeof(struct graph));
18 graph->nodes = vector_init(VECTOR_MIN_SIZE);
1eb5e8dc 19
d62a17ae 20 return graph;
1eb5e8dc 21}
16d7c050 22
9428e089
QY
23void graph_delete_graph(struct graph *graph)
24{
25 for (unsigned int i = vector_active(graph->nodes); i--; /**/)
26 graph_delete_node(graph, vector_slot(graph->nodes, i));
27
28 vector_free(graph->nodes);
29 XFREE(MTYPE_GRAPH, graph);
30}
31
d62a17ae 32struct graph_node *graph_new_node(struct graph *graph, void *data,
33 void (*del)(void *))
16d7c050 34{
d62a17ae 35 struct graph_node *node =
36 XCALLOC(MTYPE_GRAPH_NODE, sizeof(struct graph_node));
16d7c050 37
d62a17ae 38 node->from = vector_init(VECTOR_MIN_SIZE);
39 node->to = vector_init(VECTOR_MIN_SIZE);
40 node->data = data;
41 node->del = del;
16d7c050 42
d62a17ae 43 vector_set(graph->nodes, node);
16d7c050 44
d62a17ae 45 return node;
16d7c050
QY
46}
47
62bece44 48static void graph_vector_remove(vector v, unsigned int ix)
ba06a3a0 49{
d62a17ae 50 if (ix >= v->active)
51 return;
52
53 /* v->active is guaranteed >= 1 because ix can't be lower than 0
54 * and v->active is > ix. */
55 v->active--;
56 /* if ix == v->active--, we set the item to itself, then to NULL...
214d8a60 57 * still correct, no check necessary. */
d62a17ae 58 v->index[ix] = v->index[v->active];
59 v->index[v->active] = NULL;
ba06a3a0
QY
60}
61
d62a17ae 62void graph_delete_node(struct graph *graph, struct graph_node *node)
16d7c050 63{
d62a17ae 64 if (!node)
65 return;
66
67 // an adjacent node
68 struct graph_node *adj;
69
70 // remove all edges from other nodes to us
71 for (unsigned int i = vector_active(node->from); i--; /**/) {
72 adj = vector_slot(node->from, i);
73 graph_remove_edge(adj, node);
74 }
75
76 // remove all edges from us to other nodes
77 for (unsigned int i = vector_active(node->to); i--; /**/) {
78 adj = vector_slot(node->to, i);
79 graph_remove_edge(node, adj);
80 }
81
82 // if there is a deletion callback, call it
83 if (node->del && node->data)
84 (*node->del)(node->data);
85
86 // free adjacency lists
87 vector_free(node->to);
88 vector_free(node->from);
89
90 // remove node from graph->nodes
91 for (unsigned int i = vector_active(graph->nodes); i--; /**/)
92 if (vector_slot(graph->nodes, i) == node) {
62bece44 93 graph_vector_remove(graph->nodes, i);
d62a17ae 94 break;
95 }
96
97 // free the node itself
98 XFREE(MTYPE_GRAPH_NODE, node);
16d7c050
QY
99}
100
d62a17ae 101struct graph_node *graph_add_edge(struct graph_node *from,
102 struct graph_node *to)
16d7c050 103{
d62a17ae 104 vector_set(from->to, to);
105 vector_set(to->from, from);
106 return to;
16d7c050
QY
107}
108
d62a17ae 109void graph_remove_edge(struct graph_node *from, struct graph_node *to)
ba06a3a0 110{
d62a17ae 111 // remove from from to->from
112 for (unsigned int i = vector_active(to->from); i--; /**/)
113 if (vector_slot(to->from, i) == from) {
62bece44 114 graph_vector_remove(to->from, i);
d62a17ae 115 break;
116 }
117 // remove to from from->to
118 for (unsigned int i = vector_active(from->to); i--; /**/)
119 if (vector_slot(from->to, i) == to) {
62bece44 120 graph_vector_remove(from->to, i);
d62a17ae 121 break;
122 }
ba06a3a0
QY
123}
124
9428e089 125struct graph_node *graph_find_node(struct graph *graph, void *data)
16d7c050 126{
9428e089 127 struct graph_node *g;
16d7c050 128
9428e089
QY
129 for (unsigned int i = vector_active(graph->nodes); i--; /**/) {
130 g = vector_slot(graph->nodes, i);
131 if (g->data == data)
132 return g;
133 }
134
135 return NULL;
136}
137
138bool graph_has_edge(struct graph_node *from, struct graph_node *to)
139{
140 for (unsigned int i = vector_active(from->to); i--; /**/)
141 if (vector_slot(from->to, i) == to)
142 return true;
143
144 return false;
16d7c050 145}
58f8a9ec
QY
146
147static void _graph_dfs(struct graph *graph, struct graph_node *start,
148 vector visited,
149 void (*dfs_cb)(struct graph_node *, void *), void *arg)
150{
151 /* check that we have not visited this node */
152 for (unsigned int i = 0; i < vector_active(visited); i++) {
153 if (start == vector_slot(visited, i))
154 return;
155 }
156
157 /* put this node in visited stack */
158 vector_ensure(visited, vector_active(visited));
159 vector_set_index(visited, vector_active(visited), start);
160
161 /* callback */
162 dfs_cb(start, arg);
163
164 /* recurse into children */
165 for (unsigned int i = vector_active(start->to); i--; /**/) {
166 struct graph_node *c = vector_slot(start->to, i);
167
168 _graph_dfs(graph, c, visited, dfs_cb, arg);
169 }
170}
171
172void graph_dfs(struct graph *graph, struct graph_node *start,
173 void (*dfs_cb)(struct graph_node *, void *), void *arg)
174{
175 vector visited = vector_init(VECTOR_MIN_SIZE);
176
177 _graph_dfs(graph, start, visited, dfs_cb, arg);
178 vector_free(visited);
179}
180
181#ifndef BUILDING_CLIPPY
182
183void graph_dump_dot_default_print_cb(struct graph_node *gn, struct buffer *buf)
184{
185 char nbuf[64];
186
187 for (unsigned int i = 0; i < vector_active(gn->to); i++) {
188 struct graph_node *adj = vector_slot(gn->to, i);
189
190 snprintf(nbuf, sizeof(nbuf), " n%p -> n%p;\n", gn, adj);
191 buffer_putstr(buf, nbuf);
192 }
193}
194
195char *graph_dump_dot(struct graph *graph, struct graph_node *start,
196 void (*pcb)(struct graph_node *, struct buffer *))
197{
198 struct buffer *buf = buffer_new(0);
199 char *ret;
200
201 pcb = (pcb) ? pcb : graph_dump_dot_default_print_cb;
202 buffer_putstr(buf, "digraph {\n");
203
204 graph_dfs(graph, start, (void (*)(struct graph_node *, void *))pcb,
205 buf);
206
207 buffer_putstr(buf, "}\n");
208
209 ret = buffer_getstr(buf);
210 buffer_free(buf);
211
212 return ret;
213}
214
215#endif /* BUILDING_CLIPPY */