| 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 | |||
| 33 | // <editor-fold desc="Store Pointers Functionality"> | ||
| 34 | |||
| 35 | static _Thread_local cx_compare_func cx_pl_cmpfunc_impl; | ||
| 36 | |||
| 37 | 31453 | static int cx_pl_cmpfunc( | |
| 38 | const void *l, | ||
| 39 | const void *r | ||
| 40 | ) { | ||
| 41 | 31453 | void *const *lptr = l; | |
| 42 | 31453 | void *const *rptr = r; | |
| 43 |
1/2✓ Branch 0 taken 31453 times.
✗ Branch 1 not taken.
|
31453 | const void *left = lptr == NULL ? NULL : *lptr; |
| 44 |
1/2✓ Branch 0 taken 31453 times.
✗ Branch 1 not taken.
|
31453 | const void *right = rptr == NULL ? NULL : *rptr; |
| 45 | 31453 | return cx_pl_cmpfunc_impl(left, right); | |
| 46 | } | ||
| 47 | |||
| 48 | 120 | static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) { | |
| 49 | // cast away const - this is the hacky thing | ||
| 50 | 120 | struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; | |
| 51 | 120 | cx_pl_cmpfunc_impl = l->cmpfunc; | |
| 52 | 120 | l->cmpfunc = cx_pl_cmpfunc; | |
| 53 | 120 | } | |
| 54 | |||
| 55 | 120 | static void cx_pl_unhack_cmpfunc(const struct cx_list_s *list) { | |
| 56 | // cast away const - this is the hacky thing | ||
| 57 | 120 | struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; | |
| 58 | 120 | l->cmpfunc = cx_pl_cmpfunc_impl; | |
| 59 | 120 | } | |
| 60 | |||
| 61 | 72 | static void cx_pl_destructor(struct cx_list_s *list) { | |
| 62 | 72 | list->climpl->deallocate(list); | |
| 63 | 72 | } | |
| 64 | |||
| 65 | 5384 | static int cx_pl_insert_element( | |
| 66 | struct cx_list_s *list, | ||
| 67 | size_t index, | ||
| 68 | const void *element | ||
| 69 | ) { | ||
| 70 | 5384 | return list->climpl->insert_element(list, index, &element); | |
| 71 | } | ||
| 72 | |||
| 73 | 8 | static size_t cx_pl_insert_array( | |
| 74 | struct cx_list_s *list, | ||
| 75 | size_t index, | ||
| 76 | const void *array, | ||
| 77 | size_t n | ||
| 78 | ) { | ||
| 79 | 8 | return list->climpl->insert_array(list, index, array, n); | |
| 80 | } | ||
| 81 | |||
| 82 | 32 | static size_t cx_pl_insert_sorted( | |
| 83 | struct cx_list_s *list, | ||
| 84 | const void *array, | ||
| 85 | size_t n | ||
| 86 | ) { | ||
| 87 | 32 | cx_pl_hack_cmpfunc(list); | |
| 88 | 32 | size_t result = list->climpl->insert_sorted(list, array, n); | |
| 89 | 32 | cx_pl_unhack_cmpfunc(list); | |
| 90 | 32 | return result; | |
| 91 | } | ||
| 92 | |||
| 93 | 10 | static int cx_pl_insert_iter( | |
| 94 | struct cx_iterator_s *iter, | ||
| 95 | const void *elem, | ||
| 96 | int prepend | ||
| 97 | ) { | ||
| 98 | 10 | struct cx_list_s *list = iter->src_handle.m; | |
| 99 | 10 | return list->climpl->insert_iter(iter, &elem, prepend); | |
| 100 | } | ||
| 101 | |||
| 102 | 22 | static size_t cx_pl_remove( | |
| 103 | struct cx_list_s *list, | ||
| 104 | size_t index, | ||
| 105 | size_t num, | ||
| 106 | void *targetbuf | ||
| 107 | ) { | ||
| 108 | 22 | return list->climpl->remove(list, index, num, targetbuf); | |
| 109 | } | ||
| 110 | |||
| 111 | 6 | static void cx_pl_clear(struct cx_list_s *list) { | |
| 112 | 6 | list->climpl->clear(list); | |
| 113 | 6 | } | |
| 114 | |||
| 115 | 44 | static int cx_pl_swap( | |
| 116 | struct cx_list_s *list, | ||
| 117 | size_t i, | ||
| 118 | size_t j | ||
| 119 | ) { | ||
| 120 | 44 | return list->climpl->swap(list, i, j); | |
| 121 | } | ||
| 122 | |||
| 123 | 2698 | static void *cx_pl_at( | |
| 124 | const struct cx_list_s *list, | ||
| 125 | size_t index | ||
| 126 | ) { | ||
| 127 | 2698 | void **ptr = list->climpl->at(list, index); | |
| 128 |
2/2✓ Branch 0 taken 2696 times.
✓ Branch 1 taken 2 times.
|
2698 | return ptr == NULL ? NULL : *ptr; |
| 129 | } | ||
| 130 | |||
| 131 | 68 | static size_t cx_pl_find_remove( | |
| 132 | struct cx_list_s *list, | ||
| 133 | const void *elem, | ||
| 134 | bool remove | ||
| 135 | ) { | ||
| 136 | 68 | cx_pl_hack_cmpfunc(list); | |
| 137 | 68 | size_t ret = list->climpl->find_remove(list, &elem, remove); | |
| 138 | 68 | cx_pl_unhack_cmpfunc(list); | |
| 139 | 68 | return ret; | |
| 140 | } | ||
| 141 | |||
| 142 | 6 | static void cx_pl_sort(struct cx_list_s *list) { | |
| 143 | 6 | cx_pl_hack_cmpfunc(list); | |
| 144 | 6 | list->climpl->sort(list); | |
| 145 | 6 | cx_pl_unhack_cmpfunc(list); | |
| 146 | 6 | } | |
| 147 | |||
| 148 | 14 | static int cx_pl_compare( | |
| 149 | const struct cx_list_s *list, | ||
| 150 | const struct cx_list_s *other | ||
| 151 | ) { | ||
| 152 | 14 | cx_pl_hack_cmpfunc(list); | |
| 153 | 14 | int ret = list->climpl->compare(list, other); | |
| 154 | 14 | cx_pl_unhack_cmpfunc(list); | |
| 155 | 14 | return ret; | |
| 156 | } | ||
| 157 | |||
| 158 | 2 | static void cx_pl_reverse(struct cx_list_s *list) { | |
| 159 | 2 | list->climpl->reverse(list); | |
| 160 | 2 | } | |
| 161 | |||
| 162 | 3084 | static void *cx_pl_iter_current(const void *it) { | |
| 163 | 3084 | const struct cx_iterator_s *iter = it; | |
| 164 | 3084 | void **ptr = iter->base.current_impl(it); | |
| 165 |
1/2✓ Branch 0 taken 3084 times.
✗ Branch 1 not taken.
|
3084 | return ptr == NULL ? NULL : *ptr; |
| 166 | } | ||
| 167 | |||
| 168 | 112 | static struct cx_iterator_s cx_pl_iterator( | |
| 169 | const struct cx_list_s *list, | ||
| 170 | size_t index, | ||
| 171 | bool backwards | ||
| 172 | ) { | ||
| 173 | 112 | struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards); | |
| 174 | 112 | iter.base.current_impl = iter.base.current; | |
| 175 | 112 | iter.base.current = cx_pl_iter_current; | |
| 176 | 112 | return iter; | |
| 177 | } | ||
| 178 | |||
| 179 | static cx_list_class cx_pointer_list_class = { | ||
| 180 | cx_pl_destructor, | ||
| 181 | cx_pl_insert_element, | ||
| 182 | cx_pl_insert_array, | ||
| 183 | cx_pl_insert_sorted, | ||
| 184 | cx_pl_insert_iter, | ||
| 185 | cx_pl_remove, | ||
| 186 | cx_pl_clear, | ||
| 187 | cx_pl_swap, | ||
| 188 | cx_pl_at, | ||
| 189 | cx_pl_find_remove, | ||
| 190 | cx_pl_sort, | ||
| 191 | cx_pl_compare, | ||
| 192 | cx_pl_reverse, | ||
| 193 | cx_pl_iterator, | ||
| 194 | }; | ||
| 195 | // </editor-fold> | ||
| 196 | |||
| 197 | // <editor-fold desc="empty list implementation"> | ||
| 198 | |||
| 199 | 2 | static void cx_emptyl_noop(cx_attr_unused CxList *list) { | |
| 200 | // this is a noop, but MUST be implemented | ||
| 201 | 2 | } | |
| 202 | |||
| 203 | 2 | static void *cx_emptyl_at( | |
| 204 | cx_attr_unused const struct cx_list_s *list, | ||
| 205 | cx_attr_unused size_t index | ||
| 206 | ) { | ||
| 207 | 2 | return NULL; | |
| 208 | } | ||
| 209 | |||
| 210 | 2 | static size_t cx_emptyl_find_remove( | |
| 211 | cx_attr_unused struct cx_list_s *list, | ||
| 212 | cx_attr_unused const void *elem, | ||
| 213 | cx_attr_unused bool remove | ||
| 214 | ) { | ||
| 215 | 2 | return 0; | |
| 216 | } | ||
| 217 | |||
| 218 | 8 | static bool cx_emptyl_iter_valid(cx_attr_unused const void *iter) { | |
| 219 | 8 | return false; | |
| 220 | } | ||
| 221 | |||
| 222 | 10 | static CxIterator cx_emptyl_iterator( | |
| 223 | const struct cx_list_s *list, | ||
| 224 | size_t index, | ||
| 225 | cx_attr_unused bool backwards | ||
| 226 | ) { | ||
| 227 | 10 | CxIterator iter = {0}; | |
| 228 | 10 | iter.src_handle.c = list; | |
| 229 | 10 | iter.index = index; | |
| 230 | 10 | iter.base.valid = cx_emptyl_iter_valid; | |
| 231 | 10 | return iter; | |
| 232 | } | ||
| 233 | |||
| 234 | static cx_list_class cx_empty_list_class = { | ||
| 235 | cx_emptyl_noop, | ||
| 236 | NULL, | ||
| 237 | NULL, | ||
| 238 | NULL, | ||
| 239 | NULL, | ||
| 240 | NULL, | ||
| 241 | cx_emptyl_noop, | ||
| 242 | NULL, | ||
| 243 | cx_emptyl_at, | ||
| 244 | cx_emptyl_find_remove, | ||
| 245 | cx_emptyl_noop, | ||
| 246 | NULL, | ||
| 247 | cx_emptyl_noop, | ||
| 248 | cx_emptyl_iterator, | ||
| 249 | }; | ||
| 250 | |||
| 251 | CxList cx_empty_list = { | ||
| 252 | { | ||
| 253 | NULL, | ||
| 254 | NULL, | ||
| 255 | 0, | ||
| 256 | 0, | ||
| 257 | NULL, | ||
| 258 | NULL, | ||
| 259 | NULL, | ||
| 260 | false, | ||
| 261 | true, | ||
| 262 | }, | ||
| 263 | &cx_empty_list_class, | ||
| 264 | NULL | ||
| 265 | }; | ||
| 266 | |||
| 267 | CxList *const cxEmptyList = &cx_empty_list; | ||
| 268 | |||
| 269 | // </editor-fold> | ||
| 270 | |||
| 271 | #define invoke_list_func(name, list, ...) \ | ||
| 272 | ((list)->climpl == NULL ? (list)->cl->name : (list)->climpl->name) \ | ||
| 273 | (list, __VA_ARGS__) | ||
| 274 | |||
| 275 | 40 | size_t cx_list_default_insert_array( | |
| 276 | struct cx_list_s *list, | ||
| 277 | size_t index, | ||
| 278 | const void *data, | ||
| 279 | size_t n | ||
| 280 | ) { | ||
| 281 | 40 | size_t elem_size = list->collection.elem_size; | |
| 282 | 40 | const char *src = data; | |
| 283 | 40 | size_t i = 0; | |
| 284 |
2/2✓ Branch 0 taken 654 times.
✓ Branch 1 taken 40 times.
|
694 | for (; i < n; i++) { |
| 285 |
3/4✓ Branch 0 taken 610 times.
✓ Branch 1 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 654 times.
|
654 | if (0 != invoke_list_func( |
| 286 | insert_element, list, index + i, | ||
| 287 | ✗ | src + (i * elem_size))) return i; | |
| 288 | } | ||
| 289 | 40 | return i; | |
| 290 | } | ||
| 291 | |||
| 292 | 32 | size_t cx_list_default_insert_sorted( | |
| 293 | struct cx_list_s *list, | ||
| 294 | const void *sorted_data, | ||
| 295 | size_t n | ||
| 296 | ) { | ||
| 297 | // corner case | ||
| 298 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
32 | if (n == 0) return 0; |
| 299 | |||
| 300 | 32 | size_t elem_size = list->collection.elem_size; | |
| 301 | 32 | cx_compare_func cmp = list->collection.cmpfunc; | |
| 302 | 32 | const char *src = sorted_data; | |
| 303 | |||
| 304 | // track indices and number of inserted items | ||
| 305 | 32 | size_t di = 0, si = 0, inserted = 0; | |
| 306 | |||
| 307 | // search the list for insertion points | ||
| 308 |
2/2✓ Branch 0 taken 164 times.
✓ Branch 1 taken 12 times.
|
176 | for (; di < list->collection.size; di++) { |
| 309 |
2/2✓ Branch 0 taken 82 times.
✓ Branch 1 taken 82 times.
|
164 | const void *list_elm = invoke_list_func(at, list, di); |
| 310 | |||
| 311 | // compare current list element with first source element | ||
| 312 | // if less or equal, skip | ||
| 313 |
2/2✓ Branch 1 taken 124 times.
✓ Branch 2 taken 40 times.
|
164 | if (cmp(list_elm, src) <= 0) { |
| 314 | 124 | continue; | |
| 315 | } | ||
| 316 | |||
| 317 | // determine number of consecutive elements that can be inserted | ||
| 318 | 40 | size_t ins = 1; | |
| 319 | 40 | const char *next = src; | |
| 320 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
|
60 | while (++si < n) { |
| 321 | 40 | next += elem_size; | |
| 322 | // once we become larger than the list elem, break | ||
| 323 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 20 times.
|
40 | if (cmp(list_elm, next) <= 0) { |
| 324 | 20 | break; | |
| 325 | } | ||
| 326 | // otherwise, we can insert one more | ||
| 327 | 20 | ins++; | |
| 328 | } | ||
| 329 | |||
| 330 | // insert the elements at location si | ||
| 331 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 16 times.
|
40 | if (ins == 1) { |
| 332 |
3/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
|
24 | if (0 != invoke_list_func( |
| 333 | ✗ | insert_element, list, di, src)) return inserted; | |
| 334 | } else { | ||
| 335 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | size_t r = invoke_list_func(insert_array, list, di, src, ins); |
| 336 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (r < ins) return inserted + r; |
| 337 | } | ||
| 338 | 40 | inserted += ins; | |
| 339 | 40 | di += ins; | |
| 340 | |||
| 341 | // everything inserted? | ||
| 342 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
|
40 | if (inserted == n) return inserted; |
| 343 | 20 | src = next; | |
| 344 | } | ||
| 345 | |||
| 346 | // insert remaining items | ||
| 347 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (si < n) { |
| 348 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | inserted += invoke_list_func(insert_array, list, di, src, n - si); |
| 349 | } | ||
| 350 | |||
| 351 | 12 | return inserted; | |
| 352 | } | ||
| 353 | |||
| 354 | 4 | void cx_list_default_sort(struct cx_list_s *list) { | |
| 355 | 4 | size_t elem_size = list->collection.elem_size; | |
| 356 | 4 | size_t list_size = list->collection.size; | |
| 357 | 4 | void *tmp = malloc(elem_size * list_size); | |
| 358 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (tmp == NULL) abort(); |
| 359 | |||
| 360 | // copy elements from source array | ||
| 361 | 4 | char *loc = tmp; | |
| 362 |
2/2✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 4 times.
|
1004 | for (size_t i = 0; i < list_size; i++) { |
| 363 |
2/2✓ Branch 0 taken 500 times.
✓ Branch 1 taken 500 times.
|
1000 | void *src = invoke_list_func(at, list, i); |
| 364 | 1000 | memcpy(loc, src, elem_size); | |
| 365 | 1000 | loc += elem_size; | |
| 366 | } | ||
| 367 | |||
| 368 | // qsort | ||
| 369 | 4 | qsort(tmp, list_size, elem_size, | |
| 370 | 4 | list->collection.cmpfunc); | |
| 371 | |||
| 372 | // copy elements back | ||
| 373 | 4 | loc = tmp; | |
| 374 |
2/2✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 4 times.
|
1004 | for (size_t i = 0; i < list_size; i++) { |
| 375 |
2/2✓ Branch 0 taken 500 times.
✓ Branch 1 taken 500 times.
|
1000 | void *dest = invoke_list_func(at, list, i); |
| 376 | 1000 | memcpy(dest, loc, elem_size); | |
| 377 | 1000 | loc += elem_size; | |
| 378 | } | ||
| 379 | |||
| 380 | 4 | free(tmp); | |
| 381 | 4 | } | |
| 382 | |||
| 383 | 44 | int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) { | |
| 384 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 40 times.
|
44 | if (i == j) return 0; |
| 385 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 32 times.
|
40 | if (i >= list->collection.size) return 1; |
| 386 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 28 times.
|
32 | if (j >= list->collection.size) return 1; |
| 387 | |||
| 388 | 28 | size_t elem_size = list->collection.elem_size; | |
| 389 | |||
| 390 | 28 | void *tmp = malloc(elem_size); | |
| 391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (tmp == NULL) return 1; |
| 392 | |||
| 393 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
|
28 | void *ip = invoke_list_func(at, list, i); |
| 394 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
|
28 | void *jp = invoke_list_func(at, list, j); |
| 395 | |||
| 396 | 28 | memcpy(tmp, ip, elem_size); | |
| 397 | 28 | memcpy(ip, jp, elem_size); | |
| 398 | 28 | memcpy(jp, tmp, elem_size); | |
| 399 | |||
| 400 | 28 | free(tmp); | |
| 401 | |||
| 402 | 28 | return 0; | |
| 403 | } | ||
| 404 | |||
| 405 | 153 | void cx_list_init( | |
| 406 | struct cx_list_s *list, | ||
| 407 | struct cx_list_class_s *cl, | ||
| 408 | const struct cx_allocator_s *allocator, | ||
| 409 | cx_compare_func comparator, | ||
| 410 | size_t elem_size | ||
| 411 | ) { | ||
| 412 | 153 | list->cl = cl; | |
| 413 | 153 | list->collection.allocator = allocator; | |
| 414 | 153 | list->collection.cmpfunc = comparator; | |
| 415 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 72 times.
|
153 | if (elem_size > 0) { |
| 416 | 81 | list->collection.elem_size = elem_size; | |
| 417 | } else { | ||
| 418 | 72 | list->collection.elem_size = sizeof(void *); | |
| 419 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 70 times.
|
72 | if (list->collection.cmpfunc == NULL) { |
| 420 | 2 | list->collection.cmpfunc = cx_cmp_ptr; | |
| 421 | } | ||
| 422 | 72 | list->collection.store_pointer = true; | |
| 423 | 72 | list->climpl = list->cl; | |
| 424 | 72 | list->cl = &cx_pointer_list_class; | |
| 425 | } | ||
| 426 | 153 | } | |
| 427 | |||
| 428 | 177 | int cxListCompare( | |
| 429 | const CxList *list, | ||
| 430 | const CxList *other | ||
| 431 | ) { | ||
| 432 | 177 | bool cannot_optimize = false; | |
| 433 | |||
| 434 | // if one is storing pointers but the other is not | ||
| 435 | 177 | cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer; | |
| 436 | |||
| 437 | // if one class is wrapped but the other is not | ||
| 438 | 177 | cannot_optimize |= (list->climpl == NULL) ^ (other->climpl == NULL); | |
| 439 | |||
| 440 | // if the compare functions do not match or both are NULL | ||
| 441 |
2/2✓ Branch 0 taken 93 times.
✓ Branch 1 taken 84 times.
|
177 | if (!cannot_optimize) { |
| 442 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 65 times.
|
93 | cx_compare_func list_cmp = (cx_compare_func) (list->climpl != NULL ? |
| 443 | 93 | list->climpl->compare : list->cl->compare); | |
| 444 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 65 times.
|
93 | cx_compare_func other_cmp = (cx_compare_func) (other->climpl != NULL ? |
| 445 | 93 | other->climpl->compare : other->cl->compare); | |
| 446 | 93 | cannot_optimize |= list_cmp != other_cmp; | |
| 447 | 93 | cannot_optimize |= list_cmp == NULL; | |
| 448 | } | ||
| 449 | |||
| 450 |
2/2✓ Branch 0 taken 149 times.
✓ Branch 1 taken 28 times.
|
177 | if (cannot_optimize) { |
| 451 | // lists are definitely different - cannot use internal compare function | ||
| 452 |
2/2✓ Branch 0 taken 105 times.
✓ Branch 1 taken 44 times.
|
149 | if (list->collection.size == other->collection.size) { |
| 453 | 105 | CxIterator left = list->cl->iterator(list, 0, false); | |
| 454 | 105 | CxIterator right = other->cl->iterator(other, 0, false); | |
| 455 |
2/2✓ Branch 0 taken 3184 times.
✓ Branch 1 taken 65 times.
|
3249 | for (size_t i = 0; i < list->collection.size; i++) { |
| 456 | 3184 | void *leftValue = cxIteratorCurrent(left); | |
| 457 | 3184 | void *rightValue = cxIteratorCurrent(right); | |
| 458 | 3184 | int d = list->collection.cmpfunc(leftValue, rightValue); | |
| 459 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 3144 times.
|
3184 | if (d != 0) { |
| 460 | 40 | return d; | |
| 461 | } | ||
| 462 | 3144 | cxIteratorNext(left); | |
| 463 | 3144 | cxIteratorNext(right); | |
| 464 | } | ||
| 465 | 65 | return 0; | |
| 466 | } else { | ||
| 467 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
|
44 | return list->collection.size < other->collection.size ? -1 : 1; |
| 468 | } | ||
| 469 | } else { | ||
| 470 | // lists are compatible | ||
| 471 | 28 | return list->cl->compare(list, other); | |
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | 29 | CxIterator cxListMutIteratorAt( | |
| 476 | CxList *list, | ||
| 477 | size_t index | ||
| 478 | ) { | ||
| 479 | 29 | CxIterator it = list->cl->iterator(list, index, false); | |
| 480 | 29 | it.base.mutating = true; | |
| 481 | 29 | return it; | |
| 482 | } | ||
| 483 | |||
| 484 | 13 | CxIterator cxListMutBackwardsIteratorAt( | |
| 485 | CxList *list, | ||
| 486 | size_t index | ||
| 487 | ) { | ||
| 488 | 13 | CxIterator it = list->cl->iterator(list, index, true); | |
| 489 | 13 | it.base.mutating = true; | |
| 490 | 13 | return it; | |
| 491 | } | ||
| 492 | |||
| 493 | 154 | void cxListFree(CxList *list) { | |
| 494 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 154 times.
|
154 | if (list == NULL) return; |
| 495 | 154 | list->cl->deallocate(list); | |
| 496 | } | ||
| 497 |