LCOV - code coverage report
Current view: top level - libpkg - pkghash.c (source / functions) Hit Total Coverage
Test: rapport Lines: 105 138 76.1 %
Date: 2021-12-10 16:22:55 Functions: 11 14 78.6 %
Branches: 45 62 72.6 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * Copyright (c) 2021 Baptiste Daroussin <bapt@FreeBSD.org>
       3                 :            :  *
       4                 :            :  * Redistribution and use in source and binary forms, with or without
       5                 :            :  * modification, are permitted provided that the following conditions
       6                 :            :  * are met:
       7                 :            :  * 1. Redistributions of source code must retain the above copyright
       8                 :            :  *    notice, this list of conditions and the following disclaimer
       9                 :            :  *    in this position and unchanged.
      10                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      11                 :            :  *    notice, this list of conditions and the following disclaimer in the
      12                 :            :  *    documentation and/or other materials provided with the distribution.
      13                 :            :  *
      14                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      15                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      16                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      17                 :            :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      18                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      19                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      20                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      21                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      22                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      23                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      24                 :            :  */
      25                 :            : 
      26                 :            : #include "pkghash.h"
      27                 :            : 
      28                 :            : #include <stdint.h>
      29                 :            : #include <stdlib.h>
      30                 :            : #include <string.h>
      31                 :            : #include <mum.h>
      32                 :            : #include <xmalloc.h>
      33                 :            : 
      34                 :            : struct pkghash {
      35                 :            :         pkghash_entry *entries;
      36                 :            :         size_t capacity;
      37                 :            :         size_t count;
      38                 :            :         size_t index;
      39                 :            : };
      40                 :            : 
      41                 :            : pkghash *
      42                 :      12683 : pkghash_new(void)
      43                 :            : {
      44                 :      12683 :         pkghash *table = xmalloc(sizeof(pkghash));
      45                 :      12683 :         table->count = 0;
      46                 :      12683 :         table->capacity = 128;
      47                 :            : 
      48                 :      12683 :         table->entries = xcalloc(table->capacity, sizeof(pkghash_entry));
      49                 :      12683 :         return (table);
      50                 :            : }
      51                 :            : 
      52                 :            : void
      53                 :      99463 : pkghash_destroy(pkghash *table)
      54                 :            : {
      55         [ +  + ]:      99463 :         if (table == NULL)
      56                 :      87600 :                 return;
      57                 :            : 
      58         [ +  + ]:    6807767 :         for (size_t i = 0; i < table->capacity; i++) {
      59         [ +  + ]:    6795904 :                 if (table->entries[i].key != NULL)
      60                 :    5234424 :                         free(table->entries[i].key);
      61         [ +  + ]:    6795904 :                 if (table->entries[i].free_func != NULL)
      62                 :    5217662 :                         table->entries[i].free_func(table->entries[i].value);
      63                 :    6795904 :         }
      64                 :      11863 :         free(table->entries);
      65                 :      11863 :         free(table);
      66                 :      99463 : }
      67                 :            : 
      68                 :            : pkghash_entry *
      69                 :   10493761 : pkghash_get(pkghash *table, const char *key)
      70                 :            : {
      71         [ +  + ]:   10493761 :         if (table == NULL)
      72                 :      12497 :                 return (NULL);
      73                 :   10481264 :         uint64_t hash = mum_hash(key, strlen(key), 0);
      74                 :   10481264 :         size_t index = (size_t)(hash & (uint64_t)(table->capacity -1));
      75                 :            : 
      76         [ +  + ]:  372571289 :         while (table->entries[index].key != NULL) {
      77         [ +  + ]:  362128399 :                 if (strcmp(key, table->entries[index].key) == 0)
      78                 :      38374 :                         return (&table->entries[index]);
      79                 :  362090025 :                 index++;
      80         [ +  + ]:  362090025 :                 if (index >= table->capacity)
      81                 :     401660 :                         index = 0;
      82                 :            :         }
      83                 :   10442890 :         return (NULL);
      84                 :   10493761 : }
      85                 :            : 
      86                 :            : void *
      87                 :      16296 : pkghash_get_value(pkghash *table, const char *key)
      88                 :            : {
      89                 :            :         pkghash_entry *e;
      90                 :            : 
      91                 :      16296 :         e = pkghash_get(table, key);
      92         [ +  + ]:      16296 :         return (e != NULL ? e->value : NULL);
      93                 :            : 
      94                 :            : }
      95                 :            : 
      96                 :            : static bool
      97                 :   10506263 : pkghash_set_entry(pkghash_entry *entries, size_t capacity,
      98                 :            :     const char *key, void *value, size_t *pcount, void (*free_func)(void *)) {
      99                 :   10506263 :         uint64_t hash = mum_hash(key, strlen(key), 0);
     100                 :   10506263 :         size_t index = (size_t)(hash & (uint64_t)(capacity - 1));
     101                 :            : 
     102         [ +  + ]:  189976622 :         while (entries[index].key != NULL) {
     103         [ +  - ]:  179470359 :                 if (strcmp(key, entries[index].key) == 0)
     104                 :          0 :                         return (false);
     105                 :  179470359 :                 index++;
     106         [ +  + ]:  179470359 :                 if (index >= capacity)
     107                 :     195510 :                         index = 0;
     108                 :            :         }
     109                 :            : 
     110         [ +  + ]:   10506263 :         if (pcount != NULL) {
     111                 :    5235473 :                 key = xstrdup(key);
     112                 :    5235473 :                 (*pcount)++;
     113                 :    5235473 :         }
     114                 :   10506263 :         entries[index].key = (char *)key;
     115                 :   10506263 :         entries[index].value = value;
     116                 :   10506263 :         entries[index].free_func = free_func;
     117                 :   10506263 :         return (true);
     118                 :   10506263 : }
     119                 :            : 
     120                 :            : static bool
     121                 :       6650 : pkghash_expand(pkghash *table)
     122                 :            : {
     123                 :       6650 :         size_t new_capacity = table->capacity * 2;
     124         [ -  + ]:       6650 :         if (new_capacity < table->capacity)
     125                 :          0 :                 return (false);
     126                 :       6650 :         pkghash_entry *new_entries = xcalloc(new_capacity, sizeof(pkghash_entry));
     127                 :            : 
     128         [ +  + ]:    5284090 :         for (size_t i = 0; i < table->capacity; i++) {
     129                 :    5277440 :                 pkghash_entry entry = table->entries[i];
     130         [ +  + ]:    5277440 :                 if (entry.key != NULL)
     131                 :   10541580 :                         pkghash_set_entry(new_entries, new_capacity, entry.key,
     132                 :    5270790 :                             entry.value, NULL, entry.free_func);
     133                 :    5277440 :         }
     134                 :            : 
     135                 :       6650 :         free(table->entries);
     136                 :       6650 :         table->entries = new_entries;
     137                 :       6650 :         table->capacity = new_capacity;
     138                 :       6650 :         return (true);
     139                 :       6650 : }
     140                 :            : 
     141                 :            : bool
     142                 :    5235473 : pkghash_add(pkghash *table, const char *key, void *value, void (*free_func)(void *))
     143                 :            : {
     144   [ +  +  +  - ]:    5235473 :         if (table->count >= table->capacity -1 && !pkghash_expand(table))
     145                 :          0 :                 return (NULL);
     146                 :            : 
     147                 :   10470946 :         return (pkghash_set_entry(table->entries, table->capacity, key, value,
     148                 :    5235473 :             &table->count, free_func));
     149                 :    5235473 : }
     150                 :            : 
     151                 :            : size_t
     152                 :       7739 : pkghash_count(pkghash *table)
     153                 :            : {
     154         [ +  + ]:       7739 :         if (table == 0)
     155                 :       6477 :                 return (0);
     156                 :       1262 :         return (table->count);
     157                 :       7739 : }
     158                 :            : 
     159                 :            : pkghash_it
     160                 :      50999 : pkghash_iterator(pkghash *table)
     161                 :            : {
     162                 :            :         pkghash_it it;
     163                 :      50999 :         it._table = table;
     164                 :      50999 :         it._index = 0;
     165                 :      50999 :         return (it);
     166                 :            : }
     167                 :            : 
     168                 :            : bool
     169                 :      65732 : pkghash_next(pkghash_it *it)
     170                 :            : {
     171                 :      65732 :         pkghash *table = it->_table;
     172         [ +  + ]:      65732 :         if (table == NULL)
     173                 :      40606 :                 return (false);
     174         [ +  + ]:      25126 :         if (table->count == 0)
     175                 :          8 :                 return (false);
     176         [ +  + ]:    1336525 :         while (it->_index < table->capacity) {
     177                 :    1326188 :                 size_t i = it->_index;
     178                 :    1326188 :                 it->_index++;
     179         [ +  + ]:    1326188 :                 if (table->entries[i].key != NULL) {
     180                 :      14781 :                         pkghash_entry entry = table->entries[i];
     181                 :      14781 :                         it->key = entry.key;
     182                 :      14781 :                         it->value = entry.value;
     183                 :      14781 :                         return (true);
     184                 :            :                 }
     185                 :            :         }
     186                 :      10337 :         return (false);
     187                 :      65732 : }
     188                 :            : 
     189                 :            : void
     190                 :          0 : pkghash_loopinit(pkghash *h)
     191                 :            : {
     192         [ #  # ]:          0 :         if (h == NULL)
     193                 :          0 :                 return;
     194                 :          0 :         h->index = 0;
     195                 :          0 : }
     196                 :            : 
     197                 :            : pkghash_entry *
     198                 :          0 : pkghash_inext(pkghash *h)
     199                 :            : {
     200         [ #  # ]:          0 :         if (h == NULL)
     201                 :          0 :                 return (NULL);
     202         [ #  # ]:          0 :         if (h->count == 0) {
     203                 :          0 :                 h->index = 0;
     204                 :          0 :                 return (NULL);
     205                 :            :         }
     206                 :            : 
     207         [ #  # ]:          0 :         while (h->index < h->capacity) {
     208                 :          0 :                 size_t i = h->index;
     209                 :          0 :                 h->index++;
     210         [ #  # ]:          0 :                 if (h->entries[i].key != NULL)
     211                 :          0 :                         return (&h->entries[i]);
     212                 :            :         }
     213                 :            :         /* rewind just in case */
     214                 :          0 :         h->index = 0;
     215                 :          0 :         return (NULL);
     216                 :          0 : }
     217                 :            : 
     218                 :            : bool
     219                 :        145 : pkghash_del(pkghash *h, const char *key)
     220                 :            : {
     221                 :        145 :         pkghash_entry *e = pkghash_get(h, key);
     222         [ -  + ]:        145 :         if (e == NULL)
     223                 :          0 :                 return (false);
     224                 :        145 :         free(e->key);
     225                 :        145 :         e->key = NULL;
     226         [ +  - ]:        145 :         if (e->free_func != NULL)
     227                 :          0 :                 e->free_func(e->value);
     228                 :        145 :         h->count--;
     229                 :        145 :         return (true);
     230                 :        145 : }
     231                 :            : 
     232                 :            : void *
     233                 :          0 : pkghash_delete(pkghash *h, const char *key)
     234                 :            : {
     235                 :          0 :         pkghash_entry *e = pkghash_get(h, key);
     236         [ #  # ]:          0 :         if (e == NULL)
     237                 :          0 :                 return (NULL);
     238                 :          0 :         free(e->key);
     239                 :          0 :         e->key = NULL;
     240                 :          0 :         h->count--;
     241                 :          0 :         return (e->value);
     242                 :          0 : }

Generated by: LCOV version 1.15