245 } else { |
245 } else { |
246 cx_linked_list_link(insert_end, successor, loc_prev, loc_next); |
246 cx_linked_list_link(insert_end, successor, loc_prev, loc_next); |
247 } |
247 } |
248 } |
248 } |
249 |
249 |
|
250 void cx_linked_list_insert_sorted( |
|
251 void **begin, |
|
252 void **end, |
|
253 ptrdiff_t loc_prev, |
|
254 ptrdiff_t loc_next, |
|
255 void *new_node, |
|
256 cx_compare_func cmp_func |
|
257 ) { |
|
258 assert(ll_next(new_node) == NULL); |
|
259 cx_linked_list_insert_sorted_chain( |
|
260 begin, end, loc_prev, loc_next, new_node, cmp_func); |
|
261 } |
|
262 |
|
263 void cx_linked_list_insert_sorted_chain( |
|
264 void **begin, |
|
265 void **end, |
|
266 ptrdiff_t loc_prev, |
|
267 ptrdiff_t loc_next, |
|
268 void *insert_begin, |
|
269 cx_compare_func cmp_func |
|
270 ) { |
|
271 assert(begin != NULL); |
|
272 assert(loc_next >= 0); |
|
273 assert(insert_begin != NULL); |
|
274 |
|
275 // track currently observed nodes |
|
276 void *dest_prev = NULL; |
|
277 void *dest = *begin; |
|
278 void *src = insert_begin; |
|
279 |
|
280 // special case: list is empty |
|
281 if (dest == NULL) { |
|
282 *begin = src; |
|
283 if (end != NULL) { |
|
284 *end = cx_linked_list_last(src, loc_next); |
|
285 } |
|
286 return; |
|
287 } |
|
288 |
|
289 // search the list for insertion points |
|
290 while (dest != NULL && src != NULL) { |
|
291 // compare current list node with source node |
|
292 // if less or equal, skip |
|
293 if (cmp_func(dest, src) <= 0) { |
|
294 dest_prev = dest; |
|
295 dest = ll_next(dest); |
|
296 continue; |
|
297 } |
|
298 |
|
299 // determine chain of elements that can be inserted |
|
300 void *end_of_chain = src; |
|
301 void *next_in_chain = ll_next(src); |
|
302 while (next_in_chain != NULL) { |
|
303 // once we become larger than the list elem, break |
|
304 if (cmp_func(dest, next_in_chain) <= 0) { |
|
305 break; |
|
306 } |
|
307 // otherwise, we can insert one more |
|
308 end_of_chain = next_in_chain; |
|
309 next_in_chain = ll_next(next_in_chain); |
|
310 } |
|
311 |
|
312 // insert the elements |
|
313 if (dest_prev == NULL) { |
|
314 // new begin |
|
315 *begin = src; |
|
316 } else { |
|
317 cx_linked_list_link(dest_prev, src, loc_prev, loc_next); |
|
318 } |
|
319 cx_linked_list_link(end_of_chain, dest, loc_prev, loc_next); |
|
320 |
|
321 // continue with next |
|
322 src = next_in_chain; |
|
323 dest_prev = dest; |
|
324 dest = ll_next(dest); |
|
325 } |
|
326 |
|
327 // insert remaining items |
|
328 if (src != NULL) { |
|
329 cx_linked_list_link(dest_prev, src, loc_prev, loc_next); |
|
330 } |
|
331 |
|
332 // determine new end of list, if requested |
|
333 if (end != NULL) { |
|
334 *end = cx_linked_list_last( |
|
335 dest != NULL ? dest : dest_prev, loc_next); |
|
336 } |
|
337 } |
|
338 |
250 void cx_linked_list_remove( |
339 void cx_linked_list_remove( |
251 void **begin, |
340 void **begin, |
252 void **end, |
341 void **end, |
253 ptrdiff_t loc_prev, |
342 ptrdiff_t loc_prev, |
254 ptrdiff_t loc_next, |
343 ptrdiff_t loc_next, |
508 } else { |
597 } else { |
509 return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index); |
598 return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index); |
510 } |
599 } |
511 } |
600 } |
512 |
601 |
|
602 static cx_linked_list_node *cx_ll_malloc_node(struct cx_list_s const *list) { |
|
603 return cxMalloc(list->collection.allocator, |
|
604 sizeof(cx_linked_list_node) + list->collection.elem_size); |
|
605 } |
|
606 |
513 static int cx_ll_insert_at( |
607 static int cx_ll_insert_at( |
514 struct cx_list_s *list, |
608 struct cx_list_s *list, |
515 cx_linked_list_node *node, |
609 cx_linked_list_node *node, |
516 void const *elem |
610 void const *elem |
517 ) { |
611 ) { |
518 |
612 |
519 // create the new new_node |
613 // create the new new_node |
520 cx_linked_list_node *new_node = cxMalloc(list->collection.allocator, |
614 cx_linked_list_node *new_node = cx_ll_malloc_node(list); |
521 sizeof(cx_linked_list_node) + list->collection.elem_size); |
|
522 |
615 |
523 // sortir if failed |
616 // sortir if failed |
524 if (new_node == NULL) return 1; |
617 if (new_node == NULL) return 1; |
525 |
618 |
526 // initialize new new_node |
619 // initialize new new_node |
561 if (n == 1) return 1; |
654 if (n == 1) return 1; |
562 |
655 |
563 // we now know exactly where we are |
656 // we now know exactly where we are |
564 node = node == NULL ? ((cx_linked_list *) list)->begin : node->next; |
657 node = node == NULL ? ((cx_linked_list *) list)->begin : node->next; |
565 |
658 |
566 // we can add the remaining nodes and immedately advance to the inserted node |
659 // we can add the remaining nodes and immediately advance to the inserted node |
567 char const *source = array; |
660 char const *source = array; |
568 for (size_t i = 1; i < n; i++) { |
661 for (size_t i = 1; i < n; i++) { |
569 source += list->collection.elem_size; |
662 source += list->collection.elem_size; |
570 if (0 != cx_ll_insert_at(list, node, source)) { |
663 if (0 != cx_ll_insert_at(list, node, source)) { |
571 return i; |
664 return i; |
579 struct cx_list_s *list, |
672 struct cx_list_s *list, |
580 size_t index, |
673 size_t index, |
581 void const *element |
674 void const *element |
582 ) { |
675 ) { |
583 return 1 != cx_ll_insert_array(list, index, element, 1); |
676 return 1 != cx_ll_insert_array(list, index, element, 1); |
|
677 } |
|
678 |
|
679 static cx_compare_func cx_ll_insert_sorted_cmp_func; |
|
680 |
|
681 static int cx_ll_insert_sorted_cmp_helper(void const *l, void const *r) { |
|
682 cx_linked_list_node const *left = l; |
|
683 cx_linked_list_node const *right = r; |
|
684 return cx_ll_insert_sorted_cmp_func(left->payload, right->payload); |
|
685 } |
|
686 |
|
687 static size_t cx_ll_insert_sorted( |
|
688 struct cx_list_s *list, |
|
689 void const *array, |
|
690 size_t n |
|
691 ) { |
|
692 // special case |
|
693 if (n == 0) return 0; |
|
694 |
|
695 // create a new chain of nodes |
|
696 cx_linked_list_node *chain = cx_ll_malloc_node(list); |
|
697 if (chain == NULL) return 0; |
|
698 |
|
699 memcpy(chain->payload, array, list->collection.elem_size); |
|
700 chain->prev = NULL; |
|
701 chain->next = NULL; |
|
702 |
|
703 // add all elements from the array to that chain |
|
704 cx_linked_list_node *prev = chain; |
|
705 char const *src = array; |
|
706 size_t inserted = 1; |
|
707 for (; inserted < n; inserted++) { |
|
708 cx_linked_list_node *next = cx_ll_malloc_node(list); |
|
709 if (next == NULL) break; |
|
710 src += list->collection.elem_size; |
|
711 memcpy(next->payload, src, list->collection.elem_size); |
|
712 prev->next = next; |
|
713 next->prev = prev; |
|
714 prev = next; |
|
715 } |
|
716 prev->next = NULL; |
|
717 |
|
718 // invoke the low level function |
|
719 cx_linked_list *ll = (cx_linked_list *) list; |
|
720 cx_ll_insert_sorted_cmp_func = list->collection.cmpfunc; |
|
721 cx_linked_list_insert_sorted_chain( |
|
722 (void **) &ll->begin, |
|
723 (void **) &ll->end, |
|
724 CX_LL_LOC_PREV, |
|
725 CX_LL_LOC_NEXT, |
|
726 chain, |
|
727 cx_ll_insert_sorted_cmp_helper |
|
728 ); |
|
729 |
|
730 // adjust the list metadata |
|
731 list->collection.size += inserted; |
|
732 |
|
733 return inserted; |
584 } |
734 } |
585 |
735 |
586 static int cx_ll_remove( |
736 static int cx_ll_remove( |
587 struct cx_list_s *list, |
737 struct cx_list_s *list, |
588 size_t index |
738 size_t index |