ucx/list.c

changeset 852
83fdf679df99
parent 816
839fefbdedc7
equal deleted inserted replaced
850:bbe2925eb590 852:83fdf679df99
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 }
106 ) { 119 ) {
107 return list->climpl->swap(list, i, j); 120 return list->climpl->swap(list, i, j);
108 } 121 }
109 122
110 static void *cx_pl_at( 123 static void *cx_pl_at(
111 struct cx_list_s const *list, 124 const struct cx_list_s *list,
112 size_t index 125 size_t index
113 ) { 126 ) {
114 void **ptr = list->climpl->at(list, index); 127 void **ptr = list->climpl->at(list, index);
115 return ptr == NULL ? NULL : *ptr; 128 return ptr == NULL ? NULL : *ptr;
116 } 129 }
117 130
118 static ssize_t cx_pl_find_remove( 131 static ssize_t cx_pl_find_remove(
119 struct cx_list_s *list, 132 struct cx_list_s *list,
120 void const *elem, 133 const void *elem,
121 bool remove 134 bool remove
122 ) { 135 ) {
123 cx_pl_hack_cmpfunc(list); 136 cx_pl_hack_cmpfunc(list);
124 ssize_t ret = list->climpl->find_remove(list, &elem, remove); 137 ssize_t ret = list->climpl->find_remove(list, &elem, remove);
125 cx_pl_unhack_cmpfunc(list); 138 cx_pl_unhack_cmpfunc(list);
131 list->climpl->sort(list); 144 list->climpl->sort(list);
132 cx_pl_unhack_cmpfunc(list); 145 cx_pl_unhack_cmpfunc(list);
133 } 146 }
134 147
135 static int cx_pl_compare( 148 static int cx_pl_compare(
136 struct cx_list_s const *list, 149 const struct cx_list_s *list,
137 struct cx_list_s const *other 150 const struct cx_list_s *other
138 ) { 151 ) {
139 cx_pl_hack_cmpfunc(list); 152 cx_pl_hack_cmpfunc(list);
140 int ret = list->climpl->compare(list, other); 153 int ret = list->climpl->compare(list, other);
141 cx_pl_unhack_cmpfunc(list); 154 cx_pl_unhack_cmpfunc(list);
142 return ret; 155 return ret;
144 157
145 static void cx_pl_reverse(struct cx_list_s *list) { 158 static void cx_pl_reverse(struct cx_list_s *list) {
146 list->climpl->reverse(list); 159 list->climpl->reverse(list);
147 } 160 }
148 161
149 static void *cx_pl_iter_current(void const *it) { 162 static void *cx_pl_iter_current(const void *it) {
150 struct cx_iterator_s const *iter = it; 163 const struct cx_iterator_s *iter = it;
151 void **ptr = iter->base.current_impl(it); 164 void **ptr = iter->base.current_impl(it);
152 return ptr == NULL ? NULL : *ptr; 165 return ptr == NULL ? NULL : *ptr;
153 } 166 }
154 167
155 static struct cx_iterator_s cx_pl_iterator( 168 static struct cx_iterator_s cx_pl_iterator(
156 struct cx_list_s const *list, 169 const struct cx_list_s *list,
157 size_t index, 170 size_t index,
158 bool backwards 171 bool backwards
159 ) { 172 ) {
160 struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards); 173 struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards);
161 iter.base.current_impl = iter.base.current; 174 iter.base.current_impl = iter.base.current;
165 178
166 static cx_list_class cx_pointer_list_class = { 179 static cx_list_class cx_pointer_list_class = {
167 cx_pl_destructor, 180 cx_pl_destructor,
168 cx_pl_insert_element, 181 cx_pl_insert_element,
169 cx_pl_insert_array, 182 cx_pl_insert_array,
183 cx_pl_insert_sorted,
170 cx_pl_insert_iter, 184 cx_pl_insert_iter,
171 cx_pl_remove, 185 cx_pl_remove,
172 cx_pl_clear, 186 cx_pl_clear,
173 cx_pl_swap, 187 cx_pl_swap,
174 cx_pl_at, 188 cx_pl_at,
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;
245 cx_emptyl_noop, 251 cx_emptyl_noop,
246 NULL, 252 NULL,
247 NULL, 253 NULL,
248 NULL, 254 NULL,
249 NULL, 255 NULL,
256 NULL,
250 cx_emptyl_noop, 257 cx_emptyl_noop,
251 NULL, 258 NULL,
252 cx_emptyl_at, 259 cx_emptyl_at,
253 cx_emptyl_find_remove, 260 cx_emptyl_find_remove,
254 cx_emptyl_noop, 261 cx_emptyl_noop,
255 cx_emptyl_compare, 262 NULL,
256 cx_emptyl_noop, 263 cx_emptyl_noop,
257 cx_emptyl_iterator, 264 cx_emptyl_iterator,
258 }; 265 };
259 266
260 CxList cx_empty_list = { 267 CxList cx_empty_list = {
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++) {
334 ) { 479 ) {
335 CxIterator it = list->cl->iterator(list, index, true); 480 CxIterator it = list->cl->iterator(list, index, true);
336 it.base.mutating = true; 481 it.base.mutating = true;
337 return it; 482 return it;
338 } 483 }
484
485 void cxListFree(CxList *list) {
486 if (list == NULL) return;
487 list->cl->deallocate(list);
488 }

mercurial