| 29 #include "cx/list.h" |
29 #include "cx/list.h" |
| 30 |
30 |
| 31 #include <string.h> |
31 #include <string.h> |
| 32 #include <assert.h> |
32 #include <assert.h> |
| 33 |
33 |
| 34 // <editor-fold desc="Store Pointers Functionality"> |
34 int cx_list_compare_wrapper(const void *l, const void *r, void *c) { |
| 35 |
35 CxList *list = c; |
| 36 static _Thread_local cx_compare_func cx_pl_cmpfunc_impl; |
36 const void *left; |
| 37 |
37 const void *right; |
| 38 static int cx_pl_cmpfunc( |
38 if (cxCollectionStoresPointers(list)) { |
| 39 const void *l, |
39 left = *(void**)l; |
| 40 const void *r |
40 right = *(void**)r; |
| 41 ) { |
41 // for historic reasons, we are handling the NULL case here |
| 42 // l and r are guaranteed to be non-NULL pointing to the list's memory |
42 // because every UCX compare function does not support NULL arguments |
| 43 void *const *lptr = l; |
43 if (left == NULL) { |
| 44 void *const *rptr = r; |
44 if (right == NULL) return 0; |
| 45 const void *left = *lptr; |
45 return -1; |
| 46 const void *right = *rptr; |
46 } else if (right == NULL) { |
| 47 if (left == NULL) { |
47 return 1; |
| 48 // NULL is smaller than any value except NULL |
48 } |
| 49 return right == NULL ? 0 : -1; |
49 } else { |
| 50 } else if (right == NULL) { |
50 left = l; |
| 51 // any value is larger than NULL |
51 right = r; |
| 52 return 1; |
52 } |
| 53 } |
53 return cx_invoke_compare_func(list, left, right); |
| 54 return cx_pl_cmpfunc_impl(left, right); |
54 } |
| 55 } |
55 |
| 56 |
56 #define cx_list_compare_wrapper(l, r, c) cx_list_compare_wrapper(l, r, (void*)c) |
| 57 static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) { |
|
| 58 // cast away const - this is the hacky thing |
|
| 59 struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; |
|
| 60 cx_pl_cmpfunc_impl = l->cmpfunc; |
|
| 61 l->cmpfunc = cx_pl_cmpfunc; |
|
| 62 } |
|
| 63 |
|
| 64 static void cx_pl_unhack_cmpfunc(const struct cx_list_s *list) { |
|
| 65 // cast away const - this is the hacky thing |
|
| 66 struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; |
|
| 67 l->cmpfunc = cx_pl_cmpfunc_impl; |
|
| 68 } |
|
| 69 |
|
| 70 static void cx_pl_destructor(struct cx_list_s *list) { |
|
| 71 list->climpl->deallocate(list); |
|
| 72 } |
|
| 73 |
|
| 74 static void *cx_pl_insert_element( |
|
| 75 struct cx_list_s *list, |
|
| 76 size_t index, |
|
| 77 const void *element |
|
| 78 ) { |
|
| 79 return list->climpl->insert_element(list, index, &element); |
|
| 80 } |
|
| 81 |
|
| 82 static size_t cx_pl_insert_array( |
|
| 83 struct cx_list_s *list, |
|
| 84 size_t index, |
|
| 85 const void *array, |
|
| 86 size_t n |
|
| 87 ) { |
|
| 88 return list->climpl->insert_array(list, index, array, n); |
|
| 89 } |
|
| 90 |
|
| 91 static size_t cx_pl_insert_sorted( |
|
| 92 struct cx_list_s *list, |
|
| 93 const void *array, |
|
| 94 size_t n |
|
| 95 ) { |
|
| 96 cx_pl_hack_cmpfunc(list); |
|
| 97 size_t result = list->climpl->insert_sorted(list, array, n); |
|
| 98 cx_pl_unhack_cmpfunc(list); |
|
| 99 return result; |
|
| 100 } |
|
| 101 |
|
| 102 static size_t cx_pl_insert_unique( |
|
| 103 struct cx_list_s *list, |
|
| 104 const void *array, |
|
| 105 size_t n |
|
| 106 ) { |
|
| 107 cx_pl_hack_cmpfunc(list); |
|
| 108 size_t result = list->climpl->insert_unique(list, array, n); |
|
| 109 cx_pl_unhack_cmpfunc(list); |
|
| 110 return result; |
|
| 111 } |
|
| 112 |
|
| 113 static int cx_pl_insert_iter( |
|
| 114 struct cx_iterator_s *iter, |
|
| 115 const void *elem, |
|
| 116 int prepend |
|
| 117 ) { |
|
| 118 struct cx_list_s *list = iter->src_handle; |
|
| 119 return list->climpl->insert_iter(iter, &elem, prepend); |
|
| 120 } |
|
| 121 |
|
| 122 static size_t cx_pl_remove( |
|
| 123 struct cx_list_s *list, |
|
| 124 size_t index, |
|
| 125 size_t num, |
|
| 126 void *targetbuf |
|
| 127 ) { |
|
| 128 return list->climpl->remove(list, index, num, targetbuf); |
|
| 129 } |
|
| 130 |
|
| 131 static void cx_pl_clear(struct cx_list_s *list) { |
|
| 132 list->climpl->clear(list); |
|
| 133 } |
|
| 134 |
|
| 135 static int cx_pl_swap( |
|
| 136 struct cx_list_s *list, |
|
| 137 size_t i, |
|
| 138 size_t j |
|
| 139 ) { |
|
| 140 return list->climpl->swap(list, i, j); |
|
| 141 } |
|
| 142 |
|
| 143 static void *cx_pl_at( |
|
| 144 const struct cx_list_s *list, |
|
| 145 size_t index |
|
| 146 ) { |
|
| 147 void **ptr = list->climpl->at(list, index); |
|
| 148 return ptr == NULL ? NULL : *ptr; |
|
| 149 } |
|
| 150 |
|
| 151 static size_t cx_pl_find_remove( |
|
| 152 struct cx_list_s *list, |
|
| 153 const void *elem, |
|
| 154 bool remove |
|
| 155 ) { |
|
| 156 cx_pl_hack_cmpfunc(list); |
|
| 157 size_t ret = list->climpl->find_remove(list, &elem, remove); |
|
| 158 cx_pl_unhack_cmpfunc(list); |
|
| 159 return ret; |
|
| 160 } |
|
| 161 |
|
| 162 static void cx_pl_sort(struct cx_list_s *list) { |
|
| 163 cx_pl_hack_cmpfunc(list); |
|
| 164 list->climpl->sort(list); |
|
| 165 cx_pl_unhack_cmpfunc(list); |
|
| 166 } |
|
| 167 |
|
| 168 static int cx_pl_compare( |
|
| 169 const struct cx_list_s *list, |
|
| 170 const struct cx_list_s *other |
|
| 171 ) { |
|
| 172 cx_pl_hack_cmpfunc(list); |
|
| 173 int ret = list->climpl->compare(list, other); |
|
| 174 cx_pl_unhack_cmpfunc(list); |
|
| 175 return ret; |
|
| 176 } |
|
| 177 |
|
| 178 static void cx_pl_reverse(struct cx_list_s *list) { |
|
| 179 list->climpl->reverse(list); |
|
| 180 } |
|
| 181 |
|
| 182 static void *cx_pl_iter_current(const void *it) { |
|
| 183 const struct cx_iterator_s *iter = it; |
|
| 184 void **ptr = iter->base.current_impl(it); |
|
| 185 return ptr == NULL ? NULL : *ptr; |
|
| 186 } |
|
| 187 |
|
| 188 static int cx_pl_change_capacity(struct cx_list_s *list, size_t cap) { |
|
| 189 if (list->climpl->change_capacity == NULL) { |
|
| 190 return 0; |
|
| 191 } else { |
|
| 192 return list->climpl->change_capacity(list, cap); |
|
| 193 } |
|
| 194 } |
|
| 195 |
|
| 196 static struct cx_iterator_s cx_pl_iterator( |
|
| 197 const struct cx_list_s *list, |
|
| 198 size_t index, |
|
| 199 bool backwards |
|
| 200 ) { |
|
| 201 struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards); |
|
| 202 iter.base.current_impl = iter.base.current; |
|
| 203 iter.base.current = cx_pl_iter_current; |
|
| 204 return iter; |
|
| 205 } |
|
| 206 |
|
| 207 static cx_list_class cx_pointer_list_class = { |
|
| 208 cx_pl_destructor, |
|
| 209 cx_pl_insert_element, |
|
| 210 cx_pl_insert_array, |
|
| 211 cx_pl_insert_sorted, |
|
| 212 cx_pl_insert_unique, |
|
| 213 cx_pl_insert_iter, |
|
| 214 cx_pl_remove, |
|
| 215 cx_pl_clear, |
|
| 216 cx_pl_swap, |
|
| 217 cx_pl_at, |
|
| 218 cx_pl_find_remove, |
|
| 219 cx_pl_sort, |
|
| 220 cx_pl_compare, |
|
| 221 cx_pl_reverse, |
|
| 222 cx_pl_change_capacity, |
|
| 223 cx_pl_iterator, |
|
| 224 }; |
|
| 225 // </editor-fold> |
|
| 226 |
57 |
| 227 // <editor-fold desc="empty list implementation"> |
58 // <editor-fold desc="empty list implementation"> |
| 228 |
59 |
| 229 static void cx_emptyl_noop(cx_attr_unused CxList *list) { |
60 static void cx_emptyl_noop(cx_attr_unused CxList *list) { |
| 230 // this is a noop, but MUST be implemented |
61 // this is a noop, but MUST be implemented |
| 333 ) { |
160 ) { |
| 334 // corner case |
161 // corner case |
| 335 if (n == 0) return 0; |
162 if (n == 0) return 0; |
| 336 |
163 |
| 337 size_t elem_size = list->collection.elem_size; |
164 size_t elem_size = list->collection.elem_size; |
| 338 cx_compare_func cmp = list->collection.cmpfunc; |
|
| 339 const char *src = sorted_data; |
165 const char *src = sorted_data; |
| 340 |
166 |
| 341 // track indices and number of inserted items |
167 // track indices and number of inserted items |
| 342 size_t di = 0, si = 0, processed = 0; |
168 size_t di = 0, si = 0, processed = 0; |
| 343 |
169 |
| 344 // search the list for insertion points |
170 // search the list for insertion points |
| 345 while (di < list->collection.size) { |
171 while (di < list->collection.size) { |
| 346 const void *list_elm = invoke_list_func(at, list, di); |
172 const void *list_elm = list->cl->at(list, di); |
| 347 |
173 |
| 348 // compare the current list element with the first source element |
174 // compare the current list element with the first source element |
| 349 // if less, skip the list elements |
175 // if less, skip the list elements |
| 350 // if equal, skip the list elements and optionally the source elements |
176 // if equal, skip the list elements and optionally the source elements |
| 351 { |
177 { |
| 352 int d = cmp(list_elm, src); |
178 int d = cx_list_compare_wrapper(list_elm, src, list); |
| 353 if (d <= 0) { |
179 if (d <= 0) { |
| 354 if (!allow_duplicates && d == 0) { |
180 if (!allow_duplicates && d == 0) { |
| 355 src += elem_size; |
181 src += elem_size; |
| 356 si++; |
182 si++; |
| 357 processed++; // we also count duplicates for the return value |
183 processed++; // we also count duplicates for the return value |
| 358 while (si < n && cmp(list_elm, src) == 0) { |
184 while (si < n && cx_list_compare_wrapper(list_elm, src, list) == 0) { |
| 359 src += elem_size; |
185 src += elem_size; |
| 360 si++; |
186 si++; |
| 361 processed++; |
187 processed++; |
| 362 } |
188 } |
| 363 if (processed == n) { |
189 if (processed == n) { |
| 387 } |
213 } |
| 388 } |
214 } |
| 389 } |
215 } |
| 390 next += elem_size; |
216 next += elem_size; |
| 391 // once we become larger than the list elem, break |
217 // once we become larger than the list elem, break |
| 392 if (cmp(list_elm, next) <= 0) { |
218 if (cx_list_compare_wrapper(list_elm, next, list) <= 0) { |
| 393 break; |
219 break; |
| 394 } |
220 } |
| 395 // otherwise, we can insert one more |
221 // otherwise, we can insert one more |
| 396 ins++; |
222 ins++; |
| 397 } |
223 } |
| 398 |
224 |
| 399 // insert the elements at location si |
225 // insert the elements at location si |
| 400 if (ins == 1) { |
226 if (ins == 1) { |
| 401 if (NULL == invoke_list_func(insert_element, list, di, src)) { |
227 if (NULL == list->cl->insert_element(list, di, src)) { |
| 402 return processed; // LCOV_EXCL_LINE |
228 return processed; // LCOV_EXCL_LINE |
| 403 } |
229 } |
| 404 } else { |
230 } else { |
| 405 size_t r = invoke_list_func(insert_array, list, di, src, ins); |
231 size_t r = list->cl->insert_array(list, di, src, ins); |
| 406 if (r < ins) { |
232 if (r < ins) { |
| 407 return processed + r; // LCOV_EXCL_LINE |
233 return processed + r; // LCOV_EXCL_LINE |
| 408 } |
234 } |
| 409 } |
235 } |
| 410 processed += ins + skip; |
236 processed += ins + skip; |
| 418 } |
244 } |
| 419 |
245 |
| 420 // insert remaining items |
246 // insert remaining items |
| 421 if (si < n) { |
247 if (si < n) { |
| 422 if (allow_duplicates) { |
248 if (allow_duplicates) { |
| 423 processed += invoke_list_func(insert_array, list, di, src, n - si); |
249 processed += list->cl->insert_array(list, di, src, n - si); |
| 424 } else { |
250 } else { |
| 425 const void *last = di == 0 ? NULL : invoke_list_func(at, list, di - 1); |
251 const void *last = di == 0 ? NULL : list->cl->at(list, di - 1); |
| 426 for (; si < n; si++) { |
252 for (; si < n; si++) { |
| 427 // skip duplicates within the source |
253 // skip duplicates within the source |
| 428 if (last == NULL || cmp(last, src) != 0) { |
254 if (last == NULL || cx_list_compare_wrapper(last, src, list) != 0) { |
| 429 if (NULL == invoke_list_func(insert_element, list, di, src)) { |
255 if (NULL == list->cl->insert_element(list, di, src)) { |
| 430 return processed; // LCOV_EXCL_LINE |
256 return processed; // LCOV_EXCL_LINE |
| 431 } |
257 } |
| 432 last = src; |
258 last = src; |
| 433 di++; |
259 di++; |
| 434 } |
260 } |
| 455 size_t n |
281 size_t n |
| 456 ) { |
282 ) { |
| 457 return cx_list_default_insert_sorted_impl(list, sorted_data, n, false); |
283 return cx_list_default_insert_sorted_impl(list, sorted_data, n, false); |
| 458 } |
284 } |
| 459 |
285 |
| |
286 // TODO: remove this hack once we have a solution for qsort() / qsort_s() |
| |
287 static _Thread_local CxList *cx_hack_for_qsort_list; |
| |
288 static int cx_hack_cmp_for_qsort(const void *l, const void *r) { |
| |
289 return cx_list_compare_wrapper(l, r, cx_hack_for_qsort_list); |
| |
290 } |
| |
291 |
| 460 void cx_list_default_sort(struct cx_list_s *list) { |
292 void cx_list_default_sort(struct cx_list_s *list) { |
| 461 size_t elem_size = list->collection.elem_size; |
293 size_t elem_size = list->collection.elem_size; |
| 462 size_t list_size = list->collection.size; |
294 size_t list_size = list->collection.size; |
| 463 void *tmp = cxMallocDefault(elem_size * list_size); |
295 void *tmp = cxMallocDefault(elem_size * list_size); |
| 464 if (tmp == NULL) abort(); // LCOV_EXCL_LINE |
296 if (tmp == NULL) abort(); // LCOV_EXCL_LINE |
| 465 |
297 |
| 466 // copy elements from source array |
298 // copy elements from source array |
| 467 char *loc = tmp; |
299 char *loc = tmp; |
| 468 for (size_t i = 0; i < list_size; i++) { |
300 for (size_t i = 0; i < list_size; i++) { |
| 469 void *src = invoke_list_func(at, list, i); |
301 void *src = list->cl->at(list, i); |
| 470 memcpy(loc, src, elem_size); |
302 memcpy(loc, src, elem_size); |
| 471 loc += elem_size; |
303 loc += elem_size; |
| 472 } |
304 } |
| 473 |
305 |
| 474 // qsort |
306 // qsort |
| 475 qsort(tmp, list_size, elem_size, |
307 // TODO: qsort_s() is not as nice as we thought |
| 476 list->collection.cmpfunc); |
308 cx_hack_for_qsort_list = list; |
| |
309 qsort(tmp, list_size, elem_size, cx_hack_cmp_for_qsort); |
| 477 |
310 |
| 478 // copy elements back |
311 // copy elements back |
| 479 loc = tmp; |
312 loc = tmp; |
| 480 for (size_t i = 0; i < list_size; i++) { |
313 for (size_t i = 0; i < list_size; i++) { |
| 481 void *dest = invoke_list_func(at, list, i); |
314 void *dest = list->cl->at(list, i); |
| 482 memcpy(dest, loc, elem_size); |
315 memcpy(dest, loc, elem_size); |
| 483 loc += elem_size; |
316 loc += elem_size; |
| 484 } |
317 } |
| 485 |
318 |
| 486 cxFreeDefault(tmp); |
319 cxFreeDefault(tmp); |
| 514 const struct cx_allocator_s *allocator, |
347 const struct cx_allocator_s *allocator, |
| 515 size_t elem_size |
348 size_t elem_size |
| 516 ) { |
349 ) { |
| 517 list->cl = cl; |
350 list->cl = cl; |
| 518 list->collection.allocator = allocator; |
351 list->collection.allocator = allocator; |
| 519 list->collection.cmpfunc = NULL; |
352 list->collection.size = 0; |
| |
353 list->collection.sorted = false; // should be set by the implementation |
| 520 if (elem_size > 0) { |
354 if (elem_size > 0) { |
| 521 list->collection.elem_size = elem_size; |
355 list->collection.elem_size = elem_size; |
| |
356 list->collection.simple_cmp = NULL; |
| |
357 list->collection.advanced_cmp = cx_acmp_memcmp; |
| |
358 list->collection.cmp_data = &list->collection.elem_size; |
| |
359 list->collection.store_pointer = false; |
| 522 } else { |
360 } else { |
| 523 list->collection.elem_size = sizeof(void *); |
361 list->collection.elem_size = sizeof(void *); |
| 524 if (list->collection.cmpfunc == NULL) { |
362 list->collection.simple_cmp = cx_cmp_ptr; |
| 525 list->collection.cmpfunc = cx_cmp_ptr; |
363 list->collection.advanced_cmp = NULL; |
| 526 } |
364 list->collection.cmp_data = NULL; |
| 527 list->collection.store_pointer = true; |
365 list->collection.store_pointer = true; |
| 528 list->climpl = list->cl; |
|
| 529 list->cl = &cx_pointer_list_class; |
|
| 530 } |
366 } |
| 531 } |
367 } |
| 532 |
368 |
| 533 int cxListCompare( |
369 int cxListCompare( |
| 534 const CxList *list, |
370 const CxList *list, |
| 535 const CxList *other |
371 const CxList *other |
| 536 ) { |
372 ) { |
| |
373 // check if we cannot use the list internal function |
| 537 bool cannot_optimize = false; |
374 bool cannot_optimize = false; |
| 538 |
375 |
| 539 // if one is storing pointers but the other is not |
376 // if one is storing pointers but the other is not |
| 540 cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer; |
377 cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer; |
| 541 |
378 |
| 542 // if one class is wrapped but the other is not |
379 // check if the lists are incompatible or this list does not implement compare |
| 543 cannot_optimize |= (list->climpl == NULL) ^ (other->climpl == NULL); |
380 cx_compare_func list_cmp = (cx_compare_func) list->cl->compare; |
| 544 |
381 cx_compare_func other_cmp = (cx_compare_func) other->cl->compare; |
| 545 // if the compare functions do not match or both are NULL |
382 cannot_optimize |= list_cmp != other_cmp; |
| 546 if (!cannot_optimize) { |
383 cannot_optimize |= list_cmp == NULL; |
| 547 cx_compare_func list_cmp = (cx_compare_func) (list->climpl != NULL ? |
|
| 548 list->climpl->compare : list->cl->compare); |
|
| 549 cx_compare_func other_cmp = (cx_compare_func) (other->climpl != NULL ? |
|
| 550 other->climpl->compare : other->cl->compare); |
|
| 551 cannot_optimize |= list_cmp != other_cmp; |
|
| 552 cannot_optimize |= list_cmp == NULL; |
|
| 553 } |
|
| 554 |
384 |
| 555 if (cannot_optimize) { |
385 if (cannot_optimize) { |
| 556 // lists are definitely different - cannot use internal compare function |
386 // lists are definitely different - cannot use internal compare function |
| 557 if (list->collection.size == other->collection.size) { |
387 if (list->collection.size == other->collection.size) { |
| 558 CxIterator left = list->cl->iterator(list, 0, false); |
388 CxIterator left = cxListIterator(list); |
| 559 CxIterator right = other->cl->iterator(other, 0, false); |
389 CxIterator right = cxListIterator(other); |
| 560 for (size_t i = 0; i < list->collection.size; i++) { |
390 for (size_t i = 0; i < list->collection.size; i++) { |
| 561 void *leftValue = cxIteratorCurrent(left); |
391 void *leftValue = cxIteratorCurrent(left); |
| 562 void *rightValue = cxIteratorCurrent(right); |
392 void *rightValue = cxIteratorCurrent(right); |
| 563 int d = list->collection.cmpfunc(leftValue, rightValue); |
393 // values are already unwrapped, invoke immediately |
| |
394 int d = cx_invoke_compare_func(list, leftValue, rightValue); |
| 564 if (d != 0) { |
395 if (d != 0) { |
| 565 return d; |
396 return d; |
| 566 } |
397 } |
| 567 cxIteratorNext(left); |
398 cxIteratorNext(left); |
| 568 cxIteratorNext(right); |
399 cxIteratorNext(right); |
| 581 return list->collection.size; |
412 return list->collection.size; |
| 582 } |
413 } |
| 583 |
414 |
| 584 int cxListAdd(CxList *list, const void *elem) { |
415 int cxListAdd(CxList *list, const void *elem) { |
| 585 list->collection.sorted = false; |
416 list->collection.sorted = false; |
| 586 return list->cl->insert_element(list, list->collection.size, elem) == NULL; |
417 return list->cl->insert_element(list, list->collection.size, cx_ref(list, elem)) == NULL; |
| 587 } |
418 } |
| 588 |
419 |
| 589 size_t cxListAddArray(CxList *list, const void *array, size_t n) { |
420 size_t cxListAddArray(CxList *list, const void *array, size_t n) { |
| 590 list->collection.sorted = false; |
421 list->collection.sorted = false; |
| 591 return list->cl->insert_array(list, list->collection.size, array, n); |
422 return list->cl->insert_array(list, list->collection.size, array, n); |
| 592 } |
423 } |
| 593 |
424 |
| 594 int cxListInsert(CxList *list, size_t index, const void *elem) { |
425 int cxListInsert(CxList *list, size_t index, const void *elem) { |
| 595 list->collection.sorted = false; |
426 list->collection.sorted = false; |
| 596 return list->cl->insert_element(list, index, elem) == NULL; |
427 return list->cl->insert_element(list, index, cx_ref(list, elem)) == NULL; |
| 597 } |
428 } |
| 598 |
429 |
| 599 void *cxListEmplaceAt(CxList *list, size_t index) { |
430 void *cxListEmplaceAt(CxList *list, size_t index) { |
| 600 list->collection.sorted = false; |
431 list->collection.sorted = false; |
| 601 return list->cl->insert_element(list, index, NULL); |
432 return list->cl->insert_element(list, index, NULL); |
| 618 // tweak the fields of this iterator |
449 // tweak the fields of this iterator |
| 619 iter.elem_count = c; |
450 iter.elem_count = c; |
| 620 iter.index = 0; |
451 iter.index = 0; |
| 621 // replace the valid function to abort iteration when c is reached |
452 // replace the valid function to abort iteration when c is reached |
| 622 iter.base.valid = cx_list_emplace_iterator_valid; |
453 iter.base.valid = cx_list_emplace_iterator_valid; |
| 623 // if we are storing pointers, we want to return the pure pointers. |
|
| 624 // therefore, we must unwrap the "current" method |
|
| 625 if (list->collection.store_pointer) { |
|
| 626 iter.base.current = iter.base.current_impl; |
|
| 627 } |
|
| 628 return iter; |
454 return iter; |
| 629 } |
455 } |
| 630 |
456 |
| 631 CxIterator cxListEmplaceArray(CxList *list, size_t n) { |
457 CxIterator cxListEmplaceArray(CxList *list, size_t n) { |
| 632 return cxListEmplaceArrayAt(list, list->collection.size, n); |
458 return cxListEmplaceArrayAt(list, list->collection.size, n); |
| 633 } |
459 } |
| 634 |
460 |
| 635 int cxListInsertSorted(CxList *list, const void *elem) { |
461 int cxListInsertSorted(CxList *list, const void *elem) { |
| 636 assert(cxCollectionSorted(list)); |
462 assert(cxCollectionSorted(list)); |
| 637 list->collection.sorted = true; |
463 list->collection.sorted = true; |
| 638 const void *data = list->collection.store_pointer ? &elem : elem; |
464 return list->cl->insert_sorted(list, cx_ref(list, elem), 1) == 0; |
| 639 return list->cl->insert_sorted(list, data, 1) == 0; |
|
| 640 } |
465 } |
| 641 |
466 |
| 642 int cxListInsertUnique(CxList *list, const void *elem) { |
467 int cxListInsertUnique(CxList *list, const void *elem) { |
| 643 if (cxCollectionSorted(list)) { |
468 if (cxCollectionSorted(list)) { |
| 644 list->collection.sorted = true; |
469 list->collection.sorted = true; |
| 645 const void *data = list->collection.store_pointer ? &elem : elem; |
470 return list->cl->insert_unique(list, cx_ref(list, elem), 1) == 0; |
| 646 return list->cl->insert_unique(list, data, 1) == 0; |
|
| 647 } else { |
471 } else { |
| 648 if (cxListContains(list, elem)) { |
472 if (cxListContains(list, elem)) { |
| 649 return 0; |
473 return 0; |
| 650 } else { |
474 } else { |
| 651 return cxListAdd(list, elem); |
475 return cxListAdd(list, elem); |
| 684 return n; |
507 return n; |
| 685 } |
508 } |
| 686 } |
509 } |
| 687 |
510 |
| 688 int cxListInsertAfter(CxIterator *iter, const void *elem) { |
511 int cxListInsertAfter(CxIterator *iter, const void *elem) { |
| 689 CxList* list = (CxList*)iter->src_handle; |
512 CxList* list = iter->src_handle; |
| 690 list->collection.sorted = false; |
513 list->collection.sorted = false; |
| 691 return list->cl->insert_iter(iter, elem, 0); |
514 return list->cl->insert_iter(iter, cx_ref(list, elem), 0); |
| 692 } |
515 } |
| 693 |
516 |
| 694 int cxListInsertBefore(CxIterator *iter, const void *elem) { |
517 int cxListInsertBefore(CxIterator *iter, const void *elem) { |
| 695 CxList* list = (CxList*)iter->src_handle; |
518 CxList* list = iter->src_handle; |
| 696 list->collection.sorted = false; |
519 list->collection.sorted = false; |
| 697 return list->cl->insert_iter(iter, elem, 1); |
520 return list->cl->insert_iter(iter, cx_ref(list, elem), 1); |
| 698 } |
521 } |
| 699 |
522 |
| 700 int cxListRemove(CxList *list, size_t index) { |
523 int cxListRemove(CxList *list, size_t index) { |
| 701 return list->cl->remove(list, index, 1, NULL) == 0; |
524 return list->cl->remove(list, index, 1, NULL) == 0; |
| 702 } |
525 } |
| 731 list->collection.sorted = false; |
554 list->collection.sorted = false; |
| 732 return list->cl->swap(list, i, j); |
555 return list->cl->swap(list, i, j); |
| 733 } |
556 } |
| 734 |
557 |
| 735 void *cxListAt(const CxList *list, size_t index) { |
558 void *cxListAt(const CxList *list, size_t index) { |
| 736 return list->cl->at(list, index); |
559 void *result = list->cl->at(list, index); |
| |
560 if (result == NULL) return NULL; |
| |
561 return cx_deref(list, result); |
| 737 } |
562 } |
| 738 |
563 |
| 739 void *cxListFirst(const CxList *list) { |
564 void *cxListFirst(const CxList *list) { |
| 740 return list->cl->at(list, 0); |
565 return cxListAt(list, 0); |
| 741 } |
566 } |
| 742 |
567 |
| 743 void *cxListLast(const CxList *list) { |
568 void *cxListLast(const CxList *list) { |
| 744 return list->cl->at(list, list->collection.size - 1); |
569 return cxListAt(list, list->collection.size - 1); |
| 745 } |
570 } |
| 746 |
571 |
| 747 int cxListSet(CxList *list, size_t index, const void *elem) { |
572 int cxListSet(CxList *list, size_t index, const void *elem) { |
| 748 if (index >= list->collection.size) { |
573 if (index >= list->collection.size) { |
| 749 return 1; |
574 return 1; |
| 750 } |
575 } |
| 751 |
576 |
| 752 if (list->collection.store_pointer) { |
577 if (list->collection.store_pointer) { |
| 753 // For pointer collections, always use climpl |
578 void **target = list->cl->at(list, index); |
| 754 void **target = list->climpl->at(list, index); |
|
| 755 *target = (void *)elem; |
579 *target = (void *)elem; |
| 756 } else { |
580 } else { |
| 757 void *target = list->cl->at(list, index); |
581 void *target = list->cl->at(list, index); |
| 758 memcpy(target, elem, list->collection.elem_size); |
582 memcpy(target, elem, list->collection.elem_size); |
| 759 } |
583 } |
| 760 |
584 |
| 761 return 0; |
585 return 0; |
| 762 } |
586 } |
| 763 |
587 |
| |
588 static void *cx_pl_iter_current(const void *it) { |
| |
589 const struct cx_iterator_s *iter = it; |
| |
590 void **ptr = iter->base.current_impl(it); |
| |
591 return ptr == NULL ? NULL : *ptr; |
| |
592 } |
| |
593 |
| |
594 CX_INLINE CxIterator cx_pl_iter_wrap(const CxList *list, CxIterator iter) { |
| |
595 if (cxCollectionStoresPointers(list)) { |
| |
596 iter.base.current_impl = iter.base.current; |
| |
597 iter.base.current = cx_pl_iter_current; |
| |
598 return iter; |
| |
599 } else { |
| |
600 return iter; |
| |
601 } |
| |
602 } |
| |
603 |
| 764 CxIterator cxListIteratorAt(const CxList *list, size_t index) { |
604 CxIterator cxListIteratorAt(const CxList *list, size_t index) { |
| 765 if (list == NULL) list = cxEmptyList; |
605 if (list == NULL) list = cxEmptyList; |
| 766 return list->cl->iterator(list, index, false); |
606 return cx_pl_iter_wrap(list, list->cl->iterator(list, index, false)); |
| 767 } |
607 } |
| 768 |
608 |
| 769 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) { |
609 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) { |
| 770 if (list == NULL) list = cxEmptyList; |
610 if (list == NULL) list = cxEmptyList; |
| 771 return list->cl->iterator(list, index, true); |
611 return cx_pl_iter_wrap(list, list->cl->iterator(list, index, true)); |
| 772 } |
612 } |
| 773 |
613 |
| 774 CxIterator cxListIterator(const CxList *list) { |
614 CxIterator cxListIterator(const CxList *list) { |
| 775 if (list == NULL) list = cxEmptyList; |
615 if (list == NULL) list = cxEmptyList; |
| 776 return list->cl->iterator(list, 0, false); |
616 return cx_pl_iter_wrap(list, list->cl->iterator(list, 0, false)); |
| 777 } |
617 } |
| 778 |
618 |
| 779 CxIterator cxListBackwardsIterator(const CxList *list) { |
619 CxIterator cxListBackwardsIterator(const CxList *list) { |
| 780 if (list == NULL) list = cxEmptyList; |
620 if (list == NULL) list = cxEmptyList; |
| 781 return list->cl->iterator(list, list->collection.size - 1, true); |
621 return cx_pl_iter_wrap(list, list->cl->iterator(list, list->collection.size - 1, true)); |
| 782 } |
622 } |
| 783 |
623 |
| 784 size_t cxListFind(const CxList *list, const void *elem) { |
624 size_t cxListFind(const CxList *list, const void *elem) { |
| 785 return list->cl->find_remove((CxList*)list, elem, false); |
625 return list->cl->find_remove((CxList*)list, cx_ref(list, elem), false); |
| 786 } |
626 } |
| 787 |
627 |
| 788 bool cxListContains(const CxList* list, const void* elem) { |
628 bool cxListContains(const CxList* list, const void* elem) { |
| 789 return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size; |
629 return list->cl->find_remove((CxList*)list, cx_ref(list, elem), false) < list->collection.size; |
| 790 } |
630 } |
| 791 |
631 |
| 792 bool cxListIndexValid(const CxList *list, size_t index) { |
632 bool cxListIndexValid(const CxList *list, size_t index) { |
| 793 return index < list->collection.size; |
633 return index < list->collection.size; |
| 794 } |
634 } |
| 795 |
635 |
| 796 size_t cxListFindRemove(CxList *list, const void *elem) { |
636 size_t cxListFindRemove(CxList *list, const void *elem) { |
| 797 return list->cl->find_remove(list, elem, true); |
637 return list->cl->find_remove(list, cx_ref(list, elem), true); |
| 798 } |
638 } |
| 799 |
639 |
| 800 void cxListSort(CxList *list) { |
640 void cxListSort(CxList *list) { |
| 801 if (list->collection.sorted) return; |
641 if (list->collection.sorted) return; |
| 802 list->cl->sort(list); |
642 list->cl->sort(list); |
| 968 CxIterator src_iter = cxListIterator(src); |
807 CxIterator src_iter = cxListIterator(src); |
| 969 CxIterator other_iter = cxListIterator(other); |
808 CxIterator other_iter = cxListIterator(other); |
| 970 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) { |
809 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) { |
| 971 void *src_elem = cxIteratorCurrent(src_iter); |
810 void *src_elem = cxIteratorCurrent(src_iter); |
| 972 void *other_elem = cxIteratorCurrent(other_iter); |
811 void *other_elem = cxIteratorCurrent(other_iter); |
| 973 int d = src->collection.cmpfunc(src_elem, other_elem); |
812 int d = cx_list_compare_wrapper(src_elem, other_elem, src); |
| 974 if (d == 0) { |
813 if (d == 0) { |
| 975 // is contained, clone it |
814 // is contained, clone it |
| 976 void **dst_mem = cxListEmplace(dst); |
815 void **dst_mem = cxListEmplace(dst); |
| 977 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
816 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
| 978 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data); |
817 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data); |