| 36 |
36 |
| 37 static int cx_pl_cmpfunc( |
37 static int cx_pl_cmpfunc( |
| 38 const void *l, |
38 const void *l, |
| 39 const void *r |
39 const void *r |
| 40 ) { |
40 ) { |
| |
41 // l and r are guaranteed to be non-NULL pointing to the list's memory |
| 41 void *const *lptr = l; |
42 void *const *lptr = l; |
| 42 void *const *rptr = r; |
43 void *const *rptr = r; |
| 43 const void *left = lptr == NULL ? NULL : *lptr; |
44 const void *left = *lptr; |
| 44 const void *right = rptr == NULL ? NULL : *rptr; |
45 const void *right = *rptr; |
| |
46 if (left == NULL) { |
| |
47 // NULL is smaller than any value except NULL |
| |
48 return right == NULL ? 0 : -1; |
| |
49 } else if (right == NULL) { |
| |
50 // any value is larger than NULL |
| |
51 return 1; |
| |
52 } |
| 45 return cx_pl_cmpfunc_impl(left, right); |
53 return cx_pl_cmpfunc_impl(left, right); |
| 46 } |
54 } |
| 47 |
55 |
| 48 static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) { |
56 static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) { |
| 49 // cast away const - this is the hacky thing |
57 // cast away const - this is the hacky thing |
| 88 size_t result = list->climpl->insert_sorted(list, array, n); |
96 size_t result = list->climpl->insert_sorted(list, array, n); |
| 89 cx_pl_unhack_cmpfunc(list); |
97 cx_pl_unhack_cmpfunc(list); |
| 90 return result; |
98 return result; |
| 91 } |
99 } |
| 92 |
100 |
| |
101 static size_t cx_pl_insert_unique( |
| |
102 struct cx_list_s *list, |
| |
103 const void *array, |
| |
104 size_t n |
| |
105 ) { |
| |
106 cx_pl_hack_cmpfunc(list); |
| |
107 size_t result = list->climpl->insert_unique(list, array, n); |
| |
108 cx_pl_unhack_cmpfunc(list); |
| |
109 return result; |
| |
110 } |
| |
111 |
| 93 static int cx_pl_insert_iter( |
112 static int cx_pl_insert_iter( |
| 94 struct cx_iterator_s *iter, |
113 struct cx_iterator_s *iter, |
| 95 const void *elem, |
114 const void *elem, |
| 96 int prepend |
115 int prepend |
| 97 ) { |
116 ) { |
| 282 const char *src = data; |
303 const char *src = data; |
| 283 size_t i = 0; |
304 size_t i = 0; |
| 284 for (; i < n; i++) { |
305 for (; i < n; i++) { |
| 285 if (NULL == invoke_list_func( |
306 if (NULL == invoke_list_func( |
| 286 insert_element, list, index + i, |
307 insert_element, list, index + i, |
| 287 src + (i * elem_size))) return i; |
308 src + i * elem_size) |
| |
309 ) { |
| |
310 return i; // LCOV_EXCL_LINE |
| |
311 } |
| 288 } |
312 } |
| 289 return i; |
313 return i; |
| 290 } |
314 } |
| 291 |
315 |
| 292 size_t cx_list_default_insert_sorted( |
316 static size_t cx_list_default_insert_sorted_impl( |
| 293 struct cx_list_s *list, |
317 struct cx_list_s *list, |
| 294 const void *sorted_data, |
318 const void *sorted_data, |
| 295 size_t n |
319 size_t n, |
| |
320 bool allow_duplicates |
| 296 ) { |
321 ) { |
| 297 // corner case |
322 // corner case |
| 298 if (n == 0) return 0; |
323 if (n == 0) return 0; |
| 299 |
324 |
| 300 size_t elem_size = list->collection.elem_size; |
325 size_t elem_size = list->collection.elem_size; |
| 301 cx_compare_func cmp = list->collection.cmpfunc; |
326 cx_compare_func cmp = list->collection.cmpfunc; |
| 302 const char *src = sorted_data; |
327 const char *src = sorted_data; |
| 303 |
328 |
| 304 // track indices and number of inserted items |
329 // track indices and number of inserted items |
| 305 size_t di = 0, si = 0, inserted = 0; |
330 size_t di = 0, si = 0, processed = 0; |
| 306 |
331 |
| 307 // search the list for insertion points |
332 // search the list for insertion points |
| 308 for (; di < list->collection.size; di++) { |
333 while (di < list->collection.size) { |
| 309 const void *list_elm = invoke_list_func(at, list, di); |
334 const void *list_elm = invoke_list_func(at, list, di); |
| 310 |
335 |
| 311 // compare current list element with first source element |
336 // compare the current list element with the first source element |
| 312 // if less or equal, skip |
337 // if less, skip the list elements |
| 313 if (cmp(list_elm, src) <= 0) { |
338 // if equal, skip the list elements and optionally the source elements |
| 314 continue; |
339 { |
| 315 } |
340 int d = cmp(list_elm, src); |
| 316 |
341 if (d <= 0) { |
| 317 // determine number of consecutive elements that can be inserted |
342 if (!allow_duplicates && d == 0) { |
| 318 size_t ins = 1; |
343 src += elem_size; |
| |
344 si++; |
| |
345 processed++; // we also count duplicates for the return value |
| |
346 while (si < n && cmp(list_elm, src) == 0) { |
| |
347 src += elem_size; |
| |
348 si++; |
| |
349 processed++; |
| |
350 } |
| |
351 if (processed == n) { |
| |
352 return processed; |
| |
353 } |
| |
354 } |
| |
355 di++; |
| |
356 continue; |
| |
357 } |
| |
358 } |
| |
359 |
| |
360 // determine the number of consecutive elements that can be inserted |
| |
361 size_t ins = 1, skip = 0; |
| 319 const char *next = src; |
362 const char *next = src; |
| 320 while (++si < n) { |
363 while (++si < n) { |
| |
364 if (!allow_duplicates) { |
| |
365 // skip duplicates within the source |
| |
366 if (cmp(next, next + elem_size) == 0) { |
| |
367 next += elem_size; |
| |
368 skip++; |
| |
369 continue; |
| |
370 } else { |
| |
371 if (skip > 0) { |
| |
372 // if we had to skip something, we must wait for the next run |
| |
373 next += elem_size; |
| |
374 break; |
| |
375 } |
| |
376 } |
| |
377 } |
| 321 next += elem_size; |
378 next += elem_size; |
| 322 // once we become larger than the list elem, break |
379 // once we become larger than the list elem, break |
| 323 if (cmp(list_elm, next) <= 0) { |
380 if (cmp(list_elm, next) <= 0) { |
| 324 break; |
381 break; |
| 325 } |
382 } |
| 327 ins++; |
384 ins++; |
| 328 } |
385 } |
| 329 |
386 |
| 330 // insert the elements at location si |
387 // insert the elements at location si |
| 331 if (ins == 1) { |
388 if (ins == 1) { |
| 332 if (NULL == invoke_list_func( |
389 if (NULL == invoke_list_func(insert_element, list, di, src)) { |
| 333 insert_element, list, di, src)) return inserted; |
390 return processed; // LCOV_EXCL_LINE |
| |
391 } |
| 334 } else { |
392 } else { |
| 335 size_t r = invoke_list_func(insert_array, list, di, src, ins); |
393 size_t r = invoke_list_func(insert_array, list, di, src, ins); |
| 336 if (r < ins) return inserted + r; |
394 if (r < ins) { |
| 337 } |
395 return processed + r; // LCOV_EXCL_LINE |
| 338 inserted += ins; |
396 } |
| |
397 } |
| |
398 processed += ins + skip; |
| 339 di += ins; |
399 di += ins; |
| 340 |
400 |
| 341 // everything inserted? |
401 // everything inserted? |
| 342 if (inserted == n) return inserted; |
402 if (processed == n) { |
| |
403 return processed; |
| |
404 } |
| 343 src = next; |
405 src = next; |
| 344 } |
406 } |
| 345 |
407 |
| 346 // insert remaining items |
408 // insert remaining items |
| 347 if (si < n) { |
409 if (si < n) { |
| 348 inserted += invoke_list_func(insert_array, list, di, src, n - si); |
410 if (allow_duplicates) { |
| 349 } |
411 processed += invoke_list_func(insert_array, list, di, src, n - si); |
| 350 |
412 } else { |
| 351 return inserted; |
413 const void *last = di == 0 ? NULL : invoke_list_func(at, list, di - 1); |
| |
414 for (; si < n; si++) { |
| |
415 // skip duplicates within the source |
| |
416 if (last == NULL || cmp(last, src) != 0) { |
| |
417 if (NULL == invoke_list_func(insert_element, list, di, src)) { |
| |
418 return processed; // LCOV_EXCL_LINE |
| |
419 } |
| |
420 last = src; |
| |
421 di++; |
| |
422 } |
| |
423 processed++; |
| |
424 src += elem_size; |
| |
425 } |
| |
426 } |
| |
427 } |
| |
428 |
| |
429 return processed; |
| |
430 } |
| |
431 |
| |
432 size_t cx_list_default_insert_sorted( |
| |
433 struct cx_list_s *list, |
| |
434 const void *sorted_data, |
| |
435 size_t n |
| |
436 ) { |
| |
437 return cx_list_default_insert_sorted_impl(list, sorted_data, n, true); |
| |
438 } |
| |
439 |
| |
440 size_t cx_list_default_insert_unique( |
| |
441 struct cx_list_s *list, |
| |
442 const void *sorted_data, |
| |
443 size_t n |
| |
444 ) { |
| |
445 return cx_list_default_insert_sorted_impl(list, sorted_data, n, false); |
| 352 } |
446 } |
| 353 |
447 |
| 354 void cx_list_default_sort(struct cx_list_s *list) { |
448 void cx_list_default_sort(struct cx_list_s *list) { |
| 355 size_t elem_size = list->collection.elem_size; |
449 size_t elem_size = list->collection.elem_size; |
| 356 size_t list_size = list->collection.size; |
450 size_t list_size = list->collection.size; |
| 357 void *tmp = cxMallocDefault(elem_size * list_size); |
451 void *tmp = cxMallocDefault(elem_size * list_size); |
| 358 if (tmp == NULL) abort(); |
452 if (tmp == NULL) abort(); // LCOV_EXCL_LINE |
| 359 |
453 |
| 360 // copy elements from source array |
454 // copy elements from source array |
| 361 char *loc = tmp; |
455 char *loc = tmp; |
| 362 for (size_t i = 0; i < list_size; i++) { |
456 for (size_t i = 0; i < list_size; i++) { |
| 363 void *src = invoke_list_func(at, list, i); |
457 void *src = invoke_list_func(at, list, i); |
| 386 if (j >= list->collection.size) return 1; |
480 if (j >= list->collection.size) return 1; |
| 387 |
481 |
| 388 size_t elem_size = list->collection.elem_size; |
482 size_t elem_size = list->collection.elem_size; |
| 389 |
483 |
| 390 void *tmp = cxMallocDefault(elem_size); |
484 void *tmp = cxMallocDefault(elem_size); |
| 391 if (tmp == NULL) return 1; |
485 if (tmp == NULL) return 1; // LCOV_EXCL_LINE |
| 392 |
486 |
| 393 void *ip = invoke_list_func(at, list, i); |
487 void *ip = invoke_list_func(at, list, i); |
| 394 void *jp = invoke_list_func(at, list, j); |
488 void *jp = invoke_list_func(at, list, j); |
| 395 |
489 |
| 396 memcpy(tmp, ip, elem_size); |
490 memcpy(tmp, ip, elem_size); |
| 474 |
568 |
| 475 CxIterator cxListMutIteratorAt( |
569 CxIterator cxListMutIteratorAt( |
| 476 CxList *list, |
570 CxList *list, |
| 477 size_t index |
571 size_t index |
| 478 ) { |
572 ) { |
| |
573 if (list == NULL) list = cxEmptyList; |
| 479 CxIterator it = list->cl->iterator(list, index, false); |
574 CxIterator it = list->cl->iterator(list, index, false); |
| 480 it.base.mutating = true; |
575 it.base.mutating = true; |
| 481 return it; |
576 return it; |
| 482 } |
577 } |
| 483 |
578 |
| 484 CxIterator cxListMutBackwardsIteratorAt( |
579 CxIterator cxListMutBackwardsIteratorAt( |
| 485 CxList *list, |
580 CxList *list, |
| 486 size_t index |
581 size_t index |
| 487 ) { |
582 ) { |
| |
583 if (list == NULL) list = cxEmptyList; |
| 488 CxIterator it = list->cl->iterator(list, index, true); |
584 CxIterator it = list->cl->iterator(list, index, true); |
| 489 it.base.mutating = true; |
585 it.base.mutating = true; |
| 490 return it; |
586 return it; |
| 491 } |
587 } |
| 492 |
588 |