back to topotato report
topotato coverage report
Current view: top level - lib - graph.c (source / functions) Hit Total Coverage
Test: test_bgp_dont_capability_negotiate.py::BGPDontCapabilityNegotiate Lines: 58 98 59.2 %
Date: 2023-02-24 18:37:16 Functions: 11 17 64.7 %

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

Generated by: LCOV version v1.16-topotato