back to topotato report
topotato coverage report
Current view: top level - lib - typesafe.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 202 299 67.6 %
Date: 2023-02-24 19:38:44 Functions: 15 21 71.4 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2019  David Lamparter, for NetDEF, Inc.
       3             :  *
       4             :  * Permission to use, copy, modify, and distribute this software for any
       5             :  * purpose with or without fee is hereby granted, provided that the above
       6             :  * copyright notice and this permission notice appear in all copies.
       7             :  *
       8             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       9             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      10             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      11             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      12             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      13             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      14             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      15             :  */
      16             : 
      17             : #ifdef HAVE_CONFIG_H
      18             : #include "config.h"
      19             : #endif
      20             : 
      21             : #include <stdlib.h>
      22             : #include <string.h>
      23             : #include <assert.h>
      24             : 
      25             : #include "typesafe.h"
      26             : #include "memory.h"
      27             : #include "network.h"
      28             : 
      29         670 : DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket");
      30         670 : DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow");
      31         670 : DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array");
      32             : 
      33             : struct slist_item typesafe_slist_sentinel = { NULL };
      34             : 
      35           0 : bool typesafe_list_member(const struct slist_head *head,
      36             :                           const struct slist_item *item)
      37             : {
      38           0 :         struct slist_item *fromhead = head->first;
      39           0 :         struct slist_item **fromnext = (struct slist_item **)&item->next;
      40             : 
      41           0 :         while (fromhead != _SLIST_LAST) {
      42           0 :                 if (fromhead == item || fromnext == head->last_next)
      43             :                         return true;
      44             : 
      45           0 :                 fromhead = fromhead->next;
      46           0 :                 if (!*fromnext || *fromnext == _SLIST_LAST)
      47             :                         break;
      48           0 :                 fromnext = &(*fromnext)->next;
      49             :         }
      50             : 
      51             :         return false;
      52             : }
      53             : 
      54           0 : bool typesafe_dlist_member(const struct dlist_head *head,
      55             :                            const struct dlist_item *item)
      56             : {
      57           0 :         const struct dlist_item *fromhead = head->hitem.next;
      58           0 :         const struct dlist_item *fromitem = item->next;
      59             : 
      60           0 :         if (!item->prev || !item->next)
      61             :                 return false;
      62             : 
      63           0 :         while (fromhead != &head->hitem && fromitem != item) {
      64           0 :                 if (fromitem == &head->hitem || fromhead == item)
      65             :                         return true;
      66           0 :                 fromhead = fromhead->next;
      67           0 :                 fromitem = fromitem->next;
      68             :         }
      69             : 
      70             :         return false;
      71             : }
      72             : 
      73             : #if 0
      74             : static void hash_consistency_check(struct thash_head *head)
      75             : {
      76             :         uint32_t i;
      77             :         struct thash_item *item, *prev;
      78             : 
      79             :         for (i = 0; i < HASH_SIZE(*head); i++) {
      80             :                 item = head->entries[i];
      81             :                 prev = NULL;
      82             :                 while (item) {
      83             :                         assert(HASH_KEY(*head, item->hashval) == i);
      84             :                         assert(!prev || item->hashval >= prev->hashval);
      85             :                         prev = item;
      86             :                         item = item->next;
      87             :                 }
      88             :         }
      89             : }
      90             : #else
      91             : #define hash_consistency_check(x)
      92             : #endif
      93             : 
      94        6919 : void typesafe_hash_grow(struct thash_head *head)
      95             : {
      96        6919 :         uint32_t newsize = head->count, i, j;
      97        6919 :         uint8_t newshift, delta;
      98             : 
      99        6919 :         hash_consistency_check(head);
     100             : 
     101        6919 :         newsize |= newsize >> 1;
     102        6919 :         newsize |= newsize >> 2;
     103        6919 :         newsize |= newsize >> 4;
     104        6919 :         newsize |= newsize >> 8;
     105        6919 :         newsize |= newsize >> 16;
     106        6919 :         newsize++;
     107        6919 :         newshift = __builtin_ctz(newsize) + 1;
     108             : 
     109        6919 :         if (head->maxshift && newshift > head->maxshift)
     110        6919 :                 newshift = head->maxshift;
     111        6919 :         if (newshift == head->tabshift)
     112             :                 return;
     113        6919 :         newsize = _HASH_SIZE(newshift);
     114             : 
     115        6919 :         head->entries = XREALLOC(MTYPE_TYPEDHASH_BUCKET, head->entries,
     116             :                         sizeof(head->entries[0]) * newsize);
     117        6919 :         memset(head->entries + HASH_SIZE(*head), 0,
     118             :                         sizeof(head->entries[0]) *
     119        6919 :                                 (newsize - HASH_SIZE(*head)));
     120             : 
     121        6919 :         delta = newshift - head->tabshift;
     122             : 
     123        6919 :         i = HASH_SIZE(*head);
     124        6919 :         if (i == 0)
     125        2784 :                 goto out;
     126       20046 :         do {
     127       20046 :                 struct thash_item **apos, *item;
     128             : 
     129       20046 :                 i--;
     130       20046 :                 apos = &head->entries[i];
     131             : 
     132       60138 :                 for (j = 0; j < (1U << delta); j++) {
     133       40092 :                         item = *apos;
     134       40092 :                         *apos = NULL;
     135             : 
     136       40092 :                         head->entries[(i << delta) + j] = item;
     137       40092 :                         apos = &head->entries[(i << delta) + j];
     138             : 
     139       56003 :                         while ((item = *apos)) {
     140       22914 :                                 uint32_t midbits;
     141       22914 :                                 midbits = _HASH_KEY(newshift, item->hashval);
     142       22914 :                                 midbits &= (1 << delta) - 1;
     143       22914 :                                 if (midbits > j)
     144             :                                         break;
     145       15911 :                                 apos = &item->next;
     146             :                         }
     147             :                 }
     148       20046 :         } while (i > 0);
     149             : 
     150        4135 : out:
     151        6919 :         head->tabshift = newshift;
     152        6919 :         hash_consistency_check(head);
     153             : }
     154             : 
     155       14372 : void typesafe_hash_shrink(struct thash_head *head)
     156             : {
     157       14372 :         uint32_t newsize = head->count, i, j;
     158       14372 :         uint8_t newshift, delta;
     159             : 
     160       14372 :         hash_consistency_check(head);
     161             : 
     162       14372 :         if (!head->count) {
     163       10340 :                 XFREE(MTYPE_TYPEDHASH_BUCKET, head->entries);
     164       10340 :                 head->tabshift = 0;
     165       10340 :                 return;
     166             :         }
     167             : 
     168        4032 :         newsize |= newsize >> 1;
     169        4032 :         newsize |= newsize >> 2;
     170        4032 :         newsize |= newsize >> 4;
     171        4032 :         newsize |= newsize >> 8;
     172        4032 :         newsize |= newsize >> 16;
     173        4032 :         newsize++;
     174        4032 :         newshift = __builtin_ctz(newsize) + 1;
     175             : 
     176        4032 :         if (head->minshift && newshift < head->minshift)
     177        4032 :                 newshift = head->minshift;
     178        4032 :         if (newshift == head->tabshift)
     179             :                 return;
     180        4032 :         newsize = _HASH_SIZE(newshift);
     181             : 
     182        4032 :         delta = head->tabshift - newshift;
     183             : 
     184       23792 :         for (i = 0; i < newsize; i++) {
     185       19760 :                 struct thash_item **apos = &head->entries[i];
     186             : 
     187       59280 :                 for (j = 0; j < (1U << delta); j++) {
     188       39520 :                         *apos = head->entries[(i << delta) + j];
     189       55248 :                         while (*apos)
     190       15728 :                                 apos = &(*apos)->next;
     191             :                 }
     192             :         }
     193        4032 :         head->entries = XREALLOC(MTYPE_TYPEDHASH_BUCKET, head->entries,
     194             :                         sizeof(head->entries[0]) * newsize);
     195        4032 :         head->tabshift = newshift;
     196             : 
     197       14372 :         hash_consistency_check(head);
     198             : }
     199             : 
     200             : /* skiplist */
     201             : 
     202       29406 : static inline struct sskip_item *sl_level_get(const struct sskip_item *item,
     203             :                         size_t level)
     204             : {
     205       28387 :         if (level < SKIPLIST_OVERFLOW)
     206        7355 :                 return item->next[level];
     207       21032 :         if (level == SKIPLIST_OVERFLOW && !((uintptr_t)item->next[level] & 1))
     208             :                 return item->next[level];
     209             : 
     210       20958 :         uintptr_t ptrval = (uintptr_t)item->next[SKIPLIST_OVERFLOW];
     211       20958 :         ptrval &= UINTPTR_MAX - 3;
     212       20958 :         struct sskip_overflow *oflow = (struct sskip_overflow *)ptrval;
     213       20958 :         return oflow->next[level - SKIPLIST_OVERFLOW];
     214             : }
     215             : 
     216        4713 : static inline void sl_level_set(struct sskip_item *item, size_t level,
     217             :                 struct sskip_item *value)
     218             : {
     219        4713 :         if (level < SKIPLIST_OVERFLOW)
     220        4155 :                 item->next[level] = value;
     221         558 :         else if (level == SKIPLIST_OVERFLOW && !((uintptr_t)item->next[level] & 1))
     222          37 :                 item->next[level] = value;
     223             :         else {
     224         521 :                 uintptr_t ptrval = (uintptr_t)item->next[SKIPLIST_OVERFLOW];
     225         521 :                 ptrval &= UINTPTR_MAX - 3;
     226         521 :                 struct sskip_overflow *oflow = (struct sskip_overflow *)ptrval;
     227         521 :                 oflow->next[level - SKIPLIST_OVERFLOW] = value;
     228             :         }
     229        4713 : }
     230             : 
     231         795 : struct sskip_item *typesafe_skiplist_add(struct sskip_head *head,
     232             :                 struct sskip_item *item,
     233             :                 int (*cmpfn)(const struct sskip_item *a,
     234             :                                 const struct sskip_item *b))
     235             : {
     236         795 :         size_t level = SKIPLIST_MAXDEPTH, newlevel, auxlevel;
     237         795 :         struct sskip_item *prev = &head->hitem, *next, *auxprev, *auxnext;
     238         795 :         int cmpval;
     239             : 
     240             :         /* level / newlevel are 1-counted here */
     241         795 :         newlevel = __builtin_ctz(frr_weak_random()) + 1;
     242         795 :         if (newlevel > SKIPLIST_MAXDEPTH)
     243           0 :                 newlevel = SKIPLIST_MAXDEPTH;
     244             : 
     245         795 :         next = NULL;
     246       13075 :         while (level >= newlevel) {
     247       12280 :                 next = sl_level_get(prev, level - 1);
     248       12280 :                 if (!next) {
     249       11615 :                         level--;
     250       11615 :                         continue;
     251             :                 }
     252         665 :                 cmpval = cmpfn(next, item);
     253         665 :                 if (cmpval < 0) {
     254         336 :                         prev = next;
     255         336 :                         continue;
     256         329 :                 } else if (cmpval == 0) {
     257           0 :                         return next;
     258             :                 }
     259             :                 level--;
     260             :         }
     261             : 
     262             :         /* check for duplicate item - could be removed if code doesn't rely
     263             :          * on it, but not really work the complication. */
     264             :         auxlevel = level;
     265             :         auxprev = prev;
     266        1571 :         while (auxlevel) {
     267         776 :                 auxlevel--;
     268         776 :                 auxnext = sl_level_get(auxprev, auxlevel);
     269         776 :                 cmpval = 1;
     270         908 :                 while (auxnext && (cmpval = cmpfn(auxnext, item)) < 0) {
     271         132 :                         auxprev = auxnext;
     272         132 :                         auxnext = sl_level_get(auxprev, auxlevel);
     273             :                 }
     274         776 :                 if (cmpval == 0)
     275           0 :                         return auxnext;
     276         795 :         };
     277             : 
     278         795 :         head->count++;
     279         795 :         memset(item, 0, sizeof(*item));
     280         795 :         if (newlevel > SKIPLIST_EMBED) {
     281          45 :                 struct sskip_overflow *oflow;
     282          45 :                 oflow = XMALLOC(MTYPE_SKIPLIST_OFLOW, sizeof(void *)
     283             :                                 * (newlevel - SKIPLIST_OVERFLOW));
     284          45 :                 item->next[SKIPLIST_OVERFLOW] = (struct sskip_item *)
     285          45 :                                 ((uintptr_t)oflow | 1);
     286             :         }
     287             : 
     288         795 :         sl_level_set(item, level, next);
     289         795 :         sl_level_set(prev, level, item);
     290             :         /* level is now 0-counted and < newlevel*/
     291        1571 :         while (level) {
     292         776 :                 level--;
     293         776 :                 next = sl_level_get(prev, level);
     294         908 :                 while (next && cmpfn(next, item) < 0) {
     295         132 :                         prev = next;
     296         132 :                         next = sl_level_get(prev, level);
     297             :                 }
     298             : 
     299         776 :                 sl_level_set(item, level, next);
     300         776 :                 sl_level_set(prev, level, item);
     301             :         };
     302             :         return NULL;
     303             : }
     304             : 
     305             : /* NOTE: level counting below is 1-based since that makes the code simpler! */
     306             : 
     307           0 : const struct sskip_item *typesafe_skiplist_find(
     308             :                 const struct sskip_head *head,
     309             :                 const struct sskip_item *item, int (*cmpfn)(
     310             :                                 const struct sskip_item *a,
     311             :                                 const struct sskip_item *b))
     312             : {
     313           0 :         size_t level = SKIPLIST_MAXDEPTH;
     314           0 :         const struct sskip_item *prev = &head->hitem, *next;
     315           0 :         int cmpval;
     316             : 
     317           0 :         while (level) {
     318           0 :                 next = sl_level_get(prev, level - 1);
     319           0 :                 if (!next) {
     320           0 :                         level--;
     321           0 :                         continue;
     322             :                 }
     323           0 :                 cmpval = cmpfn(next, item);
     324           0 :                 if (cmpval < 0) {
     325           0 :                         prev = next;
     326           0 :                         continue;
     327             :                 }
     328           0 :                 if (cmpval == 0)
     329           0 :                         return next;
     330             :                 level--;
     331             :         }
     332             :         return NULL;
     333             : }
     334             : 
     335           0 : const struct sskip_item *typesafe_skiplist_find_gteq(
     336             :                 const struct sskip_head *head,
     337             :                 const struct sskip_item *item, int (*cmpfn)(
     338             :                                 const struct sskip_item *a,
     339             :                                 const struct sskip_item *b))
     340             : {
     341           0 :         size_t level = SKIPLIST_MAXDEPTH;
     342           0 :         const struct sskip_item *prev = &head->hitem, *next;
     343           0 :         int cmpval;
     344             : 
     345           0 :         while (level) {
     346           0 :                 next = sl_level_get(prev, level - 1);
     347           0 :                 if (!next) {
     348           0 :                         level--;
     349           0 :                         continue;
     350             :                 }
     351           0 :                 cmpval = cmpfn(next, item);
     352           0 :                 if (cmpval < 0) {
     353           0 :                         prev = next;
     354           0 :                         continue;
     355             :                 }
     356           0 :                 if (cmpval == 0)
     357           0 :                         return next;
     358             :                 level--;
     359             :         }
     360             :         return next;
     361             : }
     362             : 
     363           0 : const struct sskip_item *typesafe_skiplist_find_lt(
     364             :                 const struct sskip_head *head,
     365             :                 const struct sskip_item *item, int (*cmpfn)(
     366             :                                 const struct sskip_item *a,
     367             :                                 const struct sskip_item *b))
     368             : {
     369           0 :         size_t level = SKIPLIST_MAXDEPTH;
     370           0 :         const struct sskip_item *prev = &head->hitem, *next, *best = NULL;
     371           0 :         int cmpval;
     372             : 
     373           0 :         while (level) {
     374           0 :                 next = sl_level_get(prev, level - 1);
     375           0 :                 if (!next) {
     376           0 :                         level--;
     377           0 :                         continue;
     378             :                 }
     379           0 :                 cmpval = cmpfn(next, item);
     380           0 :                 if (cmpval < 0) {
     381           0 :                         best = prev = next;
     382           0 :                         continue;
     383             :                 }
     384             :                 level--;
     385             :         }
     386           0 :         return best;
     387             : }
     388             : 
     389           0 : struct sskip_item *typesafe_skiplist_del(
     390             :         struct sskip_head *head, struct sskip_item *item,
     391             :         int (*cmpfn)(const struct sskip_item *a, const struct sskip_item *b))
     392             : {
     393           0 :         size_t level = SKIPLIST_MAXDEPTH;
     394           0 :         struct sskip_item *prev = &head->hitem, *next;
     395           0 :         int cmpval;
     396           0 :         bool found = false;
     397             : 
     398           0 :         while (level) {
     399           0 :                 next = sl_level_get(prev, level - 1);
     400           0 :                 if (!next) {
     401           0 :                         level--;
     402           0 :                         continue;
     403             :                 }
     404           0 :                 if (next == item) {
     405           0 :                         sl_level_set(prev, level - 1,
     406             :                                 sl_level_get(item, level - 1));
     407           0 :                         level--;
     408           0 :                         found = true;
     409           0 :                         continue;
     410             :                 }
     411           0 :                 cmpval = cmpfn(next, item);
     412           0 :                 if (cmpval < 0) {
     413           0 :                         prev = next;
     414           0 :                         continue;
     415             :                 }
     416             :                 level--;
     417             :         }
     418             : 
     419           0 :         if (!found)
     420             :                 return NULL;
     421             : 
     422             :         /* TBD: assert when trying to remove non-existing item? */
     423           0 :         head->count--;
     424             : 
     425           0 :         if ((uintptr_t)item->next[SKIPLIST_OVERFLOW] & 1) {
     426           0 :                 uintptr_t ptrval = (uintptr_t)item->next[SKIPLIST_OVERFLOW];
     427           0 :                 ptrval &= UINTPTR_MAX - 3;
     428           0 :                 struct sskip_overflow *oflow = (struct sskip_overflow *)ptrval;
     429           0 :                 XFREE(MTYPE_SKIPLIST_OFLOW, oflow);
     430             :         }
     431           0 :         memset(item, 0, sizeof(*item));
     432             : 
     433           0 :         return item;
     434             : }
     435             : 
     436        1019 : struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head)
     437             : {
     438        1019 :         size_t level = SKIPLIST_MAXDEPTH;
     439        1019 :         struct sskip_item *prev = &head->hitem, *next, *item;
     440             : 
     441        1019 :         item = sl_level_get(prev, 0);
     442        1019 :         if (!item)
     443             :                 return NULL;
     444             : 
     445       12720 :         do {
     446       12720 :                 level--;
     447             : 
     448       12720 :                 next = sl_level_get(prev, level);
     449       12720 :                 if (next != item)
     450       11149 :                         continue;
     451             : 
     452        1571 :                 sl_level_set(prev, level, sl_level_get(item, level));
     453       12720 :         } while (level);
     454             : 
     455         795 :         head->count--;
     456             : 
     457         795 :         if ((uintptr_t)item->next[SKIPLIST_OVERFLOW] & 1) {
     458          45 :                 uintptr_t ptrval = (uintptr_t)item->next[SKIPLIST_OVERFLOW];
     459          45 :                 ptrval &= UINTPTR_MAX - 3;
     460          45 :                 struct sskip_overflow *oflow = (struct sskip_overflow *)ptrval;
     461          45 :                 XFREE(MTYPE_SKIPLIST_OFLOW, oflow);
     462             :         }
     463         795 :         memset(item, 0, sizeof(*item));
     464             : 
     465         795 :         return item;
     466             : }
     467             : 
     468             : /* heap */
     469             : 
     470             : #if 0
     471             : static void heap_consistency_check(struct heap_head *head,
     472             :                                    int (*cmpfn)(const struct heap_item *a,
     473             :                                                 const struct heap_item *b),
     474             :                                    uint32_t pos)
     475             : {
     476             :         uint32_t rghtpos = pos + 1;
     477             :         uint32_t downpos = HEAP_NARY * (pos + 1);
     478             : 
     479             :         if (pos + 1 > ~0U / HEAP_NARY)
     480             :                 downpos = ~0U;
     481             : 
     482             :         if ((pos & (HEAP_NARY - 1)) != HEAP_NARY - 1 && rghtpos < head->count) {
     483             :                 assert(cmpfn(head->array[rghtpos], head->array[pos]) >= 0);
     484             :                 heap_consistency_check(head, cmpfn, rghtpos);
     485             :         }
     486             :         if (downpos < head->count) {
     487             :                 assert(cmpfn(head->array[downpos], head->array[pos]) >= 0);
     488             :                 heap_consistency_check(head, cmpfn, downpos);
     489             :         }
     490             : }
     491             : #else
     492             : #define heap_consistency_check(head, cmpfn, pos)
     493             : #endif
     494             : 
     495         436 : void typesafe_heap_resize(struct heap_head *head, bool grow)
     496             : {
     497         436 :         uint32_t newsize;
     498             : 
     499         436 :         if (grow) {
     500         218 :                 newsize = head->arraysz;
     501         218 :                 if (newsize <= 36)
     502             :                         newsize = 72;
     503           0 :                 else if (newsize < 262144)
     504           0 :                         newsize += newsize / 2;
     505           0 :                 else if (newsize < 0xaaaa0000)
     506           0 :                         newsize += newsize / 3;
     507             :                 else
     508           0 :                         assert(!newsize);
     509         218 :         } else if (head->count > 0) {
     510             :                 newsize = head->count;
     511             :         } else {
     512         218 :                 XFREE(MTYPE_HEAP_ARRAY, head->array);
     513         218 :                 head->arraysz = 0;
     514         218 :                 return;
     515             :         }
     516             : 
     517         218 :         newsize += HEAP_NARY - 1;
     518         218 :         newsize &= ~(HEAP_NARY - 1);
     519         218 :         if (newsize == head->arraysz)
     520             :                 return;
     521             : 
     522         218 :         head->array = XREALLOC(MTYPE_HEAP_ARRAY, head->array,
     523             :                                newsize * sizeof(struct heap_item *));
     524         218 :         head->arraysz = newsize;
     525             : }
     526             : 
     527        6176 : void typesafe_heap_pushdown(struct heap_head *head, uint32_t pos,
     528             :                 struct heap_item *item,
     529             :                 int (*cmpfn)(const struct heap_item *a,
     530             :                              const struct heap_item *b))
     531             : {
     532       20894 :         uint32_t rghtpos, downpos, moveto;
     533             : 
     534       35612 :         while (1) {
     535             :                 /* rghtpos: neighbor to the "right", inside block of NARY.
     536             :                  *          may be invalid if last in block, check nary_last()
     537             :                  * downpos: first neighbor in the "downwards" block further
     538             :                  *          away from the root
     539             :                  */
     540       20894 :                 rghtpos = pos + 1;
     541             : 
     542             :                 /* make sure we can use the full 4G items */
     543       20894 :                 downpos = HEAP_NARY * (pos + 1);
     544       20894 :                 if (pos + 1 > ~0U / HEAP_NARY)
     545             :                         /* multiplication overflowed.  ~0U is guaranteed
     546             :                          * to be an invalid index; size limit is enforced in
     547             :                          * resize()
     548             :                          */
     549           0 :                         downpos = ~0U;
     550             : 
     551             :                 /* only used on break */
     552       20894 :                 moveto = pos;
     553             : 
     554             : #define nary_last(x) (((x) & (HEAP_NARY - 1)) == HEAP_NARY - 1)
     555       20894 :                 if (downpos >= head->count
     556        3042 :                     || cmpfn(head->array[downpos], item) >= 0) {
     557             :                         /* not moving down; either at end or down is >= item */
     558       18108 :                         if (nary_last(pos) || rghtpos >= head->count
     559       12925 :                             || cmpfn(head->array[rghtpos], item) >= 0)
     560             :                                 /* not moving right either - got our spot */
     561             :                                 break;
     562             : 
     563             :                         moveto = rghtpos;
     564             : 
     565             :                 /* else: downpos is valid and < item.  choose between down
     566             :                  * or right (if the latter is an option) */
     567        5555 :                 } else if (nary_last(pos) || cmpfn(head->array[rghtpos],
     568        2769 :                                                    head->array[downpos]) >= 0)
     569             :                         moveto = downpos;
     570             :                 else
     571             :                         moveto = rghtpos;
     572             : #undef nary_last
     573             : 
     574       14718 :                 head->array[pos] = head->array[moveto];
     575       14718 :                 head->array[pos]->index = pos;
     576       14718 :                 pos = moveto;
     577             :         }
     578             : 
     579        6176 :         head->array[moveto] = item;
     580        6176 :         item->index = moveto;
     581             : 
     582        6176 :         heap_consistency_check(head, cmpfn, 0);
     583        6176 : }
     584             : 
     585        7006 : void typesafe_heap_pullup(struct heap_head *head, uint32_t pos,
     586             :                 struct heap_item *item,
     587             :                 int (*cmpfn)(const struct heap_item *a,
     588             :                              const struct heap_item *b))
     589             : {
     590        7006 :         uint32_t moveto;
     591             : 
     592       21198 :         while (pos != 0) {
     593       19121 :                 if ((pos & (HEAP_NARY - 1)) == 0)
     594        1575 :                         moveto = pos / HEAP_NARY - 1;
     595             :                 else
     596       17546 :                         moveto = pos - 1;
     597             : 
     598       19121 :                 if (cmpfn(head->array[moveto], item) <= 0)
     599             :                         break;
     600             : 
     601       14192 :                 head->array[pos] = head->array[moveto];
     602       14192 :                 head->array[pos]->index = pos;
     603             : 
     604       14192 :                 pos = moveto;
     605             :         }
     606             : 
     607        7006 :         head->array[pos] = item;
     608        7006 :         item->index = pos;
     609             : 
     610        7006 :         heap_consistency_check(head, cmpfn, 0);
     611        7006 : }

Generated by: LCOV version v1.16-topotato