LCOV - code coverage report
Current view: top level - source/singly_linked_list.c (source / functions) Coverage Total Hit
Test: CCC Test Suite Coverage Report Lines: 98.6 % 349 344
Test Date: 2026-04-02 00:15:37 Functions: 100.0 % 33 33

            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              : /* Citation:
      15              : [1] See the sort methods for citations and change lists regarding the pintOS
      16              : educational operating system natural merge sort algorithm used for linked lists.
      17              : Code in the pintOS source is at  `src/lib/kernel.list.c`, but this may change
      18              : if they refactor. */
      19              : /** C23 provided headers. */
      20              : #include <stddef.h>
      21              : 
      22              : /** CCC provided headers. */
      23              : #include "ccc/configuration.h"
      24              : #include "ccc/private/private_singly_linked_list.h"
      25              : #include "ccc/singly_linked_list.h"
      26              : #include "ccc/sort.h"
      27              : #include "ccc/types.h"
      28              : 
      29              : /** @brief When sorting, a singly linked list is at a disadvantage for iterative
      30              : O(1) space merge sort: it doesn't have a prev pointer. This will help list
      31              : elements remember their previous element for splicing and merging. */
      32              : struct Link {
      33              :     /** The previous element of cur. Must manually update and manage. */
      34              :     struct CCC_Singly_linked_list_node *previous;
      35              :     /** The current element. Must manually manage and update. */
      36              :     struct CCC_Singly_linked_list_node *current;
      37              : };
      38              : 
      39              : /*===========================    Prototypes     =============================*/
      40              : 
      41              : static void *struct_base(
      42              :     struct CCC_Singly_linked_list const *,
      43              :     struct CCC_Singly_linked_list_node const *
      44              : );
      45              : static void remove_node(
      46              :     struct CCC_Singly_linked_list *,
      47              :     struct CCC_Singly_linked_list_node *,
      48              :     struct CCC_Singly_linked_list_node *
      49              : );
      50              : static void insert_node(
      51              :     struct CCC_Singly_linked_list *,
      52              :     struct CCC_Singly_linked_list_node *,
      53              :     struct CCC_Singly_linked_list_node *
      54              : );
      55              : static struct CCC_Singly_linked_list_node *before(
      56              :     struct CCC_Singly_linked_list const *,
      57              :     struct CCC_Singly_linked_list_node const *
      58              : );
      59              : static size_t
      60              : len(struct CCC_Singly_linked_list_node const *,
      61              :     struct CCC_Singly_linked_list_node const *);
      62              : static void erase_range(
      63              :     struct CCC_Singly_linked_list const *,
      64              :     struct CCC_Singly_linked_list_node const *,
      65              :     struct CCC_Singly_linked_list_node *,
      66              :     CCC_Allocator const *
      67              : );
      68              : static struct CCC_Singly_linked_list_node *
      69              : elem_in(struct CCC_Singly_linked_list const *, void const *);
      70              : static struct Link merge(
      71              :     CCC_Singly_linked_list *,
      72              :     struct Link,
      73              :     struct Link,
      74              :     struct Link,
      75              :     CCC_Order,
      76              :     CCC_Comparator const *
      77              : );
      78              : static struct Link first_out_of_order(
      79              :     CCC_Singly_linked_list const *,
      80              :     struct Link,
      81              :     CCC_Order,
      82              :     CCC_Comparator const *
      83              : );
      84              : static CCC_Order get_order(
      85              :     struct CCC_Singly_linked_list const *,
      86              :     struct CCC_Singly_linked_list_node const *,
      87              :     struct CCC_Singly_linked_list_node const *,
      88              :     CCC_Comparator const *
      89              : );
      90              : 
      91              : /*===========================     Interface     =============================*/
      92              : 
      93              : void *
      94           54 : CCC_singly_linked_list_push_front(
      95              :     CCC_Singly_linked_list *const list,
      96              :     CCC_Singly_linked_list_node *type_intruder,
      97              :     CCC_Allocator const *const allocator
      98              : ) {
      99           54 :     if (!list || !type_intruder || !allocator) {
     100            3 :         return NULL;
     101              :     }
     102           51 :     if (allocator->allocate) {
     103           21 :         void *const node = allocator->allocate((CCC_Allocator_arguments){
     104              :             .input = NULL,
     105            7 :             .bytes = list->sizeof_type,
     106            7 :             .context = allocator->context,
     107              :         });
     108            7 :         if (!node) {
     109            1 :             return NULL;
     110              :         }
     111            6 :         (void)memcpy(node, struct_base(list, type_intruder), list->sizeof_type);
     112            6 :         type_intruder = elem_in(list, node);
     113            7 :     }
     114           50 :     insert_node(list, NULL, type_intruder);
     115           50 :     return struct_base(list, list->head);
     116           54 : }
     117              : 
     118              : void *
     119            5 : CCC_singly_linked_list_front(CCC_Singly_linked_list const *const list) {
     120            5 :     if (!list || list->head == NULL) {
     121            1 :         return NULL;
     122              :     }
     123            4 :     return struct_base(list, list->head);
     124            5 : }
     125              : 
     126              : CCC_Result
     127            4 : CCC_singly_linked_list_pop_front(
     128              :     CCC_Singly_linked_list *const list, CCC_Allocator const *const allocator
     129              : ) {
     130            4 :     if (!list || !list->head || !allocator) {
     131            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     132              :     }
     133            3 :     struct CCC_Singly_linked_list_node *const remove = list->head;
     134            3 :     remove_node(list, NULL, list->head);
     135            3 :     if (allocator->allocate) {
     136            9 :         (void)allocator->allocate((CCC_Allocator_arguments){
     137            3 :             .input = struct_base(list, remove),
     138              :             .bytes = 0,
     139            3 :             .context = allocator->context,
     140              :         });
     141            3 :     }
     142            3 :     return CCC_RESULT_OK;
     143            4 : }
     144              : 
     145              : CCC_Result
     146           11 : CCC_singly_linked_list_splice(
     147              :     CCC_Singly_linked_list *const position_list,
     148              :     CCC_Singly_linked_list_node *const type_intruder_position,
     149              :     CCC_Singly_linked_list *const splice_list,
     150              :     CCC_Singly_linked_list_node *const type_intruder_splice
     151              : ) {
     152           11 :     if (!position_list || !type_intruder_splice || !splice_list) {
     153            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     154              :     }
     155            8 :     if ((position_list == splice_list)
     156           13 :         && (type_intruder_splice == type_intruder_position
     157            7 :             || (type_intruder_position
     158            6 :                 && type_intruder_position->next == type_intruder_splice))) {
     159            2 :         return CCC_RESULT_OK;
     160              :     }
     161            6 :     remove_node(
     162            6 :         splice_list,
     163            6 :         before(splice_list, type_intruder_splice),
     164            6 :         type_intruder_splice
     165              :     );
     166            6 :     insert_node(position_list, type_intruder_position, type_intruder_splice);
     167            6 :     return CCC_RESULT_OK;
     168           11 : }
     169              : 
     170              : CCC_Result
     171           12 : CCC_singly_linked_list_splice_range(
     172              :     CCC_Singly_linked_list *const position_list,
     173              :     CCC_Singly_linked_list_node *const type_intruder_position,
     174              :     CCC_Singly_linked_list *const to_cut_list,
     175              :     CCC_Singly_linked_list_node *const type_intruder_to_cut_begin,
     176              :     CCC_Singly_linked_list_node *const type_intruder_to_cut_exclusive_end
     177              : ) {
     178           12 :     if (!position_list || !type_intruder_to_cut_begin || !to_cut_list) {
     179            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     180              :     }
     181            9 :     if (type_intruder_position == type_intruder_to_cut_begin) {
     182            1 :         return CCC_RESULT_OK;
     183              :     }
     184           16 :     CCC_Singly_linked_list_node *const to_cut_inclusive_end
     185            8 :         = before(to_cut_list, type_intruder_to_cut_exclusive_end);
     186            8 :     if (type_intruder_to_cut_begin == to_cut_inclusive_end) {
     187            1 :         return CCC_singly_linked_list_splice(
     188            1 :             position_list,
     189            1 :             type_intruder_position,
     190            1 :             to_cut_list,
     191            1 :             type_intruder_to_cut_begin
     192              :         );
     193              :     }
     194            7 :     remove_node(
     195            7 :         to_cut_list,
     196            7 :         before(to_cut_list, type_intruder_to_cut_begin),
     197            7 :         to_cut_inclusive_end
     198              :     );
     199            7 :     if (type_intruder_position) {
     200            5 :         if (to_cut_inclusive_end) {
     201            5 :             to_cut_inclusive_end->next = type_intruder_position->next;
     202            5 :         }
     203            5 :         type_intruder_position->next = type_intruder_to_cut_begin;
     204            5 :     } else {
     205            2 :         if (to_cut_inclusive_end) {
     206            2 :             to_cut_inclusive_end->next = position_list->head;
     207            2 :         }
     208            2 :         position_list->head = type_intruder_to_cut_begin;
     209              :     }
     210            7 :     return CCC_RESULT_OK;
     211           12 : }
     212              : 
     213              : void *
     214            4 : CCC_singly_linked_list_erase(
     215              :     CCC_Singly_linked_list *const list,
     216              :     CCC_Singly_linked_list_node *const type_intruder,
     217              :     CCC_Allocator const *const allocator
     218              : ) {
     219            4 :     if (!list || !type_intruder || !allocator || !list->head
     220            1 :         || type_intruder == NULL) {
     221            3 :         return NULL;
     222              :     }
     223            2 :     struct CCC_Singly_linked_list_node const *const return_this
     224            1 :         = type_intruder->next;
     225            1 :     remove_node(list, before(list, type_intruder), type_intruder);
     226            1 :     type_intruder->next = NULL;
     227            1 :     if (allocator->allocate) {
     228            3 :         (void)allocator->allocate((CCC_Allocator_arguments){
     229            1 :             .input = struct_base(list, type_intruder),
     230              :             .bytes = 0,
     231            1 :             .context = allocator->context,
     232              :         });
     233            1 :     }
     234            1 :     return struct_base(list, return_this);
     235            4 : }
     236              : 
     237              : void *
     238            7 : CCC_singly_linked_list_erase_range(
     239              :     CCC_Singly_linked_list *const list,
     240              :     CCC_Singly_linked_list_node *const type_intruder_begin,
     241              :     CCC_Singly_linked_list_node *const type_intruder_end,
     242              :     CCC_Allocator const *const allocator
     243              : ) {
     244            7 :     if (!list || !type_intruder_begin || !allocator || !list->head) {
     245            3 :         return NULL;
     246              :     }
     247            8 :     struct CCC_Singly_linked_list_node *const inclusive_end
     248            4 :         = before(list, type_intruder_end);
     249            8 :     struct CCC_Singly_linked_list_node *const before_begin
     250            4 :         = before(list, type_intruder_begin);
     251            4 :     remove_node(list, before_begin, inclusive_end);
     252            4 :     erase_range(list, type_intruder_begin, inclusive_end, allocator);
     253            4 :     return struct_base(list, type_intruder_end);
     254            7 : }
     255              : 
     256              : void *
     257            4 : CCC_singly_linked_list_extract(
     258              :     CCC_Singly_linked_list *const list,
     259              :     CCC_Singly_linked_list_node *const type_intruder
     260              : ) {
     261            4 :     if (!list || !type_intruder || !list->head) {
     262            2 :         return NULL;
     263              :     }
     264            4 :     struct CCC_Singly_linked_list_node const *const return_this
     265            2 :         = type_intruder->next;
     266            2 :     remove_node(list, before(list, type_intruder), type_intruder);
     267            2 :     type_intruder->next = NULL;
     268            2 :     return struct_base(list, return_this);
     269            4 : }
     270              : 
     271              : void *
     272            7 : CCC_singly_linked_list_extract_range(
     273              :     CCC_Singly_linked_list *const list,
     274              :     CCC_Singly_linked_list_node *const type_intruder_begin,
     275              :     CCC_Singly_linked_list_node *const type_intruder_end
     276              : ) {
     277            7 :     if (!list || !type_intruder_begin || !list->head) {
     278            2 :         return NULL;
     279              :     }
     280           10 :     struct CCC_Singly_linked_list_node *const inclusive_end
     281            5 :         = before(list, type_intruder_end);
     282           10 :     struct CCC_Singly_linked_list_node *const before_begin
     283            5 :         = before(list, type_intruder_begin);
     284            5 :     remove_node(list, before_begin, inclusive_end);
     285            5 :     if (inclusive_end) {
     286            5 :         inclusive_end->next = NULL;
     287            5 :     }
     288            5 :     return struct_base(list, type_intruder_end);
     289            7 : }
     290              : 
     291              : void *
     292           52 : CCC_singly_linked_list_begin(CCC_Singly_linked_list const *const list) {
     293           52 :     if (!list) {
     294            1 :         return NULL;
     295              :     }
     296           51 :     return struct_base(list, list->head);
     297           52 : }
     298              : 
     299              : CCC_Singly_linked_list_node *
     300           11 : CCC_singly_linked_list_node_begin(CCC_Singly_linked_list const *const list) {
     301           11 :     if (!list) {
     302            1 :         return NULL;
     303              :     }
     304           10 :     return list->head;
     305           11 : }
     306              : 
     307              : CCC_Singly_linked_list_node *
     308            2 : CCC_singly_linked_list_node_before_begin(CCC_Singly_linked_list const *const) {
     309            2 :     return NULL;
     310              : }
     311              : 
     312              : void *
     313          343 : CCC_singly_linked_list_end(CCC_Singly_linked_list const *const) {
     314          343 :     return NULL;
     315              : }
     316              : 
     317              : void *
     318          299 : CCC_singly_linked_list_next(
     319              :     CCC_Singly_linked_list const *const list,
     320              :     CCC_Singly_linked_list_node const *const type_intruder
     321              : ) {
     322          299 :     if (!list || !type_intruder) {
     323            2 :         return NULL;
     324              :     }
     325          297 :     return struct_base(list, type_intruder->next);
     326          299 : }
     327              : 
     328              : CCC_Result
     329            6 : CCC_singly_linked_list_clear(
     330              :     CCC_Singly_linked_list *const list,
     331              :     CCC_Destructor const *const destructor,
     332              :     CCC_Allocator const *const allocator
     333              : ) {
     334            6 :     if (!list || !destructor || !allocator) {
     335            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     336              :     }
     337            3 :     if (!destructor->destroy && !allocator->allocate) {
     338            1 :         list->head = NULL;
     339            1 :         return CCC_RESULT_OK;
     340              :     }
     341           13 :     while (list->head) {
     342           11 :         struct CCC_Singly_linked_list_node *const remove = list->head;
     343           11 :         remove_node(list, NULL, remove);
     344           11 :         void *const data = struct_base(list, remove);
     345           11 :         if (destructor->destroy) {
     346           24 :             destructor->destroy((CCC_Arguments){
     347            8 :                 .type = data,
     348            8 :                 .context = destructor->context,
     349              :             });
     350            8 :         }
     351           11 :         if (allocator->allocate) {
     352           33 :             (void)allocator->allocate((CCC_Allocator_arguments){
     353           11 :                 .input = data,
     354              :                 .bytes = 0,
     355           11 :                 .context = allocator->context,
     356              :             });
     357           11 :         }
     358           11 :     }
     359            2 :     list->head = NULL;
     360            2 :     return CCC_RESULT_OK;
     361            6 : }
     362              : 
     363              : CCC_Tribool
     364           53 : CCC_singly_linked_list_validate(CCC_Singly_linked_list const *const list) {
     365           53 :     if (!list) {
     366            0 :         return CCC_TRIBOOL_ERROR;
     367              :     }
     368          334 :     for (struct CCC_Singly_linked_list_node *e = list->head; e != NULL;
     369          281 :          e = e->next) {
     370          281 :         if (!e || e->next == e) {
     371            0 :             return CCC_FALSE;
     372              :         }
     373          281 :     }
     374           53 :     return CCC_TRUE;
     375           53 : }
     376              : 
     377              : CCC_Count
     378           17 : CCC_singly_linked_list_count(CCC_Singly_linked_list const *const list) {
     379              : 
     380           17 :     if (!list) {
     381            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     382              :     }
     383           32 :     return (CCC_Count){
     384           16 :         .count = len(list->head, NULL),
     385              :     };
     386           17 : }
     387              : 
     388              : CCC_Tribool
     389           10 : CCC_singly_linked_list_is_empty(CCC_Singly_linked_list const *const list) {
     390           10 :     if (!list) {
     391            1 :         return CCC_TRIBOOL_ERROR;
     392              :     }
     393            9 :     return !list->head;
     394           10 : }
     395              : 
     396              : /*==========================     Sorting     ================================*/
     397              : 
     398              : /** Returns true if the list is sorted in non-decreasing order. The user should
     399              : flip the return values of their comparison function if they want a different
     400              : order for elements.*/
     401              : CCC_Tribool
     402           20 : CCC_singly_linked_list_is_sorted(
     403              :     CCC_Singly_linked_list const *const list,
     404              :     CCC_Order const order,
     405              :     CCC_Comparator const *const comparator
     406              : ) {
     407           20 :     if (!list || !comparator || !comparator->compare
     408           18 :         || (order != CCC_ORDER_GREATER && order != CCC_ORDER_LESSER)) {
     409            3 :         return CCC_TRIBOOL_ERROR;
     410              :     }
     411           17 :     if (!list->head) {
     412            1 :         return CCC_TRUE;
     413              :     }
     414           32 :     CCC_Order const wrong_order
     415           16 :         = order == CCC_ORDER_LESSER ? CCC_ORDER_GREATER : CCC_ORDER_LESSER;
     416          100 :     for (struct CCC_Singly_linked_list_node const *previous = list->head,
     417           16 :                                                   *current = list->head->next;
     418           75 :          current != NULL;
     419           59 :          previous = current, current = current->next) {
     420           68 :         if (get_order(list, previous, current, comparator) == wrong_order) {
     421            9 :             return CCC_FALSE;
     422              :         }
     423           59 :     }
     424            7 :     return CCC_TRUE;
     425           20 : }
     426              : 
     427              : /** Inserts an element in non-decreasing order. This means an element will go
     428              : to the end of a section of duplicate values which is good for round-robin style
     429              : list use. */
     430              : void *
     431           12 : CCC_singly_linked_list_insert_sorted(
     432              :     CCC_Singly_linked_list *list,
     433              :     CCC_Singly_linked_list_node *type_intruder,
     434              :     CCC_Order const order,
     435              :     CCC_Comparator const *const comparator,
     436              :     CCC_Allocator const *const allocator
     437              : ) {
     438           12 :     if (!list || !type_intruder || !allocator || !comparator
     439            9 :         || !comparator->compare) {
     440            4 :         return NULL;
     441              :     }
     442            8 :     if (allocator->allocate) {
     443            9 :         void *const node = allocator->allocate((CCC_Allocator_arguments){
     444              :             .input = NULL,
     445            3 :             .bytes = list->sizeof_type,
     446            3 :             .context = allocator->context,
     447              :         });
     448            3 :         if (!node) {
     449            2 :             return NULL;
     450              :         }
     451            1 :         (void)memcpy(node, struct_base(list, type_intruder), list->sizeof_type);
     452            1 :         type_intruder = elem_in(list, node);
     453            3 :     }
     454            6 :     struct CCC_Singly_linked_list_node *prev = NULL;
     455            6 :     struct CCC_Singly_linked_list_node *i = list->head;
     456           44 :     for (; i != NULL && get_order(list, type_intruder, i, comparator) != order;
     457           38 :          prev = i, i = i->next) {}
     458            6 :     insert_node(list, prev, type_intruder);
     459            6 :     return struct_base(list, type_intruder);
     460           12 : }
     461              : 
     462              : /** Sorts the list in `O(N * log(N))` time with `O(1)` context space (no
     463              : recursion). If the list is already sorted this algorithm only needs one pass.
     464              : 
     465              : The following merging algorithm and associated helper functions are based on
     466              : the iterative natural merge sort used in the list module of the pintOS project
     467              : for learning operating systems. Currently the original is located at the
     468              : following path in the pintOS source code:
     469              : 
     470              : `src/lib/kernel/list.c`
     471              : 
     472              : However, if refactors change this location, seek the list intrusive container
     473              : module for original implementations. The code has been changed for the C
     474              : Container Collection as follows:
     475              : 
     476              : - the algorithm is adapted to work with a singly linked list rather than doubly
     477              : - there is no sentinel, only NULL pointer.
     478              : - splicing in the merge operation has been simplified along with other tweaks.
     479              : - comparison callbacks are handled with three way comparison.
     480              : 
     481              : If the runtime is not obvious from the code, consider that this algorithm runs
     482              : bottom up on sorted sub-ranges. It roughly "halves" the remaining sub-ranges
     483              : that need to be sorted by roughly "doubling" the length of a sorted range on
     484              : each merge step. Therefore the number of times we must perform the merge step is
     485              : `O(log(N))`. The most elements we would have to merge in the merge step is all
     486              : `N` elements so together that gives us the runtime of `O(N * log(N))`. */
     487              : CCC_Result
     488           10 : CCC_sort_singly_linked_list_mergesort(
     489              :     CCC_Singly_linked_list *const list,
     490              :     CCC_Order const order,
     491              :     CCC_Comparator const *const comparator
     492              : ) {
     493           10 :     if (!list || !comparator || !comparator->compare
     494            8 :         || (order != CCC_ORDER_LESSER && order != CCC_ORDER_GREATER)) {
     495            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     496              :     }
     497              :     /* Algorithm is one pass if list is sorted. Merging is never true. */
     498            7 :     CCC_Tribool merging = CCC_FALSE;
     499            7 :     do {
     500           30 :         merging = CCC_FALSE;
     501              :         /* 0th index of the A list. The start of one list to merge. */
     502           30 :         struct Link a_first = {.previous = NULL, .current = list->head};
     503           72 :         while (a_first.current != NULL) {
     504              :             /* The Nth index of list A (its size) aka 0th index of B list. */
     505           60 :             struct Link a_count_b_first
     506           60 :                 = first_out_of_order(list, a_first, order, comparator);
     507           60 :             if (a_count_b_first.current == NULL) {
     508           18 :                 break;
     509              :             }
     510              :             /* A picks up the exclusive end of this merge, B, in order
     511              :                to progress the sorting algorithm with the next run that needs
     512              :                fixing. Merge returns the final B element to indicate it is the
     513              :                final sentinel that has not yet been examined. */
     514           84 :             a_first = merge(
     515           42 :                 list,
     516              :                 a_first,
     517              :                 a_count_b_first,
     518           42 :                 first_out_of_order(list, a_count_b_first, order, comparator),
     519           42 :                 order,
     520           42 :                 comparator
     521              :             );
     522           42 :             merging = CCC_TRUE;
     523           60 :         }
     524           30 :     } while (merging);
     525            7 :     return CCC_RESULT_OK;
     526           10 : }
     527              : 
     528              : /** Merges lists `[a_first, a_count_b_first)` with `[a_count_b_first, b_count)`
     529              : to form `[a_first, b_count)`. Returns the exclusive end of the range, `b_count`,
     530              : once the merge sort is complete.
     531              : 
     532              : Notice that all ranges treat the end of their range as an exclusive sentinel for
     533              : consistency. This function assumes the provided lists are already sorted
     534              : separately. A list link must be returned because the `b_count` previous field
     535              : may be updated due to arbitrary splices during comparison sorting. */
     536              : static inline struct Link
     537           42 : merge(
     538              :     CCC_Singly_linked_list *const list,
     539              :     struct Link a_first,
     540              :     struct Link a_count_b_first,
     541              :     struct Link b_count,
     542              :     CCC_Order const order,
     543              :     CCC_Comparator const *const comparator
     544              : ) {
     545          338 :     while (a_first.current && a_first.current != a_count_b_first.current
     546          173 :            && a_count_b_first.current
     547          165 :            && a_count_b_first.current != b_count.current) {
     548          131 :         if (get_order(
     549          131 :                 list, a_count_b_first.current, a_first.current, comparator
     550              :             )
     551          131 :             == order) {
     552              :             /* The current element is the lesser element that must be spliced
     553              :                out. However, a_count_b_first.previous is not updated because
     554              :                only current is spliced out. Algorithm will continue with new
     555              :                current, but same previous. */
     556          154 :             struct CCC_Singly_linked_list_node *const merged
     557           77 :                 = a_count_b_first.current;
     558           77 :             a_count_b_first.current = merged->next;
     559            0 :             assert(
     560           77 :                 a_count_b_first.previous
     561           77 :                 && "merged element must always have a previous pointer because "
     562              :                    "lists of size 1 or less are not merged and merging "
     563              :                    "iterates forward"
     564              :             );
     565           77 :             a_count_b_first.previous->next = merged->next;
     566              :             /* This is so we return an accurate b_count list link at the end. */
     567           77 :             if (merged == b_count.previous) {
     568           34 :                 b_count.previous = a_count_b_first.previous;
     569           34 :             }
     570           77 :             if (a_first.previous) {
     571           56 :                 a_first.previous->next = merged;
     572           56 :             } else {
     573           21 :                 list->head = merged;
     574              :             }
     575           77 :             merged->next = a_first.current;
     576              :             /* Another critical update reflected in our links, not the list. */
     577           77 :             a_first.previous = merged;
     578           77 :         } else {
     579           54 :             a_first.previous = a_first.current;
     580           54 :             a_first.current = a_first.current->next;
     581              :         }
     582              :     }
     583           42 :     return b_count;
     584           42 : }
     585              : 
     586              : /** Returns a pair of elements marking the first list elem that is smaller than
     587              : its previous `CCC_ORDER_LESSER` according to the user comparison callback. The
     588              : list_link returned will have the out of order element as cur and the last
     589              : remaining in order element as prev. The cur element may be the sentinel if the
     590              : run is sorted. */
     591              : static inline struct Link
     592          102 : first_out_of_order(
     593              :     CCC_Singly_linked_list const *const list,
     594              :     struct Link link,
     595              :     CCC_Order const order,
     596              :     CCC_Comparator const *const comparator
     597              : ) {
     598          102 :     do {
     599          284 :         link.previous = link.current;
     600          284 :         link.current = link.current->next;
     601          386 :     } while (link.current != NULL
     602          284 :              && get_order(list, link.current, link.previous, comparator)
     603          254 :                     != order);
     604          102 :     return link;
     605          102 : }
     606              : 
     607              : /*=========================    Private Interface   ==========================*/
     608              : 
     609              : void
     610           96 : CCC_private_singly_linked_list_push_front(
     611              :     struct CCC_Singly_linked_list *const list,
     612              :     struct CCC_Singly_linked_list_node *const type_intruder
     613              : ) {
     614           96 :     insert_node(list, NULL, type_intruder);
     615           96 : }
     616              : 
     617              : struct CCC_Singly_linked_list_node *
     618           96 : CCC_private_singly_linked_list_node_in(
     619              :     struct CCC_Singly_linked_list const *const list,
     620              :     void const *const user_struct
     621              : ) {
     622           96 :     return elem_in(list, user_struct);
     623              : }
     624              : 
     625              : /*===========================  Static Helpers   =============================*/
     626              : 
     627              : static inline void
     628          158 : insert_node(
     629              :     struct CCC_Singly_linked_list *const list,
     630              :     struct CCC_Singly_linked_list_node *const before,
     631              :     struct CCC_Singly_linked_list_node *const node
     632              : ) {
     633          158 :     if (before) {
     634           10 :         if (node) {
     635           10 :             node->next = before->next;
     636           10 :         }
     637           10 :         before->next = node;
     638           10 :     } else {
     639          148 :         if (node) {
     640          148 :             node->next = list->head;
     641          148 :         }
     642          148 :         list->head = node;
     643              :     }
     644          158 : }
     645              : 
     646              : static inline void
     647           39 : remove_node(
     648              :     struct CCC_Singly_linked_list *const list,
     649              :     struct CCC_Singly_linked_list_node *const before,
     650              :     struct CCC_Singly_linked_list_node *const node
     651              : ) {
     652           39 :     if (before) {
     653           12 :         if (node) {
     654           12 :             before->next = node->next;
     655           12 :             node->next = NULL;
     656           12 :         } else {
     657            0 :             before->next = NULL;
     658              :         }
     659           12 :     } else {
     660           27 :         if (node) {
     661           27 :             list->head = node->next;
     662           27 :             node->next = NULL;
     663           27 :         } else {
     664            0 :             list->head = NULL;
     665              :         }
     666              :     }
     667           39 : }
     668              : 
     669              : static inline struct CCC_Singly_linked_list_node *
     670           42 : before(
     671              :     struct CCC_Singly_linked_list const *const list,
     672              :     struct CCC_Singly_linked_list_node const *const to_find
     673              : ) {
     674           42 :     struct CCC_Singly_linked_list_node *i = list->head;
     675          129 :     for (; i && i->next != to_find; i = i->next) {}
     676           84 :     return i;
     677           42 : }
     678              : 
     679              : static void
     680            4 : erase_range(
     681              :     struct CCC_Singly_linked_list const *const list,
     682              :     struct CCC_Singly_linked_list_node const *begin,
     683              :     struct CCC_Singly_linked_list_node *const end,
     684              :     CCC_Allocator const *const allocator
     685              : ) {
     686            4 :     if (!allocator->allocate) {
     687            1 :         return;
     688              :     }
     689            7 :     for (;;) {
     690            7 :         CCC_Singly_linked_list_node *const next = begin->next;
     691           21 :         (void)allocator->allocate((CCC_Allocator_arguments){
     692            7 :             .input = struct_base(list, begin),
     693              :             .bytes = 0,
     694            7 :             .context = allocator->context,
     695              :         });
     696            7 :         if (begin == end) {
     697            3 :             break;
     698              :         }
     699            4 :         begin = next;
     700            7 :     }
     701            7 : }
     702              : 
     703              : /** Returns the length [begin, end] inclusive. Assumes end follows begin. */
     704              : static size_t
     705           16 : len(struct CCC_Singly_linked_list_node const *begin,
     706              :     struct CCC_Singly_linked_list_node const *const end) {
     707           16 :     size_t s = 0;
     708           61 :     for (; begin != end; begin = begin->next, ++s) {}
     709           32 :     return s;
     710           16 : }
     711              : 
     712              : /** Provides the base address of the user struct holding e. */
     713              : static inline void *
     714         1441 : struct_base(
     715              :     struct CCC_Singly_linked_list const *const list,
     716              :     struct CCC_Singly_linked_list_node const *const node
     717              : ) {
     718         1441 :     return node ? ((char *)&node->next) - list->type_intruder_offset : NULL;
     719              : }
     720              : 
     721              : /** Given the user struct provides the address of intrusive elem. */
     722              : static inline struct CCC_Singly_linked_list_node *
     723          103 : elem_in(
     724              :     struct CCC_Singly_linked_list const *const list,
     725              :     void const *const any_struct
     726              : ) {
     727          103 :     return any_struct ? (struct CCC_Singly_linked_list_node
     728          103 :                              *)((char *)any_struct + list->type_intruder_offset)
     729              :                       : NULL;
     730              : }
     731              : 
     732              : /** Calls the user provided three way comparison callback function on the user
     733              : type wrapping the provided intrusive handles. Returns the three way comparison
     734              : result value. */
     735              : static inline CCC_Order
     736          496 : get_order(
     737              :     struct CCC_Singly_linked_list const *const list,
     738              :     struct CCC_Singly_linked_list_node const *const left,
     739              :     struct CCC_Singly_linked_list_node const *const right,
     740              :     CCC_Comparator const *const comparator
     741              : ) {
     742         1984 :     return comparator->compare((CCC_Comparator_arguments){
     743          496 :         .type_left = struct_base(list, left),
     744          496 :         .type_right = struct_base(list, right),
     745          496 :         .context = comparator->context,
     746              :     });
     747              : }
        

Generated by: LCOV version 2.4.1-beta