| 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); |
| 510 |
343 |
| 511 void cx_list_init( |
344 void cx_list_init( |
| 512 struct cx_list_s *list, |
345 struct cx_list_s *list, |
| 513 struct cx_list_class_s *cl, |
346 struct cx_list_class_s *cl, |
| 514 const struct cx_allocator_s *allocator, |
347 const struct cx_allocator_s *allocator, |
| 515 cx_compare_func comparator, |
|
| 516 size_t elem_size |
348 size_t elem_size |
| 517 ) { |
349 ) { |
| 518 list->cl = cl; |
350 list->cl = cl; |
| 519 list->collection.allocator = allocator; |
351 list->collection.allocator = allocator; |
| 520 list->collection.cmpfunc = comparator; |
352 list->collection.size = 0; |
| |
353 list->collection.sorted = false; // should be set by the implementation |
| 521 if (elem_size > 0) { |
354 if (elem_size > 0) { |
| 522 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; |
| 523 } else { |
360 } else { |
| 524 list->collection.elem_size = sizeof(void *); |
361 list->collection.elem_size = sizeof(void *); |
| 525 if (list->collection.cmpfunc == NULL) { |
362 list->collection.simple_cmp = cx_cmp_ptr; |
| 526 list->collection.cmpfunc = cx_cmp_ptr; |
363 list->collection.advanced_cmp = NULL; |
| 527 } |
364 list->collection.cmp_data = NULL; |
| 528 list->collection.store_pointer = true; |
365 list->collection.store_pointer = true; |
| 529 list->climpl = list->cl; |
|
| 530 list->cl = &cx_pointer_list_class; |
|
| 531 } |
366 } |
| 532 } |
367 } |
| 533 |
368 |
| 534 int cxListCompare( |
369 int cxListCompare( |
| 535 const CxList *list, |
370 const CxList *list, |
| 536 const CxList *other |
371 const CxList *other |
| 537 ) { |
372 ) { |
| |
373 // check if we cannot use the list internal function |
| 538 bool cannot_optimize = false; |
374 bool cannot_optimize = false; |
| 539 |
375 |
| 540 // if one is storing pointers but the other is not |
376 // if one is storing pointers but the other is not |
| 541 cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer; |
377 cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer; |
| 542 |
378 |
| 543 // if one class is wrapped but the other is not |
379 // check if the lists are incompatible or this list does not implement compare |
| 544 cannot_optimize |= (list->climpl == NULL) ^ (other->climpl == NULL); |
380 cx_compare_func list_cmp = (cx_compare_func) list->cl->compare; |
| 545 |
381 cx_compare_func other_cmp = (cx_compare_func) other->cl->compare; |
| 546 // if the compare functions do not match or both are NULL |
382 cannot_optimize |= list_cmp != other_cmp; |
| 547 if (!cannot_optimize) { |
383 cannot_optimize |= list_cmp == NULL; |
| 548 cx_compare_func list_cmp = (cx_compare_func) (list->climpl != NULL ? |
|
| 549 list->climpl->compare : list->cl->compare); |
|
| 550 cx_compare_func other_cmp = (cx_compare_func) (other->climpl != NULL ? |
|
| 551 other->climpl->compare : other->cl->compare); |
|
| 552 cannot_optimize |= list_cmp != other_cmp; |
|
| 553 cannot_optimize |= list_cmp == NULL; |
|
| 554 } |
|
| 555 |
384 |
| 556 if (cannot_optimize) { |
385 if (cannot_optimize) { |
| 557 // lists are definitely different - cannot use internal compare function |
386 // lists are definitely different - cannot use internal compare function |
| 558 if (list->collection.size == other->collection.size) { |
387 if (list->collection.size == other->collection.size) { |
| 559 CxIterator left = list->cl->iterator(list, 0, false); |
388 CxIterator left = cxListIterator(list); |
| 560 CxIterator right = other->cl->iterator(other, 0, false); |
389 CxIterator right = cxListIterator(other); |
| 561 for (size_t i = 0; i < list->collection.size; i++) { |
390 for (size_t i = 0; i < list->collection.size; i++) { |
| 562 void *leftValue = cxIteratorCurrent(left); |
391 void *leftValue = cxIteratorCurrent(left); |
| 563 void *rightValue = cxIteratorCurrent(right); |
392 void *rightValue = cxIteratorCurrent(right); |
| 564 int d = list->collection.cmpfunc(leftValue, rightValue); |
393 // values are already unwrapped, invoke immediately |
| |
394 int d = cx_invoke_compare_func(list, leftValue, rightValue); |
| 565 if (d != 0) { |
395 if (d != 0) { |
| 566 return d; |
396 return d; |
| 567 } |
397 } |
| 568 cxIteratorNext(left); |
398 cxIteratorNext(left); |
| 569 cxIteratorNext(right); |
399 cxIteratorNext(right); |
| 582 return list->collection.size; |
412 return list->collection.size; |
| 583 } |
413 } |
| 584 |
414 |
| 585 int cxListAdd(CxList *list, const void *elem) { |
415 int cxListAdd(CxList *list, const void *elem) { |
| 586 list->collection.sorted = false; |
416 list->collection.sorted = false; |
| 587 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; |
| 588 } |
418 } |
| 589 |
419 |
| 590 size_t cxListAddArray(CxList *list, const void *array, size_t n) { |
420 size_t cxListAddArray(CxList *list, const void *array, size_t n) { |
| 591 list->collection.sorted = false; |
421 list->collection.sorted = false; |
| 592 return list->cl->insert_array(list, list->collection.size, array, n); |
422 return list->cl->insert_array(list, list->collection.size, array, n); |
| 593 } |
423 } |
| 594 |
424 |
| 595 int cxListInsert(CxList *list, size_t index, const void *elem) { |
425 int cxListInsert(CxList *list, size_t index, const void *elem) { |
| 596 list->collection.sorted = false; |
426 list->collection.sorted = false; |
| 597 return list->cl->insert_element(list, index, elem) == NULL; |
427 return list->cl->insert_element(list, index, cx_ref(list, elem)) == NULL; |
| 598 } |
428 } |
| 599 |
429 |
| 600 void *cxListEmplaceAt(CxList *list, size_t index) { |
430 void *cxListEmplaceAt(CxList *list, size_t index) { |
| 601 list->collection.sorted = false; |
431 list->collection.sorted = false; |
| 602 return list->cl->insert_element(list, index, NULL); |
432 return list->cl->insert_element(list, index, NULL); |
| 619 // tweak the fields of this iterator |
449 // tweak the fields of this iterator |
| 620 iter.elem_count = c; |
450 iter.elem_count = c; |
| 621 iter.index = 0; |
451 iter.index = 0; |
| 622 // replace the valid function to abort iteration when c is reached |
452 // replace the valid function to abort iteration when c is reached |
| 623 iter.base.valid = cx_list_emplace_iterator_valid; |
453 iter.base.valid = cx_list_emplace_iterator_valid; |
| 624 // if we are storing pointers, we want to return the pure pointers. |
|
| 625 // therefore, we must unwrap the "current" method |
|
| 626 if (list->collection.store_pointer) { |
|
| 627 iter.base.current = iter.base.current_impl; |
|
| 628 } |
|
| 629 return iter; |
454 return iter; |
| 630 } |
455 } |
| 631 |
456 |
| 632 CxIterator cxListEmplaceArray(CxList *list, size_t n) { |
457 CxIterator cxListEmplaceArray(CxList *list, size_t n) { |
| 633 return cxListEmplaceArrayAt(list, list->collection.size, n); |
458 return cxListEmplaceArrayAt(list, list->collection.size, n); |
| 634 } |
459 } |
| 635 |
460 |
| 636 int cxListInsertSorted(CxList *list, const void *elem) { |
461 int cxListInsertSorted(CxList *list, const void *elem) { |
| 637 assert(cxCollectionSorted(list)); |
462 assert(cxCollectionSorted(list)); |
| 638 list->collection.sorted = true; |
463 list->collection.sorted = true; |
| 639 const void *data = list->collection.store_pointer ? &elem : elem; |
464 return list->cl->insert_sorted(list, cx_ref(list, elem), 1) == 0; |
| 640 return list->cl->insert_sorted(list, data, 1) == 0; |
|
| 641 } |
465 } |
| 642 |
466 |
| 643 int cxListInsertUnique(CxList *list, const void *elem) { |
467 int cxListInsertUnique(CxList *list, const void *elem) { |
| 644 if (cxCollectionSorted(list)) { |
468 if (cxCollectionSorted(list)) { |
| 645 list->collection.sorted = true; |
469 list->collection.sorted = true; |
| 646 const void *data = list->collection.store_pointer ? &elem : elem; |
470 return list->cl->insert_unique(list, cx_ref(list, elem), 1) == 0; |
| 647 return list->cl->insert_unique(list, data, 1) == 0; |
|
| 648 } else { |
471 } else { |
| 649 if (cxListContains(list, elem)) { |
472 if (cxListContains(list, elem)) { |
| 650 return 0; |
473 return 0; |
| 651 } else { |
474 } else { |
| 652 return cxListAdd(list, elem); |
475 return cxListAdd(list, elem); |
| 685 return n; |
507 return n; |
| 686 } |
508 } |
| 687 } |
509 } |
| 688 |
510 |
| 689 int cxListInsertAfter(CxIterator *iter, const void *elem) { |
511 int cxListInsertAfter(CxIterator *iter, const void *elem) { |
| 690 CxList* list = (CxList*)iter->src_handle; |
512 CxList* list = iter->src_handle; |
| 691 list->collection.sorted = false; |
513 list->collection.sorted = false; |
| 692 return list->cl->insert_iter(iter, elem, 0); |
514 return list->cl->insert_iter(iter, cx_ref(list, elem), 0); |
| 693 } |
515 } |
| 694 |
516 |
| 695 int cxListInsertBefore(CxIterator *iter, const void *elem) { |
517 int cxListInsertBefore(CxIterator *iter, const void *elem) { |
| 696 CxList* list = (CxList*)iter->src_handle; |
518 CxList* list = iter->src_handle; |
| 697 list->collection.sorted = false; |
519 list->collection.sorted = false; |
| 698 return list->cl->insert_iter(iter, elem, 1); |
520 return list->cl->insert_iter(iter, cx_ref(list, elem), 1); |
| 699 } |
521 } |
| 700 |
522 |
| 701 int cxListRemove(CxList *list, size_t index) { |
523 int cxListRemove(CxList *list, size_t index) { |
| 702 return list->cl->remove(list, index, 1, NULL) == 0; |
524 return list->cl->remove(list, index, 1, NULL) == 0; |
| 703 } |
525 } |
| 732 list->collection.sorted = false; |
554 list->collection.sorted = false; |
| 733 return list->cl->swap(list, i, j); |
555 return list->cl->swap(list, i, j); |
| 734 } |
556 } |
| 735 |
557 |
| 736 void *cxListAt(const CxList *list, size_t index) { |
558 void *cxListAt(const CxList *list, size_t index) { |
| 737 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); |
| 738 } |
562 } |
| 739 |
563 |
| 740 void *cxListFirst(const CxList *list) { |
564 void *cxListFirst(const CxList *list) { |
| 741 return list->cl->at(list, 0); |
565 return cxListAt(list, 0); |
| 742 } |
566 } |
| 743 |
567 |
| 744 void *cxListLast(const CxList *list) { |
568 void *cxListLast(const CxList *list) { |
| 745 return list->cl->at(list, list->collection.size - 1); |
569 return cxListAt(list, list->collection.size - 1); |
| 746 } |
570 } |
| 747 |
571 |
| 748 int cxListSet(CxList *list, size_t index, const void *elem) { |
572 int cxListSet(CxList *list, size_t index, const void *elem) { |
| 749 if (index >= list->collection.size) { |
573 if (index >= list->collection.size) { |
| 750 return 1; |
574 return 1; |
| 751 } |
575 } |
| 752 |
576 |
| 753 if (list->collection.store_pointer) { |
577 if (list->collection.store_pointer) { |
| 754 // For pointer collections, always use climpl |
578 void **target = list->cl->at(list, index); |
| 755 void **target = list->climpl->at(list, index); |
|
| 756 *target = (void *)elem; |
579 *target = (void *)elem; |
| 757 } else { |
580 } else { |
| 758 void *target = list->cl->at(list, index); |
581 void *target = list->cl->at(list, index); |
| 759 memcpy(target, elem, list->collection.elem_size); |
582 memcpy(target, elem, list->collection.elem_size); |
| 760 } |
583 } |
| 761 |
584 |
| 762 return 0; |
585 return 0; |
| 763 } |
586 } |
| 764 |
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 |
| 765 CxIterator cxListIteratorAt(const CxList *list, size_t index) { |
604 CxIterator cxListIteratorAt(const CxList *list, size_t index) { |
| 766 if (list == NULL) list = cxEmptyList; |
605 if (list == NULL) list = cxEmptyList; |
| 767 return list->cl->iterator(list, index, false); |
606 return cx_pl_iter_wrap(list, list->cl->iterator(list, index, false)); |
| 768 } |
607 } |
| 769 |
608 |
| 770 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) { |
609 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) { |
| 771 if (list == NULL) list = cxEmptyList; |
610 if (list == NULL) list = cxEmptyList; |
| 772 return list->cl->iterator(list, index, true); |
611 return cx_pl_iter_wrap(list, list->cl->iterator(list, index, true)); |
| 773 } |
612 } |
| 774 |
613 |
| 775 CxIterator cxListIterator(const CxList *list) { |
614 CxIterator cxListIterator(const CxList *list) { |
| 776 if (list == NULL) list = cxEmptyList; |
615 if (list == NULL) list = cxEmptyList; |
| 777 return list->cl->iterator(list, 0, false); |
616 return cx_pl_iter_wrap(list, list->cl->iterator(list, 0, false)); |
| 778 } |
617 } |
| 779 |
618 |
| 780 CxIterator cxListBackwardsIterator(const CxList *list) { |
619 CxIterator cxListBackwardsIterator(const CxList *list) { |
| 781 if (list == NULL) list = cxEmptyList; |
620 if (list == NULL) list = cxEmptyList; |
| 782 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)); |
| 783 } |
622 } |
| 784 |
623 |
| 785 size_t cxListFind(const CxList *list, const void *elem) { |
624 size_t cxListFind(const CxList *list, const void *elem) { |
| 786 return list->cl->find_remove((CxList*)list, elem, false); |
625 return list->cl->find_remove((CxList*)list, cx_ref(list, elem), false); |
| 787 } |
626 } |
| 788 |
627 |
| 789 bool cxListContains(const CxList* list, const void* elem) { |
628 bool cxListContains(const CxList* list, const void* elem) { |
| 790 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; |
| 791 } |
630 } |
| 792 |
631 |
| 793 bool cxListIndexValid(const CxList *list, size_t index) { |
632 bool cxListIndexValid(const CxList *list, size_t index) { |
| 794 return index < list->collection.size; |
633 return index < list->collection.size; |
| 795 } |
634 } |
| 796 |
635 |
| 797 size_t cxListFindRemove(CxList *list, const void *elem) { |
636 size_t cxListFindRemove(CxList *list, const void *elem) { |
| 798 return list->cl->find_remove(list, elem, true); |
637 return list->cl->find_remove(list, cx_ref(list, elem), true); |
| 799 } |
638 } |
| 800 |
639 |
| 801 void cxListSort(CxList *list) { |
640 void cxListSort(CxList *list) { |
| 802 if (list->collection.sorted) return; |
641 if (list->collection.sorted) return; |
| 803 list->cl->sort(list); |
642 list->cl->sort(list); |
| 827 } |
666 } |
| 828 list->collection.simple_destructor = destr_bak; |
667 list->collection.simple_destructor = destr_bak; |
| 829 list->collection.advanced_destructor = destr2_bak; |
668 list->collection.advanced_destructor = destr2_bak; |
| 830 } |
669 } |
| 831 |
670 |
| 832 static void* cx_list_simple_clone_func(void *dst, const void *src, const CxAllocator *al, void *data) { |
671 static void* cx_list_shallow_clone_func(void *dst, const void *src, const CxAllocator *al, void *data) { |
| 833 size_t elem_size = *(size_t*)data; |
672 size_t elem_size = *(size_t*)data; |
| 834 if (dst == NULL) dst = cxMalloc(al, elem_size); |
673 if (dst == NULL) dst = cxMalloc(al, elem_size); |
| 835 if (dst != NULL) memcpy(dst, src, elem_size); |
674 if (dst != NULL) memcpy(dst, src, elem_size); |
| 836 return dst; |
675 return dst; |
| 837 } |
676 } |
| 838 |
677 |
| 839 #define use_simple_clone_func(list) cx_list_simple_clone_func, NULL, (void*)&((list)->collection.elem_size) |
678 #define use_shallow_clone_func(list) cx_list_shallow_clone_func, NULL, (void*)&((list)->collection.elem_size) |
| 840 |
679 |
| 841 int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func, |
680 int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func, |
| 842 const CxAllocator *clone_allocator, void *data) { |
681 const CxAllocator *clone_allocator, void *data) { |
| 843 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; |
682 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; |
| 844 |
683 |
| 969 CxIterator src_iter = cxListIterator(src); |
807 CxIterator src_iter = cxListIterator(src); |
| 970 CxIterator other_iter = cxListIterator(other); |
808 CxIterator other_iter = cxListIterator(other); |
| 971 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) { |
809 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) { |
| 972 void *src_elem = cxIteratorCurrent(src_iter); |
810 void *src_elem = cxIteratorCurrent(src_iter); |
| 973 void *other_elem = cxIteratorCurrent(other_iter); |
811 void *other_elem = cxIteratorCurrent(other_iter); |
| 974 int d = src->collection.cmpfunc(src_elem, other_elem); |
812 int d = cx_list_compare_wrapper(src_elem, other_elem, src); |
| 975 if (d == 0) { |
813 if (d == 0) { |
| 976 // is contained, clone it |
814 // is contained, clone it |
| 977 void **dst_mem = cxListEmplace(dst); |
815 void **dst_mem = cxListEmplace(dst); |
| 978 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
816 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
| 979 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data); |
817 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data); |
| 1095 } |
933 } |
| 1096 |
934 |
| 1097 return 0; |
935 return 0; |
| 1098 } |
936 } |
| 1099 |
937 |
| 1100 int cxListCloneSimple(CxList *dst, const CxList *src) { |
938 int cxListCloneShallow(CxList *dst, const CxList *src) { |
| 1101 return cxListClone(dst, src, use_simple_clone_func(src)); |
939 return cxListClone(dst, src, use_shallow_clone_func(src)); |
| 1102 } |
940 } |
| 1103 |
941 |
| 1104 int cxListDifferenceSimple(CxList *dst, const CxList *minuend, const CxList *subtrahend) { |
942 int cxListDifferenceShallow(CxList *dst, const CxList *minuend, const CxList *subtrahend) { |
| 1105 return cxListDifference(dst, minuend, subtrahend, use_simple_clone_func(minuend)); |
943 return cxListDifference(dst, minuend, subtrahend, use_shallow_clone_func(minuend)); |
| 1106 } |
944 } |
| 1107 |
945 |
| 1108 int cxListIntersectionSimple(CxList *dst, const CxList *src, const CxList *other) { |
946 int cxListIntersectionShallow(CxList *dst, const CxList *src, const CxList *other) { |
| 1109 return cxListIntersection(dst, src, other, use_simple_clone_func(src)); |
947 return cxListIntersection(dst, src, other, use_shallow_clone_func(src)); |
| 1110 } |
948 } |
| 1111 |
949 |
| 1112 int cxListUnionSimple(CxList *dst, const CxList *src, const CxList *other) { |
950 int cxListUnionShallow(CxList *dst, const CxList *src, const CxList *other) { |
| 1113 return cxListUnion(dst, src, other, use_simple_clone_func(src)); |
951 return cxListUnion(dst, src, other, use_shallow_clone_func(src)); |
| 1114 } |
952 } |
| 1115 |
953 |
| 1116 int cxListReserve(CxList *list, size_t capacity) { |
954 int cxListReserve(CxList *list, size_t capacity) { |
| 1117 if (list->cl->change_capacity == NULL) { |
955 if (list->cl->change_capacity == NULL) { |
| 1118 return 0; |
956 return 0; |