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++) { |