About Docs Source
LCOV - code coverage report
Current view: top level - src/lib/crater - hash.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 233 263 88.6 %
Date: 2024-02-13 04:57:17 Functions: 29 30 96.7 %

          Line data    Source code
       1             : #define _POSIX_C_SOURCE  200809L
       2             : #include <stdlib.h>
       3             : #include <string.h>
       4             : #include <inttypes.h>
       5             : #include <math.h>
       6             : 
       7             : #include <crater/hash.h>
       8             : 
       9             : //these are the prime infimums of powers of two in the uint64_t range so which one to use can be calculated by a bit scan (__builtin_clzll() aka bsfq)
      10             : uint64_t exp_primes[64] = {0UL, 3UL, 7UL, 13UL, 31UL, 61UL, 127UL, 251UL, 509UL, 1021UL, 2039UL, 4093UL, 8191UL, 16381UL, 32749UL, 65537UL, 131071UL, 262139UL, 524287UL, 1048573UL,
      11             :     2097143UL, 4194301UL, 8388593UL, 16777213UL, 33554393UL, 67108859UL, 134217689UL, 268435399UL, 536870909UL, 1073741789UL, 2147483647UL, 4294967291UL, 8589934583UL, 17179869143UL,
      12             :     34359738337UL, 68719476731UL, 137438953447UL, 274877906899UL, 549755813881UL, 1099511627689UL, 2199023255531UL, 4398046511093UL, 8796093022151UL, 17592186044399UL,
      13             :     35184372088777UL, 70368744177643UL, 140737488355213UL, 281474976710597UL, 562949953421231UL, 1125899906842597UL, 2251799813685119UL, 4503599627370449UL, 9007199254740881UL,
      14             :     18014398509481951UL, 36028797018963913UL, 72057594037927931UL, 144115188075855859UL, 288230376151711717UL, 576460752303423433UL, 1152921504606846883UL, 2305843009213693951UL,
      15             :     4611686018427387847UL, 9223372036854775783UL, 18446744073709551557UL};
      16             : 
      17             : 
      18             : const uint64_t cr8r_hash_u64_prime = 536870909;
      19             : 
      20             : CR8R_ATTR_NO_SAN("unsigned-integer-overflow")
      21     1358044 : uint64_t cr8r_default_hash_u64(const cr8r_base_ft *ft, const void *_a){
      22     1358044 :     uint64_t a = *(const uint64_t*)_a;
      23     1358044 :     unsigned __int128 prod = a*((unsigned __int128)cr8r_hash_u64_prime);
      24     1358044 :     return (uint64_t)(prod >> 64) ^ (uint64_t)prod;
      25             : }
      26             : 
      27             : CR8R_ATTR_NO_SAN("unsigned-integer-overflow")
      28        2398 : uint64_t cr8r_default_hash(const cr8r_base_ft *ft, const void *_a){
      29        2398 :     const char *a = _a;
      30        2398 :     uint64_t h = 5381;
      31       21582 :     for(uint64_t i = 0; i < ft->size; ++i){
      32       19184 :         h = 31*h + a[i];
      33             :     }
      34        2398 :     return h;
      35             : }
      36             : 
      37             : CR8R_ATTR_NO_SAN("unsigned-integer-overflow")
      38       93911 : uint64_t cr8r_default_hash_cstr(const cr8r_base_ft *ft, const void *_a){
      39       93911 :     const char *a = *(const char**)_a;
      40       93911 :     uint64_t h = 5381;
      41      549289 :     for(char c = *a; c; c = *++a){
      42      455378 :         h = 31*h + c;
      43             :     }
      44       93911 :     return h;
      45             : }
      46             : 
      47  1029731407 : int cr8r_default_cmp_u64(const cr8r_base_ft *ft, const void *_a, const void *_b){
      48  1029731407 :     uint64_t a = *(const uint64_t*)_a, b = *(const uint64_t*)_b;
      49  1029731407 :     if(a < b){
      50             :         return -1;
      51   553537207 :     }else if(a == b){
      52   188575859 :         return 0;
      53             :     }
      54             :     return 1;
      55             : }
      56             : 
      57         147 : int cr8r_default_cmp_i64(const cr8r_base_ft *ft, const void *_a, const void *_b){
      58         147 :     int64_t a = *(const int64_t*)_a, b = *(const int64_t*)_b;
      59         147 :     if(a < b){
      60             :         return -1;
      61          50 :     }else if(a == b){
      62           7 :         return 0;
      63             :     }
      64             :     return 1;
      65             : }
      66             : 
      67        6143 : int cr8r_default_cmp_u8(const cr8r_base_ft *ft, const void *_a, const void *_b){
      68        6143 :     uint8_t a = *(const uint8_t*)_a, b = *(const uint8_t*)_b;
      69        6143 :     if(a < b){
      70             :         return -1;
      71        3145 :     }else if(a == b){
      72         480 :         return 0;
      73             :     }
      74             :     return 1;
      75             : }
      76             : 
      77      838239 : int cr8r_default_cmp_cstr(const cr8r_base_ft *ft, const void *_a, const void *_b){
      78      838239 :     return strcmp(*(const char**)_a, *(const char**)_b);
      79             : }
      80             : 
      81       42232 : int cr8r_default_replace(cr8r_base_ft *ft, void *_a, void *_b){
      82       42232 :     memcpy(_a, _b, ft->size);
      83       42232 :     return 1;
      84             : }
      85             : 
      86        7051 : void cr8r_default_free(cr8r_base_ft *ft, void *_p){
      87        7051 :     free(*(void**)_p);
      88        7051 : }
      89             : 
      90           0 : void cr8r_default_copy_cstr(cr8r_base_ft *ft, void *dest, const void *src){
      91           0 :     *(char**)dest = strdup(*(const char**)src);
      92           0 : }
      93             : 
      94             : cr8r_hashtbl_ft cr8r_htft_u64_void = {
      95             :     .base = {
      96             :         .data = NULL,
      97             :         .size = sizeof(uint64_t)
      98             :     },
      99             :     .hash = cr8r_default_hash_u64,
     100             :     .cmp = cr8r_default_cmp_u64,
     101             :     .load_factor = .7
     102             : };
     103             : 
     104             : cr8r_hashtbl_ft cr8r_htft_cstr_u64 = {
     105             :     .base.data = NULL,
     106             :     .base.size = sizeof(cr8r_htent_cstr_u64),
     107             :     .hash = cr8r_default_hash_cstr,
     108             :     .cmp = cr8r_default_cmp_cstr,
     109             :     .load_factor = .5
     110             : };
     111             : 
     112             : cr8r_hashtbl_ft cr8r_htft_u64_u64 = {
     113             :     .base.data = NULL,
     114             :     .base.size = 2*sizeof(uint64_t),
     115             :     .hash = cr8r_default_hash_u64,
     116             :     .cmp = cr8r_default_cmp_u64,
     117             :     .load_factor = .7
     118             : };
     119             : 
     120           1 : bool cr8r_hash_ft_init(cr8r_hashtbl_ft *ft,
     121             :     void *data, uint64_t size,
     122             :     uint64_t (*hash)(const cr8r_base_ft*, const void*),
     123             :     int (*cmp)(const cr8r_base_ft*, const void*, const void*),
     124             :     int (*add)(cr8r_base_ft*, void*, void*),
     125             :     void (*del)(cr8r_base_ft*, void*)
     126             : ){
     127           1 :     if(!hash || !cmp){
     128             :         return 0;
     129             :     }
     130           1 :     ft->base.data = data;
     131           1 :     ft->base.size = size;
     132           1 :     ft->hash = hash;
     133           1 :     ft->cmp = cmp;
     134           1 :     ft->add = add;
     135           1 :     ft->del = del;
     136           1 :     return 1;
     137             : }
     138             : 
     139             : 
     140          37 : int cr8r_hash_init(cr8r_hashtbl_t *self, const cr8r_hashtbl_ft *ft, uint64_t reserve){
     141          37 :     *self = (cr8r_hashtbl_t){};
     142          37 :     if(!reserve){
     143             :         return 1;
     144             :     }
     145          37 :     uint64_t i = 64 - __builtin_clzll(reserve - 1);
     146          37 :     self->len_a = exp_primes[i];
     147          37 :     self->table_a = calloc(ft->base.size, self->len_a);
     148          37 :     if(!self->table_a){
     149             :         return 0;
     150             :     }
     151          37 :     self->flags_a = calloc(sizeof(uint64_t), ((self->len_a - 1) >> 5) + 1);
     152          37 :     if(!self->flags_a){
     153           0 :         free(self->table_a);
     154           0 :         self->table_a = NULL;
     155           0 :         return 0;
     156             :     }
     157          37 :     self->cap = self->len_a*(long double)ft->load_factor;
     158          37 :     return 1;
     159             : }
     160             : 
     161       31909 : inline static uint64_t cr8r_hash_find_slot_re(cr8r_hashtbl_t *self, const cr8r_hashtbl_ft *ft, uint64_t a){
     162       45493 :     for(uint64_t j = 0, i; j < self->len_a; ++j){
     163       45493 :         i = (a + (j&1 ? j*j : self->len_a - j*j%self->len_a))%self->len_a;
     164       45493 :         uint64_t f = (self->flags_a[i >> 5] >> (i&0x1F))&0x100000001ULL;
     165       45493 :         if(!(f&0x100000000ULL)){
     166             :             return i;
     167             :         }
     168             :     }
     169             :     return ~0ULL;
     170             : }
     171             : 
     172     1368306 : inline static uint64_t cr8r_hash_find_slot_ap(cr8r_hashtbl_t *self, const cr8r_hashtbl_ft *ft, const void *key){
     173     1368306 :     uint64_t a = ft->hash(&ft->base,key) % self->len_a;
     174     1471732 :     for(uint64_t j = 0, i; j < self->len_a; ++j){
     175     1471732 :         i = (a + (j&1 ? j*j : self->len_a - j*j%self->len_a))%self->len_a;
     176     1471732 :         uint64_t f = (self->flags_a[i >> 5] >> (i&0x1F))&0x100000001ULL;
     177     1471732 :         if(!(f&0x100000000ULL && ft->cmp(&ft->base, key, self->table_a + i*ft->base.size))){
     178     1368306 :             return i;
     179             :         }
     180             :     }
     181             :     return ~0ULL;
     182             : }
     183             : 
     184          13 : inline static int cr8r_hash_ix_start(cr8r_hashtbl_t *self, const cr8r_hashtbl_ft *ft){
     185          13 :     uint64_t i = self->len_a ? 64 - __builtin_clzll(self->len_a - 1) : 1;
     186          13 :     uint64_t new_len = exp_primes[i];
     187          13 :     void *new_table = calloc(ft->base.size, new_len);
     188          13 :     if(!new_table){
     189             :         return 0;
     190             :     }
     191          13 :     uint64_t *new_flags = calloc(sizeof(uint64_t), ((new_len - 1) >> 5) + 1);
     192          13 :     if(!new_flags){
     193           0 :         free(new_table);
     194           0 :         return 0;
     195             :     }
     196          13 :     uint64_t new_cap = new_len*(double)ft->load_factor;
     197             :     //we currently have full entries and can fit new_cap before resizing.  This means we must move full/(new_cap - full)
     198             :     //entries on average per insertion.  Because full == cap + 1, new_cap == new_len*load_factor, cap == len_a*load_factor,
     199             :     //and new_len == len_a*growth_factor, full/(new_cap - full) ~~ cap/(new_cap - cap) ~~ len_a/(new_len - len_a)
     200             :     //~~ len_a/(len_a*growth_factor - len_a) ~~ 1/(growth_factor - 1).  I picked the largest prime number before each power
     201             :     //of 2 so full/(new_cap - full) is very close to 1.  It is always less than 2 so I might just use 2 instead of r
     202             :     #ifdef DEBUG
     203          13 :     if(self->table_b){
     204           0 :         abort();
     205             :     }
     206             :     #endif
     207          13 :     self->table_b = self->table_a;
     208          13 :     self->table_a = new_table;
     209          13 :     self->flags_b = self->flags_a;
     210          13 :     self->flags_a = new_flags;
     211          13 :     self->len_b = self->len_a;
     212          13 :     self->len_a = new_len;
     213          13 :     self->cap = new_cap;
     214          13 :     self->r = ceill((self->full + 1.)/(new_cap - self->full - 1.));
     215          13 :     self->i = 0;
     216          13 :     return 1;
     217             : }
     218             : 
     219       21012 : inline static void cr8r_hash_ix_move(cr8r_hashtbl_t *self, const cr8r_hashtbl_ft *ft, uint64_t n){
     220       21012 :     uint64_t b = self->i;
     221       71178 :     for(uint64_t a; b < self->len_b; ++b){
     222       71167 :         uint64_t f = (self->flags_b[b >> 5] >> (b&0x1F))&0x100000001ULL;
     223       71167 :         if(!(f&0x100000000ULL)){
     224       39258 :             continue;
     225             :         }
     226       31909 :         void *ent = self->table_b + b*ft->base.size;
     227       31909 :         a = ft->hash(&ft->base,ent) % self->len_a;
     228       31909 :         a = cr8r_hash_find_slot_re(self, ft, a);
     229       31909 :         memcpy(self->table_a + a*ft->base.size, ent, ft->base.size);
     230       31909 :         self->flags_b[b >> 5] |= 0x1ULL << (b&0x1F);
     231       31909 :         self->flags_b[b >> 5] &= ~(0x100000000ULL << (b&0x1F));
     232       31909 :         self->flags_a[a >> 5] |= 0x100000000ULL << (a&0x1F);
     233       31909 :         self->flags_a[a >> 5] &= ~(0x1ULL << (a&0x1F));
     234       31909 :         if(!--n){
     235             :             break;
     236             :         }
     237             :     }
     238       21012 :     self->i = b;
     239       21012 :     if(b == self->len_b){
     240          11 :         free(self->table_b);
     241          11 :         free(self->flags_b);
     242          11 :         self->table_b = NULL;
     243          11 :         self->flags_b = NULL;
     244          11 :         self->len_b = 0;
     245          11 :         self->i = 0;
     246             :     }
     247       21012 : }
     248             : 
     249      220326 : inline static uint64_t cr8r_hash_get_index(void *table, uint64_t *flags, uint64_t len, uint64_t a, const cr8r_hashtbl_ft *ft, const void *key){
     250      220326 :     a %= len;
     251      323950 :     for(uint64_t j = 0, i; j < len; ++j){
     252      323950 :         i = (a + (j&1 ? j*j : len - j*j%len))%len;
     253      323950 :         uint64_t f = (flags[i >> 5] >> (i&0x1F))&0x100000001ULL;
     254      323950 :         if(!f){
     255             :             return ~0ULL;
     256             :         }
     257      282738 :         if(f&0x100000000ULL && !ft->cmp(&ft->base, key, table + i*ft->base.size)){
     258             :             return i;
     259             :         }
     260             :     }
     261             :     return ~0ULL;
     262             : }
     263             : 
     264      175967 : inline static void *cr8r_hash_get_single_a(cr8r_hashtbl_t *self, uint64_t i, const cr8r_hashtbl_ft *ft, const void *key){
     265      175967 :     uint64_t a = cr8r_hash_get_index(self->table_a, self->flags_a, self->len_a, i, ft, key);
     266      175967 :     return (~a) ? self->table_a + a*ft->base.size : NULL;
     267             : }
     268             : 
     269       43564 : inline static void *cr8r_hash_get_single_b(cr8r_hashtbl_t *self, uint64_t i, const cr8r_hashtbl_ft *ft, const void *key){
     270       43564 :     uint64_t b = cr8r_hash_get_index(self->table_b, self->flags_b, self->len_b, i, ft, key);
     271       43564 :     return (~b) ? self->table_b + b*ft->base.size : NULL;
     272             : }
     273             : 
     274       29114 : inline static void *cr8r_hash_get_split(cr8r_hashtbl_t *self, const cr8r_hashtbl_ft *ft, const void *key){
     275       29114 :     uint64_t i = ft->hash(&ft->base,key);
     276       29114 :     if(self->i << 1 < self->len_b){
     277       27508 :         return cr8r_hash_get_single_a(self, i, ft, key) ?: cr8r_hash_get_single_b(self, i, ft, key);
     278             :     }
     279        1606 :     return cr8r_hash_get_single_b(self, i, ft, key) ?: cr8r_hash_get_single_a(self, i, ft, key);
     280             : }
     281             : 
     282      175967 : void *cr8r_hash_get(cr8r_hashtbl_t *self, const cr8r_hashtbl_ft *ft, const void *key){
     283      175967 :     if(!self->table_a){
     284             :         return NULL;
     285             :     }
     286      175967 :     return self->table_b ? cr8r_hash_get_split(self, ft, key) : cr8r_hash_get_single_a(self, ft->hash(&ft->base,key), ft, key);
     287             : }
     288             : 
     289      155928 : void *cr8r_hash_insert(cr8r_hashtbl_t *self, const cr8r_hashtbl_ft *ft, const void *key, int *_status){
     290      155928 :     void *ret = NULL;
     291      155928 :     int status = 0;
     292      155928 :     if(self->full == self->cap){
     293           7 :         if(!cr8r_hash_ix_start(self, ft)){
     294           0 :             if(_status){
     295           0 :                 *_status = 0;
     296             :             }
     297           0 :             return NULL;
     298             :         }
     299             :     }
     300      155928 :     if(self->table_b){
     301       15260 :         cr8r_hash_ix_move(self, ft, self->r);
     302       15260 :         if(self->table_b){
     303       15255 :             if(cr8r_hash_get_single_b(self, ft->hash(&ft->base,key), ft, key)){
     304           0 :                 if(_status){
     305           0 :                     *_status = 2;
     306             :                 }
     307           0 :                 return NULL;
     308             :             }
     309             :         }
     310             :     }
     311      155928 :     uint64_t i = cr8r_hash_find_slot_ap(self, ft, key);
     312      155928 :     if(!~i){
     313           0 :         if(_status){
     314           0 :             *_status = 0;
     315             :         }
     316           0 :         return NULL;
     317             :     }
     318      155928 :     if((self->flags_a[i >> 5] >> (i&0x1F))&0x100000000ULL){
     319             :         status = 2;
     320             :     }else{
     321      121409 :         ret = self->table_a + i*ft->base.size;
     322      121409 :         memcpy(ret, key, ft->base.size);
     323      121409 :         self->flags_a[i >> 5] |= 0x100000000ULL << (i&0x1F);
     324      121409 :         self->flags_a[i >> 5] &= ~(0x1ULL << (i&0x1F));
     325      121409 :         ++self->full;
     326      121409 :         status = 1;
     327             :     }
     328      155928 :     if(_status){
     329       51013 :         *_status = status;
     330             :     }
     331             :     return ret;
     332             : }
     333             : 
     334     1214903 : void *cr8r_hash_append(cr8r_hashtbl_t *self, cr8r_hashtbl_ft *ft, void *key, int *_status){
     335     1214903 :     void *ret = NULL;
     336     1214903 :     int status = 0;
     337     1214903 :     if(self->full == self->cap){
     338           6 :         if(!cr8r_hash_ix_start(self, ft)){
     339           0 :             if(_status){
     340           0 :                 *_status = 0;
     341             :             }
     342           0 :             return NULL;
     343             :         }
     344             :     }
     345     1214903 :     if(self->table_b){
     346        5752 :         cr8r_hash_ix_move(self, ft, self->r);
     347        5752 :         if(self->table_b){
     348        5746 :             if((ret = cr8r_hash_get_single_b(self, ft->hash(&ft->base,key), ft, key))){
     349        2525 :                 status = ft->add(&ft->base,ret, key) ? 2 : 0;
     350        2525 :                 if(_status){
     351        2525 :                     *_status = status;
     352             :                 }
     353        2525 :                 return ret;
     354             :             }
     355             :         }
     356             :     }
     357     1212378 :     uint64_t i = cr8r_hash_find_slot_ap(self, ft, key);
     358     1212378 :     if(!~i){
     359           0 :         if(_status){
     360           0 :             *_status = 0;
     361             :         }
     362           0 :         return NULL;
     363             :     }
     364     1212378 :     ret = self->table_a + i*ft->base.size;
     365     1212378 :     if((self->flags_a[i >> 5] >> (i&0x1F))&0x100000000ULL){
     366      108058 :         status = ft->add(&ft->base,ret, key) ? 2 : 0;
     367             :     }else{
     368     1104320 :         memcpy(ret, key, ft->base.size);
     369     1104320 :         self->flags_a[i >> 5] |= 0x100000000ULL << (i&0x1F);
     370     1104320 :         self->flags_a[i >> 5] &= ~(0x1ULL << (i&0x1F));
     371     1104320 :         ++self->full;
     372     1104320 :         status = 1;
     373             :     }
     374     1212378 :     if(_status){
     375       72803 :         *_status = status;
     376             :     }
     377             :     return ret;
     378             : }
     379             : 
     380         788 : inline static int cr8r_hash_remove_single_a(cr8r_hashtbl_t *self, uint64_t i, cr8r_hashtbl_ft *ft, const void *key){
     381         788 :     uint64_t a = cr8r_hash_get_index(self->table_a, self->flags_a, self->len_a, i, ft, key);
     382         788 :     if(!~a){
     383             :         return 0;
     384             :     }
     385         711 :     self->flags_a[a >> 5] ^= 0x100000001ULL << (a&0x1F);
     386         711 :     --self->full;
     387         711 :     if(ft->del){
     388           0 :         ft->del(&ft->base, self->table_a + a*ft->base.size);
     389             :     }
     390             :     return 1;
     391             : }
     392             : 
     393           7 : inline static int cr8r_hash_remove_single_b(cr8r_hashtbl_t *self, uint64_t i, cr8r_hashtbl_ft *ft, const void *key){
     394           7 :     uint64_t b = cr8r_hash_get_index(self->table_b, self->flags_b, self->len_b, i, ft, key);
     395           7 :     if(!~b){
     396             :         return 0;
     397             :     }
     398           7 :     self->flags_b[b >> 5] ^= 0x100000001ULL << (b&0x1F);
     399           7 :     --self->full;
     400           7 :     if(ft->del){
     401           0 :         ft->del(&ft->base, self->table_b + b*ft->base.size);
     402             :     }
     403             :     return 1;
     404             : }
     405             : 
     406           7 : inline static int cr8r_hash_remove_split(cr8r_hashtbl_t *self, cr8r_hashtbl_ft *ft, const void *key){
     407           7 :     uint64_t i = ft->hash(&ft->base,key);
     408           7 :     if(self->i << 1 < self->len_b){
     409           5 :         return cr8r_hash_remove_single_a(self, i, ft, key) ?: cr8r_hash_remove_single_b(self, i, ft, key);
     410             :     }
     411           2 :     return cr8r_hash_remove_single_b(self, i, ft, key) ?: cr8r_hash_remove_single_a(self, i, ft, key);
     412             : }
     413             : 
     414         790 : int cr8r_hash_remove(cr8r_hashtbl_t *self, cr8r_hashtbl_ft *ft, const void *key){
     415         790 :     if(!self->table_a){
     416             :         return 0;
     417             :     }
     418         790 :     return self->table_b ? cr8r_hash_remove_split(self, ft, key) : cr8r_hash_remove_single_a(self, ft->hash(&ft->base,key), ft, key);
     419             : }
     420             : 
     421        1976 : void cr8r_hash_delete(cr8r_hashtbl_t *self, cr8r_hashtbl_ft *ft, void *ent){
     422        1976 :     if(self->table_a <= ent && ent < self->table_a + self->len_a*ft->base.size){
     423        1975 :         uint64_t i = (ent - self->table_a)/ft->base.size;
     424        1975 :         self->flags_a[i >> 5] ^= 0x100000001ULL << (i&0x1F);
     425             :     }else{
     426           1 :         uint64_t i = (ent - self->table_b)/ft->base.size;
     427           1 :         self->flags_b[i >> 5] ^= 0x100000001ULL << (i&0x1F);
     428             :     }
     429        1976 :     --self->full;
     430        1976 :     if(ft->del){
     431           0 :         ft->del(&ft->base,ent);
     432             :     }
     433        1976 : }
     434             : 
     435          33 : void cr8r_hash_clear(cr8r_hashtbl_t *self, cr8r_hashtbl_ft *ft){
     436          33 :     if(ft->del){
     437       81920 :         for(uint64_t a = 0; a < self->len_a; ++a){
     438       81918 :             uint64_t f = (self->flags_a[a >> 5] >> (a&0x1F))&0x100000001ULL;
     439       81918 :             if(f&0x100000000ULL){
     440       14777 :                 ft->del(&ft->base, self->table_a + a*ft->base.size);
     441             :             }
     442             :         }
     443           2 :         for(uint64_t b = 0; b < self->len_b; ++b){
     444           0 :             uint64_t f = (self->flags_b[b >> 5] >> (b&0x1F))&0x100000001ULL;
     445           0 :             if(f&0x100000000ULL){
     446           0 :                 ft->del(&ft->base, self->table_b + b*ft->base.size);
     447             :             }
     448             :         }
     449             :     }
     450          33 :     free(self->table_b);
     451          33 :     self->table_b = NULL;
     452          33 :     free(self->flags_b);
     453          33 :     self->flags_b = NULL;
     454          33 :     self->len_b = 0;
     455          33 :     memset(self->flags_a, 0, (((self->len_a - 1) >> 5) + 1)*sizeof(uint64_t));
     456          33 :     self->full = 0;
     457          33 : }
     458             : 
     459          33 : void cr8r_hash_destroy(cr8r_hashtbl_t *self, cr8r_hashtbl_ft *ft){
     460          33 :     cr8r_hash_clear(self, ft);
     461          33 :     free(self->table_a);
     462          33 :     self->table_a = NULL;
     463          33 :     free(self->flags_a);
     464          33 :     self->flags_a = NULL;
     465          33 :     self->len_a = 0;
     466          33 :     self->cap = 0;
     467          33 : }
     468             : 

Generated by: LCOV version 1.14