| 33 // <editor-fold desc="Store Pointers Functionality"> |
33 // <editor-fold desc="Store Pointers Functionality"> |
| 34 |
34 |
| 35 static _Thread_local cx_compare_func cx_pl_cmpfunc_impl; |
35 static _Thread_local cx_compare_func cx_pl_cmpfunc_impl; |
| 36 |
36 |
| 37 static int cx_pl_cmpfunc( |
37 static int cx_pl_cmpfunc( |
| 38 void const *l, |
38 const void *l, |
| 39 void const *r |
39 const void *r |
| 40 ) { |
40 ) { |
| 41 void *const *lptr = l; |
41 void *const *lptr = l; |
| 42 void *const *rptr = r; |
42 void *const *rptr = r; |
| 43 void const *left = lptr == NULL ? NULL : *lptr; |
43 const void *left = lptr == NULL ? NULL : *lptr; |
| 44 void const *right = rptr == NULL ? NULL : *rptr; |
44 const void *right = rptr == NULL ? NULL : *rptr; |
| 45 return cx_pl_cmpfunc_impl(left, right); |
45 return cx_pl_cmpfunc_impl(left, right); |
| 46 } |
46 } |
| 47 |
47 |
| 48 static void cx_pl_hack_cmpfunc(struct cx_list_s const *list) { |
48 static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) { |
| 49 // cast away const - this is the hacky thing |
49 // cast away const - this is the hacky thing |
| 50 struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; |
50 struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; |
| 51 cx_pl_cmpfunc_impl = l->cmpfunc; |
51 cx_pl_cmpfunc_impl = l->cmpfunc; |
| 52 l->cmpfunc = cx_pl_cmpfunc; |
52 l->cmpfunc = cx_pl_cmpfunc; |
| 53 } |
53 } |
| 54 |
54 |
| 55 static void cx_pl_unhack_cmpfunc(struct cx_list_s const *list) { |
55 static void cx_pl_unhack_cmpfunc(const struct cx_list_s *list) { |
| 56 // cast away const - this is the hacky thing |
56 // cast away const - this is the hacky thing |
| 57 struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; |
57 struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; |
| 58 l->cmpfunc = cx_pl_cmpfunc_impl; |
58 l->cmpfunc = cx_pl_cmpfunc_impl; |
| 59 } |
59 } |
| 60 |
60 |
| 61 static void cx_pl_destructor(struct cx_list_s *list) { |
61 static void cx_pl_destructor(struct cx_list_s *list) { |
| 62 list->climpl->destructor(list); |
62 list->climpl->deallocate(list); |
| 63 } |
63 } |
| 64 |
64 |
| 65 static int cx_pl_insert_element( |
65 static int cx_pl_insert_element( |
| 66 struct cx_list_s *list, |
66 struct cx_list_s *list, |
| 67 size_t index, |
67 size_t index, |
| 68 void const *element |
68 const void *element |
| 69 ) { |
69 ) { |
| 70 return list->climpl->insert_element(list, index, &element); |
70 return list->climpl->insert_element(list, index, &element); |
| 71 } |
71 } |
| 72 |
72 |
| 73 static size_t cx_pl_insert_array( |
73 static size_t cx_pl_insert_array( |
| 74 struct cx_list_s *list, |
74 struct cx_list_s *list, |
| 75 size_t index, |
75 size_t index, |
| 76 void const *array, |
76 const void *array, |
| 77 size_t n |
77 size_t n |
| 78 ) { |
78 ) { |
| 79 return list->climpl->insert_array(list, index, array, n); |
79 return list->climpl->insert_array(list, index, array, n); |
| |
80 } |
| |
81 |
| |
82 static size_t cx_pl_insert_sorted( |
| |
83 struct cx_list_s *list, |
| |
84 const void *array, |
| |
85 size_t n |
| |
86 ) { |
| |
87 cx_pl_hack_cmpfunc(list); |
| |
88 size_t result = list->climpl->insert_sorted(list, array, n); |
| |
89 cx_pl_unhack_cmpfunc(list); |
| |
90 return result; |
| 80 } |
91 } |
| 81 |
92 |
| 82 static int cx_pl_insert_iter( |
93 static int cx_pl_insert_iter( |
| 83 struct cx_iterator_s *iter, |
94 struct cx_iterator_s *iter, |
| 84 void const *elem, |
95 const void *elem, |
| 85 int prepend |
96 int prepend |
| 86 ) { |
97 ) { |
| 87 struct cx_list_s *list = iter->src_handle.m; |
98 struct cx_list_s *list = iter->src_handle.m; |
| 88 return list->climpl->insert_iter(iter, &elem, prepend); |
99 return list->climpl->insert_iter(iter, &elem, prepend); |
| 89 } |
100 } |
| 90 |
101 |
| 91 static int cx_pl_remove( |
102 static size_t cx_pl_remove( |
| 92 struct cx_list_s *list, |
103 struct cx_list_s *list, |
| 93 size_t index |
104 size_t index, |
| 94 ) { |
105 size_t num, |
| 95 return list->climpl->remove(list, index); |
106 void *targetbuf |
| |
107 ) { |
| |
108 return list->climpl->remove(list, index, num, targetbuf); |
| 96 } |
109 } |
| 97 |
110 |
| 98 static void cx_pl_clear(struct cx_list_s *list) { |
111 static void cx_pl_clear(struct cx_list_s *list) { |
| 99 list->climpl->clear(list); |
112 list->climpl->clear(list); |
| 100 } |
113 } |
| 196 |
210 |
| 197 // </editor-fold> |
211 // </editor-fold> |
| 198 |
212 |
| 199 // <editor-fold desc="empty list implementation"> |
213 // <editor-fold desc="empty list implementation"> |
| 200 |
214 |
| 201 static void cx_emptyl_noop(__attribute__((__unused__)) CxList *list) { |
215 static void cx_emptyl_noop(cx_attr_unused CxList *list) { |
| 202 // this is a noop, but MUST be implemented |
216 // this is a noop, but MUST be implemented |
| 203 } |
217 } |
| 204 |
218 |
| 205 static void *cx_emptyl_at( |
219 static void *cx_emptyl_at( |
| 206 __attribute__((__unused__)) struct cx_list_s const *list, |
220 cx_attr_unused const struct cx_list_s *list, |
| 207 __attribute__((__unused__)) size_t index |
221 cx_attr_unused size_t index |
| 208 ) { |
222 ) { |
| 209 return NULL; |
223 return NULL; |
| 210 } |
224 } |
| 211 |
225 |
| 212 static ssize_t cx_emptyl_find_remove( |
226 static ssize_t cx_emptyl_find_remove( |
| 213 __attribute__((__unused__)) struct cx_list_s *list, |
227 cx_attr_unused struct cx_list_s *list, |
| 214 __attribute__((__unused__)) void const *elem, |
228 cx_attr_unused const void *elem, |
| 215 __attribute__((__unused__)) bool remove |
229 cx_attr_unused bool remove |
| 216 ) { |
230 ) { |
| 217 return -1; |
231 return -1; |
| 218 } |
232 } |
| 219 |
233 |
| 220 static int cx_emptyl_compare( |
234 static bool cx_emptyl_iter_valid(cx_attr_unused const void *iter) { |
| 221 __attribute__((__unused__)) struct cx_list_s const *list, |
|
| 222 struct cx_list_s const *other |
|
| 223 ) { |
|
| 224 if (other->collection.size == 0) return 0; |
|
| 225 return -1; |
|
| 226 } |
|
| 227 |
|
| 228 static bool cx_emptyl_iter_valid(__attribute__((__unused__)) void const *iter) { |
|
| 229 return false; |
235 return false; |
| 230 } |
236 } |
| 231 |
237 |
| 232 static CxIterator cx_emptyl_iterator( |
238 static CxIterator cx_emptyl_iterator( |
| 233 struct cx_list_s const *list, |
239 const struct cx_list_s *list, |
| 234 size_t index, |
240 size_t index, |
| 235 __attribute__((__unused__)) bool backwards |
241 cx_attr_unused bool backwards |
| 236 ) { |
242 ) { |
| 237 CxIterator iter = {0}; |
243 CxIterator iter = {0}; |
| 238 iter.src_handle.c = list; |
244 iter.src_handle.c = list; |
| 239 iter.index = index; |
245 iter.index = index; |
| 240 iter.base.valid = cx_emptyl_iter_valid; |
246 iter.base.valid = cx_emptyl_iter_valid; |
| 274 |
281 |
| 275 CxList *const cxEmptyList = &cx_empty_list; |
282 CxList *const cxEmptyList = &cx_empty_list; |
| 276 |
283 |
| 277 // </editor-fold> |
284 // </editor-fold> |
| 278 |
285 |
| 279 void cxListDestroy(CxList *list) { |
286 #define invoke_list_func(name, list, ...) \ |
| 280 list->cl->destructor(list); |
287 ((list)->climpl == NULL ? (list)->cl->name : (list)->climpl->name) \ |
| |
288 (list, __VA_ARGS__) |
| |
289 |
| |
290 size_t cx_list_default_insert_array( |
| |
291 struct cx_list_s *list, |
| |
292 size_t index, |
| |
293 const void *data, |
| |
294 size_t n |
| |
295 ) { |
| |
296 size_t elem_size = list->collection.elem_size; |
| |
297 const char *src = data; |
| |
298 size_t i = 0; |
| |
299 for (; i < n; i++) { |
| |
300 if (0 != invoke_list_func( |
| |
301 insert_element, list, index + i, |
| |
302 src + (i * elem_size))) return i; |
| |
303 } |
| |
304 return i; |
| |
305 } |
| |
306 |
| |
307 size_t cx_list_default_insert_sorted( |
| |
308 struct cx_list_s *list, |
| |
309 const void *sorted_data, |
| |
310 size_t n |
| |
311 ) { |
| |
312 // corner case |
| |
313 if (n == 0) return 0; |
| |
314 |
| |
315 size_t elem_size = list->collection.elem_size; |
| |
316 cx_compare_func cmp = list->collection.cmpfunc; |
| |
317 const char *src = sorted_data; |
| |
318 |
| |
319 // track indices and number of inserted items |
| |
320 size_t di = 0, si = 0, inserted = 0; |
| |
321 |
| |
322 // search the list for insertion points |
| |
323 for (; di < list->collection.size; di++) { |
| |
324 const void *list_elm = invoke_list_func(at, list, di); |
| |
325 |
| |
326 // compare current list element with first source element |
| |
327 // if less or equal, skip |
| |
328 if (cmp(list_elm, src) <= 0) { |
| |
329 continue; |
| |
330 } |
| |
331 |
| |
332 // determine number of consecutive elements that can be inserted |
| |
333 size_t ins = 1; |
| |
334 const char *next = src; |
| |
335 while (++si < n) { |
| |
336 next += elem_size; |
| |
337 // once we become larger than the list elem, break |
| |
338 if (cmp(list_elm, next) <= 0) { |
| |
339 break; |
| |
340 } |
| |
341 // otherwise, we can insert one more |
| |
342 ins++; |
| |
343 } |
| |
344 |
| |
345 // insert the elements at location si |
| |
346 if (ins == 1) { |
| |
347 if (0 != invoke_list_func( |
| |
348 insert_element, list, di, src)) return inserted; |
| |
349 } else { |
| |
350 size_t r = invoke_list_func(insert_array, list, di, src, ins); |
| |
351 if (r < ins) return inserted + r; |
| |
352 } |
| |
353 inserted += ins; |
| |
354 di += ins; |
| |
355 |
| |
356 // everything inserted? |
| |
357 if (inserted == n) return inserted; |
| |
358 src = next; |
| |
359 } |
| |
360 |
| |
361 // insert remaining items |
| |
362 if (si < n) { |
| |
363 inserted += invoke_list_func(insert_array, list, di, src, n - si); |
| |
364 } |
| |
365 |
| |
366 return inserted; |
| |
367 } |
| |
368 |
| |
369 void cx_list_default_sort(struct cx_list_s *list) { |
| |
370 size_t elem_size = list->collection.elem_size; |
| |
371 size_t list_size = list->collection.size; |
| |
372 void *tmp = malloc(elem_size * list_size); |
| |
373 if (tmp == NULL) abort(); |
| |
374 |
| |
375 // copy elements from source array |
| |
376 char *loc = tmp; |
| |
377 for (size_t i = 0; i < list_size; i++) { |
| |
378 void *src = invoke_list_func(at, list, i); |
| |
379 memcpy(loc, src, elem_size); |
| |
380 loc += elem_size; |
| |
381 } |
| |
382 |
| |
383 // qsort |
| |
384 qsort(tmp, list_size, elem_size, |
| |
385 list->collection.cmpfunc); |
| |
386 |
| |
387 // copy elements back |
| |
388 loc = tmp; |
| |
389 for (size_t i = 0; i < list_size; i++) { |
| |
390 void *dest = invoke_list_func(at, list, i); |
| |
391 memcpy(dest, loc, elem_size); |
| |
392 loc += elem_size; |
| |
393 } |
| |
394 |
| |
395 free(tmp); |
| |
396 } |
| |
397 |
| |
398 int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) { |
| |
399 if (i == j) return 0; |
| |
400 if (i >= list->collection.size) return 1; |
| |
401 if (j >= list->collection.size) return 1; |
| |
402 |
| |
403 size_t elem_size = list->collection.elem_size; |
| |
404 |
| |
405 void *tmp = malloc(elem_size); |
| |
406 if (tmp == NULL) return 1; |
| |
407 |
| |
408 void *ip = invoke_list_func(at, list, i); |
| |
409 void *jp = invoke_list_func(at, list, j); |
| |
410 |
| |
411 memcpy(tmp, ip, elem_size); |
| |
412 memcpy(ip, jp, elem_size); |
| |
413 memcpy(jp, tmp, elem_size); |
| |
414 |
| |
415 free(tmp); |
| |
416 |
| |
417 return 0; |
| 281 } |
418 } |
| 282 |
419 |
| 283 int cxListCompare( |
420 int cxListCompare( |
| 284 CxList const *list, |
421 const CxList *list, |
| 285 CxList const *other |
422 const CxList *other |
| 286 ) { |
423 ) { |
| 287 if ( |
424 bool cannot_optimize = false; |
| 288 // if one is storing pointers but the other is not |
425 |
| 289 (list->collection.store_pointer ^ other->collection.store_pointer) || |
426 // if one is storing pointers but the other is not |
| 290 |
427 cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer; |
| 291 // if one class is wrapped but the other is not |
428 |
| 292 ((list->climpl == NULL) ^ (other->climpl == NULL)) || |
429 // if one class is wrapped but the other is not |
| 293 |
430 cannot_optimize |= (list->climpl == NULL) ^ (other->climpl == NULL); |
| 294 // if the resolved compare functions are not the same |
431 |
| 295 ((list->climpl != NULL ? list->climpl->compare : list->cl->compare) != |
432 // if the compare functions do not match or both are NULL |
| 296 (other->climpl != NULL ? other->climpl->compare : other->cl->compare)) |
433 if (!cannot_optimize) { |
| 297 ) { |
434 cx_compare_func list_cmp = (cx_compare_func) (list->climpl != NULL ? |
| |
435 list->climpl->compare : list->cl->compare); |
| |
436 cx_compare_func other_cmp = (cx_compare_func) (other->climpl != NULL ? |
| |
437 other->climpl->compare : other->cl->compare); |
| |
438 cannot_optimize |= list_cmp != other_cmp; |
| |
439 cannot_optimize |= list_cmp == NULL; |
| |
440 } |
| |
441 |
| |
442 if (cannot_optimize) { |
| 298 // lists are definitely different - cannot use internal compare function |
443 // lists are definitely different - cannot use internal compare function |
| 299 if (list->collection.size == other->collection.size) { |
444 if (list->collection.size == other->collection.size) { |
| 300 CxIterator left = list->cl->iterator(list, 0, false); |
445 CxIterator left = list->cl->iterator(list, 0, false); |
| 301 CxIterator right = other->cl->iterator(other, 0, false); |
446 CxIterator right = other->cl->iterator(other, 0, false); |
| 302 for (size_t i = 0; i < list->collection.size; i++) { |
447 for (size_t i = 0; i < list->collection.size; i++) { |