About Docs Source
LCOV - code coverage report
Current view: top level - src/lib/crater - avl.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 425 465 91.4 %
Date: 2024-02-13 04:57:17 Functions: 46 47 97.9 %

          Line data    Source code
       1             : #include <stddef.h>
       2             : #include <stdlib.h>
       3             : #include <string.h>
       4             : 
       5             : #include <crater/avl_check.h>
       6             : #include <crater/avl.h>
       7             : 
       8             : static cr8r_avl_node *cr8r_avl_insert_recursive(cr8r_avl_node *r, void *key, cr8r_avl_ft *ft);
       9             : inline static cr8r_avl_node *cr8r_avl_insert_rebalance_r(cr8r_avl_node *p, cr8r_avl_node *n);
      10             : inline static cr8r_avl_node *cr8r_avl_insert_rebalance_l(cr8r_avl_node *p, cr8r_avl_node *n);
      11             : static cr8r_avl_node *cr8r_avl_insert_retrace(cr8r_avl_node *n);
      12             : inline static cr8r_avl_node *cr8r_avl_remove_rebalance_r(cr8r_avl_node *p);
      13             : inline static cr8r_avl_node *cr8r_avl_remove_rebalance_l(cr8r_avl_node *p);
      14             : static cr8r_avl_node *cr8r_avl_remove_retrace(cr8r_avl_node *n);
      15             : inline static cr8r_avl_node *cr8r_avl_remove_trunk(cr8r_avl_node *n, cr8r_avl_ft *ft);
      16             : inline static cr8r_avl_node *cr8r_avl_rotate_r(cr8r_avl_node *n);
      17             : inline static cr8r_avl_node *cr8r_avl_rotate_l(cr8r_avl_node *n);
      18             : 
      19             : inline static void cr8r_avl_swap_data(cr8r_avl_node *a, cr8r_avl_node *b, uint64_t size);
      20             : inline static void cr8r_avl_sift_down_bounded(cr8r_avl_node *r, cr8r_avl_node *u, cr8r_avl_ft *ft);
      21             : inline static void cr8r_avl_reorder_recursive(cr8r_avl_node *r, cr8r_avl_ft *ft);
      22             : inline static void cr8r_avl_reorder_retrace(cr8r_avl_node *n);
      23             : inline static cr8r_avl_node *cr8r_avl_reorder_relink(cr8r_avl_node *n);
      24             : 
      25             : 
      26           1 : bool cr8r_avl_ft_init(cr8r_avl_ft *ft,
      27             :     void *data, uint64_t size,
      28             :     int (*cmp)(const cr8r_base_ft*, const void*, const void*),
      29             :     int (*add)(cr8r_base_ft*, void*, void*),
      30             :     void *(*alloc)(cr8r_base_ft*),
      31             :     void (*free)(cr8r_base_ft*, void*)
      32             : ){
      33           1 :     if(!cmp || !alloc || !free){
      34             :         return 0;
      35             :     }
      36           1 :     ft->base.data = data;
      37           1 :     ft->base.size = size;
      38           1 :     ft->cmp = cmp;
      39           1 :     ft->add = add;
      40           1 :     ft->alloc = alloc;
      41           1 :     ft->free = free;
      42           1 :     return 1;
      43             : }
      44             : 
      45           2 : bool cr8r_avl_ft_initsla(cr8r_avl_ft *ft,
      46             :     cr8r_sla *sla, uint64_t size, uint64_t reserve,
      47             :     int (*cmp)(const cr8r_base_ft*, const void*, const void*),
      48             :     int (*add)(cr8r_base_ft*, void*, void*)
      49             : ){
      50           2 :     if(!cmp || !sla || !cr8r_sla_init(sla, offsetof(cr8r_avl_node, data) + size, reserve)){
      51           0 :         return 0;
      52             :     }
      53           2 :     ft->base.data = sla;
      54           2 :     ft->base.size = size;
      55           2 :     ft->cmp = cmp;
      56           2 :     ft->add = add;
      57           2 :     ft->alloc = cr8r_default_alloc_sla;
      58           2 :     ft->free = cr8r_default_free_sla;
      59           2 :     return 1;
      60             : }
      61             : 
      62   177828274 : void *cr8r_default_alloc_sla(cr8r_base_ft *ft){
      63   177828274 :     return cr8r_sla_alloc(ft->data);
      64             : }
      65             : 
      66   177821201 : void cr8r_default_free_sla(cr8r_base_ft *ft, void *p){
      67   177821201 :     cr8r_sla_free(ft->data, p);
      68   177821201 : }
      69             : 
      70             : 
      71   355636926 : cr8r_avl_node *cr8r_avl_next(cr8r_avl_node *n){
      72   355636926 :     if(n->right){
      73   128887576 :         return cr8r_avl_first(n->right);
      74             :     }
      75             :     cr8r_avl_node *s = n;//inorder successor of n
      76   355636752 :     while(s->parent && s->parent->left != s){
      77   128887402 :         s = s->parent;
      78             :     }
      79   226749350 :     return s->parent;
      80             : }
      81             : 
      82         192 : cr8r_avl_node *cr8r_avl_prev(cr8r_avl_node *n){
      83         192 :     if(n->left){
      84         102 :         return cr8r_avl_last(n->left);
      85             :     }
      86             :     cr8r_avl_node *p = n;//inorder predecessor of n
      87         192 :     while(p->parent && p->parent->right != p){
      88         102 :         p = p->parent;
      89             :     }
      90          90 :     return p->parent;
      91             : }
      92             : 
      93   177818273 : cr8r_avl_node *cr8r_avl_new(void *key, cr8r_avl_node *left, cr8r_avl_node *right, cr8r_avl_node *parent, char balance, cr8r_avl_ft *ft){
      94   177818273 :     cr8r_avl_node *ret = ft->alloc(&ft->base);
      95   177818273 :     if(ret){
      96   177818273 :         *ret = (cr8r_avl_node){left, right, parent, balance};
      97   177818273 :         memcpy(ret->data, key, ft->base.size);
      98             :     }
      99   177818273 :     return ret;
     100             : }
     101             : 
     102   174189738 : cr8r_avl_node *cr8r_avl_root(cr8r_avl_node *n){
     103   243442215 :     while(n && n->parent){
     104    69252477 :         n = n->parent;
     105             :     }
     106   174189738 :     return n;
     107             : }
     108             : 
     109   335561382 : cr8r_avl_node *cr8r_avl_get(cr8r_avl_node *r, void *key, cr8r_avl_ft *ft){
     110   335561382 :     if(!r){
     111             :         return NULL;
     112             :     }
     113   335561382 :     int ord = ft->cmp(&ft->base, r->data, key);
     114   335561382 :     if(ord < 0){
     115    74941115 :         return cr8r_avl_get(r->right, key, ft);
     116   260620267 :     }else if(ord > 0){
     117    82808875 :         return cr8r_avl_get(r->left, key, ft);
     118             :     }//otherwise r->data "==" key
     119             :     return r;
     120             : }
     121             : 
     122          96 : cr8r_avl_node *cr8r_avl_search_dups(cr8r_avl_node *r, void *key, cr8r_avl_ft *ft, int *is_duplicate){
     123          96 :     if(!r){
     124           0 :         if(is_duplicate){
     125           0 :             *is_duplicate = 0;
     126             :         }
     127           0 :         return NULL;
     128             :     }
     129             :     int found_dup = 0;
     130         619 :     while(1){
     131         619 :         int ord = ft->cmp(&ft->base, r->data, key);
     132         619 :         if(ord < 0){
     133         379 :             if(!r->right){
     134             :                 break;
     135             :             }
     136         332 :             r = r->right;
     137         240 :         }else if(ord > 0){
     138         240 :             if(!r->left){
     139             :                 break;
     140             :             }
     141         191 :             r = r->left;
     142             :         }else{
     143           0 :             found_dup = 1;
     144           0 :             if(r->balance < 0){
     145           0 :                 if(!r->right){
     146             :                     break;
     147             :                 }
     148           0 :                 r = r->right;
     149           0 :             }else if(!r->left){
     150             :                 break;
     151             :             }else{
     152           0 :                 r = r->left;
     153             :             }
     154             :         }
     155             :     }
     156          96 :     if(is_duplicate){
     157           0 :         *is_duplicate = found_dup;
     158             :     }
     159             :     return r;
     160             : }
     161             : 
     162        1218 : cr8r_avl_node *cr8r_avl_search(cr8r_avl_node *r, void *key, cr8r_avl_ft *ft){
     163        1218 :     if(!r){
     164             :         return NULL;
     165             :     }
     166        1218 :     int ord = ft->cmp(&ft->base, r->data, key);
     167        1218 :     if(ord < 0){
     168         588 :         return r->right ? cr8r_avl_search(r->right, key, ft) : r;
     169         630 :     }else if(ord > 0){
     170         534 :         return r->left ? cr8r_avl_search(r->left, key, ft) : r;
     171             :     }
     172             :     return r;
     173             : }
     174             : 
     175        1323 : cr8r_avl_node *cr8r_avl_lower_bound(cr8r_avl_node *r, void *key, cr8r_avl_ft *ft){
     176        1323 :     cr8r_avl_node *ret = NULL;
     177        1323 :     if(!r){
     178             :         return NULL;
     179             :     }//find largest element l of r such that l <= key
     180        1225 :     int ord = ft->cmp(&ft->base, r->data, key);
     181        1225 :     if(ord < 0){
     182         588 :         ret = cr8r_avl_lower_bound(r->right, key, ft);
     183         588 :         return ret ? ret : r;
     184         637 :     }else if(ord > 0){
     185         541 :         return cr8r_avl_lower_bound(r->left, key, ft);
     186             :     }//otherwise r->data "==" key
     187             :     return r;
     188             : }
     189             : 
     190        1323 : cr8r_avl_node *cr8r_avl_upper_bound(cr8r_avl_node *r, void *key, cr8r_avl_ft *ft){
     191        1323 :     cr8r_avl_node *ret = NULL;
     192        1323 :     if(!r){
     193             :         return NULL;
     194             :     }//find smallest element u of r such that r > key
     195        1225 :     int ord = ft->cmp(&ft->base, r->data, key);
     196        1225 :     if(ord < 0){
     197         588 :         return cr8r_avl_upper_bound(r->right, key, ft);
     198         637 :     }else if(ord > 0){
     199         541 :         ret = cr8r_avl_upper_bound(r->left, key, ft);
     200         541 :         return ret ? ret : r;
     201             :     }//otherwise r->data "==" key
     202          96 :     return cr8r_avl_next(r);
     203             : }
     204             : 
     205   154289183 : cr8r_avl_node *cr8r_avl_first(cr8r_avl_node *r){
     206   241252065 :     while(r && r->left){
     207    86962882 :         r = r->left;
     208             :     }
     209   154289183 :     return r;
     210             : }
     211             : 
     212         157 : cr8r_avl_node *cr8r_avl_last(cr8r_avl_node *r){
     213         281 :     while(r && r->right){
     214         124 :         r = r->right;
     215             :     }
     216         157 :     return r;
     217             : }
     218             : 
     219   177811296 : int cr8r_avl_insert(cr8r_avl_node **r, void *key, cr8r_avl_ft *ft){
     220   177811296 :     cr8r_avl_node *t = cr8r_avl_insert_recursive(*r, key, ft);
     221   177811296 :     CR8R_AVL_ASSERT_ALL(*r);
     222   177811296 :     if(t){
     223   177811296 :         *r = t;
     224             :     }
     225   177811296 :     return !!t;
     226             : }
     227             : 
     228   345220348 : cr8r_avl_node *cr8r_avl_insert_recursive(cr8r_avl_node *r, void *key, cr8r_avl_ft *ft){
     229   345220348 :     if(!r){
     230    25401601 :         return cr8r_avl_new(key, NULL, NULL, NULL, 0, ft);
     231             :     }
     232   319818747 :     int ord = ft->cmp(&ft->base, r->data, key);
     233   319818747 :     if(ord < 0){
     234   159909390 :         if(r->right){
     235    83704543 :             return cr8r_avl_insert_recursive(r->right, key, ft);
     236             :         }//otherwise insert on the right side
     237    76204847 :         r->right = cr8r_avl_new(key, NULL, NULL, r, 0, ft);
     238    76204847 :         if(!r->right){//allocation failed
     239             :             return NULL;
     240             :         }
     241    76204847 :         return cr8r_avl_insert_retrace(r->right);//rebalance
     242   159909357 :     }else if(ord > 0){
     243   159909357 :         if(r->left){
     244    83704509 :             return cr8r_avl_insert_recursive(r->left, key, ft);
     245             :         }//otherwise insert on the left side
     246    76204848 :         r->left = cr8r_avl_new(key, NULL, NULL, r, 0, ft);
     247    76204848 :         if(!r->left){//allocation failed
     248             :             return NULL;
     249             :         }
     250    76204848 :         return cr8r_avl_insert_retrace(r->left);//rebalance
     251             :     }
     252             :     return NULL;
     253             : }
     254             : 
     255       75328 : int cr8r_avl_insert_update(cr8r_avl_node **r, void *key, cr8r_avl_ft *ft){
     256       75328 :     if(!*r){
     257           1 :         *r = cr8r_avl_new(key, NULL, NULL, NULL, 0, ft);
     258           1 :         return *r ? CR8R_AVL_INSERTED : 0;
     259             :     }
     260       75327 :     for(cr8r_avl_node *t = *r;;){
     261      740570 :         int ord = ft->cmp(&ft->base, t->data, key);
     262      740570 :         if(ord < 0){
     263      326831 :             if(t->right){
     264      323299 :                 t = t->right;
     265             :             }else{
     266        3532 :                 if(!(t->right = cr8r_avl_new(key, NULL, NULL, t, 0, ft))){
     267             :                     return 0;
     268             :                 }
     269        3532 :                 *r = cr8r_avl_insert_retrace(t->right);
     270        3532 :                 CR8R_AVL_ASSERT_ALL(*r);
     271             :                 return CR8R_AVL_INSERTED;
     272             :             }
     273      413739 :         }else if(ord > 0){
     274      345388 :             if(t->left){
     275      341944 :                 t = t->left;
     276             :             }else{
     277        3444 :                 if(!(t->left = cr8r_avl_new(key, NULL, NULL, t, 0, ft))){
     278             :                     return 0;
     279             :                 }
     280        3444 :                 *r = cr8r_avl_insert_retrace(t->left);
     281        3444 :                 CR8R_AVL_ASSERT_ALL(*r);
     282             :                 return CR8R_AVL_INSERTED;
     283             :             }
     284             :         }else{
     285       68351 :             return ft->add(&ft->base, t->data, key) ? CR8R_AVL_UPDATED : 0;
     286             :         }
     287             :     }
     288             : }
     289             : 
     290   177811200 : int cr8r_avl_remove(cr8r_avl_node **r, void *key, cr8r_avl_ft *ft){
     291   177811200 :     cr8r_avl_node *n = cr8r_avl_get(*r, key, ft);
     292   177811200 :     CR8R_AVL_ASSERT_ALL(*r);
     293   177811200 :     if(n){
     294   177811200 :         *r = cr8r_avl_remove_node(n, ft);
     295             :     }
     296   177811200 :     return !!n;
     297             : }
     298             : 
     299   177811296 : cr8r_avl_node *cr8r_avl_remove_node(cr8r_avl_node *n, cr8r_avl_ft *ft){
     300   177811296 :     cr8r_avl_node *s = cr8r_avl_next(n);
     301   177811296 :     if((!n->left) || (!n->right)){//no need to swap with a scapegoat
     302   138516530 :         return cr8r_avl_remove_trunk(n, ft);
     303             :     }
     304             :     //swap all of n and s's parent, left, right, and balance fields
     305             :     //it would be easier to swap the data fields but that would invalidate iterators to s
     306    39294766 :     cr8r_avl_node t = *s;//t is an automatic storage variable that holds a copy of *s
     307    39294766 :     if((s->left = n->left)){
     308    39294766 :         s->left->parent = s;
     309             :     }
     310    39294766 :     if((s->right = n->right)){
     311    39294766 :         s->right->parent = s;
     312             :     }
     313    39294766 :     if((s->parent = n->parent)){
     314    11534445 :         *(s->parent->left == n ? &s->parent->left : &s->parent->right) = s;//dereference(reference) allows the ternary operator to be an lvalue
     315             :     }
     316    39294766 :     s->balance = n->balance;
     317    39294766 :     n->left = NULL;//s is n's inorder successor and n has a right child so s does not have a left child.
     318    39294766 :     if((n->right = t.right)){
     319     5440608 :         n->right->parent = n;
     320             :     }
     321    39294766 :     if((n->parent = t.parent)){
     322    39294766 :         *(n->parent->left == s ? &n->parent->left : &n->parent->right) = n;
     323             :     }
     324    39294766 :     n->balance = t.balance;
     325    39294766 :     if(t.parent == n){//s was n's child.  In this case, these pointers loop back and need to be fixed.
     326    28803179 :         s->right = n;
     327    28803179 :         n->parent = s;
     328    28803179 :         n->right = t.right;
     329             :     }
     330    39294766 :     return cr8r_avl_remove_trunk(n, ft);
     331             : }
     332             : 
     333   177811296 : cr8r_avl_node *cr8r_avl_remove_trunk(cr8r_avl_node *n, cr8r_avl_ft *ft){
     334   177811296 :     cr8r_avl_node *p = n->parent, *c = n->left ? n->left : n->right, *r;//Parent, Child
     335   177811296 :     if(!p){
     336    38102400 :         if(c){
     337    12700800 :             c->parent = NULL;
     338             :         }
     339    38102400 :         ft->free(&ft->base, n);
     340    38102400 :         return c;//This does not indicate an error if NULL.
     341             :     }
     342   139708896 :     if(p->left == n){
     343    63785734 :         r = cr8r_avl_remove_retrace(n);//r is the root now
     344    63785734 :         n->parent->left = c;
     345    63785734 :         if(c){
     346    10800026 :             c->parent = n->parent;
     347             :         }
     348    63785734 :         ft->free(&ft->base, n);
     349    63785734 :         return r;
     350             :     }//p->right == n
     351    75923162 :     r = cr8r_avl_remove_retrace(n);//r is the root
     352    75923162 :     n->parent->right = c;
     353    75923162 :     if(c){
     354    15298863 :         c->parent = n->parent;
     355             :     }
     356    75923162 :     ft->free(&ft->base, n);
     357    75923162 :     return r;
     358             : }
     359             : 
     360   348868644 : cr8r_avl_node *cr8r_avl_insert_retrace(cr8r_avl_node *n){
     361   348868644 :     cr8r_avl_node *p = n->parent;
     362   348868644 :     if(!p){
     363             :         return n;
     364             :     }
     365   283550223 :     if(n == p->right){//+2 cases
     366   141775229 :         switch(p->balance){
     367    17904003 :             case -1://height change absorbed
     368    17904003 :             p->balance = 0;
     369    17904003 :             return cr8r_avl_root(p);
     370    98225937 :             case 0:
     371    98225937 :             p->balance = 1;
     372    98225937 :             return cr8r_avl_insert_retrace(p);
     373             :         }//default: p->balance == 1
     374    25645289 :         return cr8r_avl_insert_rebalance_r(p, n);//height change will be absorbed
     375             :     }//otherwise n == p->left
     376   141774994 :     switch(p->balance){//-2 cases
     377    17903877 :         case 1://height change absorbed
     378    17903877 :         p->balance = 0;
     379    17903877 :         return cr8r_avl_root(p);
     380    98225940 :         case 0:
     381    98225940 :         p->balance = -1;
     382    98225940 :         return cr8r_avl_insert_retrace(p);
     383             :     }//default: p->balance == -1
     384    25645177 :     return cr8r_avl_insert_rebalance_l(p, n);//height change will be absorbed
     385             : }
     386             : 
     387    25645289 : cr8r_avl_node *cr8r_avl_insert_rebalance_r(cr8r_avl_node *p, cr8r_avl_node *n){
     388    25645289 :     if(n->balance == 1){//right-right case: only one rotation needed
     389    12822689 :         cr8r_avl_rotate_r(p);//note n becomes the parent of p
     390    12822689 :         p->balance = n->balance = 0;
     391    12822689 :         return cr8r_avl_root(n);
     392             :     }//otherwise right-left case: two rotations are required and the balance factors have 3 cases
     393    12822600 :     cr8r_avl_rotate_l(n);
     394    12822600 :     cr8r_avl_rotate_r(p);//note p, n->left, n change roles from parent, right child, right-left grandchild to left child, parent, right child
     395    12822600 :     n->balance = +(n->parent->balance == -1);//n, now the right child of n->parent, its old left child, has a balance factor of 1 if the child was -1, else 0
     396    12822600 :     p->balance = -(n->parent->balance == 1);//p, now the right child of n->parent, has a balance factor of -1 if n->parent was 1, else 0
     397    12822600 :     n->parent->balance = 0;//if this is still confusing, try drawing out all of the possible trees with root +2 and right child +/-1 with irrelevant subtrees only marked as heights.
     398    12822600 :     return cr8r_avl_root(n->parent);//there are 4 cases and I will try to put them in a pdf somewhere if I can figure out how to draw it on a computer.
     399             : }
     400             : 
     401    25645177 : cr8r_avl_node *cr8r_avl_insert_rebalance_l(cr8r_avl_node *p, cr8r_avl_node *n){//mirror image of cr8r_avl_insert_rebalance_r
     402    25645177 :     if(n->balance == -1){
     403    12822590 :         cr8r_avl_rotate_l(p);
     404    12822590 :         p->balance = n->balance = 0;
     405    12822590 :         return cr8r_avl_root(n);
     406             :     }
     407    12822587 :     cr8r_avl_rotate_r(n);
     408    12822587 :     cr8r_avl_rotate_l(p);
     409    12822587 :     n->balance = -(n->parent->balance == 1);
     410    12822587 :     p->balance = +(n->parent->balance == -1);//unary + for symmetry
     411    12822587 :     n->parent->balance = 0;
     412    12822587 :     return cr8r_avl_root(n->parent);
     413             : }
     414             : 
     415   227511220 : cr8r_avl_node *cr8r_avl_remove_retrace(cr8r_avl_node *n){
     416   227511220 :     cr8r_avl_node *p = n->parent;
     417   227511220 :     if(!p){
     418             :         return n;
     419             :     }
     420   174893620 :     if(n == p->left){//+2 cases
     421    78732966 :         switch(p->balance){
     422    38686487 :             case -1:
     423    38686487 :             p->balance = 0;
     424    38686487 :             return cr8r_avl_remove_retrace(p);
     425    32607414 :             case 0://change in height absorbed
     426    32607414 :             p->balance = 1;
     427    32607414 :             return cr8r_avl_root(p);
     428             :         }//default: p->balance == 1
     429     7439065 :         return cr8r_avl_remove_rebalance_l(p);
     430             :     }//otherwise n == p->right
     431    96160654 :     switch(p->balance){//-2 cases
     432    30565751 :         case 1:
     433    30565751 :         p->balance = 0;
     434    30565751 :         return cr8r_avl_remove_retrace(p);
     435    51096983 :         case 0://change in height absorbed
     436    51096983 :         p->balance = -1;
     437    51096983 :         return cr8r_avl_root(p);
     438             :     }//default: p->balance == -1
     439    14497920 :     return cr8r_avl_remove_rebalance_r(p);
     440             : }
     441             : 
     442     7439065 : cr8r_avl_node *cr8r_avl_remove_rebalance_l(cr8r_avl_node *p){//do not try to understand this until you understand cr8r_avl_insert_rebalance_r
     443     7439065 :     cr8r_avl_node *n = p->right;//If we've become off balance by a left REMOVAL there must be a right child
     444     7439065 :     if(n->balance != -1){//not the right-left case
     445     3878519 :         cr8r_avl_rotate_r(p);//nb. the pointers n and p point to the same nodes but now n is the parent
     446     3878519 :         p->balance -= n->balance--;//if n is +1, n and p become 0, otherwise n is 0 and they become -1 and +1
     447     3878519 :         return n->balance ? cr8r_avl_root(n) : cr8r_avl_remove_retrace(n);//if n->balance becomes 0 by removal we still have height decrease to propagate
     448             :     }//right-left case.  This is exactly the same as insertion whereas the previous part included a right-even case not present in insertion
     449     3560546 :     cr8r_avl_rotate_l(n);
     450     3560546 :     cr8r_avl_rotate_r(p);
     451     3560546 :     p->balance = -(n->parent->balance == 1);
     452     3560546 :     n->balance = +(n->parent->balance == -1);
     453     3560546 :     n->parent->balance = 0;
     454     3560546 :     return cr8r_avl_remove_retrace(n->parent);
     455             : }
     456             : 
     457    14497920 : cr8r_avl_node *cr8r_avl_remove_rebalance_r(cr8r_avl_node *p){//mirror image of cr8r_avl_remove_rebalance_l
     458    14497920 :     cr8r_avl_node *n = p->left;
     459    14497920 :     if(n->balance != 1){
     460     9331200 :         cr8r_avl_rotate_l(p);
     461     9331200 :         p->balance -= n->balance++;//if n is -1, n and p become 0, otherwise n is 0 and they become +1 and -1.  Note the -= needn't be flipped since -- was
     462     9331200 :         return n->balance ? cr8r_avl_root(n) : cr8r_avl_remove_retrace(n);
     463             :     }
     464     5166720 :     cr8r_avl_rotate_r(n);
     465     5166720 :     cr8r_avl_rotate_l(p);
     466     5166720 :     p->balance = +(n->parent->balance == -1);
     467     5166720 :     n->balance = -(n->parent->balance == 1);
     468     5166720 :     n->parent->balance = 0;
     469     5166720 :     return cr8r_avl_remove_retrace(n->parent);
     470             : }
     471             : 
     472    56526243 : cr8r_avl_node *cr8r_avl_rotate_l(cr8r_avl_node *n){//does not update balance factors because the caller knows better
     473    56526243 :     cr8r_avl_node *l = n->left;//assume existence of swapped node
     474    56526243 :     l->parent = n->parent;
     475    56526243 :     if(n->parent){
     476    30554401 :         if(n->parent->left == n){
     477     7448551 :             n->parent->left = l;
     478             :         }else{//n->parent->right == n
     479    23105850 :             n->parent->right = l;
     480             :         }
     481             :     }
     482    56526243 :     n->parent = l;
     483    56526243 :     n->left = l->right;
     484    56526243 :     if(n->left){
     485    10472505 :         n->left->parent = n;
     486             :     }
     487    56526243 :     l->right = n;
     488    56526243 :     return l;
     489             : }
     490             : 
     491    51073661 : cr8r_avl_node *cr8r_avl_rotate_r(cr8r_avl_node *n){
     492    51073661 :     cr8r_avl_node *r = n->right;//assume existence of swapped node
     493    51073661 :     r->parent = n->parent;
     494    51073661 :     if(n->parent){
     495    31642295 :         if(n->parent->left == n){
     496    24193647 :             n->parent->left = r;
     497             :         }else{//n->parent->right == n
     498     7448648 :             n->parent->right = r;
     499             :         }
     500             :     }
     501    51073661 :     n->parent = r;
     502    51073661 :     n->right = r->left;
     503    51073661 :     if(n->right){
     504     8260731 :         n->right->parent = n;
     505             :     }
     506    51073661 :     r->left = n;
     507    51073661 :     return r;
     508             : }
     509             : 
     510         193 : void cr8r_avl_delete(cr8r_avl_node *r, cr8r_avl_ft *ft){
     511         193 :     if(!r)return;
     512          96 :     cr8r_avl_delete(r->left, ft);
     513          96 :     cr8r_avl_delete(r->right, ft);
     514          96 :     ft->free(&ft->base, r);
     515             : }
     516             : 
     517          96 : cr8r_avl_node *cr8r_avl_attach(cr8r_avl_node *r, cr8r_avl_node *n, cr8r_avl_ft *ft, int *is_duplicate){
     518          96 :     if(!r){
     519           0 :         if(is_duplicate){
     520           0 :             *is_duplicate = 0;
     521             :         }
     522           0 :         return n;
     523             :     }
     524          96 :     r = cr8r_avl_search_dups(r, n->data, ft, is_duplicate);
     525          96 :     int ord = ft->cmp(&ft->base, r->data, n->data);
     526          96 :     if(ord > 0){
     527          49 :         r->left = n;
     528          47 :     }else if(ord < 0 || r->balance < 0){
     529          47 :         r->right = n;
     530             :     }else{
     531           0 :         r->left = n;
     532             :     }
     533          96 :     n->parent = r;
     534          96 :     return cr8r_avl_insert_retrace(n);
     535             : }
     536             : 
     537           0 : cr8r_avl_node *cr8r_avl_attach_exclusive(cr8r_avl_node *r, cr8r_avl_node *n, cr8r_avl_ft *ft){
     538           0 :     if(!r){
     539             :         return n;
     540             :     }
     541           0 :     r = cr8r_avl_search(r, n->data, ft);
     542           0 :     int ord = ft->cmp(&ft->base, r->data, n->data);
     543           0 :     if(!ord){
     544             :         return NULL;
     545             :     }
     546           0 :     if(ord > 0){
     547           0 :         r->left = n;
     548             :     }else{
     549           0 :         r->right = n;
     550             :     }
     551           0 :     n->parent = r;
     552           0 :     return cr8r_avl_insert_retrace(n);
     553             : }
     554             : 
     555          96 : void cr8r_default_free_pass(cr8r_base_ft *ft, void *p){}
     556             : 
     557          96 : cr8r_avl_node *cr8r_avl_detach(cr8r_avl_node *n, cr8r_avl_ft *ft){
     558          96 :     cr8r_avl_ft ft_cpy = *ft;
     559          96 :     ft_cpy.free = cr8r_default_free_pass;
     560          96 :     cr8r_avl_node *r = cr8r_avl_remove_node(n, &ft_cpy);
     561          96 :     n->left = n->right = n->parent = NULL;
     562          96 :     n->balance = 0;
     563          96 :     return r;
     564             : }
     565             : 
     566          96 : cr8r_avl_node *cr8r_avl_decrease(cr8r_avl_node *n, cr8r_avl_ft *ft, int *is_duplicate){
     567          96 :     cr8r_avl_node *p = cr8r_avl_prev(n);
     568          96 :     int ord;
     569          96 :     if(!p || (ord = ft->cmp(&ft->base, p->data, n->data)) < 0){
     570          96 :         if(is_duplicate){
     571           0 :             *is_duplicate = 0;
     572             :         }
     573          96 :         return cr8r_avl_root(n);
     574           0 :     }else if(!ord){
     575           0 :         if(is_duplicate){
     576           0 :             *is_duplicate = 1;
     577             :         }
     578           0 :         return cr8r_avl_root(n);
     579             :     }
     580           0 :     p = cr8r_avl_detach(n, ft);
     581           0 :     return cr8r_avl_attach(p, n, ft, is_duplicate);
     582             : }
     583             : 
     584          96 : cr8r_avl_node *cr8r_avl_increase(cr8r_avl_node *n, cr8r_avl_ft *ft, int *is_duplicate){
     585          96 :     cr8r_avl_node *s = cr8r_avl_next(n);
     586          96 :     int ord;
     587          96 :     if(!s || (ord = ft->cmp(&ft->base, s->data, n->data)) > 0){
     588           0 :         if(is_duplicate){
     589           0 :             *is_duplicate = 0;
     590             :         }
     591           0 :         return cr8r_avl_root(n);
     592          96 :     }else if(!ord){
     593           0 :         if(is_duplicate){
     594           0 :             *is_duplicate = 1;
     595             :         }
     596           0 :         return cr8r_avl_root(n);
     597             :     }
     598          96 :     s = cr8r_avl_detach(n, ft);
     599          96 :     return cr8r_avl_attach(s, n, ft, is_duplicate);
     600             : }
     601             : 
     602        3037 : cr8r_avl_node *cr8r_avl_first_post(cr8r_avl_node *r){
     603        7073 :     while(1){
     604        7073 :         if(r->left){
     605        3553 :             r = r->left;
     606        3520 :         }else if(r->right){
     607         483 :             r = r->right;
     608             :         }else{
     609        3037 :             return r;
     610             :         }
     611             :     }
     612             : }
     613             : 
     614        7073 : cr8r_avl_node *cr8r_avl_next_post(cr8r_avl_node *n){
     615        7073 :     return n->parent && n == n->parent->left && n->parent->right ? cr8r_avl_first_post(n->parent->right) : n->parent;
     616             : }
     617             : 
     618        6320 : void cr8r_avl_swap_data(cr8r_avl_node *a, cr8r_avl_node *b, uint64_t size){
     619        6320 :     char tmp[size];
     620        6320 :     memcpy(tmp, a->data, size);
     621        6320 :     memcpy(a->data, b->data, size);
     622        6320 :     memcpy(b->data, tmp, size);
     623        6320 : }
     624             : 
     625        4136 : void cr8r_avl_sift_down(cr8r_avl_node *r, cr8r_avl_ft *ft){
     626        4136 :     cr8r_avl_sift_down_bounded(r, NULL, ft);
     627        4136 : }
     628             : 
     629             : // sift down for a partially max heap / partially bst avl tree, where u is the first node (in inorder traversal order)
     630             : // in the bst portion (and also an upper bound for the max heap under ft->cmp).
     631             : // When u is NULL, this decays to sift down for a fully max heap avl tree.
     632             : // Partially max heap / partially bst avl trees only arise during execution of avl_reorder,
     633             : // and that function does some extra pointer juggling to ensure that only checking right children for u and stopping once
     634             : // it is found is correct; see that function for more info
     635        4224 : void cr8r_avl_sift_down_bounded(cr8r_avl_node *r, cr8r_avl_node *u, cr8r_avl_ft *ft){
     636       10456 :     cr8r_avl_node *max_child;
     637       16688 :     while(1){
     638       10456 :         if(r->right && r->right != u){
     639        7716 :             if(r->left){
     640        6948 :                 max_child = ft->cmp(&ft->base, r->left->data, r->right->data) >= 0 ? r->left : r->right;
     641             :             }else{
     642         768 :                 max_child = r->right;
     643             :             }
     644        2740 :         }else if(r->left){
     645         900 :             max_child = r->left;
     646             :         }else{
     647             :             break;
     648             :         }
     649        8616 :         if(ft->cmp(&ft->base, max_child->data, r->data) <= 0){
     650             :             break;
     651             :         }
     652        6232 :         cr8r_avl_swap_data(max_child, r, ft->base.size);
     653        6232 :         r = max_child;
     654             :     }
     655        4224 : }
     656             : 
     657           2 : void cr8r_avl_heapify(cr8r_avl_node *r, cr8r_avl_ft *ft){
     658        7075 :     for(r = cr8r_avl_first_post(r); r; r = cr8r_avl_next_post(r)){
     659        7073 :         if(r->left || r->right){
     660        4036 :             cr8r_avl_sift_down(r, ft);
     661             :         }
     662             :     }
     663           2 : }
     664             : 
     665         100 : cr8r_avl_node *cr8r_avl_heappop_node(cr8r_avl_node **r, cr8r_avl_ft *ft){
     666         100 :     if(!*r){
     667             :         return NULL;
     668             :     }
     669         100 :     cr8r_avl_node *s = *r;
     670        1500 :     while(1){
     671        1500 :         if(s->balance == -1){
     672         726 :             s = s->left;
     673         774 :         }else if(s->right){
     674         674 :             s = s->right;
     675             :         }else{
     676             :             break;
     677             :         }
     678             :     }
     679         100 :     if(s == *r){
     680           0 :         *r = NULL;
     681           0 :         return s;
     682             :     }
     683         451 :     for(cr8r_avl_node *u = s; u != *r; u = u->parent){
     684         451 :         signed char db = u->parent->left == u ? 1 : -1;
     685         451 :         u->parent->balance += db;
     686         451 :         if(u->parent->balance){
     687             :             break;
     688             :         }
     689             :     }
     690         100 :     if(s->parent->left == s){
     691          48 :         s->parent->left = NULL;
     692             :     }else{
     693          52 :         s->parent->right = NULL;
     694             :     }
     695         100 :     s->parent = NULL;//(*r)->parent must be NULL
     696         100 :     if((s->left = (*r)->left)){
     697         100 :         s->left->parent = s;
     698             :     }
     699         100 :     if((s->right = (*r)->right)){
     700         100 :         s->right->parent = s;
     701             :     }
     702         100 :     s->balance = (*r)->balance;
     703         100 :     CR8R_AVL_ASSERT_ALL(s);
     704         100 :     (*r)->left = (*r)->right = NULL;
     705         100 :     (*r)->balance = 0;
     706         100 :     cr8r_avl_node *res = *r;
     707         100 :     *r = s;
     708         100 :     cr8r_avl_sift_down(s, ft);
     709         100 :     return res;
     710             : }
     711             : 
     712           1 : void cr8r_avl_reorder(cr8r_avl_node *r, cr8r_avl_ft *ft){
     713           1 :     cr8r_avl_heapify(r, ft);
     714           1 :     cr8r_avl_reorder_recursive(r, ft);
     715           1 : }
     716             : 
     717           9 : void cr8r_avl_reorder_recursive(cr8r_avl_node *r, cr8r_avl_ft *ft){
     718           9 :     if(!r){
     719             :         return;
     720             :     }
     721             :     // in this function, r is initially fully a max heap, but as we proceed, we convert
     722             :     // it to a bst in reverse inorder order.  We do this by repeatedly swapping the data
     723             :     // in the root of the max heap portion with the first unvisited node in reverse inorder order.
     724             :     // Then we sift down the root of the max heap to preserve the max heap invariant on the
     725             :     // heap portion of the avl tree.  The bst portion trivially has its bst invariant satisfied,
     726             :     // and we never break the avl invariants because we never actually change the shape of the tree.
     727             :     // HOWEVER, if leave the links in the tree alone, then the max heap region and the bst region
     728             :     // are not "nice": in particular if the node we are on in reverse inorder traversal has a left subtree,
     729             :     // then we have visited it and its right subtree and when we call sift down it would have to
     730             :     // determine if it ever ran into u or one of u's reverse inorder predecessors and skip any such nodes.
     731             :     // To avoid this, we use sift_down_bounded and adjust the links in the tree as we go
     732          96 :     for(cr8r_avl_node *u = cr8r_avl_last(r); u != r;){
     733          88 :         cr8r_avl_swap_data(u, r, ft->base.size);
     734          88 :         cr8r_avl_sift_down_bounded(r, u, ft);
     735          88 :         if(u->left){
     736             :             // if u has a left subtree, the next node in reverse inorder is cr8r_avl_first(u->left),
     737             :             // but we want sift_down_bounded to skip u and its reverse inorder predecessors (ie the nodes
     738             :             // in the bst portion of the avl tree).  Therefore, we find the FIRST ancestor of u where u is in its right subtree,
     739             :             // and we change its right pointer to point to u->left instead.  This ancestor is guaranteed to exist because
     740             :             // u is a right descendent of the root (in a reverse inorder traversal this is true until we hit the root, so once we
     741             :             // hit the root we force it to continue to be true by recursing on the left subtree, see below).
     742             :             // Changing the first left ancestor of u (first ancestor where u is a right descendent) so its right child is u->left
     743             :             // breaks the structure of the tree, but we will fix it later.
     744             :             // Notice that for ancestors where u is in their left subtree, they are reverse inorder predecessors of u, so
     745             :             // they have already been visited.
     746          46 :             cr8r_avl_reorder_retrace(u->left);
     747          46 :             u = cr8r_avl_last(u->left);
     748             :         }else{
     749             :             // find the first left ancestor of u (which must itself be either the root or in the right subtree of the root, since u is in
     750             :             // the right subtree of the root).  Since u has no left subtree, this is u's successor in reverse inorder traversal.
     751             :             // We also fix this first left ancestor so that its right child pointer points at its descendent again and not u.
     752          42 :             u = cr8r_avl_reorder_relink(u);
     753             :         }
     754             :     }
     755             :     // if u == r, we have reached the root node.  At this point, the top of the heap and the current node in reverse inorder traversal
     756             :     // are the same, so we don't actually have to call avl_swap_data here.
     757             :     // We also don't need to temporarily set r->left->parent to NULL, because this recursive call will only look for left ancestors of
     758             :     // u for u in the right subtree of r->left, so the left ancestor search will always terminate at or before r->left.
     759             :     // Then the recursive call will recurse to r->left->left if needed and so on.
     760           8 :     cr8r_avl_reorder_recursive(r->left, ft);
     761             : }
     762             : 
     763             : // given n the nonempty left subtree of the just-filled current reverse inorder traversal node u,
     764             : // find the first left ancestor of n (the first ancestor where n is a right descendent),
     765             : // and change this ancestor's right link to point at n instead.  Note that u == n->parent, and the
     766             : // original shape of the tree can be recovered later: when we walk up from u, any ancestor that is
     767             : // a left child of its parent will still have the correct parent pointer and its parent will still have
     768             : // it as a left child.  However, the first ancestor that is a right child of its parent will have its parent
     769             : // pointer correct but its parent's right child will point to n instead of it.
     770             : // this might fail to find a left ancestor, but recursing on the left subtree when u reaches the root ensures
     771             : // the root is always a left ancestor.  This ensures calling sift_down_bounded on the root with u as the
     772             : // bound will see all nodes after u in the reverse inorder traversal of the original tree: when u has a left
     773             : // subtree, its entire left subtree is after it in this traversal, and in particular the rightmost element of
     774             : // its left subtree is its successor in the traversal.  Also, any time we visit a node on the left edge of the
     775             : // left subtree, we update the first left ancestor to point at its left subtree as well, if any.
     776          46 : void cr8r_avl_reorder_retrace(cr8r_avl_node *n){
     777          46 :     cr8r_avl_node *a = n;
     778         129 :     while(a == a->parent->left){
     779          83 :         a = a->parent;
     780             :     }
     781          46 :     a->parent->right = n;
     782          46 : }
     783             : 
     784             : // when u does not have a left child, its reverse inorder successor will instead be its first left ancestor.
     785             : // of course, this is also the node whose right child pointer we clobbered when first moving from any
     786             : // ancestor of u before its first left ancestor, so now is when we fix it up.
     787          42 : cr8r_avl_node *cr8r_avl_reorder_relink(cr8r_avl_node *n){
     788          88 :     while(n == n->parent->left){
     789          46 :         n = n->parent;
     790             :     }
     791          42 :     n->parent->right = n;
     792          42 :     return n->parent;
     793             : }
     794             : 

Generated by: LCOV version 1.14