Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is to exceed 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - language - hash.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31042-0fbe168e69) Lines: 91.2 % 250 228
Test Date: 2026-07-23 17:04:59 Functions: 97.5 % 40 39
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2000  The PARI group.
       2              : 
       3              : This file is part of the PARI/GP package.
       4              : 
       5              : PARI/GP is free software; you can redistribute it and/or modify it under the
       6              : terms of the GNU General Public License as published by the Free Software
       7              : Foundation; either version 2 of the License, or (at your option) any later
       8              : version. It is distributed in the hope that it will be useful, but WITHOUT
       9              : ANY WARRANTY WHATSOEVER.
      10              : 
      11              : Check the License for details. You should have received a copy of it, along
      12              : with the package; see the file 'COPYING'. If not, write to the Free Software
      13              : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14              : #include "pari.h"
      15              : #include "paripriv.h"
      16              : 
      17              : /********************************************************************/
      18              : /*                                                                  */
      19              : /*                    GENERAL HASHTABLES                            */
      20              : /*                                                                  */
      21              : /********************************************************************/
      22              : /* http://planetmath.org/encyclopedia/GoodHashTablePrimes.html */
      23              : static const ulong hashprimes[] = {
      24              :   53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613,
      25              :   393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653,
      26              :   100663319, 201326611, 402653189, 805306457, 1610612741
      27              : };
      28              : static const int hashprimes_len = numberof(hashprimes);
      29              : 
      30              : INLINE void
      31        61992 : setlen(hashtable *h, ulong len) {
      32        61992 :   h->maxnb = (ulong)ceil(len * 0.65);
      33        61992 :   h->len  = len;
      34        61992 : }
      35              : 
      36              : static int
      37        57054 : get_prime_index(ulong len)
      38              : {
      39              :   int i;
      40        88334 :   for (i=0; i < hashprimes_len; i++)
      41        88334 :     if (hashprimes[i] > len) return i;
      42            0 :   pari_err_OVERFLOW("hash table [too large]");
      43              :   return -1; /* LCOV_EXCL_LINE */
      44              : }
      45              : 
      46              : /* link hashentry e to hashtable h, setting e->hash / e->next */
      47              : INLINE void
      48      1884108 : hash_link2(hashtable *h, hashentry *e, ulong hash)
      49              : {
      50              :   ulong index;
      51      1884108 :   e->hash = hash; index = e->hash % h->len;
      52      1884108 :   e->next = h->table[index]; h->table[index] = e;
      53      1884108 : }
      54              : INLINE void
      55        16475 : hash_link(hashtable *h, hashentry *e) { hash_link2(h,e,h->hash(e->key));}
      56              : 
      57              : hashtable *
      58        41165 : hash_create(ulong minsize, ulong (*hash)(void*), int (*eq)(void*,void*),
      59              :             int use_stack)
      60              : {
      61        41165 :   hashtable *h = (hashtable*)(use_stack? stack_malloc(sizeof(hashtable))
      62         3815 :                                        : pari_malloc(sizeof(hashtable)));
      63        41165 :   hash_init(h, minsize, hash, eq, use_stack); return h;
      64              : }
      65              : static ulong
      66       760366 : hash_id(void *x) { return (ulong)x; }
      67              : static int
      68       315202 : eq_id(void *x, void *y) { return x == y; }
      69              : hashtable *
      70         1344 : hash_create_ulong(ulong s, long stack)
      71         1344 : { return hash_create(s, &hash_id, &eq_id, stack); }
      72              : hashtable *
      73          259 : hash_create_INT(ulong s, long use_stack)
      74          259 : { return hash_create(s, (ulong(*)(void*))&hash_GEN,
      75              :                         (int(*)(void*,void*))&equalii, use_stack); }
      76              : hashtable *
      77        35075 : hash_create_GEN(ulong s, long use_stack)
      78        35075 : { return hash_create(s, (ulong(*)(void*))&hash_GEN,
      79              :                         (int(*)(void*,void*))&gidentical, use_stack); }
      80              : void
      81        57054 : hash_init(hashtable *h, ulong minsize, ulong (*hash)(void*),
      82              :                                        int (*eq)(void*,void*), int use_stack)
      83              : {
      84        57054 :   int i = get_prime_index(minsize);
      85        57054 :   ulong len = hashprimes[i];
      86        57054 :   if (use_stack)
      87        53239 :     h->table = (hashentry**)stack_calloc(len * sizeof(hashentry*));
      88              :   else
      89         3815 :     h->table = (hashentry**)pari_calloc(len * sizeof(hashentry*));
      90        57054 :   h->use_stack = use_stack;
      91        57054 :   h->pindex = i;
      92        57054 :   h->nb = 0;
      93        57054 :   h->hash = hash;
      94        57054 :   h->eq   = eq;
      95        57054 :   setlen(h, len);
      96        57054 : }
      97              : 
      98              : void
      99        12207 : hash_init_GEN(hashtable *h, ulong minsize, int (*eq)(GEN,GEN), int use_stack)
     100        12207 : { hash_init(h, minsize,(ulong (*)(void*)) hash_GEN,
     101              :                        (int (*)(void*,void*)) eq, use_stack);
     102        12207 : }
     103              : 
     104              : void
     105         3682 : hash_init_ulong(hashtable *h, ulong minsize, int use_stack)
     106         3682 : { hash_init(h, minsize,hash_id, eq_id, use_stack); }
     107              : 
     108              : void
     109      1867633 : hash_insert2(hashtable *h, void *k, void *v, ulong hash)
     110              : {
     111              :   hashentry *e;
     112              :   ulong index;
     113              : 
     114      1867633 :   if (h->use_stack)
     115      1858101 :     e = (hashentry*) stack_malloc(sizeof(hashentry));
     116              :   else
     117         9532 :     e = (hashentry*) pari_malloc(sizeof(hashentry));
     118              : 
     119      1867633 :   if (++(h->nb) > h->maxnb && h->pindex < hashprimes_len-1)
     120              :   { /* double table size */
     121         4938 :     ulong i, newlen = hashprimes[++(h->pindex)];
     122              :     hashentry *E, **newtable;
     123         4938 :     if (h->use_stack)
     124         4938 :       newtable = (hashentry**)stack_calloc(newlen*sizeof(hashentry*));
     125              :     else
     126            0 :       newtable = (hashentry**)pari_calloc(newlen*sizeof(hashentry*));
     127      1492206 :     for (i = 0; i < h->len; i++)
     128      2456913 :       while ( (E = h->table[i]) )
     129              :       {
     130       969645 :         h->table[i] = E->next;
     131       969645 :         index = E->hash % newlen;
     132       969645 :         E->next = newtable[index];
     133       969645 :         newtable[index] = E;
     134              :       }
     135         4938 :     if (!h->use_stack) pari_free(h->table);
     136         4938 :     h->table = newtable;
     137         4938 :     setlen(h, newlen);
     138              :   }
     139      1867633 :   e->key = k;
     140      1867633 :   e->val = v; hash_link2(h, e, hash);
     141      1867633 : }
     142              : void
     143       847632 : hash_insert(hashtable *h, void *k, void *v)
     144       847632 : { hash_insert2(h,k,v,h->hash(k)); }
     145              : 
     146              : void
     147        54599 : hash_insert_long(hashtable *h, void *k, long v)
     148        54599 : { hash_insert2(h,k,(void*)v,h->hash(k)); }
     149              : 
     150              : /* the key 'k' may correspond to different values in the hash, return
     151              :  * one satisfying the selection callback */
     152              : hashentry *
     153           77 : hash_select(hashtable *h, void *k, void *E,int(*select)(void *,hashentry *))
     154              : {
     155           77 :   ulong hash = h->hash(k);
     156           77 :   hashentry *e = h->table[ hash % h->len ];
     157          147 :   while (e)
     158              :   {
     159           91 :     if (hash == e->hash && h->eq(k, e->key) && select(E,e)) return e;
     160           70 :     e = e->next;
     161              :   }
     162           56 :   return NULL;
     163              : }
     164              : 
     165              : GEN
     166         1350 : hash_keys(hashtable *h)
     167              : {
     168         1350 :   long k = 1;
     169              :   ulong i;
     170         1350 :   GEN v = cgetg(h->nb+1, t_VECSMALL);
     171       261060 :   for (i = 0; i < h->len; i++)
     172              :   {
     173       259710 :     hashentry *e = h->table[i];
     174       260883 :     while (e) { v[k++] = (long)e->key; e = e->next; }
     175              :   }
     176         1350 :   return v;
     177              : }
     178              : 
     179              : GEN
     180         3919 : hash_keys_GEN(hashtable *h)
     181              : {
     182         3919 :   long k = 1;
     183              :   ulong i;
     184         3919 :   GEN v = cgetg(h->nb+1, t_VEC);
     185       996028 :   for (i = 0; i < h->len; i++)
     186              :   {
     187       992109 :     hashentry *e = h->table[i];
     188      1418400 :     while (e) { gel(v,k++) = (GEN)e->key; e = e->next; }
     189              :   }
     190         3919 :   return v;
     191              : }
     192              : 
     193              : GEN
     194         2027 : hash_values(hashtable *h)
     195              : {
     196         2027 :   long k = 1;
     197              :   ulong i;
     198         2027 :   GEN v = cgetg(h->nb+1, t_VECSMALL);
     199       393238 :   for (i = 0; i < h->len; i++)
     200              :   {
     201       391211 :     hashentry *e = h->table[i];
     202       399534 :     while (e) { v[k++] = (long)e->val; e = e->next; }
     203              :   }
     204         2027 :   return v;
     205              : }
     206              : 
     207              : GEN
     208          525 : hash_values_GEN(hashtable *h)
     209              : {
     210          525 :   long k = 1;
     211              :   ulong i;
     212          525 :   GEN v = cgetg(h->nb+1, t_VEC);
     213        30870 :   for (i = 0; i < h->len; i++)
     214              :   {
     215        30345 :     hashentry *e = h->table[i];
     216        37646 :     while (e) { gel(v,k++) = (GEN)e->val; e = e->next; }
     217              :   }
     218          525 :   return v;
     219              : }
     220              : 
     221              : /* assume hash = h->hash(k) */
     222              : hashentry *
     223      3663628 : hash_search2(hashtable *h, void *k, ulong hash)
     224              : {
     225      3663628 :   hashentry *e = h->table[ hash % h->len ];
     226      4617808 :   while (e)
     227              :   {
     228      2984227 :     if (hash == e->hash && h->eq(k, e->key)) return e;
     229       954180 :     e = e->next;
     230              :   }
     231      1633581 :   return NULL; /* not found */
     232              : }
     233              : /* returns entry attached to key k or NULL */
     234              : hashentry *
     235      1791619 : hash_search(hashtable *h, void *k)
     236              : {
     237      1791619 :   if (h->nb == 0) return NULL;
     238      1785517 :   return hash_search2(h, k, h->hash(k));
     239              : }
     240              : 
     241              : int
     242       335446 : hash_haskey_long(hashtable *h, void *k, long *v)
     243              : {
     244       335446 :   hashentry * e = hash_search(h, k);
     245       335446 :   if (e) { *v = (long) e->val; return 1; }
     246        48103 :   else return 0;
     247              : }
     248              : 
     249              : GEN
     250       277831 : hash_haskey_GEN(hashtable *h, void *k)
     251              : {
     252       277831 :   hashentry * e = hash_search(h, k);
     253       277831 :   return e ? (GEN) e->val: NULL;
     254              : }
     255              : 
     256              : hashentry *
     257         3010 : hash_remove_select(hashtable *h, void *k, void *E,
     258              :   int (*select)(void*,hashentry*))
     259              : {
     260         3010 :   ulong hash = h->hash(k), index = hash % h->len;
     261         3010 :   hashentry **pE = &(h->table[index]), *e = *pE;
     262         3010 :   while (e)
     263              :   {
     264         3010 :     if (hash == e->hash && h->eq(k, e->key) && select(E,e)) {
     265         3010 :       *pE = e->next; h->nb--;
     266         3010 :       return e;
     267              :     }
     268            0 :     pE = &(e->next);
     269            0 :     e = e->next;
     270              :   }
     271            0 :   return NULL;
     272              : }
     273              : 
     274              : hashentry *
     275           24 : hash_remove(hashtable *h, void *k)
     276              : {
     277           24 :   ulong hash = h->hash(k), index = hash % h->len;
     278           24 :   hashentry **pE = &(h->table[index]), *e = *pE;
     279           24 :   while (e)
     280              :   {
     281           24 :     if (hash == e->hash && h->eq(k, e->key)) {
     282           24 :       *pE = e->next; h->nb--;
     283           24 :       return e;
     284              :     }
     285            0 :     pE = &(e->next);
     286            0 :     e = e->next;
     287              :   }
     288            0 :   return NULL;
     289              : }
     290              : void
     291         3774 : hash_destroy(hashtable *h)
     292              : {
     293              :   ulong i;
     294         3774 :   if (h->use_stack) return;
     295       467976 :   for (i = 0; i < h->len; i++)
     296              :   {
     297       464202 :     hashentry *e = h->table[i];
     298       470684 :     while (e) { hashentry *f = e; e = e->next; pari_free(f); }
     299              :   }
     300         3774 :   pari_free(h->table); pari_free(h);
     301              : }
     302              : 
     303              : static int
     304        15862 : strequal(void *a, void *b) { return !strcmp((char*)a,(char*)b); }
     305              : hashtable *
     306         3815 : hash_create_str(ulong s, long stack)
     307         3815 : { return hash_create(s, (ulong (*)(void *))&hash_str, strequal, stack); }
     308              : 
     309              : hashtable *
     310           25 : hashstr_import_static(hashentry *e, ulong size)
     311              : {
     312           25 :   hashtable *h = hash_create_str(size, 0);
     313        16500 :   for ( ; e->key; e++) { hash_link(h, e); h->nb++; }
     314           25 :   return h;
     315              : }
     316              : 
     317              : void
     318            0 : hash_dbg(hashtable *h)
     319              : {
     320            0 :   ulong n, Total = 0, Max = 0;
     321            0 :   hashentry *e, **table = h->table;
     322            0 :   for (n=0; n < h->len; n++)
     323              :   {
     324            0 :     ulong m=0;
     325            0 :     for (e=table[n]; e; e=e->next) m++;
     326            0 :     Total += m; if (Max < m) Max = m;
     327            0 :     pari_printf("%4ld:%2ld ",n,m);
     328            0 :     if (n%9 == 8) pari_putc('\n');
     329              :   }
     330            0 :   pari_printf("\nTotal = %ld, Max = %ld\n", Total, Max);
     331            0 : }
     332              : 
     333              : /********************************************************************/
     334              : /*                                                                  */
     335              : /*                          HASH FUNCTIONS                          */
     336              : /*                                                                  */
     337              : /********************************************************************/
     338              : 
     339              : INLINE ulong
     340    553237776 : glue(ulong h, ulong a) { return 404936533*h + a; }
     341              : 
     342              : /* asume h, a >= 0 */
     343              : static GEN
     344        10549 : glueb(GEN h, GEN a, long b)
     345        10549 : { return remi2n(addmuliu(a, h, 404936533), b); }
     346              : 
     347              : /* asume h >= 0 */
     348              : static GEN
     349         3325 : glueisb(GEN h, long a, long b)
     350              : {
     351         3325 :   GEN A = a >= 0? utoi(a): modsi(a, int2n(b));
     352         3325 :   return remi2n(addmuliu(A, h, 404936533), b);
     353              : }
     354              : 
     355              : static ulong
     356     57518623 : hashi(GEN x)
     357              : {
     358     57518623 :   ulong h = glue(evaltyp(t_INT), x[1]);
     359     57518623 :   long i, lx = lgefint(x);
     360     57518623 :   GEN xp = int_MSW(x);
     361    123013376 :   for (i = 2; i < lx; i++, xp = int_precW(xp)) h = glue(h, *xp);
     362     57518623 :   return h;
     363              : }
     364              : 
     365              : /* t_INT */
     366              : static GEN
     367         1267 : hashib(GEN x, long b)
     368              : {
     369         1267 :   pari_sp av = avma;
     370         1267 :   GEN h = glueisb(utoi(t_INT), signe(x), b);
     371         1267 :   GEN v = binary_2k(x, b);
     372         1267 :   long i, l = lg(v);
     373        10192 :   for (i = 1; i < l; i++) h = glueb(h, gel(v,i), b);
     374         1267 :   return gc_INT(av, h);
     375              : }
     376              : 
     377              : /* slow but kernel/architecture independent */
     378              : GEN
     379         2261 : fingerprint(GEN x, long b)
     380              : {
     381         2261 :   long i, l, tx = typ(x);
     382         2261 :   pari_sp av = avma;
     383              :   GEN h;
     384         2261 :   if (b <= 0) pari_err_DOMAIN("fingerprint", "b", "<=", gen_0, stoi(b));
     385         2254 :   if (tx == t_INT) return hashib(x, b);
     386         1078 :   h = utoi(tx);
     387         1078 :   switch(tx)
     388              :   {
     389           35 :     case t_REAL:
     390              :     {
     391              :       long e;
     392           35 :       x = mantissa_real(x, &e);
     393           35 :       h = glueisb(h, signe(x), b);
     394           35 :       h = glueisb(h, e, b);
     395           35 :       h = glueb(h, hashib(x, b), b); return gc_INT(av, h);
     396              :     }
     397          147 :     case t_VECSMALL:
     398          147 :       l = lg(x);
     399          679 :       for (i = 1; i < l; i++) h = glueisb(h, x[i], b);
     400          147 :       return gc_INT(av, h);
     401          112 :     case t_STR:
     402          112 :       return gc_INT(av, fingerprint(gtovecsmall(x), b));
     403           56 :     case t_FFELT:
     404              :     {
     405           56 :       pari_sp av = avma;
     406           56 :       h = glueisb(h, FF_var(x), b);
     407           56 :       h = glueb(h, hashib(FF_p(x), b), b);
     408           56 :       h = glueb(h, fingerprint(FF_to_FpXQ(x), b), b);
     409           56 :       h = glueb(h, fingerprint(FF_mod(x), b), b);
     410           56 :       return gc_INT(av, h);
     411              :     }
     412           42 :     case t_PADIC:
     413           42 :       h = glueisb(h, precp(x), b);
     414           42 :       h = glueisb(h, valp(x), b); break;
     415           49 :     case t_SER:
     416           49 :       h = glueisb(h, valser(x), b); /* fall through */
     417          273 :     case t_POL:
     418          273 :       h = glueisb(h, signe(x), b);
     419          273 :       h = glueisb(h, varn(x), b); break;
     420           28 :     case t_CLOSURE:
     421           28 :       h = glueisb(h, closure_arity(x), b);
     422           28 :       h = glueb(h, fingerprint(closure_get_code(x), b), b);
     423           28 :       h = glueb(h, fingerprint(closure_get_data(x), b), b);
     424           28 :       if (lg(x) > 6)
     425           21 :         h = glueb(h, fingerprint(closure_get_text(x), b), b);
     426           28 :       return gc_INT(av, h);
     427           21 :     case t_LIST:
     428           21 :       x = list_data(x);
     429           21 :       if (!x) return h;
     430              :       /* fall through */
     431              :   }
     432              :   /* recursive type with GEN entries */
     433          693 :   l = lg(x); h = glueisb(h, l, b);
     434         2037 :   for (i = lontyp[tx]; i < l; i++) h = glueb(h, fingerprint(gel(x,i), b), b);
     435          693 :   return gc_INT(av, h);
     436              : }
     437              : 
     438              : ulong
     439    144368817 : hash_GEN(GEN x)
     440              : {
     441    144368817 :   long tx = typ(x), lx, i;
     442              :   ulong h;
     443    144368817 :   if (tx == t_INT) return hashi(x);
     444     86850194 :   h = x[0] & ~CLONEBIT;
     445     86850194 :   switch(tx)
     446              :   { /* other non recursive types */
     447     66327220 :     case t_REAL:
     448              :     case t_STR:
     449              :     case t_VECSMALL:
     450     66327220 :       lx = lg(x);
     451    434134972 :       for (i = 1; i < lx; i++) h = glue(h, uel(x,i));
     452     66327220 :       return h;
     453              :     /* one more special case */
     454            0 :     case t_LIST:
     455            0 :       x = list_data(x);
     456            0 :       if (!x) return h;
     457              :       /* fall through */
     458              :     default:
     459     20522974 :       lx = lg(x);
     460     23317644 :       for(i = 1; i < lontyp[tx]; i++) h = glue(h, x[i]);
     461     80067840 :       for (; i < lx; i++) h = glue(h, hash_GEN(gel(x,i)));
     462     20522974 :       return h;
     463              :   }
     464              : }
     465              : ulong
     466        17507 : hash_zv(GEN x)
     467              : {
     468        17507 :   long i, lx = lg(x);
     469              :   ulong h;
     470        17507 :   if (lx == 1) return 0;
     471        15701 :   h = uel(x,1);
     472        92813 :   for (i = 2; i < lx; i++) h = glue(h, uel(x,i));
     473        15701 :   return h;
     474              : }
        

Generated by: LCOV version 2.0-1