LCOV - code coverage report
Current view: top level - source/flat_priority_queue.c (source / functions) Coverage Total Hit
Test: CCC Test Suite Coverage Report Lines: 98.8 % 335 331
Test Date: 2026-04-02 00:15:37 Functions: 100.0 % 31 31

            Line data    Source code
       1              : /** Copyright 2025 Alexander G. Lopez
       2              : 
       3              : Licensed under the Apache License, Version 2.0 (the "License");
       4              : you may not use this file except in compliance with the License.
       5              : You may obtain a copy of the License at
       6              : 
       7              :    http://www.apache.org/licenses/LICENSE-2.0
       8              : 
       9              : Unless required by applicable law or agreed to in writing, software
      10              : distributed under the License is distributed on an "AS IS" BASIS,
      11              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12              : See the License for the specific language governing permissions and
      13              : limitations under the License. */
      14              : /** C23 provided headers. */
      15              : #include <limits.h>
      16              : #include <stddef.h>
      17              : #include <stdint.h>
      18              : 
      19              : /** CCC provided headers. */
      20              : #include "ccc/buffer.h"
      21              : #include "ccc/configuration.h"
      22              : #include "ccc/flat_priority_queue.h"
      23              : #include "ccc/private/private_flat_priority_queue.h"
      24              : #include "ccc/sort.h"
      25              : #include "ccc/types.h"
      26              : 
      27              : enum : size_t {
      28              :     START_CAP = 8,
      29              : };
      30              : 
      31              : /*=====================      Prototypes      ================================*/
      32              : 
      33              : static size_t index_of(struct CCC_Flat_priority_queue const *, void const *);
      34              : static CCC_Tribool
      35              : wins(void const *, void const *, CCC_Order, CCC_Comparator const *);
      36              : static size_t
      37              : bubble_up(CCC_Buffer *, size_t, void *, CCC_Order, CCC_Comparator const *);
      38              : static size_t
      39              : bubble_down(CCC_Buffer *, size_t, void *, CCC_Order, CCC_Comparator const *);
      40              : static size_t update_fixup(struct CCC_Flat_priority_queue *, void *, void *);
      41              : static void heapify(CCC_Buffer *, void *, CCC_Order, CCC_Comparator const *);
      42              : static void heapsort(CCC_Buffer *, void *, CCC_Order, CCC_Comparator const *);
      43              : static void
      44              : destroy_each(struct CCC_Flat_priority_queue *, CCC_Destructor const *);
      45              : 
      46              : /*=====================       Interface      ================================*/
      47              : 
      48              : CCC_Result
      49            3 : CCC_flat_priority_queue_copy_heapify(
      50              :     CCC_Flat_priority_queue *const priority_queue,
      51              :     CCC_Buffer const *const buffer,
      52              :     void *const temp,
      53              :     CCC_Allocator const *const allocator
      54              : ) {
      55            3 :     if (!priority_queue || !temp || !allocator) {
      56            1 :         return CCC_RESULT_ARGUMENT_ERROR;
      57              :     }
      58            4 :     CCC_Result const copy_result
      59            2 :         = CCC_buffer_copy(&priority_queue->buffer, buffer, allocator);
      60            2 :     if (copy_result != CCC_RESULT_OK) {
      61            1 :         return copy_result;
      62              :     }
      63            1 :     heapify(
      64            1 :         &priority_queue->buffer,
      65            1 :         temp,
      66            1 :         priority_queue->order,
      67            1 :         &priority_queue->comparator
      68              :     );
      69            1 :     return CCC_RESULT_OK;
      70            3 : }
      71              : 
      72              : CCC_Flat_priority_queue
      73            2 : CCC_flat_priority_queue_in_place_heapify(
      74              :     CCC_Buffer *const buffer,
      75              :     void *const temp,
      76              :     CCC_Order const order,
      77              :     CCC_Comparator const *const comparator
      78              : ) {
      79            2 :     if (!buffer || !temp || !comparator || !comparator->compare
      80            2 :         || (order != CCC_ORDER_GREATER && order != CCC_ORDER_LESSER)) {
      81            1 :         return (CCC_Flat_priority_queue){
      82              :             .order = CCC_ORDER_ERROR,
      83              :         };
      84              :     }
      85            3 :     CCC_Flat_priority_queue priority_queue = {
      86            1 :         .buffer = *buffer,
      87            1 :         .order = order,
      88            1 :         .comparator = *comparator,
      89              :     };
      90            1 :     heapify(
      91            1 :         &priority_queue.buffer,
      92            1 :         temp,
      93            1 :         priority_queue.order,
      94            1 :         &priority_queue.comparator
      95              :     );
      96            1 :     *buffer = (CCC_Buffer){};
      97            1 :     return priority_queue;
      98            2 : }
      99              : 
     100              : void *
     101         1223 : CCC_flat_priority_queue_push(
     102              :     CCC_Flat_priority_queue *const priority_queue,
     103              :     void const *const type,
     104              :     void *const temp,
     105              :     CCC_Allocator const *const allocator
     106              : ) {
     107         1223 :     if (!priority_queue || !type || !temp || !allocator) {
     108            1 :         return NULL;
     109              :     }
     110         2444 :     void *const new
     111         1222 :         = CCC_buffer_allocate_back(&priority_queue->buffer, allocator);
     112         1222 :     if (!new) {
     113            2 :         return NULL;
     114              :     }
     115         1220 :     if (new != type) {
     116         1219 :         (void)memcpy(new, type, priority_queue->buffer.sizeof_type);
     117         1219 :     }
     118         1220 :     assert(temp);
     119         2440 :     size_t const i = bubble_up(
     120         1220 :         &priority_queue->buffer,
     121         1220 :         priority_queue->buffer.count - 1,
     122         1220 :         temp,
     123         1220 :         priority_queue->order,
     124         1220 :         &priority_queue->comparator
     125              :     );
     126         1220 :     assert(i < priority_queue->buffer.count);
     127         1220 :     return CCC_buffer_at(&priority_queue->buffer, i);
     128         1223 : }
     129              : 
     130              : CCC_Result
     131          925 : CCC_flat_priority_queue_pop(
     132              :     CCC_Flat_priority_queue *const priority_queue, void *const temp
     133              : ) {
     134          925 :     if (!priority_queue || !temp || !priority_queue->buffer.count) {
     135            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     136              :     }
     137          924 :     --priority_queue->buffer.count;
     138          924 :     if (!priority_queue->buffer.count) {
     139           13 :         return CCC_RESULT_OK;
     140              :     }
     141          911 :     CCC_buffer_swap(
     142          911 :         &priority_queue->buffer, temp, 0, priority_queue->buffer.count
     143              :     );
     144          911 :     (void)bubble_down(
     145          911 :         &priority_queue->buffer,
     146              :         0,
     147          911 :         temp,
     148          911 :         priority_queue->order,
     149          911 :         &priority_queue->comparator
     150              :     );
     151          911 :     return CCC_RESULT_OK;
     152          925 : }
     153              : 
     154              : CCC_Result
     155          528 : CCC_flat_priority_queue_erase(
     156              :     CCC_Flat_priority_queue *const priority_queue,
     157              :     void *const type,
     158              :     void *const temp
     159              : ) {
     160          528 :     if (!priority_queue || !type || !temp || !priority_queue->buffer.count) {
     161            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     162              :     }
     163          527 :     size_t const i = index_of(priority_queue, type);
     164          527 :     --priority_queue->buffer.count;
     165          527 :     if (i == priority_queue->buffer.count) {
     166           20 :         return CCC_RESULT_OK;
     167              :     }
     168          507 :     (void)CCC_buffer_swap(
     169          507 :         &priority_queue->buffer, temp, i, priority_queue->buffer.count
     170              :     );
     171         1014 :     CCC_Order const order_res
     172         2028 :         = priority_queue->comparator.compare((CCC_Comparator_arguments){
     173          507 :             .type_left = CCC_buffer_at(&priority_queue->buffer, i),
     174          507 :             .type_right = CCC_buffer_at(
     175          507 :                 &priority_queue->buffer, priority_queue->buffer.count
     176              :             ),
     177          507 :             .context = priority_queue->comparator.context,
     178              :         });
     179          507 :     if (order_res == priority_queue->order) {
     180          139 :         (void)bubble_up(
     181          139 :             &priority_queue->buffer,
     182          139 :             i,
     183          139 :             temp,
     184          139 :             priority_queue->order,
     185          139 :             &priority_queue->comparator
     186              :         );
     187          507 :     } else if (order_res != CCC_ORDER_EQUAL) {
     188          367 :         (void)bubble_down(
     189          367 :             &priority_queue->buffer,
     190          367 :             i,
     191          367 :             temp,
     192          367 :             priority_queue->order,
     193          367 :             &priority_queue->comparator
     194              :         );
     195          367 :     }
     196              :     /* If the comparison is equal do nothing. Element is in right spot. */
     197          507 :     return CCC_RESULT_OK;
     198          528 : }
     199              : 
     200              : void *
     201          690 : CCC_flat_priority_queue_update(
     202              :     CCC_Flat_priority_queue *const priority_queue,
     203              :     void *const type,
     204              :     void *const temp,
     205              :     CCC_Modifier const *const modifier
     206              : ) {
     207          690 :     if (!priority_queue || !type || !temp || !modifier || !modifier->modify
     208          688 :         || !priority_queue->buffer.count) {
     209            3 :         return NULL;
     210              :     }
     211         2061 :     modifier->modify((CCC_Arguments){
     212          687 :         .type = type,
     213          687 :         .context = modifier->context,
     214              :     });
     215          687 :     return CCC_buffer_at(
     216          687 :         &priority_queue->buffer, update_fixup(priority_queue, type, temp)
     217              :     );
     218          690 : }
     219              : 
     220              : /* There are no efficiency benefits in knowing an increase will occur. */
     221              : void *
     222          233 : CCC_flat_priority_queue_increase(
     223              :     CCC_Flat_priority_queue *const priority_queue,
     224              :     void *const type,
     225              :     void *const temp,
     226              :     CCC_Modifier const *const modifier
     227              : ) {
     228          233 :     return CCC_flat_priority_queue_update(priority_queue, type, temp, modifier);
     229              : }
     230              : 
     231              : /* There are no efficiency benefits in knowing an decrease will occur. */
     232              : void *
     233          227 : CCC_flat_priority_queue_decrease(
     234              :     CCC_Flat_priority_queue *const priority_queue,
     235              :     void *const type,
     236              :     void *const temp,
     237              :     CCC_Modifier const *const modifier
     238              : ) {
     239          227 :     return CCC_flat_priority_queue_update(priority_queue, type, temp, modifier);
     240              : }
     241              : 
     242              : void *
     243          432 : CCC_flat_priority_queue_front(
     244              :     CCC_Flat_priority_queue const *const priority_queue
     245              : ) {
     246          432 :     if (!priority_queue || !priority_queue->buffer.count) {
     247            1 :         return NULL;
     248              :     }
     249          431 :     return CCC_buffer_at(&priority_queue->buffer, 0);
     250          432 : }
     251              : 
     252              : CCC_Tribool
     253         1250 : CCC_flat_priority_queue_is_empty(
     254              :     CCC_Flat_priority_queue const *const priority_queue
     255              : ) {
     256         1250 :     if (!priority_queue) {
     257            1 :         return CCC_TRIBOOL_ERROR;
     258              :     }
     259         1249 :     return CCC_buffer_is_empty(&priority_queue->buffer);
     260         1250 : }
     261              : 
     262              : CCC_Count
     263         1008 : CCC_flat_priority_queue_count(
     264              :     CCC_Flat_priority_queue const *const priority_queue
     265              : ) {
     266         1008 :     if (!priority_queue) {
     267            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     268              :     }
     269         1007 :     return CCC_buffer_count(&priority_queue->buffer);
     270         1008 : }
     271              : 
     272              : CCC_Count
     273            9 : CCC_flat_priority_queue_capacity(
     274              :     CCC_Flat_priority_queue const *const priority_queue
     275              : ) {
     276            9 :     if (!priority_queue) {
     277            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     278              :     }
     279            8 :     return CCC_buffer_capacity(&priority_queue->buffer);
     280            9 : }
     281              : 
     282              : void *
     283            1 : CCC_flat_priority_queue_data(
     284              :     CCC_Flat_priority_queue const *const priority_queue
     285              : ) {
     286            1 :     return priority_queue ? CCC_buffer_begin(&priority_queue->buffer) : NULL;
     287              : }
     288              : 
     289              : CCC_Order
     290            1 : CCC_flat_priority_queue_order(
     291              :     CCC_Flat_priority_queue const *const priority_queue
     292              : ) {
     293            1 :     return priority_queue ? priority_queue->order : CCC_ORDER_ERROR;
     294              : }
     295              : 
     296              : CCC_Result
     297            3 : CCC_flat_priority_queue_reserve(
     298              :     CCC_Flat_priority_queue *const priority_queue,
     299              :     size_t const to_add,
     300              :     CCC_Allocator const *const allocator
     301              : ) {
     302            3 :     if (!priority_queue || !allocator) {
     303            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     304              :     }
     305            2 :     return CCC_buffer_reserve(&priority_queue->buffer, to_add, allocator);
     306            3 : }
     307              : 
     308              : CCC_Result
     309            7 : CCC_flat_priority_queue_copy(
     310              :     CCC_Flat_priority_queue *const destination,
     311              :     CCC_Flat_priority_queue const *const source,
     312              :     CCC_Allocator const *const allocator
     313              : ) {
     314            7 :     if (!destination || !source || source == destination || !allocator
     315            7 :         || (destination->buffer.capacity < source->buffer.capacity
     316            7 :             && !allocator->allocate)) {
     317            2 :         return CCC_RESULT_ARGUMENT_ERROR;
     318              :     }
     319            5 :     destination->order = source->order;
     320            5 :     destination->comparator = source->comparator;
     321            5 :     if (destination->buffer.capacity < source->buffer.capacity) {
     322            4 :         CCC_Result const r = CCC_buffer_allocate(
     323            2 :             &destination->buffer, source->buffer.capacity, allocator
     324              :         );
     325            2 :         if (r != CCC_RESULT_OK) {
     326            1 :             return r;
     327              :         }
     328            1 :         destination->buffer.capacity = source->buffer.capacity;
     329            2 :     }
     330            4 :     destination->buffer.count = source->buffer.count;
     331              :     /* It is ok to only copy count elements because we know that all elements
     332              :        in a binary heap are contiguous from [0, C), where C is count. */
     333            4 :     if (source->buffer.count) {
     334            3 :         if (!source->buffer.data || !destination->buffer.data) {
     335            1 :             return CCC_RESULT_ARGUMENT_ERROR;
     336              :         }
     337            2 :         (void)memcpy(
     338            2 :             destination->buffer.data,
     339            2 :             source->buffer.data,
     340            2 :             source->buffer.count * source->buffer.sizeof_type
     341              :         );
     342            2 :     }
     343            3 :     return CCC_RESULT_OK;
     344            7 : }
     345              : 
     346              : CCC_Result
     347            4 : CCC_flat_priority_queue_clear(
     348              :     CCC_Flat_priority_queue *const priority_queue,
     349              :     CCC_Destructor const *const destructor
     350              : ) {
     351            4 :     if (!priority_queue || !destructor) {
     352            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     353              :     }
     354            1 :     if (destructor->destroy) {
     355            1 :         destroy_each(priority_queue, destructor);
     356            1 :     }
     357            1 :     return CCC_buffer_count_set(&priority_queue->buffer, 0);
     358            4 : }
     359              : 
     360              : CCC_Result
     361           13 : CCC_flat_priority_queue_clear_and_free(
     362              :     CCC_Flat_priority_queue *const priority_queue,
     363              :     CCC_Destructor const *const destructor,
     364              :     CCC_Allocator const *const allocator
     365              : ) {
     366           13 :     if (!priority_queue || !destructor || !allocator) {
     367            2 :         return CCC_RESULT_ARGUMENT_ERROR;
     368              :     }
     369           11 :     if (destructor->destroy) {
     370            1 :         destroy_each(priority_queue, destructor);
     371            1 :     }
     372           11 :     return CCC_buffer_allocate(&priority_queue->buffer, 0, allocator);
     373           13 : }
     374              : 
     375              : CCC_Tribool
     376         7073 : CCC_flat_priority_queue_validate(
     377              :     CCC_Flat_priority_queue const *const priority_queue
     378              : ) {
     379         7073 :     if (!priority_queue) {
     380            0 :         return CCC_TRIBOOL_ERROR;
     381              :     }
     382         7073 :     size_t const count = priority_queue->buffer.count;
     383         7073 :     if (count <= 1) {
     384           33 :         return CCC_TRUE;
     385              :     }
     386       991925 :     for (size_t i = 0,
     387         7040 :                 left = (i * 2) + 1,
     388         7040 :                 right = (i * 2) + 2,
     389         7040 :                 end = (count - 2) / 2;
     390       970805 :          i <= end;
     391       963765 :          ++i, left = (i * 2) + 1, right = (i * 2) + 2) {
     392      1927530 :         void const *const this_pointer
     393       963765 :             = CCC_buffer_at(&priority_queue->buffer, i);
     394              :         /* Putting the child in the comparison function first evaluates
     395              :            the child's three way comparison in relation to the parent. If
     396              :            the child beats the parent in total ordering (min/max) something
     397              :            has gone wrong. */
     398       963765 :         if (left < count
     399       963765 :             && wins(
     400       963765 :                 CCC_buffer_at(&priority_queue->buffer, left),
     401       963765 :                 this_pointer,
     402       963765 :                 priority_queue->order,
     403       963765 :                 &priority_queue->comparator
     404              :             )) {
     405            0 :             return CCC_FALSE;
     406              :         }
     407       963765 :         if (right < count
     408       963765 :             && wins(
     409       959549 :                 CCC_buffer_at(&priority_queue->buffer, right),
     410       959549 :                 this_pointer,
     411       959549 :                 priority_queue->order,
     412       959549 :                 &priority_queue->comparator
     413              :             )) {
     414            0 :             return CCC_FALSE;
     415              :         }
     416       963765 :     }
     417         7040 :     return CCC_TRUE;
     418         7073 : }
     419              : 
     420              : /*===================     Interface in sort.h   =============================*/
     421              : 
     422              : CCC_Result
     423           10 : CCC_sort_heapsort(
     424              :     CCC_Buffer *const buffer,
     425              :     void *const temp,
     426              :     CCC_Order order,
     427              :     CCC_Comparator const *const comparator
     428              : ) {
     429           10 :     if (!buffer || !temp || !comparator || !comparator->compare
     430            8 :         || (order != CCC_ORDER_GREATER && order != CCC_ORDER_LESSER)) {
     431            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     432              :     }
     433              :     /* For sorting the user expects the buffer to be in the order they specify.
     434              :        Just like they would expect their input order to the priority queue to
     435              :        place the least or greatest element closest to the root. However,
     436              :        heap sort fills a buffer from back to front, so flip it. */
     437            7 :     order == CCC_ORDER_GREATER ? (order = CCC_ORDER_LESSER)
     438            6 :                                : (order = CCC_ORDER_GREATER);
     439            7 :     heapify(buffer, temp, order, comparator);
     440            7 :     heapsort(buffer, temp, order, comparator);
     441            7 :     return CCC_RESULT_OK;
     442           10 : }
     443              : 
     444              : /*===================     Private Interface     =============================*/
     445              : 
     446              : size_t
     447         3496 : CCC_private_flat_priority_queue_bubble_up(
     448              :     struct CCC_Flat_priority_queue *const priority_queue,
     449              :     void *const temp,
     450              :     size_t index
     451              : ) {
     452         3496 :     return bubble_up(
     453         3496 :         &priority_queue->buffer,
     454         3496 :         index,
     455         3496 :         temp,
     456         3496 :         priority_queue->order,
     457         3496 :         &priority_queue->comparator
     458              :     );
     459              : }
     460              : 
     461              : void *
     462          687 : CCC_private_flat_priority_queue_update_fixup(
     463              :     struct CCC_Flat_priority_queue *const priority_queue,
     464              :     void *const type,
     465              :     void *const temp
     466              : ) {
     467          687 :     return CCC_buffer_at(
     468          687 :         &priority_queue->buffer, update_fixup(priority_queue, type, temp)
     469              :     );
     470              : }
     471              : 
     472              : void
     473            2 : CCC_private_flat_priority_queue_heap_order(
     474              :     struct CCC_Flat_priority_queue *const priority_queue, void *const temp
     475              : ) {
     476            2 :     heapify(
     477            2 :         &priority_queue->buffer,
     478            2 :         temp,
     479            2 :         priority_queue->order,
     480            2 :         &priority_queue->comparator
     481              :     );
     482            2 : }
     483              : 
     484              : /*====================     Static Helpers     ===============================*/
     485              : 
     486              : /* Orders the heap in O(N) time. Assumes n > 0 and n <= capacity. */
     487              : static inline void
     488           11 : heapify(
     489              :     CCC_Buffer *const buffer,
     490              :     void *temp,
     491              :     CCC_Order const order,
     492              :     CCC_Comparator const *const comparator
     493              : ) {
     494           11 :     size_t i = ((buffer->count - 1) / 2) + 1;
     495          365 :     while (i--) {
     496          354 :         (void)bubble_down(buffer, i, temp, order, comparator);
     497              :     }
     498           11 : }
     499              : 
     500              : static inline void
     501            7 : heapsort(
     502              :     CCC_Buffer *const buffer,
     503              :     void *const temp,
     504              :     CCC_Order const order,
     505              :     CCC_Comparator const *const comparator
     506              : ) {
     507            7 :     if (buffer->count > 1) {
     508            7 :         size_t const start = buffer->count;
     509          400 :         while (--buffer->count) {
     510          393 :             CCC_buffer_swap(buffer, temp, 0, buffer->count);
     511          393 :             (void)bubble_down(buffer, 0, temp, order, comparator);
     512              :         }
     513            7 :         buffer->count = start;
     514            7 :     }
     515            7 : }
     516              : 
     517              : /* Fixes the position of element e after its key value has been changed. */
     518              : static size_t
     519         1374 : update_fixup(
     520              :     struct CCC_Flat_priority_queue *const priority_queue,
     521              :     void *const type,
     522              :     void *const temp
     523              : ) {
     524         1374 :     size_t const index = index_of(priority_queue, type);
     525         1374 :     if (!index) {
     526            2 :         return bubble_down(
     527            2 :             &priority_queue->buffer,
     528              :             0,
     529            2 :             temp,
     530            2 :             priority_queue->order,
     531            2 :             &priority_queue->comparator
     532              :         );
     533              :     }
     534         2744 :     CCC_Order const parent_order
     535         5488 :         = priority_queue->comparator.compare((CCC_Comparator_arguments){
     536         1372 :             .type_left = CCC_buffer_at(&priority_queue->buffer, index),
     537              :             .type_right
     538         1372 :             = CCC_buffer_at(&priority_queue->buffer, (index - 1) / 2),
     539         1372 :             .context = priority_queue->comparator.context,
     540              :         });
     541         1372 :     if (parent_order == priority_queue->order) {
     542          228 :         return bubble_up(
     543          228 :             &priority_queue->buffer,
     544          228 :             index,
     545          228 :             temp,
     546          228 :             priority_queue->order,
     547          228 :             &priority_queue->comparator
     548              :         );
     549              :     }
     550         1144 :     if (parent_order != CCC_ORDER_EQUAL) {
     551         1144 :         return bubble_down(
     552         1144 :             &priority_queue->buffer,
     553         1144 :             index,
     554         1144 :             temp,
     555         1144 :             priority_queue->order,
     556         1144 :             &priority_queue->comparator
     557              :         );
     558              :     }
     559              :     /* If the comparison is equal do nothing. Element is in right spot. */
     560            0 :     return index;
     561         1374 : }
     562              : 
     563              : /* Returns the sorted position of the element starting at position i. */
     564              : static inline size_t
     565         5083 : bubble_up(
     566              :     CCC_Buffer *const buffer,
     567              :     size_t index,
     568              :     void *const temp,
     569              :     CCC_Order const order,
     570              :     CCC_Comparator const *const comparator
     571              : ) {
     572        15627 :     for (size_t parent = (index - 1) / 2; index;
     573         5565 :          index = parent, parent = (parent - 1) / 2) {
     574        10544 :         void const *const parent_pointer = CCC_buffer_at(buffer, parent);
     575        10544 :         void const *const this_pointer = CCC_buffer_at(buffer, index);
     576              :         /* Not winning here means we are in correct order or equal. */
     577        10544 :         if (!wins(this_pointer, parent_pointer, order, comparator)) {
     578         4979 :             return index;
     579              :         }
     580         5565 :         (void)CCC_buffer_swap(buffer, temp, index, parent);
     581        10544 :     }
     582          104 :     return 0;
     583         5083 : }
     584              : 
     585              : /* Returns the sorted position of the element starting at position i. */
     586              : static inline size_t
     587         3171 : bubble_down(
     588              :     CCC_Buffer *const buffer,
     589              :     size_t index,
     590              :     void *const temp,
     591              :     CCC_Order const order,
     592              :     CCC_Comparator const *const comparator
     593              : ) {
     594        11234 :     for (size_t next = 0, left = (index * 2) + 1, right = left + 1;
     595        10604 :          left < buffer->count;
     596         7433 :          index = next, left = (index * 2) + 1, right = left + 1) {
     597         8063 :         void const *const left_pointer = CCC_buffer_at(buffer, left);
     598         8063 :         next = left;
     599         8063 :         if (right < buffer->count) {
     600         7947 :             void const *const right_pointer = CCC_buffer_at(buffer, right);
     601         7947 :             if (wins(right_pointer, left_pointer, order, comparator)) {
     602         4002 :                 next = right;
     603         4002 :             }
     604         7947 :         }
     605         8063 :         void const *const next_pointer = CCC_buffer_at(buffer, next);
     606         8063 :         void const *const this_pointer = CCC_buffer_at(buffer, index);
     607              :         /* If the child beats the parent we must swap. Equal is OK to break. */
     608         8063 :         if (!wins(next_pointer, this_pointer, order, comparator)) {
     609          630 :             return index;
     610              :         }
     611         7433 :         (void)CCC_buffer_swap(buffer, temp, index, next);
     612         8063 :     }
     613         2541 :     return index;
     614         3171 : }
     615              : 
     616              : /* Returns true if the winner (the "left hand side") wins the comparison.
     617              :    Winning in a three-way comparison means satisfying the total order of the
     618              :    priority queue. So, there is no winner if the elements are equal and this
     619              :    function would return false. If the winner is in the wrong order, thus
     620              :    losing the total order comparison, the function also returns false. */
     621              : static inline CCC_Tribool
     622      1949868 : wins(
     623              :     void const *const winner,
     624              :     void const *const loser,
     625              :     CCC_Order const order,
     626              :     CCC_Comparator const *const comparator
     627              : ) {
     628      9749340 :     return comparator->compare((CCC_Comparator_arguments){
     629      1949868 :                .type_left = winner,
     630      1949868 :                .type_right = loser,
     631      1949868 :                .context = comparator->context,
     632              :            })
     633      1949868 :         == order;
     634              : }
     635              : 
     636              : /* Flat priority queue code that uses indices of the underlying Buffer should
     637              :    always be within the Buffer range. It should never exceed the current size
     638              :    and start at or after the Buffer base. Only checked in debug. */
     639              : static inline size_t
     640         1901 : index_of(
     641              :     struct CCC_Flat_priority_queue const *const priority_queue,
     642              :     void const *const slot
     643              : ) {
     644         1901 :     assert(slot >= priority_queue->buffer.data);
     645         3802 :     size_t const i
     646         1901 :         = (size_t)((char *)slot - (char *)priority_queue->buffer.data)
     647         1901 :         / priority_queue->buffer.sizeof_type;
     648         1901 :     assert(i < priority_queue->buffer.count);
     649         3802 :     return i;
     650         1901 : }
     651              : 
     652              : static inline void
     653            2 : destroy_each(
     654              :     struct CCC_Flat_priority_queue *const priority_queue,
     655              :     CCC_Destructor const *const destructor
     656              : ) {
     657            2 :     size_t const count = priority_queue->buffer.count;
     658           34 :     for (size_t i = 0; i < count; ++i) {
     659           96 :         destructor->destroy((CCC_Arguments){
     660           32 :             .type = CCC_buffer_at(&priority_queue->buffer, i),
     661           32 :             .context = destructor->context,
     662              :         });
     663           32 :     }
     664            2 : }
        

Generated by: LCOV version 2.4.1-beta