| /* |
| * Copyright (c) 2015 Cisco and/or its affiliates. |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <vppinfra/graph.h> |
| |
| /* Set link distance, creating link if not found. */ |
| u32 |
| graph_set_link (graph_t * g, u32 src, u32 dst, u32 distance) |
| { |
| graph_node_t *src_node, *dst_node; |
| graph_link_t *l; |
| u32 old_distance; |
| |
| /* The following validate will not work if src or dst are on the |
| pool free list. */ |
| if (src < vec_len (g->nodes)) |
| ASSERT (!pool_is_free_index (g->nodes, src)); |
| if (dst < vec_len (g->nodes)) |
| ASSERT (!pool_is_free_index (g->nodes, dst)); |
| |
| /* Make new (empty) nodes to make src and dst valid. */ |
| pool_validate_index (g->nodes, clib_max (src, dst)); |
| |
| src_node = pool_elt_at_index (g->nodes, src); |
| dst_node = pool_elt_at_index (g->nodes, dst); |
| |
| l = graph_dir_get_link_to_node (&src_node->next, dst); |
| if (l) |
| { |
| old_distance = l->distance; |
| l->distance = distance; |
| |
| l = graph_dir_get_link_to_node (&dst_node->prev, src); |
| l->distance = distance; |
| } |
| else |
| { |
| uword li_next, li_prev; |
| |
| old_distance = ~0; |
| |
| li_next = graph_dir_add_link (&src_node->next, dst, distance); |
| li_prev = graph_dir_add_link (&dst_node->prev, src, distance); |
| |
| l = vec_elt_at_index (src_node->next.links, li_next); |
| l->link_to_self_index = li_prev; |
| |
| l = vec_elt_at_index (dst_node->prev.links, li_prev); |
| l->link_to_self_index = li_next; |
| } |
| |
| return old_distance; |
| } |
| |
| void |
| graph_del_link (graph_t * g, u32 src, u32 dst) |
| { |
| graph_node_t *src_node, *dst_node; |
| |
| src_node = pool_elt_at_index (g->nodes, src); |
| dst_node = pool_elt_at_index (g->nodes, dst); |
| |
| graph_dir_del_link (&src_node->next, dst); |
| graph_dir_del_link (&dst_node->next, src); |
| } |
| |
| /* Delete source node and all links from other nodes from/to source. */ |
| uword |
| graph_del_node (graph_t * g, u32 src) |
| { |
| graph_node_t *src_node, *n; |
| uword index; |
| graph_link_t *l; |
| |
| src_node = pool_elt_at_index (g->nodes, src); |
| |
| vec_foreach (l, src_node->next.links) |
| { |
| n = pool_elt_at_index (g->nodes, l->node_index); |
| graph_dir_del_link (&n->prev, src); |
| } |
| |
| vec_foreach (l, src_node->prev.links) |
| { |
| n = pool_elt_at_index (g->nodes, l->node_index); |
| graph_dir_del_link (&n->next, src); |
| } |
| |
| graph_dir_free (&src_node->next); |
| graph_dir_free (&src_node->prev); |
| |
| index = src_node - g->nodes; |
| pool_put (g->nodes, src_node); |
| clib_memset (src_node, ~0, sizeof (src_node[0])); |
| |
| return index; |
| } |
| |
| uword |
| unformat_graph (unformat_input_t * input, va_list * args) |
| { |
| graph_t *g = va_arg (*args, graph_t *); |
| typedef struct |
| { |
| u32 src, dst, distance; |
| } T; |
| T *links = 0, *l; |
| uword result; |
| |
| while (1) |
| { |
| vec_add2 (links, l, 1); |
| if (!unformat (input, "%d%d%d", &l->src, &l->dst, &l->distance)) |
| break; |
| } |
| _vec_len (links) -= 1; |
| result = vec_len (links) > 0; |
| vec_foreach (l, links) |
| { |
| graph_set_link (g, l->src, l->dst, l->distance); |
| graph_set_link (g, l->dst, l->src, l->distance); |
| } |
| |
| vec_free (links); |
| return result; |
| } |
| |
| u8 * |
| format_graph_node (u8 * s, va_list * args) |
| { |
| graph_t *g = va_arg (*args, graph_t *); |
| u32 node_index = va_arg (*args, u32); |
| |
| if (g->format_node) |
| s = format (s, "%U", g->format_node, g, node_index); |
| else |
| s = format (s, "%d", node_index); |
| |
| return s; |
| } |
| |
| u8 * |
| format_graph (u8 * s, va_list * args) |
| { |
| graph_t *g = va_arg (*args, graph_t *); |
| graph_node_t *n; |
| graph_link_t *l; |
| u32 indent = format_get_indent (s); |
| |
| s = format (s, "graph %d nodes", pool_elts (g->nodes)); |
| /* *INDENT-OFF* */ |
| pool_foreach (n, g->nodes, ({ |
| s = format (s, "\n%U", format_white_space, indent + 2); |
| s = format (s, "%U -> ", format_graph_node, g, n - g->nodes); |
| vec_foreach (l, n->next.links) |
| s = format (s, "%U (%d), ", |
| format_graph_node, g, l->node_index, |
| l->distance); |
| })); |
| /* *INDENT-ON* */ |
| |
| return s; |
| } |
| |
| /* |
| * fd.io coding-style-patch-verification: ON |
| * |
| * Local Variables: |
| * eval: (c-set-style "gnu") |
| * End: |
| */ |