ucx/list.c

changeset 112
c3f2f16fa4b8
parent 108
77254bd6dccb
child 113
dde28a806552
equal deleted inserted replaced
111:81c4f73236a4 112:c3f2f16fa4b8
36 36
37 static int cx_pl_cmpfunc( 37 static int cx_pl_cmpfunc(
38 const void *l, 38 const void *l,
39 const void *r 39 const void *r
40 ) { 40 ) {
41 // l and r are guaranteed to be non-NULL pointing to the list's memory
41 void *const *lptr = l; 42 void *const *lptr = l;
42 void *const *rptr = r; 43 void *const *rptr = r;
43 const void *left = lptr == NULL ? NULL : *lptr; 44 const void *left = *lptr;
44 const void *right = rptr == NULL ? NULL : *rptr; 45 const void *right = *rptr;
46 if (left == NULL) {
47 // NULL is smaller than any value except NULL
48 return right == NULL ? 0 : -1;
49 } else if (right == NULL) {
50 // any value is larger than NULL
51 return 1;
52 }
45 return cx_pl_cmpfunc_impl(left, right); 53 return cx_pl_cmpfunc_impl(left, right);
46 } 54 }
47 55
48 static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) { 56 static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) {
49 // cast away const - this is the hacky thing 57 // cast away const - this is the hacky thing
88 size_t result = list->climpl->insert_sorted(list, array, n); 96 size_t result = list->climpl->insert_sorted(list, array, n);
89 cx_pl_unhack_cmpfunc(list); 97 cx_pl_unhack_cmpfunc(list);
90 return result; 98 return result;
91 } 99 }
92 100
101 static size_t cx_pl_insert_unique(
102 struct cx_list_s *list,
103 const void *array,
104 size_t n
105 ) {
106 cx_pl_hack_cmpfunc(list);
107 size_t result = list->climpl->insert_unique(list, array, n);
108 cx_pl_unhack_cmpfunc(list);
109 return result;
110 }
111
93 static int cx_pl_insert_iter( 112 static int cx_pl_insert_iter(
94 struct cx_iterator_s *iter, 113 struct cx_iterator_s *iter,
95 const void *elem, 114 const void *elem,
96 int prepend 115 int prepend
97 ) { 116 ) {
179 static cx_list_class cx_pointer_list_class = { 198 static cx_list_class cx_pointer_list_class = {
180 cx_pl_destructor, 199 cx_pl_destructor,
181 cx_pl_insert_element, 200 cx_pl_insert_element,
182 cx_pl_insert_array, 201 cx_pl_insert_array,
183 cx_pl_insert_sorted, 202 cx_pl_insert_sorted,
203 cx_pl_insert_unique,
184 cx_pl_insert_iter, 204 cx_pl_insert_iter,
185 cx_pl_remove, 205 cx_pl_remove,
186 cx_pl_clear, 206 cx_pl_clear,
187 cx_pl_swap, 207 cx_pl_swap,
188 cx_pl_at, 208 cx_pl_at,
236 NULL, 256 NULL,
237 NULL, 257 NULL,
238 NULL, 258 NULL,
239 NULL, 259 NULL,
240 NULL, 260 NULL,
261 NULL,
241 cx_emptyl_noop, 262 cx_emptyl_noop,
242 NULL, 263 NULL,
243 cx_emptyl_at, 264 cx_emptyl_at,
244 cx_emptyl_find_remove, 265 cx_emptyl_find_remove,
245 cx_emptyl_noop, 266 cx_emptyl_noop,
282 const char *src = data; 303 const char *src = data;
283 size_t i = 0; 304 size_t i = 0;
284 for (; i < n; i++) { 305 for (; i < n; i++) {
285 if (NULL == invoke_list_func( 306 if (NULL == invoke_list_func(
286 insert_element, list, index + i, 307 insert_element, list, index + i,
287 src + (i * elem_size))) return i; 308 src + i * elem_size)
309 ) {
310 return i; // LCOV_EXCL_LINE
311 }
288 } 312 }
289 return i; 313 return i;
290 } 314 }
291 315
292 size_t cx_list_default_insert_sorted( 316 static size_t cx_list_default_insert_sorted_impl(
293 struct cx_list_s *list, 317 struct cx_list_s *list,
294 const void *sorted_data, 318 const void *sorted_data,
295 size_t n 319 size_t n,
320 bool allow_duplicates
296 ) { 321 ) {
297 // corner case 322 // corner case
298 if (n == 0) return 0; 323 if (n == 0) return 0;
299 324
300 size_t elem_size = list->collection.elem_size; 325 size_t elem_size = list->collection.elem_size;
301 cx_compare_func cmp = list->collection.cmpfunc; 326 cx_compare_func cmp = list->collection.cmpfunc;
302 const char *src = sorted_data; 327 const char *src = sorted_data;
303 328
304 // track indices and number of inserted items 329 // track indices and number of inserted items
305 size_t di = 0, si = 0, inserted = 0; 330 size_t di = 0, si = 0, processed = 0;
306 331
307 // search the list for insertion points 332 // search the list for insertion points
308 for (; di < list->collection.size; di++) { 333 while (di < list->collection.size) {
309 const void *list_elm = invoke_list_func(at, list, di); 334 const void *list_elm = invoke_list_func(at, list, di);
310 335
311 // compare current list element with first source element 336 // compare the current list element with the first source element
312 // if less or equal, skip 337 // if less, skip the list elements
313 if (cmp(list_elm, src) <= 0) { 338 // if equal, skip the list elements and optionally the source elements
314 continue; 339 {
315 } 340 int d = cmp(list_elm, src);
316 341 if (d <= 0) {
317 // determine number of consecutive elements that can be inserted 342 if (!allow_duplicates && d == 0) {
318 size_t ins = 1; 343 src += elem_size;
344 si++;
345 processed++; // we also count duplicates for the return value
346 while (si < n && cmp(list_elm, src) == 0) {
347 src += elem_size;
348 si++;
349 processed++;
350 }
351 if (processed == n) {
352 return processed;
353 }
354 }
355 di++;
356 continue;
357 }
358 }
359
360 // determine the number of consecutive elements that can be inserted
361 size_t ins = 1, skip = 0;
319 const char *next = src; 362 const char *next = src;
320 while (++si < n) { 363 while (++si < n) {
364 if (!allow_duplicates) {
365 // skip duplicates within the source
366 if (cmp(next, next + elem_size) == 0) {
367 next += elem_size;
368 skip++;
369 continue;
370 } else {
371 if (skip > 0) {
372 // if we had to skip something, we must wait for the next run
373 next += elem_size;
374 break;
375 }
376 }
377 }
321 next += elem_size; 378 next += elem_size;
322 // once we become larger than the list elem, break 379 // once we become larger than the list elem, break
323 if (cmp(list_elm, next) <= 0) { 380 if (cmp(list_elm, next) <= 0) {
324 break; 381 break;
325 } 382 }
327 ins++; 384 ins++;
328 } 385 }
329 386
330 // insert the elements at location si 387 // insert the elements at location si
331 if (ins == 1) { 388 if (ins == 1) {
332 if (NULL == invoke_list_func( 389 if (NULL == invoke_list_func(insert_element, list, di, src)) {
333 insert_element, list, di, src)) return inserted; 390 return processed; // LCOV_EXCL_LINE
391 }
334 } else { 392 } else {
335 size_t r = invoke_list_func(insert_array, list, di, src, ins); 393 size_t r = invoke_list_func(insert_array, list, di, src, ins);
336 if (r < ins) return inserted + r; 394 if (r < ins) {
337 } 395 return processed + r; // LCOV_EXCL_LINE
338 inserted += ins; 396 }
397 }
398 processed += ins + skip;
339 di += ins; 399 di += ins;
340 400
341 // everything inserted? 401 // everything inserted?
342 if (inserted == n) return inserted; 402 if (processed == n) {
403 return processed;
404 }
343 src = next; 405 src = next;
344 } 406 }
345 407
346 // insert remaining items 408 // insert remaining items
347 if (si < n) { 409 if (si < n) {
348 inserted += invoke_list_func(insert_array, list, di, src, n - si); 410 if (allow_duplicates) {
349 } 411 processed += invoke_list_func(insert_array, list, di, src, n - si);
350 412 } else {
351 return inserted; 413 const void *last = di == 0 ? NULL : invoke_list_func(at, list, di - 1);
414 for (; si < n; si++) {
415 // skip duplicates within the source
416 if (last == NULL || cmp(last, src) != 0) {
417 if (NULL == invoke_list_func(insert_element, list, di, src)) {
418 return processed; // LCOV_EXCL_LINE
419 }
420 last = src;
421 di++;
422 }
423 processed++;
424 src += elem_size;
425 }
426 }
427 }
428
429 return processed;
430 }
431
432 size_t cx_list_default_insert_sorted(
433 struct cx_list_s *list,
434 const void *sorted_data,
435 size_t n
436 ) {
437 return cx_list_default_insert_sorted_impl(list, sorted_data, n, true);
438 }
439
440 size_t cx_list_default_insert_unique(
441 struct cx_list_s *list,
442 const void *sorted_data,
443 size_t n
444 ) {
445 return cx_list_default_insert_sorted_impl(list, sorted_data, n, false);
352 } 446 }
353 447
354 void cx_list_default_sort(struct cx_list_s *list) { 448 void cx_list_default_sort(struct cx_list_s *list) {
355 size_t elem_size = list->collection.elem_size; 449 size_t elem_size = list->collection.elem_size;
356 size_t list_size = list->collection.size; 450 size_t list_size = list->collection.size;
357 void *tmp = cxMallocDefault(elem_size * list_size); 451 void *tmp = cxMallocDefault(elem_size * list_size);
358 if (tmp == NULL) abort(); 452 if (tmp == NULL) abort(); // LCOV_EXCL_LINE
359 453
360 // copy elements from source array 454 // copy elements from source array
361 char *loc = tmp; 455 char *loc = tmp;
362 for (size_t i = 0; i < list_size; i++) { 456 for (size_t i = 0; i < list_size; i++) {
363 void *src = invoke_list_func(at, list, i); 457 void *src = invoke_list_func(at, list, i);
386 if (j >= list->collection.size) return 1; 480 if (j >= list->collection.size) return 1;
387 481
388 size_t elem_size = list->collection.elem_size; 482 size_t elem_size = list->collection.elem_size;
389 483
390 void *tmp = cxMallocDefault(elem_size); 484 void *tmp = cxMallocDefault(elem_size);
391 if (tmp == NULL) return 1; 485 if (tmp == NULL) return 1; // LCOV_EXCL_LINE
392 486
393 void *ip = invoke_list_func(at, list, i); 487 void *ip = invoke_list_func(at, list, i);
394 void *jp = invoke_list_func(at, list, j); 488 void *jp = invoke_list_func(at, list, j);
395 489
396 memcpy(tmp, ip, elem_size); 490 memcpy(tmp, ip, elem_size);
474 568
475 CxIterator cxListMutIteratorAt( 569 CxIterator cxListMutIteratorAt(
476 CxList *list, 570 CxList *list,
477 size_t index 571 size_t index
478 ) { 572 ) {
573 if (list == NULL) list = cxEmptyList;
479 CxIterator it = list->cl->iterator(list, index, false); 574 CxIterator it = list->cl->iterator(list, index, false);
480 it.base.mutating = true; 575 it.base.mutating = true;
481 return it; 576 return it;
482 } 577 }
483 578
484 CxIterator cxListMutBackwardsIteratorAt( 579 CxIterator cxListMutBackwardsIteratorAt(
485 CxList *list, 580 CxList *list,
486 size_t index 581 size_t index
487 ) { 582 ) {
583 if (list == NULL) list = cxEmptyList;
488 CxIterator it = list->cl->iterator(list, index, true); 584 CxIterator it = list->cl->iterator(list, index, true);
489 it.base.mutating = true; 585 it.base.mutating = true;
490 return it; 586 return it;
491 } 587 }
492 588

mercurial