diff --git a/m-list.h b/m-list.h index 7653b096..630c1c70 100644 --- a/m-list.h +++ b/m-list.h @@ -1145,8 +1145,8 @@ { \ LISTI_DUAL_PUSH_CONTRACT(list1); \ LISTI_DUAL_PUSH_CONTRACT(list2); \ - assert(it->current != NULL); \ - /* First remove 'it' from list2 */ \ + assert (it->current != NULL); \ + /* First remove the item 'it' from the list 'list2' */ \ struct M_C(name, _s) *current = it->current; \ struct M_C(name, _s) *next = current->next; \ if (it->previous == NULL) { \ @@ -1154,20 +1154,63 @@ } else { \ it->previous->next = next; \ } \ - /* Update front */ \ + /* Update the front of 'list2' if it was the last element */ \ struct M_C(name, _s) *front = list2->front; \ front = (next == NULL) ? it->previous : front; \ list2->front = front; \ - /* Update it to next element */ \ + /* Update 'it' to point to the next element */ \ it->current = next; \ - /* Move current in nv */ \ + /* Move the extracted 'current' into the list 'nv' */ \ current->next = list1->back; \ list1->back = current; \ - /* Update front too if the list was empty */ \ + /* Update the front field if the list 'nv' was empty */ \ /* This C code shall generate branchless code */ \ front = list1->front; \ front = (front == NULL) ? current : front; \ list1->front = front; \ + LISTI_DUAL_PUSH_CONTRACT(list1); \ + LISTI_DUAL_PUSH_CONTRACT(list2); \ + } \ + \ + static inline void \ + M_C(name, _splice_at)(list_t nlist, list_it_t npos, \ + list_t olist, list_it_t opos) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(nlist); \ + LISTI_DUAL_PUSH_CONTRACT(olist); \ + assert (npos != NULL && opos != NULL); \ + /* First remove the item 'opos' from the list 'olist' */ \ + struct M_C(name, _s) *current = opos->current; \ + struct M_C(name, _s) *next = current->next; \ + if (opos->previous == NULL) { \ + olist->back = next; \ + } else { \ + opos->previous->next = next; \ + } \ + /* Update the front of 'olist' if it was the last element */ \ + struct M_C(name, _s) *front = olist->front; \ + front = (next == NULL) ? opos->previous : front; \ + olist->front = front; \ + /* Update 'opos' to point to the next element */ \ + opos->current = next; \ + /* Insert into 'nlist' */ \ + if (M_UNLIKELY (npos->current == NULL)) { \ + current->next = nlist->back; \ + nlist->back = current; \ + /* update 'front' if the list was empty (branchless) */ \ + front = nlist->front; \ + front = (front == NULL) ? current : front; \ + nlist->front = front; \ + } else { \ + current->next = npos->current->next; \ + npos->current->next = current; \ + /* update front if current == front (branchless) */ \ + front = nlist->front; \ + front = (front == npos->current) ? next : front; \ + nlist->front = front; \ + } \ + LISTI_DUAL_PUSH_CONTRACT(nlist); \ + LISTI_DUAL_PUSH_CONTRACT(olist); \ } \ \ static inline void \ diff --git a/tests/test-mlist.c b/tests/test-mlist.c index 62f7a94f..f3ae7fbe 100644 --- a/tests/test-mlist.c +++ b/tests/test-mlist.c @@ -33,6 +33,7 @@ LIST_DUAL_PUSH_DEF(list2_double, double) END_COVERAGE LIST_DUAL_PUSH_DEF(list2_mpz, testobj_t, TESTOBJ_OPLIST) #define LIST_UINT_OPLIST LIST_OPLIST(list_uint) +#define LIST2_DOUBLE_OPLIST LIST_OPLIST(list2_double) static void test_uint(void) { @@ -567,6 +568,23 @@ static void test_dual_it1(void) list2_double_next(it2); assert(*list2_double_cref(it2) == 1.0); + list2_double_clean(list); + list2_double_clean(list2); + for(double i = 0; i < 10; i++) + list2_double_push_back (list, i); + list2_double_it (it, list); + list2_double_it_end (it2, list2); + for(double i = 0; i < 10; i++) { + list2_double_splice_at (list2, it2, list, it); + } + assert (list2_double_empty_p(list)); + assert (list2_double_size (list2) == 10); + double s = 0.0; + for M_EACH(item, list2, LIST2_DOUBLE_OPLIST) { + assert (*item == s); + s += 1.0; + } + list2_double_clear(list2); list2_double_clear(list); }