About Docs Source
LCOV - code coverage report
Current view: top level - src/lib/crater - minmax_heap.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 80 81 98.8 %
Date: 2024-02-13 04:57:17 Functions: 11 11 100.0 %

          Line data    Source code
       1             : #include <stdlib.h>
       2             : #include <string.h>
       3             : #include <inttypes.h>
       4             : #include <limits.h>
       5             : 
       6             : #include <crater/minmax_heap.h>
       7             : 
       8             : CR8R_ATTR_NO_SAN("unsigned-integer-overflow")
       9           1 : void cr8r_mmheap_ify(cr8r_vec *self, cr8r_vec_ft *ft){
      10         512 :     for(uint64_t i = (ULLONG_MAX >> 1) >> __builtin_clzll(self->len); i--;){
      11         511 :         cr8r_mmheap_sift_down(self, ft, self->buf + i*ft->base.size);//void pointer arithmetic works like char pointer arithmetic
      12             :     }
      13           1 : }
      14             : 
      15        2001 : void *cr8r_mmheap_peek_min(cr8r_vec *self, cr8r_vec_ft *ft){
      16        2001 :     return self->len ? self->buf : NULL;
      17             : }
      18             : 
      19      477002 : void *cr8r_mmheap_peek_max(cr8r_vec *self, cr8r_vec_ft *ft){
      20      477002 :     if(self->len < 3){
      21           1 :         return self->len ? self->buf + (self->len - 1)*ft->base.size : NULL;
      22             :     }
      23      477001 :     void *l = self->buf + 1*ft->base.size, *r = self->buf + 2*ft->base.size;
      24      477001 :     return ft->cmp(&ft->base, l, r) > 0 ? l : r;
      25             : }
      26             : 
      27     2500000 : void cr8r_mmheap_sift_up(cr8r_vec *self, cr8r_vec_ft *ft, void *e){
      28     2500000 :     if(e == self->buf){
      29             :         return;
      30             :     }
      31     2497500 :     uint64_t i = (e - self->buf)/ft->base.size;
      32             :     // the bit length of i + 1 gives a good way to compute the ceil of the
      33             :     // binary log of i + 2, which is the height of the shortest complete
      34             :     // heap containing an ith element.  If there is an odd number of layers,
      35             :     // i is in a min layer, otherwise it is in a max layer.  Finally,
      36             :     // note the parity of the bit length of i + 1 is the same as the parity of
      37             :     // the number of leading zeros of i + 1.
      38     2497500 :     bool is_min_layer = __builtin_clzll(i + 1)&1;
      39     2497500 :     uint64_t i1 = (i - 1) >> 1;
      40     2497500 :     void *e1 = self->buf + i1*ft->base.size;
      41     2497500 :     int ord = is_min_layer ? 1 : -1;
      42     2497500 :     if(ord*ft->cmp(&ft->base, e1, e) < 0){
      43      837362 :         ft->swap(&ft->base, e, e1);
      44      837362 :         i = i1;
      45      837362 :         e = e1;
      46      837362 :         ord = -ord;
      47             :     }
      48     6798772 :     while(i > 2){
      49     5043231 :         i1 = (i - 3) >> 2;
      50     5043231 :         e1 = self->buf + i1*ft->base.size;
      51     5043231 :         if(ord*ft->cmp(&ft->base, e, e1) < 0){
      52     4301272 :             ft->swap(&ft->base, e, e1);
      53     4301272 :             i = i1;
      54     4301272 :             e = e1;
      55             :         }else{
      56             :             break;
      57             :         }
      58             :     }
      59             : }
      60             : 
      61     2275511 : void cr8r_mmheap_sift_down(cr8r_vec *self, cr8r_vec_ft *ft, void *e){
      62     2275511 :     uint64_t i = (e - self->buf)/ft->base.size;
      63     2275511 :     bool is_min_layer = __builtin_clzll(i + 1)&1;
      64     2275511 :     int ord = is_min_layer ? 1 : -1;
      65     6558243 :     while(2*i + 1 < self->len){
      66             :         // Find m and em, the index of the extremal element and a pointer to the extremal element
      67             :         // respectively among the children and grandchildren of e.  For min layers, extremal means
      68             :         // minimal, and for max layers it means maximal
      69     6294867 :         uint64_t m = 2*i + 1;
      70     6294867 :         void *em = self->buf + m*ft->base.size;
      71     6294867 :         const uint64_t idxs[] = {2*i + 2, 4*i + 3, 4*i + 4, 4*i + 5, 4*i + 6};
      72    30925032 :         for(uint64_t ii = 0; ii < sizeof(idxs)/sizeof(uint64_t) && idxs[ii] < self->len; ++ii){
      73    24630165 :             void *ei = self->buf + idxs[ii]*ft->base.size;
      74    24630165 :             if(ord*ft->cmp(&ft->base, ei, em) < 0){
      75    12449233 :                 m = idxs[ii];
      76    12449233 :                 em = ei;
      77             :             }
      78             :         }
      79             :         // If em is a grandchild of e (as should be the case most of the time)
      80             :         // we may have to sift down farther after fixing up here
      81     6294867 :         if(m > 2*i + 2){
      82     5029008 :             if(ord*ft->cmp(&ft->base, em, e) < 0){
      83     4282732 :                 ft->swap(&ft->base, em, e);
      84     4282732 :                 uint64_t p = (m - 1) >> 1;
      85     4282732 :                 void *ep = self->buf + p*ft->base.size;
      86     4282732 :                 if(ord*ft->cmp(&ft->base, ep, em) < 0){
      87      199642 :                     ft->swap(&ft->base, em, ep);
      88             :                 }
      89     4282732 :                 i = m;
      90     4282732 :                 e = em;
      91             :             }else{
      92             :                 break;
      93             :             }
      94             :         }else{// otherwise em is a direct child so it must be a leaf or its invariant would be wrong
      95     1265859 :             if(ord*ft->cmp(&ft->base, em, e) < 0){
      96      176063 :                 ft->swap(&ft->base, em, e);
      97             :             }
      98             :             break;
      99             :         }
     100             :     }
     101     2275511 : }
     102             : 
     103     2500001 : bool cr8r_mmheap_push(cr8r_vec *self, cr8r_vec_ft *ft, const void *e){
     104     2500001 :     if(!cr8r_vec_pushr(self, ft, e)){
     105             :         return 0;
     106             :     }
     107     2500000 :     cr8r_mmheap_sift_up(self, ft, cr8r_vec_getx(self, ft, -1));
     108     2500000 :     return 1;
     109             : }
     110             : 
     111      900000 : bool cr8r_mmheap_pop_min(cr8r_vec *self, cr8r_vec_ft *ft, void *o){
     112      900000 :     return cr8r_mmheap_pop_idx(self, ft, o, 0);
     113             : }
     114             : 
     115     1375001 : bool cr8r_mmheap_pop_max(cr8r_vec *self, cr8r_vec_ft *ft, void *o){
     116     1375001 :     if(self->len < 3){
     117           1 :         return self->len ? cr8r_mmheap_pop_idx(self, ft, o, self->len - 1) : false;
     118             :     }
     119     1375000 :     void *l = self->buf + 1*ft->base.size, *r = self->buf + 2*ft->base.size;
     120     2548741 :     return cr8r_mmheap_pop_idx(self, ft, o, ft->cmp(&ft->base, l, r) > 0 ? 1 : 2);
     121             : }
     122             : 
     123     2275000 : bool cr8r_mmheap_pop_idx(cr8r_vec *self, cr8r_vec_ft *ft, void *o, uint64_t i){
     124     2275000 :     if(i == self->len - 1){
     125           0 :         return cr8r_vec_popr(self, ft, o);
     126     2275000 :     }else if(!self->len){
     127             :         return 0;
     128             :     }
     129     2275000 :     void *e = self->buf + i*ft->base.size;
     130     2275000 :     memcpy(o, e, ft->base.size);
     131     2275000 :     cr8r_vec_popr(self, ft, e);
     132     2275000 :     cr8r_mmheap_sift_down(self, ft, e);
     133     2275000 :     return 1;
     134             : }
     135             : 
     136      900000 : bool cr8r_mmheap_pushpop_min(cr8r_vec *self, cr8r_vec_ft *ft, const void *e, void *o){
     137      900000 :     if(!cr8r_mmheap_push(self, ft, e)){
     138             :         return 0;
     139             :     }
     140      900000 :     return cr8r_mmheap_pop_min(self, ft, o);
     141             : }
     142             : 
     143     1375000 : bool cr8r_mmheap_pushpop_max(cr8r_vec *self, cr8r_vec_ft *ft, const void *e, void *o){
     144     1375000 :     if(!cr8r_mmheap_push(self, ft, e)){
     145             :         return 0;
     146             :     }
     147     1375000 :     return cr8r_mmheap_pop_max(self, ft, o);
     148             : }
     149             : 

Generated by: LCOV version 1.14