LCOV - code coverage report
Current view: top level - src/flisp - equal.c (source / functions) Hit Total Coverage
Test: [build process] commit ef510b1f346f4c9f9d86eaceace5ca54961a1dbc Lines: 101 249 40.6 %
Date: 2022-07-17 01:01:28 Functions: 7 14 50.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 71 234 30.3 %

           Branch data     Line data    Source code
       1                 :            : #define BOUNDED_COMPARE_BOUND 4096
       2                 :            : #define BOUNDED_HASH_BOUND    16384
       3                 :            : 
       4                 :            : // comparable tag
       5                 :            : #define cmptag(v) (isfixnum(v) ? TAG_NUM : tag(v))
       6                 :            : 
       7                 :          0 : static value_t eq_class(fl_context_t *fl_ctx, htable_t *table, value_t key)
       8                 :            : {
       9                 :          0 :     value_t c = (value_t)ptrhash_get(table, (void*)key);
      10         [ #  # ]:          0 :     if (c == (value_t)HT_NOTFOUND)
      11                 :          0 :         return fl_ctx->NIL;
      12         [ #  # ]:          0 :     if (c == key)
      13                 :          0 :         return c;
      14                 :          0 :     return eq_class(fl_ctx, table, c);
      15                 :            : }
      16                 :            : 
      17                 :          0 : static void eq_union(fl_context_t *fl_ctx, htable_t *table, value_t a,
      18                 :            :                      value_t b, value_t c, value_t cb)
      19                 :            : {
      20         [ #  # ]:          0 :     value_t ca = (c==fl_ctx->NIL ? a : c);
      21         [ #  # ]:          0 :     if (cb != fl_ctx->NIL)
      22                 :          0 :         ptrhash_put(table, (void*)cb, (void*)ca);
      23                 :          0 :     ptrhash_put(table, (void*)a, (void*)ca);
      24                 :          0 :     ptrhash_put(table, (void*)b, (void*)ca);
      25                 :          0 : }
      26                 :            : 
      27                 :            : static value_t bounded_compare(fl_context_t *fl_ctx, value_t a, value_t b, int bound, int eq);
      28                 :            : static value_t cyc_compare(fl_context_t *fl_ctx, value_t a, value_t b, htable_t *table, int eq);
      29                 :            : 
      30                 :          0 : static value_t bounded_vector_compare(fl_context_t *fl_ctx, value_t a, value_t b, int bound, int eq)
      31                 :            : {
      32                 :          0 :     size_t la = vector_size(a);
      33                 :          0 :     size_t lb = vector_size(b);
      34                 :            :     size_t m, i;
      35   [ #  #  #  # ]:          0 :     if (eq && (la!=lb)) return fixnum(1);
      36                 :          0 :     m = la < lb ? la : lb;
      37         [ #  # ]:          0 :     for (i = 0; i < m; i++) {
      38                 :          0 :         value_t d = bounded_compare(fl_ctx, vector_elt(a,i), vector_elt(b,i),
      39                 :            :                                     bound-1, eq);
      40   [ #  #  #  # ]:          0 :         if (d==fl_ctx->NIL || numval(d)!=0) return d;
      41                 :            :     }
      42         [ #  # ]:          0 :     if (la < lb) return fixnum(-1);
      43         [ #  # ]:          0 :     if (la > lb) return fixnum(1);
      44                 :          0 :     return fixnum(0);
      45                 :            : }
      46                 :            : 
      47                 :            : // strange comparisons are resolved arbitrarily but consistently.
      48                 :            : // ordering: number < cprim < function < vector < cvalue < symbol < cons
      49                 :  298750000 : static value_t bounded_compare(fl_context_t *fl_ctx, value_t a, value_t b, int bound, int eq)
      50                 :            : {
      51                 :            :     value_t d;
      52                 :            : 
      53                 :  298750000 :  compare_top:
      54         [ +  + ]:  298750000 :     if (a == b) return fixnum(0);
      55         [ -  + ]:  296114000 :     if (bound <= 0)
      56                 :          0 :         return fl_ctx->NIL;
      57                 :  296114000 :     int taga = tag(a);
      58         [ +  + ]:  296114000 :     int tagb = cmptag(b);
      59                 :            :     int c;
      60   [ +  +  -  +  :  296114000 :     switch (taga) {
             +  +  +  - ]
      61                 :    1019900 :     case TAG_NUM :
      62                 :            :     case TAG_NUM1:
      63         [ +  + ]:    1019900 :         if (isfixnum(b)) {
      64         [ +  + ]:     332062 :             return (numval(a) < numval(b)) ? fixnum(-1) : fixnum(1);
      65                 :            :         }
      66         [ +  + ]:     687838 :         if (iscprim(b)) {
      67         [ +  - ]:     672382 :             if (cp_class((cprim_t*)ptr(b)) == fl_ctx->wchartype)
      68                 :     672382 :                 return fixnum(1);
      69                 :          0 :             return fixnum(numeric_compare(fl_ctx, a, b, eq, 1, NULL));
      70                 :            :         }
      71                 :      15456 :         return fixnum(-1);
      72                 :  123711000 :     case TAG_SYM:
      73         [ +  + ]:  123711000 :         if (eq) return fixnum(1);
      74         [ -  + ]:         32 :         if (tagb < TAG_SYM) return fixnum(1);
      75         [ -  + ]:         32 :         if (tagb > TAG_SYM) return fixnum(-1);
      76                 :         32 :         return fixnum(strcmp(symbol_name(fl_ctx, a), symbol_name(fl_ctx, b)));
      77                 :          0 :     case TAG_VECTOR:
      78         [ #  # ]:          0 :         if (isvector(b))
      79                 :          0 :             return bounded_vector_compare(fl_ctx, a, b, bound, eq);
      80                 :          0 :         break;
      81                 :  163072200 :     case TAG_CPRIM:
      82         [ +  + ]:  163072200 :         if (cp_class((cprim_t*)ptr(a)) == fl_ctx->wchartype) {
      83   [ +  +  +  + ]:  162874400 :             if (!iscprim(b) || cp_class((cprim_t*)ptr(b)) != fl_ctx->wchartype)
      84                 :   13623820 :                 return fixnum(-1);
      85                 :            :         }
      86   [ +  +  +  + ]:     197802 :         else if (iscprim(b) && cp_class((cprim_t*)ptr(b)) == fl_ctx->wchartype) {
      87                 :      89392 :             return fixnum(1);
      88                 :            :         }
      89                 :  149359000 :         c = numeric_compare(fl_ctx, a, b, eq, 1, NULL);
      90         [ +  + ]:  149359000 :         if (c != 2)
      91                 :  149352400 :             return fixnum(c);
      92                 :       6566 :         break;
      93                 :     387214 :     case TAG_CVALUE:
      94         [ +  + ]:     387214 :         if (iscvalue(b)) {
      95   [ +  -  +  - ]:     235660 :             if (cv_isPOD((cvalue_t*)ptr(a)) && cv_isPOD((cvalue_t*)ptr(b)))
      96                 :     235660 :                 return cvalue_compare(a, b);
      97                 :          0 :             return fixnum(1);
      98                 :            :         }
      99                 :     151554 :         break;
     100                 :     144686 :     case TAG_FUNCTION:
     101         [ -  + ]:     144686 :         if (tagb == TAG_FUNCTION) {
     102   [ #  #  #  # ]:          0 :             if (uintval(a) > N_BUILTINS && uintval(b) > N_BUILTINS) {
     103                 :          0 :                 function_t *fa = (function_t*)ptr(a);
     104                 :          0 :                 function_t *fb = (function_t*)ptr(b);
     105                 :          0 :                 d = bounded_compare(fl_ctx, fa->bcode, fb->bcode, bound-1, eq);
     106   [ #  #  #  # ]:          0 :                 if (d==fl_ctx->NIL || numval(d) != 0) return d;
     107                 :          0 :                 d = bounded_compare(fl_ctx, fa->vals, fb->vals, bound-1, eq);
     108   [ #  #  #  # ]:          0 :                 if (d==fl_ctx->NIL || numval(d) != 0) return d;
     109                 :          0 :                 d = bounded_compare(fl_ctx, fa->env, fb->env, bound-1, eq);
     110   [ #  #  #  # ]:          0 :                 if (d==fl_ctx->NIL || numval(d) != 0) return d;
     111                 :          0 :                 return fixnum(0);
     112                 :            :             }
     113         [ #  # ]:          0 :             return (uintval(a) < uintval(b)) ? fixnum(-1) : fixnum(1);
     114                 :            :         }
     115                 :     144686 :         break;
     116                 :    7778200 :     case TAG_CONS:
     117         [ +  + ]:    7778200 :         if (tagb < TAG_CONS) return fixnum(1);
     118                 :    4380060 :         d = bounded_compare(fl_ctx, car_(a), car_(b), bound-1, eq);
     119   [ +  -  +  + ]:    4380060 :         if (d==fl_ctx->NIL || numval(d) != 0) return d;
     120                 :    1792522 :         a = cdr_(a); b = cdr_(b);
     121                 :    1792522 :         bound--;
     122                 :    1792522 :         goto compare_top;
     123                 :            :     }
     124         [ +  + ]:     302806 :     return (taga < tagb) ? fixnum(-1) : fixnum(1);
     125                 :            : }
     126                 :            : 
     127                 :          0 : static value_t cyc_vector_compare(fl_context_t *fl_ctx, value_t a,
     128                 :            :                                   value_t b, htable_t *table, int eq)
     129                 :            : {
     130                 :          0 :     size_t la = vector_size(a);
     131                 :          0 :     size_t lb = vector_size(b);
     132                 :            :     size_t m, i;
     133                 :            :     value_t d, xa, xb, ca, cb;
     134                 :            : 
     135                 :            :     // first try to prove them different with no recursion
     136   [ #  #  #  # ]:          0 :     if (eq && (la!=lb)) return fixnum(1);
     137                 :          0 :     m = la < lb ? la : lb;
     138         [ #  # ]:          0 :     for (i = 0; i < m; i++) {
     139                 :          0 :         xa = vector_elt(a,i);
     140                 :          0 :         xb = vector_elt(b,i);
     141   [ #  #  #  # ]:          0 :         if (leafp(xa) || leafp(xb)) {
     142                 :          0 :             d = bounded_compare(fl_ctx, xa, xb, 1, eq);
     143   [ #  #  #  # ]:          0 :             if (d!=fl_ctx->NIL && numval(d)!=0) return d;
     144                 :            :         }
     145         [ #  # ]:          0 :         else if (tag(xa) < tag(xb)) {
     146                 :          0 :             return fixnum(-1);
     147                 :            :         }
     148         [ #  # ]:          0 :         else if (tag(xa) > tag(xb)) {
     149                 :          0 :             return fixnum(1);
     150                 :            :         }
     151                 :            :     }
     152                 :            : 
     153                 :          0 :     ca = eq_class(fl_ctx, table, a);
     154                 :          0 :     cb = eq_class(fl_ctx, table, b);
     155   [ #  #  #  # ]:          0 :     if (ca!=fl_ctx->NIL && ca==cb)
     156                 :          0 :         return fixnum(0);
     157                 :            : 
     158                 :          0 :     eq_union(fl_ctx, table, a, b, ca, cb);
     159                 :            : 
     160         [ #  # ]:          0 :     for (i = 0; i < m; i++) {
     161                 :          0 :         xa = vector_elt(a,i);
     162                 :          0 :         xb = vector_elt(b,i);
     163   [ #  #  #  # ]:          0 :         if (!leafp(xa) || tag(xa)==TAG_FUNCTION) {
     164                 :          0 :             d = cyc_compare(fl_ctx, xa, xb, table, eq);
     165         [ #  # ]:          0 :             if (numval(d)!=0)
     166                 :          0 :                 return d;
     167                 :            :         }
     168                 :            :     }
     169                 :            : 
     170         [ #  # ]:          0 :     if (la < lb) return fixnum(-1);
     171         [ #  # ]:          0 :     if (la > lb) return fixnum(1);
     172                 :          0 :     return fixnum(0);
     173                 :            : }
     174                 :            : 
     175                 :          0 : static value_t cyc_compare(fl_context_t *fl_ctx, value_t a, value_t b, htable_t *table, int eq)
     176                 :            : {
     177                 :            :     value_t d, ca, cb;
     178                 :          0 :  cyc_compare_top:
     179         [ #  # ]:          0 :     if (a==b)
     180                 :          0 :         return fixnum(0);
     181         [ #  # ]:          0 :     if (iscons(a)) {
     182         [ #  # ]:          0 :         if (iscons(b)) {
     183                 :          0 :             value_t aa = car_(a); value_t da = cdr_(a);
     184                 :          0 :             value_t ab = car_(b); value_t db = cdr_(b);
     185                 :          0 :             int tagaa = tag(aa); int tagda = tag(da);
     186                 :          0 :             int tagab = tag(ab); int tagdb = tag(db);
     187   [ #  #  #  # ]:          0 :             if (leafp(aa) || leafp(ab)) {
     188                 :          0 :                 d = bounded_compare(fl_ctx, aa, ab, 1, eq);
     189   [ #  #  #  # ]:          0 :                 if (d!=fl_ctx->NIL && numval(d)!=0) return d;
     190                 :            :             }
     191         [ #  # ]:          0 :             else if (tagaa < tagab)
     192                 :          0 :                 return fixnum(-1);
     193         [ #  # ]:          0 :             else if (tagaa > tagab)
     194                 :          0 :                 return fixnum(1);
     195   [ #  #  #  # ]:          0 :             if (leafp(da) || leafp(db)) {
     196                 :          0 :                 d = bounded_compare(fl_ctx, da, db, 1, eq);
     197   [ #  #  #  # ]:          0 :                 if (d!=fl_ctx->NIL && numval(d)!=0) return d;
     198                 :            :             }
     199         [ #  # ]:          0 :             else if (tagda < tagdb)
     200                 :          0 :                 return fixnum(-1);
     201         [ #  # ]:          0 :             else if (tagda > tagdb)
     202                 :          0 :                 return fixnum(1);
     203                 :            : 
     204                 :          0 :             ca = eq_class(fl_ctx, table, a);
     205                 :          0 :             cb = eq_class(fl_ctx, table, b);
     206   [ #  #  #  # ]:          0 :             if (ca!=fl_ctx->NIL && ca==cb)
     207                 :          0 :                 return fixnum(0);
     208                 :            : 
     209                 :          0 :             eq_union(fl_ctx, table, a, b, ca, cb);
     210                 :          0 :             d = cyc_compare(fl_ctx, aa, ab, table, eq);
     211         [ #  # ]:          0 :             if (numval(d)!=0) return d;
     212                 :          0 :             a = da;
     213                 :          0 :             b = db;
     214                 :          0 :             goto cyc_compare_top;
     215                 :            :         }
     216                 :            :         else {
     217                 :          0 :             return fixnum(1);
     218                 :            :         }
     219                 :            :     }
     220   [ #  #  #  # ]:          0 :     else if (isvector(a) && isvector(b)) {
     221                 :          0 :         return cyc_vector_compare(fl_ctx, a, b, table, eq);
     222                 :            :     }
     223   [ #  #  #  #  :          0 :     else if (isclosure(a) && isclosure(b)) {
             #  #  #  # ]
     224                 :          0 :         function_t *fa = (function_t*)ptr(a);
     225                 :          0 :         function_t *fb = (function_t*)ptr(b);
     226                 :          0 :         d = bounded_compare(fl_ctx, fa->bcode, fb->bcode, 1, eq);
     227         [ #  # ]:          0 :         if (numval(d) != 0) return d;
     228                 :            : 
     229                 :          0 :         ca = eq_class(fl_ctx, table, a);
     230                 :          0 :         cb = eq_class(fl_ctx, table, b);
     231   [ #  #  #  # ]:          0 :         if (ca!=fl_ctx->NIL && ca==cb)
     232                 :          0 :             return fixnum(0);
     233                 :            : 
     234                 :          0 :         eq_union(fl_ctx, table, a, b, ca, cb);
     235                 :          0 :         d = cyc_compare(fl_ctx, fa->vals, fb->vals, table, eq);
     236         [ #  # ]:          0 :         if (numval(d) != 0) return d;
     237                 :          0 :         a = fa->env;
     238                 :          0 :         b = fb->env;
     239                 :          0 :         goto cyc_compare_top;
     240                 :            :     }
     241                 :          0 :     return bounded_compare(fl_ctx, a, b, 1, eq);
     242                 :            : }
     243                 :            : 
     244                 :         30 : void comparehash_init(fl_context_t *fl_ctx)
     245                 :            : {
     246                 :         30 :     htable_new(&fl_ctx->equal_eq_hashtable, 512);
     247                 :         30 : }
     248                 :            : 
     249                 :            : // 'eq' means unordered comparison is sufficient
     250                 :  292576000 : static value_t compare_(fl_context_t *fl_ctx, value_t a, value_t b, int eq)
     251                 :            : {
     252                 :  292576000 :     value_t guess = bounded_compare(fl_ctx, a, b, BOUNDED_COMPARE_BOUND, eq);
     253         [ -  + ]:  292576000 :     if (guess == fl_ctx->NIL) {
     254                 :          0 :         guess = cyc_compare(fl_ctx, a, b, &fl_ctx->equal_eq_hashtable, eq);
     255                 :          0 :         htable_reset(&fl_ctx->equal_eq_hashtable, 512);
     256                 :            :     }
     257                 :  292576000 :     return guess;
     258                 :            : }
     259                 :            : 
     260                 :     530386 : value_t fl_compare(fl_context_t *fl_ctx, value_t a, value_t b)
     261                 :            : {
     262                 :     530386 :     return compare_(fl_ctx, a, b, 0);
     263                 :            : }
     264                 :            : 
     265                 :          0 : value_t fl_equal(fl_context_t *fl_ctx, value_t a, value_t b)
     266                 :            : {
     267         [ #  # ]:          0 :     if (eq_comparable(a, b))
     268         [ #  # ]:          0 :         return (a == b) ? fl_ctx->T : fl_ctx->F;
     269         [ #  # ]:          0 :     return (numval(compare_(fl_ctx, a,b,1))==0 ? fl_ctx->T : fl_ctx->F);
     270                 :            : }
     271                 :            : 
     272                 :            : /*
     273                 :            :   optimizations:
     274                 :            :   - use hash updates instead of calling lookup then insert. i.e. get the
     275                 :            :     bp once and use it twice.
     276                 :            :   * preallocate hash table and call reset() instead of new/free
     277                 :            :   * less redundant tag checking, 3-bit tags
     278                 :            : */
     279                 :            : 
     280                 :            : #ifdef _P64
     281                 :            : #define MIX(a, b) int64hash((int64_t)(a) ^ (int64_t)(b));
     282                 :            : #define doublehash(a) int64hash(a)
     283                 :            : #else
     284                 :            : #define MIX(a, b) int64to32hash(((int64_t)(a))<<32 | ((int64_t)(b)))
     285                 :            : #define doublehash(a) int64to32hash(a)
     286                 :            : #endif
     287                 :            : 
     288                 :            : // *oob: output argument, means we hit the limit specified by 'bound'
     289                 :   81541400 : static uintptr_t bounded_hash(fl_context_t *fl_ctx, value_t a, int bound, int *oob)
     290                 :            : {
     291                 :   81541400 :     *oob = 0;
     292                 :            :     union {
     293                 :            :         double d;
     294                 :            :         int64_t i64;
     295                 :            :     } u;
     296                 :            :     numerictype_t nt;
     297                 :            :     size_t i, len;
     298                 :            :     cvalue_t *cv;
     299                 :            :     cprim_t *cp;
     300                 :            :     void *data;
     301                 :   81541400 :     uintptr_t h = 0;
     302                 :   81541400 :     int oob2, tg = tag(a);
     303   [ +  +  +  +  :   81541400 :     switch(tg) {
             +  -  +  - ]
     304                 :    8116720 :     case TAG_NUM :
     305                 :            :     case TAG_NUM1:
     306                 :    8116720 :         u.d = (double)numval(a);
     307                 :    8116720 :         return doublehash(u.i64);
     308                 :    6358460 :     case TAG_FUNCTION:
     309         [ -  + ]:    6358460 :         if (uintval(a) > N_BUILTINS)
     310                 :          0 :             return bounded_hash(fl_ctx, ((function_t*)ptr(a))->bcode, bound, oob);
     311                 :    6358460 :         return inthash(a);
     312                 :   50348400 :     case TAG_SYM:
     313                 :   50348400 :         return ((symbol_t*)ptr(a))->hash;
     314                 :   10240260 :     case TAG_CPRIM:
     315                 :   10240260 :         cp = (cprim_t*)ptr(a);
     316                 :   10240260 :         data = cp_data(cp);
     317         [ +  + ]:   10240260 :         if (cp_class(cp) == fl_ctx->wchartype)
     318                 :   10228900 :             return inthash(*(int32_t*)data);
     319                 :      11346 :         nt = cp_numtype(cp);
     320                 :      11346 :         u.d = conv_to_double(data, nt);
     321                 :      11346 :         return doublehash(u.i64);
     322                 :     187956 :     case TAG_CVALUE:
     323                 :     187956 :         cv = (cvalue_t*)ptr(a);
     324                 :     187956 :         data = cv_data(cv);
     325                 :     187956 :         return memhash((char*)data, cv_len(cv));
     326                 :            : 
     327                 :          0 :     case TAG_VECTOR:
     328         [ #  # ]:          0 :         if (bound <= 0) {
     329                 :          0 :             *oob = 1;
     330                 :          0 :             return 1;
     331                 :            :         }
     332                 :          0 :         len = vector_size(a);
     333         [ #  # ]:          0 :         for(i=0; i < len; i++) {
     334                 :          0 :             h = MIX(h, bounded_hash(fl_ctx, vector_elt(a,i), bound/2, &oob2)^1);
     335         [ #  # ]:          0 :             if (oob2)
     336                 :          0 :                 bound/=2;
     337   [ #  #  #  # ]:          0 :             *oob = *oob || oob2;
     338                 :            :         }
     339                 :          0 :         return h;
     340                 :            : 
     341                 :    6498660 :     case TAG_CONS:
     342                 :            :         do {
     343         [ +  + ]:   12788380 :             if (bound <= 0) {
     344                 :         48 :                 *oob = 1;
     345                 :         48 :                 return h;
     346                 :            :             }
     347                 :   12788320 :             h = MIX(h, bounded_hash(fl_ctx, car_(a), bound/2, &oob2));
     348                 :            :             // bounds balancing: try to share the bounds efficiently
     349                 :            :             // so we can hash better when a list is cdr-deep (a common case)
     350         [ +  + ]:   12788320 :             if (oob2)
     351                 :        140 :                 bound/=2;
     352                 :            :             else
     353                 :   12788180 :                 bound--;
     354                 :            :             // recursive OOB propagation. otherwise this case is slow:
     355                 :            :             // (hash '#2=((#0=(#1=(#1#) . #0#)) . #2#))
     356   [ +  +  +  + ]:   12788320 :             *oob = *oob || oob2;
     357                 :   12788320 :             a = cdr_(a);
     358         [ +  + ]:   12788320 :         } while (iscons(a));
     359                 :    6289660 :         h = MIX(h, bounded_hash(fl_ctx, a, bound-1, &oob2)^2);
     360   [ +  +  -  + ]:    6289660 :         *oob = *oob || oob2;
     361                 :    6289660 :         return h;
     362                 :            :     }
     363                 :          0 :     return 0;
     364                 :            : }
     365                 :            : 
     366                 :   62526000 : int equal_lispvalue(fl_context_t *fl_ctx, value_t a, value_t b)
     367                 :            : {
     368         [ +  + ]:   62526000 :     if (eq_comparable(a, b))
     369                 :   48968800 :         return (a==b);
     370                 :   13557160 :     return (numval(compare_(fl_ctx, a, b, 1))==0);
     371                 :            : }
     372                 :            : 
     373                 :   62463400 : uintptr_t hash_lispvalue(fl_context_t *fl_ctx, value_t a)
     374                 :            : {
     375                 :   62463400 :     int oob = 0;
     376                 :   62463400 :     uintptr_t n = bounded_hash(fl_ctx, a, BOUNDED_HASH_BOUND, &oob);
     377                 :   62463400 :     return n;
     378                 :            : }
     379                 :            : 
     380                 :          0 : value_t fl_hash(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
     381                 :            : {
     382                 :          0 :     argcount(fl_ctx, "hash", nargs, 1);
     383                 :          0 :     return fixnum(hash_lispvalue(fl_ctx, args[0]));
     384                 :            : }

Generated by: LCOV version 1.14