LCOV - code coverage report
Current view: top level - lib - shash.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 108 124 87.1 %
Date: 2016-09-14 01:02:56 Functions: 25 29 86.2 %
Branches: 32 52 61.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #include "openvswitch/shash.h"
      19                 :            : #include "hash.h"
      20                 :            : 
      21                 :            : static struct shash_node *shash_find__(const struct shash *,
      22                 :            :                                        const char *name, size_t name_len,
      23                 :            :                                        size_t hash);
      24                 :            : 
      25                 :            : static size_t
      26                 :   44071513 : hash_name(const char *name)
      27                 :            : {
      28                 :   44071513 :     return hash_string(name, 0);
      29                 :            : }
      30                 :            : 
      31                 :            : void
      32                 :   10637025 : shash_init(struct shash *sh)
      33                 :            : {
      34                 :   10637025 :     hmap_init(&sh->map);
      35                 :   10637025 : }
      36                 :            : 
      37                 :            : void
      38                 :   10506441 : shash_destroy(struct shash *sh)
      39                 :            : {
      40         [ +  + ]:   10506441 :     if (sh) {
      41                 :   10505148 :         shash_clear(sh);
      42                 :   10505148 :         hmap_destroy(&sh->map);
      43                 :            :     }
      44                 :   10506441 : }
      45                 :            : 
      46                 :            : /* Like shash_destroy(), but also free() each node's 'data'. */
      47                 :            : void
      48                 :      97562 : shash_destroy_free_data(struct shash *sh)
      49                 :            : {
      50         [ +  - ]:      97562 :     if (sh) {
      51                 :      97562 :         shash_clear_free_data(sh);
      52                 :      97562 :         hmap_destroy(&sh->map);
      53                 :            :     }
      54                 :      97562 : }
      55                 :            : 
      56                 :            : void
      57                 :      11708 : shash_swap(struct shash *a, struct shash *b)
      58                 :            : {
      59                 :      11708 :     hmap_swap(&a->map, &b->map);
      60                 :      11708 : }
      61                 :            : 
      62                 :            : void
      63                 :       6569 : shash_moved(struct shash *sh)
      64                 :            : {
      65                 :       6569 :     hmap_moved(&sh->map);
      66                 :       6569 : }
      67                 :            : 
      68                 :            : void
      69                 :   10506748 : shash_clear(struct shash *sh)
      70                 :            : {
      71                 :            :     struct shash_node *node, *next;
      72                 :            : 
      73 [ +  + ][ -  + ]:   12108210 :     SHASH_FOR_EACH_SAFE (node, next, sh) {
                 [ +  + ]
      74                 :    1601462 :         hmap_remove(&sh->map, &node->node);
      75                 :    1601462 :         free(node->name);
      76                 :    1601462 :         free(node);
      77                 :            :     }
      78                 :   10506748 : }
      79                 :            : 
      80                 :            : /* Like shash_clear(), but also free() each node's 'data'. */
      81                 :            : void
      82                 :      98835 : shash_clear_free_data(struct shash *sh)
      83                 :            : {
      84                 :            :     struct shash_node *node, *next;
      85                 :            : 
      86 [ +  + ][ -  + ]:     236162 :     SHASH_FOR_EACH_SAFE (node, next, sh) {
                 [ +  + ]
      87                 :     137327 :         hmap_remove(&sh->map, &node->node);
      88                 :     137327 :         free(node->data);
      89                 :     137327 :         free(node->name);
      90                 :     137327 :         free(node);
      91                 :            :     }
      92                 :      98835 : }
      93                 :            : 
      94                 :            : bool
      95                 :     167617 : shash_is_empty(const struct shash *shash)
      96                 :            : {
      97                 :     167617 :     return hmap_is_empty(&shash->map);
      98                 :            : }
      99                 :            : 
     100                 :            : size_t
     101                 :    1663254 : shash_count(const struct shash *shash)
     102                 :            : {
     103                 :    1663254 :     return hmap_count(&shash->map);
     104                 :            : }
     105                 :            : 
     106                 :            : static struct shash_node *
     107                 :   26165699 : shash_add_nocopy__(struct shash *sh, char *name, const void *data, size_t hash)
     108                 :            : {
     109                 :   26165699 :     struct shash_node *node = xmalloc(sizeof *node);
     110                 :   26165699 :     node->name = name;
     111                 :   26165699 :     node->data = CONST_CAST(void *, data);
     112                 :   26165699 :     hmap_insert(&sh->map, &node->node, hash);
     113                 :   26165699 :     return node;
     114                 :            : }
     115                 :            : 
     116                 :            : /* It is the caller's responsibility to avoid duplicate names, if that is
     117                 :            :  * desirable. */
     118                 :            : struct shash_node *
     119                 :    2632000 : shash_add_nocopy(struct shash *sh, char *name, const void *data)
     120                 :            : {
     121                 :    2632000 :     return shash_add_nocopy__(sh, name, data, hash_name(name));
     122                 :            : }
     123                 :            : 
     124                 :            : /* It is the caller's responsibility to avoid duplicate names, if that is
     125                 :            :  * desirable. */
     126                 :            : struct shash_node *
     127                 :    2631267 : shash_add(struct shash *sh, const char *name, const void *data)
     128                 :            : {
     129                 :    2631267 :     return shash_add_nocopy(sh, xstrdup(name), data);
     130                 :            : }
     131                 :            : 
     132                 :            : bool
     133                 :    1631906 : shash_add_once(struct shash *sh, const char *name, const void *data)
     134                 :            : {
     135         [ +  - ]:    1631906 :     if (!shash_find(sh, name)) {
     136                 :    1631906 :         shash_add(sh, name, data);
     137                 :    1631906 :         return true;
     138                 :            :     } else {
     139                 :          0 :         return false;
     140                 :            :     }
     141                 :            : }
     142                 :            : 
     143                 :            : void
     144                 :    1416063 : shash_add_assert(struct shash *sh, const char *name, const void *data)
     145                 :            : {
     146                 :    1416063 :     bool added OVS_UNUSED = shash_add_once(sh, name, data);
     147         [ -  + ]:    1416063 :     ovs_assert(added);
     148                 :    1416063 : }
     149                 :            : 
     150                 :            : /* Searches for 'name' in 'sh'.  If it does not already exist, adds it along
     151                 :            :  * with 'data' and returns NULL.  If it does already exist, replaces its data
     152                 :            :  * by 'data' and returns the data that it formerly contained. */
     153                 :            : void *
     154                 :   23533710 : shash_replace(struct shash *sh, const char *name, const void *data)
     155                 :            : {
     156                 :   23533710 :     size_t hash = hash_name(name);
     157                 :            :     struct shash_node *node;
     158                 :            : 
     159                 :   23533710 :     node = shash_find__(sh, name, strlen(name), hash);
     160         [ +  + ]:   23533710 :     if (!node) {
     161                 :   23533699 :         shash_add_nocopy__(sh, xstrdup(name), data, hash);
     162                 :   23533699 :         return NULL;
     163                 :            :     } else {
     164                 :         11 :         void *old_data = node->data;
     165                 :         11 :         node->data = CONST_CAST(void *, data);
     166                 :         11 :         return old_data;
     167                 :            :     }
     168                 :            : }
     169                 :            : 
     170                 :            : /* Deletes 'node' from 'sh' and frees the node's name.  The caller is still
     171                 :            :  * responsible for freeing the node's data, if necessary. */
     172                 :            : void
     173                 :   23810401 : shash_delete(struct shash *sh, struct shash_node *node)
     174                 :            : {
     175                 :   23810401 :     free(shash_steal(sh, node));
     176                 :   23810401 : }
     177                 :            : 
     178                 :            : /* Deletes 'node' from 'sh'.  Neither the node's name nor its data is freed;
     179                 :            :  * instead, ownership is transferred to the caller.  Returns the node's
     180                 :            :  * name. */
     181                 :            : char *
     182                 :   23810401 : shash_steal(struct shash *sh, struct shash_node *node)
     183                 :            : {
     184                 :   23810401 :     char *name = node->name;
     185                 :            : 
     186                 :   23810401 :     hmap_remove(&sh->map, &node->node);
     187                 :   23810401 :     free(node);
     188                 :   23810401 :     return name;
     189                 :            : }
     190                 :            : 
     191                 :            : static struct shash_node *
     192                 :   41439513 : shash_find__(const struct shash *sh, const char *name, size_t name_len,
     193                 :            :              size_t hash)
     194                 :            : {
     195                 :            :     struct shash_node *node;
     196                 :            : 
     197 [ +  + ][ -  + ]:   41439513 :     HMAP_FOR_EACH_WITH_HASH (node, node, hash, &sh->map) {
     198 [ +  - ][ +  - ]:   13499916 :         if (!strncmp(node->name, name, name_len) && !node->name[name_len]) {
     199                 :   13499916 :             return node;
     200                 :            :         }
     201                 :            :     }
     202                 :   27939597 :     return NULL;
     203                 :            : }
     204                 :            : 
     205                 :            : /* If there are duplicates, returns a random element. */
     206                 :            : struct shash_node *
     207                 :   17905803 : shash_find(const struct shash *sh, const char *name)
     208                 :            : {
     209                 :   17905803 :     return shash_find__(sh, name, strlen(name), hash_name(name));
     210                 :            : }
     211                 :            : 
     212                 :            : /* Finds and returns a shash_node within 'sh' that has the given 'name' that is
     213                 :            :  * exactly 'len' bytes long.  Returns NULL if no node in 'sh' has that name. */
     214                 :            : struct shash_node *
     215                 :          0 : shash_find_len(const struct shash *sh, const char *name, size_t len)
     216                 :            : {
     217                 :          0 :     return shash_find__(sh, name, len, hash_bytes(name, len, 0));
     218                 :            : }
     219                 :            : 
     220                 :            : void *
     221                 :   15408001 : shash_find_data(const struct shash *sh, const char *name)
     222                 :            : {
     223                 :   15408001 :     struct shash_node *node = shash_find(sh, name);
     224         [ +  + ]:   15408001 :     return node ? node->data : NULL;
     225                 :            : }
     226                 :            : 
     227                 :            : void *
     228                 :     503650 : shash_find_and_delete(struct shash *sh, const char *name)
     229                 :            : {
     230                 :     503650 :     struct shash_node *node = shash_find(sh, name);
     231         [ +  + ]:     503650 :     if (node) {
     232                 :     314601 :         void *data = node->data;
     233                 :     314601 :         shash_delete(sh, node);
     234                 :     314601 :         return data;
     235                 :            :     } else {
     236                 :     189049 :         return NULL;
     237                 :            :     }
     238                 :            : }
     239                 :            : 
     240                 :            : void *
     241                 :          0 : shash_find_and_delete_assert(struct shash *sh, const char *name)
     242                 :            : {
     243                 :          0 :     void *data = shash_find_and_delete(sh, name);
     244         [ #  # ]:          0 :     ovs_assert(data != NULL);
     245                 :          0 :     return data;
     246                 :            : }
     247                 :            : 
     248                 :            : struct shash_node *
     249                 :         29 : shash_first(const struct shash *shash)
     250                 :            : {
     251                 :         29 :     struct hmap_node *node = hmap_first(&shash->map);
     252                 :         29 :     return node ? CONTAINER_OF(node, struct shash_node, node) : NULL;
     253                 :            : }
     254                 :            : 
     255                 :            : static int
     256                 :     105737 : compare_nodes_by_name(const void *a_, const void *b_)
     257                 :            : {
     258                 :     105737 :     const struct shash_node *const *a = a_;
     259                 :     105737 :     const struct shash_node *const *b = b_;
     260                 :     105737 :     return strcmp((*a)->name, (*b)->name);
     261                 :            : }
     262                 :            : 
     263                 :            : const struct shash_node **
     264                 :      10554 : shash_sort(const struct shash *sh)
     265                 :            : {
     266         [ +  + ]:      10554 :     if (shash_is_empty(sh)) {
     267                 :        114 :         return NULL;
     268                 :            :     } else {
     269                 :            :         const struct shash_node **nodes;
     270                 :            :         struct shash_node *node;
     271                 :            :         size_t i, n;
     272                 :            : 
     273                 :      10440 :         n = shash_count(sh);
     274                 :      10440 :         nodes = xmalloc(n * sizeof *nodes);
     275                 :      10440 :         i = 0;
     276 [ +  + ][ -  + ]:      63031 :         SHASH_FOR_EACH (node, sh) {
     277                 :      52591 :             nodes[i++] = node;
     278                 :            :         }
     279         [ -  + ]:      10440 :         ovs_assert(i == n);
     280                 :            : 
     281                 :      10440 :         qsort(nodes, n, sizeof *nodes, compare_nodes_by_name);
     282                 :            : 
     283                 :      10440 :         return nodes;
     284                 :            :     }
     285                 :            : }
     286                 :            : 
     287                 :            : /* Returns true if 'a' and 'b' contain the same keys (regardless of their
     288                 :            :  * values), false otherwise. */
     289                 :            : bool
     290                 :          0 : shash_equal_keys(const struct shash *a, const struct shash *b)
     291                 :            : {
     292                 :            :     struct shash_node *node;
     293                 :            : 
     294         [ #  # ]:          0 :     if (hmap_count(&a->map) != hmap_count(&b->map)) {
     295                 :          0 :         return false;
     296                 :            :     }
     297 [ #  # ][ #  # ]:          0 :     SHASH_FOR_EACH (node, a) {
     298         [ #  # ]:          0 :         if (!shash_find(b, node->name)) {
     299                 :          0 :             return false;
     300                 :            :         }
     301                 :            :     }
     302                 :          0 :     return true;
     303                 :            : }
     304                 :            : 
     305                 :            : /* Chooses and returns a randomly selected node from 'sh', which must not be
     306                 :            :  * empty.
     307                 :            :  *
     308                 :            :  * I wouldn't depend on this algorithm to be fair, since I haven't analyzed it.
     309                 :            :  * But it does at least ensure that any node in 'sh' can be chosen. */
     310                 :            : struct shash_node *
     311                 :          0 : shash_random_node(struct shash *sh)
     312                 :            : {
     313                 :          0 :     return CONTAINER_OF(hmap_random_node(&sh->map), struct shash_node, node);
     314                 :            : }

Generated by: LCOV version 1.12