LCOV - code coverage report
Current view: top level - libpkg - pkghash.c (source / functions) Hit Total Coverage
Test: plop Lines: 102 119 85.7 %
Date: 2024-12-28 18:40:32 Functions: 11 12 91.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 42 52 80.8 %

           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                 :            : #ifndef STREQ
      35                 :            : #define STREQ(s1, s2) (strcmp(s1, s2) == 0)
      36                 :            : #endif
      37                 :            : 
      38                 :            : struct pkghash {
      39                 :            :         pkghash_entry *entries;
      40                 :            :         size_t capacity;
      41                 :            :         size_t count;
      42                 :            :         size_t index;
      43                 :            : };
      44                 :            : 
      45                 :            : pkghash *
      46                 :       2076 : pkghash_new(void)
      47                 :            : {
      48                 :       2076 :         pkghash *table = xmalloc(sizeof(pkghash));
      49                 :       2076 :         table->count = 0;
      50                 :       2076 :         table->capacity = 128;
      51                 :            : 
      52                 :       2076 :         table->entries = xcalloc(table->capacity, sizeof(pkghash_entry));
      53                 :       2076 :         return (table);
      54                 :            : }
      55                 :            : 
      56                 :            : void
      57                 :      16902 : pkghash_destroy(pkghash *table)
      58                 :            : {
      59         [ +  + ]:      16902 :         if (table == NULL)
      60                 :      15000 :                 return;
      61                 :            : 
      62         [ +  + ]:     325102 :         for (size_t i = 0; i < table->capacity; i++) {
      63         [ +  + ]:     323200 :                 if (table->entries[i].key != NULL)
      64                 :      31030 :                         free(table->entries[i].key);
      65         [ +  - ]:     323200 :                 if (table->entries[i].free_func != NULL)
      66                 :          0 :                         table->entries[i].free_func(table->entries[i].value);
      67                 :     323200 :         }
      68                 :       1902 :         free(table->entries);
      69                 :       1902 :         free(table);
      70                 :      16902 : }
      71                 :            : 
      72                 :            : pkghash_entry *
      73                 :      35090 : pkghash_get(pkghash *table, const char *key)
      74                 :            : {
      75         [ +  + ]:      35090 :         if (table == NULL)
      76                 :       2079 :                 return (NULL);
      77                 :      33011 :         uint64_t hash = mum_hash(key, strlen(key), 0);
      78                 :      33011 :         size_t index = (size_t)(hash & (uint64_t)(table->capacity -1));
      79                 :            : 
      80         [ +  + ]:      52036 :         while (table->entries[index].key != NULL) {
      81         [ +  + ]:      21787 :                 if (STREQ(key, table->entries[index].key))
      82                 :       2762 :                         return (&table->entries[index]);
      83                 :      19025 :                 index++;
      84         [ +  - ]:      19025 :                 if (index >= table->capacity)
      85                 :          0 :                         index = 0;
      86                 :            :         }
      87                 :      30249 :         return (NULL);
      88                 :      35090 : }
      89                 :            : 
      90                 :            : void *
      91                 :       4501 : pkghash_get_value(pkghash *table, const char *key)
      92                 :            : {
      93                 :            :         pkghash_entry *e;
      94                 :            : 
      95                 :       4501 :         e = pkghash_get(table, key);
      96         [ +  + ]:       4501 :         return (e != NULL ? e->value : NULL);
      97                 :            : 
      98                 :            : }
      99                 :            : 
     100                 :            : static bool
     101                 :      71142 : pkghash_set_entry(pkghash_entry *entries, size_t capacity,
     102                 :            :     const char *key, void *value, size_t *pcount, void (*free_func)(void *)) {
     103                 :      71142 :         uint64_t hash = mum_hash(key, strlen(key), 0);
     104                 :      71142 :         size_t index = (size_t)(hash & (uint64_t)(capacity - 1));
     105                 :            : 
     106         [ +  + ]:      95560 :         while (entries[index].key != NULL) {
     107         [ -  + ]:      24418 :                 if (STREQ(key, entries[index].key))
     108                 :          0 :                         return (false);
     109                 :      24418 :                 index++;
     110         [ +  - ]:      24418 :                 if (index >= capacity)
     111                 :          0 :                         index = 0;
     112                 :            :         }
     113                 :            : 
     114         [ +  + ]:      71142 :         if (pcount != NULL) {
     115                 :      31270 :                 key = xstrdup(key);
     116                 :      31270 :                 (*pcount)++;
     117                 :      31270 :         }
     118                 :      71142 :         entries[index].key = (char *)key;
     119                 :      71142 :         entries[index].value = value;
     120                 :      71142 :         entries[index].free_func = free_func;
     121                 :      71142 :         return (true);
     122                 :      71142 : }
     123                 :            : 
     124                 :            : static bool
     125                 :        267 : pkghash_expand(pkghash *table)
     126                 :            : {
     127                 :        267 :         size_t new_capacity = table->capacity * 2;
     128         [ -  + ]:        267 :         if (new_capacity < table->capacity)
     129                 :          0 :                 return (false);
     130                 :        267 :         pkghash_entry *new_entries = xcalloc(new_capacity, sizeof(pkghash_entry));
     131                 :            : 
     132         [ +  + ]:      80011 :         for (size_t i = 0; i < table->capacity; i++) {
     133                 :      79744 :                 pkghash_entry entry = table->entries[i];
     134         [ +  + ]:      79744 :                 if (entry.key != NULL)
     135                 :      79744 :                         pkghash_set_entry(new_entries, new_capacity, entry.key,
     136                 :      39872 :                             entry.value, NULL, entry.free_func);
     137                 :      79744 :         }
     138                 :            : 
     139                 :        267 :         free(table->entries);
     140                 :        267 :         table->entries = new_entries;
     141                 :        267 :         table->capacity = new_capacity;
     142                 :        267 :         return (true);
     143                 :        267 : }
     144                 :            : 
     145                 :            : bool
     146                 :      31270 : pkghash_add(pkghash *table, const char *key, void *value, void (*free_func)(void *))
     147                 :            : {
     148   [ +  +  +  - ]:      31270 :         if (table->count * 2 >= table->capacity && !pkghash_expand(table))
     149                 :          0 :                 return (false);
     150                 :            : 
     151                 :      62540 :         return (pkghash_set_entry(table->entries, table->capacity, key, value,
     152                 :      31270 :             &table->count, free_func));
     153                 :      31270 : }
     154                 :            : 
     155                 :            : size_t
     156                 :        930 : pkghash_count(pkghash *table)
     157                 :            : {
     158         [ +  + ]:        930 :         if (table == NULL)
     159                 :        596 :                 return (0);
     160                 :        334 :         return (table->count);
     161                 :        930 : }
     162                 :            : 
     163                 :            : pkghash_it
     164                 :       4534 : pkghash_iterator(pkghash *table)
     165                 :            : {
     166                 :            :         pkghash_it it;
     167                 :       4534 :         it._table = table;
     168                 :       4534 :         it._index = 0;
     169                 :       4534 :         return (it);
     170                 :            : }
     171                 :            : 
     172                 :            : bool
     173                 :       7721 : pkghash_next(pkghash_it *it)
     174                 :            : {
     175                 :       7721 :         pkghash *table = it->_table;
     176         [ +  + ]:       7721 :         if (table == NULL)
     177                 :       2773 :                 return (false);
     178         [ +  + ]:       4948 :         if (table->count == 0)
     179                 :          2 :                 return (false);
     180         [ +  + ]:     226390 :         while (it->_index < table->capacity) {
     181                 :     224640 :                 size_t i = it->_index;
     182                 :     224640 :                 it->_index++;
     183         [ +  + ]:     224640 :                 if (table->entries[i].key != NULL) {
     184                 :       3196 :                         pkghash_entry entry = table->entries[i];
     185                 :       3196 :                         it->key = entry.key;
     186                 :       3196 :                         it->value = entry.value;
     187                 :       3196 :                         return (true);
     188                 :            :                 }
     189                 :            :         }
     190                 :       1750 :         return (false);
     191                 :       7721 : }
     192                 :            : 
     193                 :            : bool
     194                 :         55 : pkghash_del(pkghash *h, const char *key)
     195                 :            : {
     196                 :         55 :         pkghash_entry *e = pkghash_get(h, key);
     197         [ +  - ]:         55 :         if (e == NULL)
     198                 :          0 :                 return (false);
     199                 :         55 :         free(e->key);
     200                 :         55 :         e->key = NULL;
     201         [ +  - ]:         55 :         if (e->free_func != NULL)
     202                 :          0 :                 e->free_func(e->value);
     203                 :         55 :         h->count--;
     204                 :         55 :         return (true);
     205                 :         55 : }
     206                 :            : 
     207                 :            : void *
     208                 :          0 : pkghash_delete(pkghash *h, const char *key)
     209                 :            : {
     210                 :          0 :         pkghash_entry *e = pkghash_get(h, key);
     211         [ #  # ]:          0 :         if (e == NULL)
     212                 :          0 :                 return (NULL);
     213                 :          0 :         free(e->key);
     214                 :          0 :         e->key = NULL;
     215                 :          0 :         h->count--;
     216                 :          0 :         return (e->value);
     217                 :          0 : }

Generated by: LCOV version 1.15