GCC Code Coverage Report


Directory: ./
File: list.c
Date: 2025-12-31 16:19:05
Exec Total Coverage
Lines: 494 494 100.0%
Functions: 67 67 100.0%
Branches: 263 296 88.9%

Line Branch Exec Source
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "cx/list.h"
30
31 #include <string.h>
32 #include <assert.h>
33
34 // we don't want to include the full array_list.h.
35 // therefore, we only forward declare the one function we want to use
36 CX_EXPORT void cx_array_qsort_c(void *array, size_t nmemb, size_t size,
37 cx_compare_func2 fn, void *context);
38
39
40 127077 int cx_list_compare_wrapper(const void *l, const void *r, void *c) {
41 127077 CxList *list = c;
42 const void *left;
43 const void *right;
44
2/2
✓ Branch 0 (2→3) taken 48500 times.
✓ Branch 1 (2→9) taken 78577 times.
127077 if (cxCollectionStoresPointers(list)) {
45 48500 left = *(void**)l;
46 48500 right = *(void**)r;
47 // for historic reasons, we are handling the NULL case here
48 // because every UCX compare function does not support NULL arguments
49
2/2
✓ Branch 0 (3→4) taken 2 times.
✓ Branch 1 (3→7) taken 48498 times.
48500 if (left == NULL) {
50
2/2
✓ Branch 0 (4→5) taken 1 times.
✓ Branch 1 (4→6) taken 1 times.
2 if (right == NULL) return 0;
51 1 return -1;
52
2/2
✓ Branch 0 (7→8) taken 4 times.
✓ Branch 1 (7→10) taken 48494 times.
48498 } else if (right == NULL) {
53 4 return 1;
54 }
55 } else {
56 78577 left = l;
57 78577 right = r;
58 }
59
2/2
✓ Branch 0 (10→11) taken 2739 times.
✓ Branch 1 (10→12) taken 124332 times.
127071 return cx_invoke_compare_func(list, left, right);
60 }
61
62 #define cx_list_compare_wrapper(l, r, c) cx_list_compare_wrapper(l, r, (void*)c)
63
64 // <editor-fold desc="empty list implementation">
65
66 2 static void cx_emptyl_noop(CX_UNUSED CxList *list) {
67 // this is a noop, but MUST be implemented
68 2 }
69
70 2 static void *cx_emptyl_at(
71 CX_UNUSED const struct cx_list_s *list,
72 CX_UNUSED size_t index
73 ) {
74 2 return NULL;
75 }
76
77 2 static size_t cx_emptyl_find_remove(
78 CX_UNUSED struct cx_list_s *list,
79 CX_UNUSED const void *elem,
80 CX_UNUSED bool remove
81 ) {
82 2 return 0;
83 }
84
85 12 static bool cx_emptyl_iter_valid(CX_UNUSED const void *iter) {
86 12 return false;
87 }
88
89 12 static CxIterator cx_emptyl_iterator(
90 const struct cx_list_s *list,
91 size_t index,
92 CX_UNUSED bool backwards
93 ) {
94 12 CxIterator iter = {0};
95 12 iter.src_handle = (void*) list;
96 12 iter.index = index;
97 12 iter.base.valid = cx_emptyl_iter_valid;
98 12 return iter;
99 }
100
101 static cx_list_class cx_empty_list_class = {
102 cx_emptyl_noop,
103 NULL,
104 NULL,
105 NULL,
106 NULL,
107 NULL,
108 NULL,
109 cx_emptyl_noop,
110 NULL,
111 cx_emptyl_at,
112 cx_emptyl_find_remove,
113 cx_emptyl_noop,
114 NULL,
115 cx_emptyl_noop,
116 NULL,
117 cx_emptyl_iterator,
118 };
119
120 CxList cx_empty_list = {
121 {
122 NULL,
123 0,
124 0,
125 NULL,
126 NULL,
127 NULL,
128 NULL,
129 NULL,
130 NULL,
131 false,
132 true,
133 },
134 &cx_empty_list_class,
135 };
136
137 CxList *const cxEmptyList = &cx_empty_list;
138
139 // </editor-fold>
140
141 67 size_t cx_list_default_insert_array(
142 struct cx_list_s *list,
143 size_t index,
144 const void *data,
145 size_t n
146 ) {
147 67 const char *src = data;
148 67 size_t i = 0;
149
2/2
✓ Branch 0 (9→3) taken 741 times.
✓ Branch 1 (9→10) taken 67 times.
808 for (; i < n; i++) {
150
1/2
✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 741 times.
741 if (NULL == list->cl->insert_element(list, index + i, src)) {
151 return i; // LCOV_EXCL_LINE
152 }
153
2/2
✓ Branch 0 (6→7) taken 701 times.
✓ Branch 1 (6→8) taken 40 times.
741 if (src != NULL) {
154 701 src += list->collection.elem_size;
155 }
156 }
157 67 return i;
158 }
159
160 83 static size_t cx_list_default_insert_sorted_impl(
161 struct cx_list_s *list,
162 const void *sorted_data,
163 size_t n,
164 bool allow_duplicates
165 ) {
166 // corner case
167
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 83 times.
83 if (n == 0) return 0;
168
169 83 size_t elem_size = list->collection.elem_size;
170 83 const char *src = sorted_data;
171
172 // track indices and number of inserted items
173 83 size_t di = 0, si = 0, processed = 0;
174
175 // search the list for insertion points
176
2/2
✓ Branch 0 (42→5) taken 603 times.
✓ Branch 1 (42→43) taken 31 times.
634 while (di < list->collection.size) {
177 603 const void *list_elm = list->cl->at(list, di);
178
179 // compare the current list element with the first source element
180 // if less, skip the list elements
181 // if equal, skip the list elements and optionally the source elements
182 {
183 603 int d = cx_list_compare_wrapper(list_elm, src, list);
184
2/2
✓ Branch 0 (7→8) taken 494 times.
✓ Branch 1 (7→18) taken 109 times.
603 if (d <= 0) {
185
4/4
✓ Branch 0 (8→9) taken 250 times.
✓ Branch 1 (8→17) taken 244 times.
✓ Branch 2 (9→10) taken 20 times.
✓ Branch 3 (9→17) taken 230 times.
494 if (!allow_duplicates && d == 0) {
186 20 src += elem_size;
187 20 si++;
188 20 processed++; // we also count duplicates for the return value
189
4/4
✓ Branch 0 (12→13) taken 16 times.
✓ Branch 1 (12→15) taken 8 times.
✓ Branch 2 (14→11) taken 4 times.
✓ Branch 3 (14→15) taken 12 times.
24 while (si < n && cx_list_compare_wrapper(list_elm, src, list) == 0) {
190 4 src += elem_size;
191 4 si++;
192 4 processed++;
193 }
194
2/2
✓ Branch 0 (15→16) taken 8 times.
✓ Branch 1 (15→17) taken 12 times.
20 if (processed == n) {
195 8 return processed;
196 }
197 }
198 486 di++;
199 486 continue;
200 }
201 }
202
203 // determine the number of consecutive elements that can be inserted
204 109 size_t ins = 1, skip = 0;
205 109 const char *next = src;
206
2/2
✓ Branch 0 (30→19) taken 125 times.
✓ Branch 1 (30→31) taken 44 times.
169 while (++si < n) {
207
2/2
✓ Branch 0 (19→20) taken 77 times.
✓ Branch 1 (19→25) taken 48 times.
125 if (!allow_duplicates) {
208 // skip duplicates within the source
209
2/2
✓ Branch 0 (21→22) taken 21 times.
✓ Branch 1 (21→23) taken 56 times.
77 if (cx_list_compare_wrapper(next, next + elem_size, list) == 0) {
210 21 next += elem_size;
211 21 skip++;
212 21 continue;
213 } else {
214
2/2
✓ Branch 0 (23→24) taken 17 times.
✓ Branch 1 (23→25) taken 39 times.
56 if (skip > 0) {
215 // if we had to skip something, we must wait for the next run
216 17 next += elem_size;
217 17 break;
218 }
219 }
220 }
221 87 next += elem_size;
222 // once we become larger than the list elem, break
223
2/2
✓ Branch 0 (26→27) taken 48 times.
✓ Branch 1 (26→28) taken 39 times.
87 if (cx_list_compare_wrapper(list_elm, next, list) <= 0) {
224 48 break;
225 }
226 // otherwise, we can insert one more
227 39 ins++;
228 }
229
230 // insert the elements at location si
231
2/2
✓ Branch 0 (31→32) taken 79 times.
✓ Branch 1 (31→35) taken 30 times.
109 if (ins == 1) {
232
1/2
✗ Branch 0 (33→34) not taken.
✓ Branch 1 (33→38) taken 79 times.
79 if (NULL == list->cl->insert_element(list, di, src)) {
233 return processed; // LCOV_EXCL_LINE
234 }
235 } else {
236 30 size_t r = list->cl->insert_array(list, di, src, ins);
237
1/2
✗ Branch 0 (36→37) not taken.
✓ Branch 1 (36→38) taken 30 times.
30 if (r < ins) {
238 return processed + r; // LCOV_EXCL_LINE
239 }
240 }
241 109 processed += ins + skip;
242 109 di += ins;
243
244 // everything inserted?
245
2/2
✓ Branch 0 (38→39) taken 44 times.
✓ Branch 1 (38→40) taken 65 times.
109 if (processed == n) {
246 44 return processed;
247 }
248 65 src = next;
249 }
250
251 // insert remaining items
252
1/2
✓ Branch 0 (43→44) taken 31 times.
✗ Branch 1 (43→60) not taken.
31 if (si < n) {
253
2/2
✓ Branch 0 (44→45) taken 17 times.
✓ Branch 1 (44→47) taken 14 times.
31 if (allow_duplicates) {
254 17 processed += list->cl->insert_array(list, di, src, n - si);
255 } else {
256
2/2
✓ Branch 0 (47→48) taken 9 times.
✓ Branch 1 (47→49) taken 5 times.
14 const void *last = di == 0 ? NULL : list->cl->at(list, di - 1);
257
2/2
✓ Branch 0 (59→51) taken 37 times.
✓ Branch 1 (59→60) taken 14 times.
51 for (; si < n; si++) {
258 // skip duplicates within the source
259
4/4
✓ Branch 0 (51→52) taken 32 times.
✓ Branch 1 (51→54) taken 5 times.
✓ Branch 2 (53→54) taken 27 times.
✓ Branch 3 (53→58) taken 5 times.
37 if (last == NULL || cx_list_compare_wrapper(last, src, list) != 0) {
260
1/2
✗ Branch 0 (55→56) not taken.
✓ Branch 1 (55→57) taken 32 times.
32 if (NULL == list->cl->insert_element(list, di, src)) {
261 return processed; // LCOV_EXCL_LINE
262 }
263 32 last = src;
264 32 di++;
265 }
266 37 processed++;
267 37 src += elem_size;
268 }
269 }
270 }
271
272 31 return processed;
273 }
274
275 41 size_t cx_list_default_insert_sorted(
276 struct cx_list_s *list,
277 const void *sorted_data,
278 size_t n
279 ) {
280 41 return cx_list_default_insert_sorted_impl(list, sorted_data, n, true);
281 }
282
283 42 size_t cx_list_default_insert_unique(
284 struct cx_list_s *list,
285 const void *sorted_data,
286 size_t n
287 ) {
288 42 return cx_list_default_insert_sorted_impl(list, sorted_data, n, false);
289 }
290
291 4 void cx_list_default_sort(struct cx_list_s *list) {
292 4 size_t elem_size = list->collection.elem_size;
293 4 size_t list_size = list->collection.size;
294 4 void *tmp = cxMallocDefault(elem_size * list_size);
295 if (tmp == NULL) abort(); // LCOV_EXCL_LINE
296
297 // copy elements from source array
298 4 char *loc = tmp;
299
2/2
✓ Branch 0 (8→6) taken 1000 times.
✓ Branch 1 (8→9) taken 4 times.
1004 for (size_t i = 0; i < list_size; i++) {
300 1000 void *src = list->cl->at(list, i);
301 1000 memcpy(loc, src, elem_size);
302 1000 loc += elem_size;
303 }
304
305 // qsort
306 4 cx_array_qsort_c(tmp, list_size, elem_size, cx_list_compare_wrapper, list);
307
308 // copy elements back
309 4 loc = tmp;
310
2/2
✓ Branch 0 (13→11) taken 1000 times.
✓ Branch 1 (13→14) taken 4 times.
1004 for (size_t i = 0; i < list_size; i++) {
311 1000 void *dest = list->cl->at(list, i);
312 1000 memcpy(dest, loc, elem_size);
313 1000 loc += elem_size;
314 }
315
316 4 cxFreeDefault(tmp);
317 4 }
318
319 44 int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) {
320
2/2
✓ Branch 0 (2→3) taken 4 times.
✓ Branch 1 (2→4) taken 40 times.
44 if (i == j) return 0;
321
2/2
✓ Branch 0 (4→5) taken 8 times.
✓ Branch 1 (4→6) taken 32 times.
40 if (i >= list->collection.size) return 1;
322
2/2
✓ Branch 0 (6→7) taken 4 times.
✓ Branch 1 (6→8) taken 28 times.
32 if (j >= list->collection.size) return 1;
323
324 28 size_t elem_size = list->collection.elem_size;
325
326 28 void *tmp = cxMallocDefault(elem_size);
327 if (tmp == NULL) return 1; // LCOV_EXCL_LINE
328
329 28 void *ip = list->cl->at(list, i);
330 28 void *jp = list->cl->at(list, j);
331
332 28 memcpy(tmp, ip, elem_size);
333 28 memcpy(ip, jp, elem_size);
334 28 memcpy(jp, tmp, elem_size);
335
336 28 cxFreeDefault(tmp);
337
338 28 return 0;
339 }
340
341 1307 static int cx_list_cmpfunc2_safe_memcmp(const void *a, const void *b, void *c) {
342 // it is not safe to store a pointer to the size in the list
343 // because the entire list structure might get reallocated
344 1307 size_t elem_size = (size_t)(uintptr_t)c;
345 1307 return memcmp(a, b, elem_size);
346 }
347
348 675 void cx_list_init(
349 struct cx_list_s *list,
350 struct cx_list_class_s *cl,
351 const struct cx_allocator_s *allocator,
352 size_t elem_size
353 ) {
354 675 list->cl = cl;
355 675 list->collection.allocator = allocator;
356 675 list->collection.size = 0;
357 675 list->collection.sorted = false; // should be set by the implementation
358
2/2
✓ Branch 0 (2→3) taken 303 times.
✓ Branch 1 (2→4) taken 372 times.
675 if (elem_size > 0) {
359 303 list->collection.elem_size = elem_size;
360 303 list->collection.simple_cmp = NULL;
361 303 list->collection.advanced_cmp = cx_list_cmpfunc2_safe_memcmp;
362 303 list->collection.cmp_data = (void*)(uintptr_t)list->collection.elem_size;
363 303 list->collection.store_pointer = false;
364 } else {
365 372 list->collection.elem_size = sizeof(void *);
366 372 list->collection.simple_cmp = cx_cmp_ptr;
367 372 list->collection.advanced_cmp = NULL;
368 372 list->collection.cmp_data = NULL;
369 372 list->collection.store_pointer = true;
370 }
371 675 }
372
373 417 int cxListCompare(
374 const CxList *list,
375 const CxList *other
376 ) {
377 // check if we cannot use the list internal function
378 417 bool cannot_optimize = false;
379
380 // if one is storing pointers but the other is not
381 417 cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer;
382
383 // check if the lists are incompatible or this list does not implement compare
384 417 cx_compare_func list_cmp = (cx_compare_func) list->cl->compare;
385 417 cx_compare_func other_cmp = (cx_compare_func) other->cl->compare;
386 417 cannot_optimize |= list_cmp != other_cmp;
387 417 cannot_optimize |= list_cmp == NULL;
388
389
2/2
✓ Branch 0 (2→3) taken 329 times.
✓ Branch 1 (2→24) taken 88 times.
417 if (cannot_optimize) {
390 // lists are definitely different - cannot use internal compare function
391
2/2
✓ Branch 0 (3→4) taken 237 times.
✓ Branch 1 (3→20) taken 92 times.
329 if (list->collection.size == other->collection.size) {
392 237 CxIterator left = cxListIterator(list);
393 237 CxIterator right = cxListIterator(other);
394
2/2
✓ Branch 0 (17→7) taken 7940 times.
✓ Branch 1 (17→18) taken 149 times.
8089 for (size_t i = 0; i < list->collection.size; i++) {
395 7940 void *leftValue = cxIteratorCurrent(left);
396 7940 void *rightValue = cxIteratorCurrent(right);
397 // values are already unwrapped, invoke immediately
398
2/2
✓ Branch 0 (9→10) taken 3168 times.
✓ Branch 1 (9→11) taken 4772 times.
7940 int d = cx_invoke_compare_func(list, leftValue, rightValue);
399
2/2
✓ Branch 0 (12→13) taken 88 times.
✓ Branch 1 (12→14) taken 7852 times.
7940 if (d != 0) {
400 88 return d;
401 }
402 7852 cxIteratorNext(left);
403 7852 cxIteratorNext(right);
404 }
405 149 return 0;
406 } else {
407
2/2
✓ Branch 0 (20→21) taken 46 times.
✓ Branch 1 (20→22) taken 46 times.
92 return list->collection.size < other->collection.size ? -1 : 1;
408 }
409 } else {
410 // lists are compatible
411 88 return list->cl->compare(list, other);
412 }
413 }
414
415 817 size_t cxListSize(const CxList *list) {
416 817 return list->collection.size;
417 }
418
419 17378 int cxListAdd(CxList *list, const void *elem) {
420 17378 list->collection.sorted = false;
421
2/2
✓ Branch 0 (2→3) taken 14579 times.
✓ Branch 1 (2→4) taken 2799 times.
17378 return list->cl->insert_element(list, list->collection.size, cx_ref(list, elem)) == NULL;
422 }
423
424 119 size_t cxListAddArray(CxList *list, const void *array, size_t n) {
425 119 list->collection.sorted = false;
426 119 return list->cl->insert_array(list, list->collection.size, array, n);
427 }
428
429 142 int cxListInsert(CxList *list, size_t index, const void *elem) {
430 142 list->collection.sorted = false;
431
2/2
✓ Branch 0 (2→3) taken 67 times.
✓ Branch 1 (2→4) taken 75 times.
142 return list->cl->insert_element(list, index, cx_ref(list, elem)) == NULL;
432 }
433
434 12 void *cxListEmplaceAt(CxList *list, size_t index) {
435 12 list->collection.sorted = false;
436 12 return list->cl->insert_element(list, index, NULL);
437 }
438
439 416 void *cxListEmplace(CxList *list) {
440 416 list->collection.sorted = false;
441 416 return list->cl->insert_element(list, list->collection.size, NULL);
442 }
443
444 120 static bool cx_list_emplace_iterator_valid(const void *it) {
445 120 const CxIterator *iter = it;
446 120 return iter->index < iter->elem_count;
447 }
448
449 71 CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n) {
450 71 list->collection.sorted = false;
451 71 size_t c = list->cl->insert_array(list, index, NULL, n);
452 71 CxIterator iter = list->cl->iterator(list, index, false);
453 // tweak the fields of this iterator
454 71 iter.elem_count = c;
455 71 iter.index = 0;
456 // replace the valid function to abort iteration when c is reached
457 71 iter.base.valid = cx_list_emplace_iterator_valid;
458 71 return iter;
459 }
460
461 61 CxIterator cxListEmplaceArray(CxList *list, size_t n) {
462 61 return cxListEmplaceArrayAt(list, list->collection.size, n);
463 }
464
465 70 int cxListInsertSorted(CxList *list, const void *elem) {
466 assert(cxCollectionSorted(list));
467 70 list->collection.sorted = true;
468
2/2
✓ Branch 0 (2→3) taken 35 times.
✓ Branch 1 (2→4) taken 35 times.
70 return list->cl->insert_sorted(list, cx_ref(list, elem), 1) == 0;
469 }
470
471 100 int cxListInsertUnique(CxList *list, const void *elem) {
472
4/4
✓ Branch 0 (2→3) taken 40 times.
✓ Branch 1 (2→4) taken 60 times.
✓ Branch 2 (3→4) taken 10 times.
✓ Branch 3 (3→9) taken 30 times.
100 if (cxCollectionSorted(list)) {
473 70 list->collection.sorted = true;
474
2/2
✓ Branch 0 (4→5) taken 35 times.
✓ Branch 1 (4→6) taken 35 times.
70 return list->cl->insert_unique(list, cx_ref(list, elem), 1) == 0;
475 } else {
476
2/2
✓ Branch 0 (10→11) taken 10 times.
✓ Branch 1 (10→12) taken 20 times.
30 if (cxListContains(list, elem)) {
477 10 return 0;
478 } else {
479 20 return cxListAdd(list, elem);
480 }
481 }
482 }
483
484 20 size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n) {
485 20 list->collection.sorted = false;
486 20 return list->cl->insert_array(list, index, array, n);
487 }
488
489 37 size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n) {
490 assert(cxCollectionSorted(list));
491 37 list->collection.sorted = true;
492 37 return list->cl->insert_sorted(list, array, n);
493 }
494
495 66 size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n) {
496
4/4
✓ Branch 0 (2→3) taken 33 times.
✓ Branch 1 (2→4) taken 33 times.
✓ Branch 2 (3→4) taken 3 times.
✓ Branch 3 (3→6) taken 30 times.
66 if (cxCollectionSorted(list)) {
497 36 list->collection.sorted = true;
498 36 return list->cl->insert_unique(list, array, n);
499 } else {
500 30 const char *source = array;
501
2/2
✓ Branch 0 (16→7) taken 150 times.
✓ Branch 1 (16→17) taken 30 times.
180 for (size_t i = 0 ; i < n; i++) {
502 // note: this also checks elements added in a previous iteration
503
2/2
✓ Branch 0 (7→8) taken 75 times.
✓ Branch 1 (7→9) taken 75 times.
150 const void *data = cx_deref(list, source);
504
2/2
✓ Branch 0 (11→12) taken 130 times.
✓ Branch 1 (11→15) taken 20 times.
150 if (!cxListContains(list, data)) {
505
1/2
✗ Branch 0 (13→14) not taken.
✓ Branch 1 (13→15) taken 130 times.
130 if (cxListAdd(list, data)) {
506 return i; // LCOV_EXCL_LINE
507 }
508 }
509 150 source += list->collection.elem_size;
510 }
511 30 return n;
512 }
513 }
514
515 12 int cxListInsertAfter(CxIterator *iter, const void *elem) {
516 12 CxList* list = iter->src_handle;
517 12 list->collection.sorted = false;
518
2/2
✓ Branch 0 (2→3) taken 6 times.
✓ Branch 1 (2→4) taken 6 times.
12 return list->cl->insert_iter(iter, cx_ref(list, elem), 0);
519 }
520
521 18 int cxListInsertBefore(CxIterator *iter, const void *elem) {
522 18 CxList* list = iter->src_handle;
523 18 list->collection.sorted = false;
524
2/2
✓ Branch 0 (2→3) taken 9 times.
✓ Branch 1 (2→4) taken 9 times.
18 return list->cl->insert_iter(iter, cx_ref(list, elem), 1);
525 }
526
527 63 int cxListRemove(CxList *list, size_t index) {
528 63 return list->cl->remove(list, index, 1, NULL) == 0;
529 }
530
531 33 int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf) {
532 33 return list->cl->remove(list, index, 1, targetbuf) == 0;
533 }
534
535 18 int cxListRemoveAndGetFirst(CxList *list, void *targetbuf) {
536 18 return list->cl->remove(list, 0, 1, targetbuf) == 0;
537 }
538
539 18 int cxListRemoveAndGetLast(CxList *list, void *targetbuf) {
540 // note: index may wrap - member function will catch that
541 18 return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0;
542 }
543
544 31 size_t cxListRemoveArray(CxList *list, size_t index, size_t num) {
545 31 return list->cl->remove(list, index, num, NULL);
546 }
547
548 13 size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf) {
549 13 return list->cl->remove(list, index, num, targetbuf);
550 }
551
552 29 void cxListClear(CxList *list) {
553 29 list->cl->clear(list);
554 29 list->collection.sorted = true; // empty lists are always sorted
555 29 }
556
557 111 int cxListSwap(CxList *list, size_t i, size_t j) {
558 111 list->collection.sorted = false;
559 111 return list->cl->swap(list, i, j);
560 }
561
562 22682 void *cxListAt(const CxList *list, size_t index) {
563 22682 void *result = list->cl->at(list, index);
564
2/2
✓ Branch 0 (3→4) taken 10 times.
✓ Branch 1 (3→5) taken 22672 times.
22682 if (result == NULL) return NULL;
565
2/2
✓ Branch 0 (5→6) taken 11269 times.
✓ Branch 1 (5→7) taken 11403 times.
22672 return cx_deref(list, result);
566 }
567
568 6 void *cxListFirst(const CxList *list) {
569 6 return cxListAt(list, 0);
570 }
571
572 9 void *cxListLast(const CxList *list) {
573 9 return cxListAt(list, list->collection.size - 1);
574 }
575
576 18 int cxListSet(CxList *list, size_t index, const void *elem) {
577
2/2
✓ Branch 0 (2→3) taken 6 times.
✓ Branch 1 (2→4) taken 12 times.
18 if (index >= list->collection.size) {
578 6 return 1;
579 }
580
581
2/2
✓ Branch 0 (4→5) taken 6 times.
✓ Branch 1 (4→7) taken 6 times.
12 if (list->collection.store_pointer) {
582 6 void **target = list->cl->at(list, index);
583 6 *target = (void *)elem;
584 } else {
585 6 void *target = list->cl->at(list, index);
586 6 memcpy(target, elem, list->collection.elem_size);
587 }
588
589 12 return 0;
590 }
591
592 8194 static void *cx_pl_iter_current(const void *it) {
593 8194 const struct cx_iterator_s *iter = it;
594 8194 void **ptr = iter->base.current_impl(it);
595
1/2
✓ Branch 0 (3→4) taken 8194 times.
✗ Branch 1 (3→5) not taken.
8194 return ptr == NULL ? NULL : *ptr;
596 }
597
598 CX_INLINE CxIterator cx_pl_iter_wrap(const CxList *list, CxIterator iter) {
599
8/8
✓ Branch 0 (5→6) taken 8 times.
✓ Branch 1 (5→7) taken 10 times.
✓ Branch 2 (5→6) taken 247 times.
✓ Branch 3 (5→7) taken 327 times.
✓ Branch 4 (5→6) taken 9 times.
✓ Branch 5 (5→7) taken 10 times.
✓ Branch 6 (5→6) taken 18 times.
✓ Branch 7 (5→7) taken 19 times.
648 if (cxCollectionStoresPointers(list)) {
600 282 iter.base.current_impl = iter.base.current;
601 282 iter.base.current = cx_pl_iter_current;
602 282 return iter;
603 } else {
604 366 return iter;
605 }
606 }
607
608 37 CxIterator cxListIteratorAt(const CxList *list, size_t index) {
609
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 36 times.
37 if (list == NULL) list = cxEmptyList;
610 74 return cx_pl_iter_wrap(list, list->cl->iterator(list, index, false));
611 }
612
613 19 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) {
614
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 18 times.
19 if (list == NULL) list = cxEmptyList;
615 38 return cx_pl_iter_wrap(list, list->cl->iterator(list, index, true));
616 }
617
618 574 CxIterator cxListIterator(const CxList *list) {
619
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 573 times.
574 if (list == NULL) list = cxEmptyList;
620 1148 return cx_pl_iter_wrap(list, list->cl->iterator(list, 0, false));
621 }
622
623 18 CxIterator cxListBackwardsIterator(const CxList *list) {
624
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 17 times.
18 if (list == NULL) list = cxEmptyList;
625 36 return cx_pl_iter_wrap(list, list->cl->iterator(list, list->collection.size - 1, true));
626 }
627
628 177 size_t cxListFind(const CxList *list, const void *elem) {
629
2/2
✓ Branch 0 (2→3) taken 88 times.
✓ Branch 1 (2→4) taken 89 times.
177 return list->cl->find_remove((CxList*)list, cx_ref(list, elem), false);
630 }
631
632 486 bool cxListContains(const CxList* list, const void* elem) {
633
2/2
✓ Branch 0 (2→3) taken 102 times.
✓ Branch 1 (2→4) taken 384 times.
486 return list->cl->find_remove((CxList*)list, cx_ref(list, elem), false) < list->collection.size;
634 }
635
636 774 bool cxListIndexValid(const CxList *list, size_t index) {
637 774 return index < list->collection.size;
638 }
639
640 44 size_t cxListFindRemove(CxList *list, const void *elem) {
641
2/2
✓ Branch 0 (2→3) taken 18 times.
✓ Branch 1 (2→4) taken 26 times.
44 return list->cl->find_remove(list, cx_ref(list, elem), true);
642 }
643
644 36 void cxListSort(CxList *list) {
645
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 35 times.
36 if (list->collection.sorted) return;
646 35 list->cl->sort(list);
647 35 list->collection.sorted = true;
648 }
649
650 6 void cxListReverse(CxList *list) {
651 // still sorted, but not according to the cmp_func
652 6 list->collection.sorted = false;
653 6 list->cl->reverse(list);
654 6 }
655
656 512 void cxListFree(CxList *list) {
657
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 511 times.
512 if (list == NULL) return;
658 511 list->cl->deallocate(list);
659 }
660
661 30 static void cx_list_pop_uninitialized_elements(CxList *list, size_t n) {
662 30 cx_destructor_func destr_bak = list->collection.simple_destructor;
663 30 cx_destructor_func2 destr2_bak = list->collection.advanced_destructor;
664 30 list->collection.simple_destructor = NULL;
665 30 list->collection.advanced_destructor = NULL;
666
2/2
✓ Branch 0 (2→3) taken 6 times.
✓ Branch 1 (2→4) taken 24 times.
30 if (n == 1) {
667 6 cxListRemove(list, list->collection.size - 1);
668 } else {
669 24 cxListRemoveArray(list,list->collection.size - n, n);
670 }
671 30 list->collection.simple_destructor = destr_bak;
672 30 list->collection.advanced_destructor = destr2_bak;
673 30 }
674
675 19 static void* cx_list_shallow_clone_func(void *dst, const void *src, const CxAllocator *al, void *data) {
676 19 size_t elem_size = *(size_t*)data;
677
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 19 times.
19 if (dst == NULL) dst = cxMalloc(al, elem_size);
678
1/2
✓ Branch 0 (4→5) taken 19 times.
✗ Branch 1 (4→6) not taken.
19 if (dst != NULL) memcpy(dst, src, elem_size);
679 19 return dst;
680 }
681
682 #define use_shallow_clone_func(list) cx_list_shallow_clone_func, NULL, (void*)&((list)->collection.elem_size)
683
684 51 int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func,
685 const CxAllocator *clone_allocator, void *data) {
686
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 50 times.
51 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
687
688 // remember the original size
689 51 size_t orig_size = dst->collection.size;
690
691 // first, try to allocate the memory in the new list
692 51 CxIterator empl_iter = cxListEmplaceArray(dst, src->collection.size);
693
694 // get an iterator over the source elements
695 51 CxIterator src_iter = cxListIterator(src);
696
697 // now clone the elements
698 51 size_t cloned = empl_iter.elem_count;
699
2/2
✓ Branch 0 (20→7) taken 441 times.
✓ Branch 1 (20→21) taken 27 times.
468 for (size_t i = 0 ; i < empl_iter.elem_count; i++) {
700 441 void *src_elem = cxIteratorCurrent(src_iter);
701 441 void **dest_memory = cxIteratorCurrent(empl_iter);
702
2/2
✓ Branch 0 (9→10) taken 268 times.
✓ Branch 1 (9→11) taken 173 times.
441 void *target = cxCollectionStoresPointers(dst) ? NULL : dest_memory;
703 441 void *dest_ptr = clone_func(target, src_elem, clone_allocator, data);
704
2/2
✓ Branch 0 (13→14) taken 24 times.
✓ Branch 1 (13→15) taken 417 times.
441 if (dest_ptr == NULL) {
705 24 cloned = i;
706 24 break;
707 }
708
2/2
✓ Branch 0 (15→16) taken 256 times.
✓ Branch 1 (15→17) taken 161 times.
417 if (cxCollectionStoresPointers(dst)) {
709 256 *dest_memory = dest_ptr;
710 }
711 417 cxIteratorNext(src_iter);
712 417 cxIteratorNext(empl_iter);
713 }
714
715 // if we could not clone everything, free the allocated memory
716 // (disable the destructors!)
717
2/2
✓ Branch 0 (21→22) taken 24 times.
✓ Branch 1 (21→24) taken 27 times.
51 if (cloned < src->collection.size) {
718 24 cx_list_pop_uninitialized_elements(dst,
719 24 dst->collection.size - cloned - orig_size);
720 24 return 1;
721 }
722
723 // set the sorted flag when we know it's sorted
724
3/4
✓ Branch 0 (24→25) taken 1 times.
✓ Branch 1 (24→27) taken 26 times.
✓ Branch 2 (25→26) taken 1 times.
✗ Branch 3 (25→27) not taken.
27 if (orig_size == 0 && src->collection.sorted) {
725 1 dst->collection.sorted = true;
726 }
727
728 27 return 0;
729 }
730
731 5 int cxListDifference(CxList *dst,
732 const CxList *minuend, const CxList *subtrahend,
733 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
734
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 4 times.
5 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
735
736 // optimize for sorted collections
737
4/8
✓ Branch 0 (4→5) taken 2 times.
✓ Branch 1 (4→6) taken 3 times.
✗ Branch 2 (5→6) not taken.
✓ Branch 3 (5→36) taken 2 times.
✗ Branch 4 (6→7) not taken.
✓ Branch 5 (6→8) taken 3 times.
✗ Branch 6 (7→8) not taken.
✗ Branch 7 (7→36) not taken.
5 if (cxCollectionSorted(minuend) && cxCollectionSorted(subtrahend)) {
738 3 bool dst_was_empty = cxCollectionSize(dst) == 0;
739
740 3 CxIterator min_iter = cxListIterator(minuend);
741 3 CxIterator sub_iter = cxListIterator(subtrahend);
742
2/2
✓ Branch 0 (34→11) taken 188 times.
✓ Branch 1 (34→35) taken 2 times.
190 while (cxIteratorValid(min_iter)) {
743 188 void *min_elem = cxIteratorCurrent(min_iter);
744 void *sub_elem;
745 int d;
746
2/2
✓ Branch 0 (13→14) taken 187 times.
✓ Branch 1 (13→16) taken 1 times.
188 if (cxIteratorValid(sub_iter)) {
747 187 sub_elem = cxIteratorCurrent(sub_iter);
748 187 d = cx_list_compare_wrapper(sub_elem, min_elem, subtrahend);
749 } else {
750 // no more elements in the subtrahend,
751 // i.e., the min_elem is larger than any elem of the subtrahend
752 1 d = 1;
753 }
754
2/2
✓ Branch 0 (17→18) taken 25 times.
✓ Branch 1 (17→19) taken 163 times.
188 if (d == 0) {
755 // is contained, so skip it
756 25 cxIteratorNext(min_iter);
757
2/2
✓ Branch 0 (19→20) taken 94 times.
✓ Branch 1 (19→21) taken 69 times.
163 } else if (d < 0) {
758 // subtrahend is smaller than minuend,
759 // check the next element
760 94 cxIteratorNext(sub_iter);
761 } else {
762 // subtrahend is larger than the dst element,
763 // clone the minuend and advance
764 69 void **dst_mem = cxListEmplace(dst);
765
2/2
✓ Branch 0 (22→23) taken 67 times.
✓ Branch 1 (22→24) taken 2 times.
69 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
766 69 void* dst_ptr = clone_func(target, min_elem, clone_allocator, data);
767
2/2
✓ Branch 0 (26→27) taken 1 times.
✓ Branch 1 (26→29) taken 68 times.
69 if (dst_ptr == NULL) {
768 1 cx_list_pop_uninitialized_elements(dst, 1);
769 1 return 1;
770 }
771
2/2
✓ Branch 0 (29→30) taken 66 times.
✓ Branch 1 (29→31) taken 2 times.
68 if (cxCollectionStoresPointers(dst)) {
772 66 *dst_mem = dst_ptr;
773 }
774 68 cxIteratorNext(min_iter);
775 }
776 }
777
778 // if dst was empty, it is now guaranteed to be sorted
779 2 dst->collection.sorted = dst_was_empty;
780 } else {
781 2 CxIterator min_iter = cxListIterator(minuend);
782
3/4
✓ Branch 0 (53→54) taken 93 times.
✓ Branch 1 (53→56) taken 1 times.
✓ Branch 2 (55→38) taken 93 times.
✗ Branch 3 (55→56) not taken.
94 cx_foreach(void *, elem, min_iter) {
783
2/2
✓ Branch 0 (39→40) taken 26 times.
✓ Branch 1 (39→41) taken 67 times.
93 if (cxListContains(subtrahend, elem)) {
784 26 continue;
785 }
786 67 void **dst_mem = cxListEmplace(dst);
787
1/2
✓ Branch 0 (42→43) taken 67 times.
✗ Branch 1 (42→44) not taken.
67 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
788 67 void* dst_ptr = clone_func(target, elem, clone_allocator, data);
789
2/2
✓ Branch 0 (46→47) taken 1 times.
✓ Branch 1 (46→49) taken 66 times.
67 if (dst_ptr == NULL) {
790 1 cx_list_pop_uninitialized_elements(dst, 1);
791 1 return 1;
792 }
793
1/2
✓ Branch 0 (49→50) taken 66 times.
✗ Branch 1 (49→51) not taken.
66 if (cxCollectionStoresPointers(dst)) {
794 66 *dst_mem = dst_ptr;
795 }
796 }
797 }
798
799 3 return 0;
800 }
801
802 5 int cxListIntersection(CxList *dst,
803 const CxList *src, const CxList *other,
804 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
805
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 4 times.
5 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
806
807 // optimize for sorted collections
808
4/8
✓ Branch 0 (4→5) taken 2 times.
✓ Branch 1 (4→6) taken 3 times.
✗ Branch 2 (5→6) not taken.
✓ Branch 3 (5→35) taken 2 times.
✗ Branch 4 (6→7) not taken.
✓ Branch 5 (6→8) taken 3 times.
✗ Branch 6 (7→8) not taken.
✗ Branch 7 (7→35) not taken.
5 if (cxCollectionSorted(src) && cxCollectionSorted(other)) {
809 3 bool dst_was_empty = cxCollectionSize(dst) == 0;
810
811 3 CxIterator src_iter = cxListIterator(src);
812 3 CxIterator other_iter = cxListIterator(other);
813
4/4
✓ Branch 0 (31→32) taken 200 times.
✓ Branch 1 (31→34) taken 1 times.
✓ Branch 2 (33→11) taken 199 times.
✓ Branch 3 (33→34) taken 1 times.
201 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) {
814 199 void *src_elem = cxIteratorCurrent(src_iter);
815 199 void *other_elem = cxIteratorCurrent(other_iter);
816 199 int d = cx_list_compare_wrapper(src_elem, other_elem, src);
817
2/2
✓ Branch 0 (14→15) taken 28 times.
✓ Branch 1 (14→26) taken 171 times.
199 if (d == 0) {
818 // is contained, clone it
819 28 void **dst_mem = cxListEmplace(dst);
820
2/2
✓ Branch 0 (16→17) taken 25 times.
✓ Branch 1 (16→18) taken 3 times.
28 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
821 28 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data);
822
2/2
✓ Branch 0 (20→21) taken 1 times.
✓ Branch 1 (20→23) taken 27 times.
28 if (dst_ptr == NULL) {
823 1 cx_list_pop_uninitialized_elements(dst, 1);
824 1 return 1;
825 }
826
2/2
✓ Branch 0 (23→24) taken 24 times.
✓ Branch 1 (23→25) taken 3 times.
27 if (cxCollectionStoresPointers(dst)) {
827 24 *dst_mem = dst_ptr;
828 }
829 27 cxIteratorNext(src_iter);
830
2/2
✓ Branch 0 (26→27) taken 74 times.
✓ Branch 1 (26→28) taken 97 times.
171 } else if (d < 0) {
831 // the other element is larger, skip the source element
832 74 cxIteratorNext(src_iter);
833 } else {
834 // the source element is larger, try to find it in the other list
835 97 cxIteratorNext(other_iter);
836 }
837 }
838
839 // if dst was empty, it is now guaranteed to be sorted
840 2 dst->collection.sorted = dst_was_empty;
841 } else {
842 2 CxIterator src_iter = cxListIterator(src);
843
3/4
✓ Branch 0 (52→53) taken 89 times.
✓ Branch 1 (52→55) taken 1 times.
✓ Branch 2 (54→37) taken 89 times.
✗ Branch 3 (54→55) not taken.
90 cx_foreach(void *, elem, src_iter) {
844
2/2
✓ Branch 0 (38→39) taken 64 times.
✓ Branch 1 (38→40) taken 25 times.
89 if (!cxListContains(other, elem)) {
845 64 continue;
846 }
847 25 void **dst_mem = cxListEmplace(dst);
848
1/2
✓ Branch 0 (41→42) taken 25 times.
✗ Branch 1 (41→43) not taken.
25 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
849 25 void* dst_ptr = clone_func(target, elem, clone_allocator, data);
850
2/2
✓ Branch 0 (45→46) taken 1 times.
✓ Branch 1 (45→48) taken 24 times.
25 if (dst_ptr == NULL) {
851 1 cx_list_pop_uninitialized_elements(dst, 1);
852 1 return 1;
853 }
854
1/2
✓ Branch 0 (48→49) taken 24 times.
✗ Branch 1 (48→50) not taken.
24 if (cxCollectionStoresPointers(dst)) {
855 24 *dst_mem = dst_ptr;
856 }
857 }
858 }
859
860 3 return 0;
861 }
862
863 5 int cxListUnion(CxList *dst,
864 const CxList *src, const CxList *other,
865 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
866
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 4 times.
5 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
867
868 // optimize for sorted collections
869
4/8
✓ Branch 0 (4→5) taken 2 times.
✓ Branch 1 (4→6) taken 3 times.
✗ Branch 2 (5→6) not taken.
✓ Branch 3 (5→45) taken 2 times.
✗ Branch 4 (6→7) not taken.
✓ Branch 5 (6→8) taken 3 times.
✗ Branch 6 (7→8) not taken.
✗ Branch 7 (7→45) not taken.
5 if (cxCollectionSorted(src) && cxCollectionSorted(other)) {
870 3 bool dst_was_empty = cxCollectionSize(dst) == 0;
871
872 3 CxIterator src_iter = cxListIterator(src);
873 3 CxIterator other_iter = cxListIterator(other);
874
4/4
✓ Branch 0 (41→11) taken 161 times.
✓ Branch 1 (41→42) taken 3 times.
✓ Branch 2 (43→11) taken 1 times.
✓ Branch 3 (43→44) taken 2 times.
167 while (cxIteratorValid(src_iter) || cxIteratorValid(other_iter)) {
875 162 void *src_elem = NULL, *other_elem = NULL;
876 int d;
877
2/2
✓ Branch 0 (12→13) taken 1 times.
✓ Branch 1 (12→15) taken 161 times.
162 if (!cxIteratorValid(src_iter)) {
878 1 other_elem = cxIteratorCurrent(other_iter);
879 1 d = 1;
880
2/2
✓ Branch 0 (16→17) taken 1 times.
✓ Branch 1 (16→19) taken 160 times.
161 } else if (!cxIteratorValid(other_iter)) {
881 1 src_elem = cxIteratorCurrent(src_iter);
882 1 d = -1;
883 } else {
884 160 src_elem = cxIteratorCurrent(src_iter);
885 160 other_elem = cxIteratorCurrent(other_iter);
886 160 d = cx_list_compare_wrapper(src_elem, other_elem, src);
887 }
888 void *clone_from;
889
2/2
✓ Branch 0 (22→23) taken 67 times.
✓ Branch 1 (22→24) taken 95 times.
162 if (d < 0) {
890 // source element is smaller clone it
891 67 clone_from = src_elem;
892 67 cxIteratorNext(src_iter);
893
2/2
✓ Branch 0 (24→25) taken 24 times.
✓ Branch 1 (24→27) taken 71 times.
95 } else if (d == 0) {
894 // both elements are equal, clone from the source, skip other
895 24 clone_from = src_elem;
896 24 cxIteratorNext(src_iter);
897 24 cxIteratorNext(other_iter);
898 } else {
899 // the other element is smaller, clone it
900 71 clone_from = other_elem;
901 71 cxIteratorNext(other_iter);
902 }
903 162 void **dst_mem = cxListEmplace(dst);
904
2/2
✓ Branch 0 (29→30) taken 153 times.
✓ Branch 1 (29→31) taken 9 times.
162 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
905 162 void* dst_ptr = clone_func(target, clone_from, clone_allocator, data);
906
2/2
✓ Branch 0 (33→34) taken 1 times.
✓ Branch 1 (33→36) taken 161 times.
162 if (dst_ptr == NULL) {
907 1 cx_list_pop_uninitialized_elements(dst, 1);
908 1 return 1;
909 }
910
2/2
✓ Branch 0 (36→37) taken 9 times.
✓ Branch 1 (36→38) taken 152 times.
161 if (cxCollectionStoresPointers(dst)) {
911 152 *dst_mem = dst_ptr;
912 }
913 }
914
915 // if dst was empty, it is now guaranteed to be sorted
916 2 dst->collection.sorted = dst_was_empty;
917 } else {
918
1/2
✗ Branch 0 (46→47) not taken.
✓ Branch 1 (46→48) taken 2 times.
2 if (cxListClone(dst, src, clone_func, clone_allocator, data)) {
919 1 return 1;
920 }
921 2 CxIterator other_iter = cxListIterator(other);
922
3/4
✓ Branch 0 (65→66) taken 73 times.
✓ Branch 1 (65→68) taken 1 times.
✓ Branch 2 (67→50) taken 73 times.
✗ Branch 3 (67→68) not taken.
74 cx_foreach(void *, elem, other_iter) {
923
2/2
✓ Branch 0 (51→52) taken 20 times.
✓ Branch 1 (51→53) taken 53 times.
73 if (cxListContains(src, elem)) {
924 20 continue;
925 }
926 53 void **dst_mem = cxListEmplace(dst);
927
1/2
✓ Branch 0 (54→55) taken 53 times.
✗ Branch 1 (54→56) not taken.
53 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
928 53 void* dst_ptr = clone_func(target, elem, clone_allocator, data);
929
2/2
✓ Branch 0 (58→59) taken 1 times.
✓ Branch 1 (58→61) taken 52 times.
53 if (dst_ptr == NULL) {
930 1 cx_list_pop_uninitialized_elements(dst, 1);
931 1 return 1;
932 }
933
1/2
✓ Branch 0 (61→62) taken 52 times.
✗ Branch 1 (61→63) not taken.
52 if (cxCollectionStoresPointers(dst)) {
934 52 *dst_mem = dst_ptr;
935 }
936 }
937 }
938
939 3 return 0;
940 }
941
942 1 int cxListCloneShallow(CxList *dst, const CxList *src) {
943 1 return cxListClone(dst, src, use_shallow_clone_func(src));
944 }
945
946 1 int cxListDifferenceShallow(CxList *dst, const CxList *minuend, const CxList *subtrahend) {
947 1 return cxListDifference(dst, minuend, subtrahend, use_shallow_clone_func(minuend));
948 }
949
950 1 int cxListIntersectionShallow(CxList *dst, const CxList *src, const CxList *other) {
951 1 return cxListIntersection(dst, src, other, use_shallow_clone_func(src));
952 }
953
954 1 int cxListUnionShallow(CxList *dst, const CxList *src, const CxList *other) {
955 1 return cxListUnion(dst, src, other, use_shallow_clone_func(src));
956 }
957
958 12 int cxListReserve(CxList *list, size_t capacity) {
959
2/2
✓ Branch 0 (2→3) taken 4 times.
✓ Branch 1 (2→4) taken 8 times.
12 if (list->cl->change_capacity == NULL) {
960 4 return 0;
961 }
962
2/2
✓ Branch 0 (4→5) taken 4 times.
✓ Branch 1 (4→6) taken 4 times.
8 if (capacity <= cxCollectionSize(list)) {
963 4 return 0;
964 }
965 4 return list->cl->change_capacity(list, capacity);
966 }
967
968 6 int cxListShrink(CxList *list) {
969
2/2
✓ Branch 0 (2→3) taken 2 times.
✓ Branch 1 (2→4) taken 4 times.
6 if (list->cl->change_capacity == NULL) {
970 2 return 0;
971 }
972 4 return list->cl->change_capacity(list, cxCollectionSize(list));
973 }
974