192 char *ptr = arl->data; |
192 char *ptr = arl->data; |
193 |
193 |
194 if (list->base.simple_destructor) { |
194 if (list->base.simple_destructor) { |
195 for (size_t i = 0; i < list->base.size; i++) { |
195 for (size_t i = 0; i < list->base.size; i++) { |
196 cx_invoke_simple_destructor(list, ptr); |
196 cx_invoke_simple_destructor(list, ptr); |
197 ptr += list->base.item_size; |
197 ptr += list->base.elem_size; |
198 } |
198 } |
199 } |
199 } |
200 if (list->base.advanced_destructor) { |
200 if (list->base.advanced_destructor) { |
201 for (size_t i = 0; i < list->base.size; i++) { |
201 for (size_t i = 0; i < list->base.size; i++) { |
202 cx_invoke_advanced_destructor(list, ptr); |
202 cx_invoke_advanced_destructor(list, ptr); |
203 ptr += list->base.item_size; |
203 ptr += list->base.elem_size; |
204 } |
204 } |
205 } |
205 } |
206 |
206 |
207 cxFree(list->base.allocator, arl->data); |
207 cxFree(list->base.allocator, arl->data); |
208 cxFree(list->base.allocator, list); |
208 cxFree(list->base.allocator, list); |
221 cx_array_list *arl = (cx_array_list *) list; |
221 cx_array_list *arl = (cx_array_list *) list; |
222 |
222 |
223 // do we need to move some elements? |
223 // do we need to move some elements? |
224 if (index < list->base.size) { |
224 if (index < list->base.size) { |
225 char const *first_to_move = (char const *) arl->data; |
225 char const *first_to_move = (char const *) arl->data; |
226 first_to_move += index * list->base.item_size; |
226 first_to_move += index * list->base.elem_size; |
227 size_t elems_to_move = list->base.size - index; |
227 size_t elems_to_move = list->base.size - index; |
228 size_t start_of_moved = index + n; |
228 size_t start_of_moved = index + n; |
229 |
229 |
230 if (CX_ARRAY_SUCCESS != cx_array_copy( |
230 if (CX_ARRAY_SUCCESS != cx_array_copy( |
231 &arl->data, |
231 &arl->data, |
232 &list->base.size, |
232 &list->base.size, |
233 &arl->capacity, |
233 &arl->capacity, |
234 start_of_moved, |
234 start_of_moved, |
235 first_to_move, |
235 first_to_move, |
236 list->base.item_size, |
236 list->base.elem_size, |
237 elems_to_move, |
237 elems_to_move, |
238 &arl->reallocator |
238 &arl->reallocator |
239 )) { |
239 )) { |
240 // if moving existing elems is unsuccessful, abort |
240 // if moving existing elems is unsuccessful, abort |
241 return 0; |
241 return 0; |
284 iter->index + 1 - prepend, |
284 iter->index + 1 - prepend, |
285 elem |
285 elem |
286 ); |
286 ); |
287 if (result == 0 && prepend != 0) { |
287 if (result == 0 && prepend != 0) { |
288 iter->index++; |
288 iter->index++; |
289 iter->elem_handle = ((char *) iter->elem_handle) + list->base.item_size; |
289 iter->elem_handle = ((char *) iter->elem_handle) + list->base.elem_size; |
290 } |
290 } |
291 return result; |
291 return result; |
292 } else { |
292 } else { |
293 int result = cx_arl_insert_element(list, list->base.size, elem); |
293 int result = cx_arl_insert_element(list, list->base.size, elem); |
294 iter->index = list->base.size; |
294 iter->index = list->base.size; |
306 if (index >= list->base.size) { |
306 if (index >= list->base.size) { |
307 return 1; |
307 return 1; |
308 } |
308 } |
309 |
309 |
310 // content destruction |
310 // content destruction |
311 cx_invoke_destructor(list, ((char *) arl->data) + index * list->base.item_size); |
311 cx_invoke_destructor(list, ((char *) arl->data) + index * list->base.elem_size); |
312 |
312 |
313 // short-circuit removal of last element |
313 // short-circuit removal of last element |
314 if (index == list->base.size - 1) { |
314 if (index == list->base.size - 1) { |
315 list->base.size--; |
315 list->base.size--; |
316 return 0; |
316 return 0; |
320 int result = cx_array_copy( |
320 int result = cx_array_copy( |
321 &arl->data, |
321 &arl->data, |
322 &list->base.size, |
322 &list->base.size, |
323 &arl->capacity, |
323 &arl->capacity, |
324 index, |
324 index, |
325 ((char *) arl->data) + (index + 1) * list->base.item_size, |
325 ((char *) arl->data) + (index + 1) * list->base.elem_size, |
326 list->base.item_size, |
326 list->base.elem_size, |
327 list->base.size - index - 1, |
327 list->base.size - index - 1, |
328 &arl->reallocator |
328 &arl->reallocator |
329 ); |
329 ); |
330 |
330 |
331 // cx_array_copy cannot fail, array cannot grow |
331 // cx_array_copy cannot fail, array cannot grow |
344 char *ptr = arl->data; |
344 char *ptr = arl->data; |
345 |
345 |
346 if (list->base.simple_destructor) { |
346 if (list->base.simple_destructor) { |
347 for (size_t i = 0; i < list->base.size; i++) { |
347 for (size_t i = 0; i < list->base.size; i++) { |
348 cx_invoke_simple_destructor(list, ptr); |
348 cx_invoke_simple_destructor(list, ptr); |
349 ptr += list->base.item_size; |
349 ptr += list->base.elem_size; |
350 } |
350 } |
351 } |
351 } |
352 if (list->base.advanced_destructor) { |
352 if (list->base.advanced_destructor) { |
353 for (size_t i = 0; i < list->base.size; i++) { |
353 for (size_t i = 0; i < list->base.size; i++) { |
354 cx_invoke_advanced_destructor(list, ptr); |
354 cx_invoke_advanced_destructor(list, ptr); |
355 ptr += list->base.item_size; |
355 ptr += list->base.elem_size; |
356 } |
356 } |
357 } |
357 } |
358 |
358 |
359 memset(arl->data, 0, list->base.size * list->base.item_size); |
359 memset(arl->data, 0, list->base.size * list->base.elem_size); |
360 list->base.size = 0; |
360 list->base.size = 0; |
361 } |
361 } |
362 |
362 |
363 static int cx_arl_swap( |
363 static int cx_arl_swap( |
364 struct cx_list_s *list, |
364 struct cx_list_s *list, |
365 size_t i, |
365 size_t i, |
366 size_t j |
366 size_t j |
367 ) { |
367 ) { |
368 if (i >= list->base.size || j >= list->base.size) return 1; |
368 if (i >= list->base.size || j >= list->base.size) return 1; |
369 cx_array_list *arl = (cx_array_list *) list; |
369 cx_array_list *arl = (cx_array_list *) list; |
370 cx_array_swap(arl->data, list->base.item_size, i, j); |
370 cx_array_swap(arl->data, list->base.elem_size, i, j); |
371 return 0; |
371 return 0; |
372 } |
372 } |
373 |
373 |
374 static void *cx_arl_at( |
374 static void *cx_arl_at( |
375 struct cx_list_s const *list, |
375 struct cx_list_s const *list, |
376 size_t index |
376 size_t index |
377 ) { |
377 ) { |
378 if (index < list->base.size) { |
378 if (index < list->base.size) { |
379 cx_array_list const *arl = (cx_array_list const *) list; |
379 cx_array_list const *arl = (cx_array_list const *) list; |
380 char *space = arl->data; |
380 char *space = arl->data; |
381 return space + index * list->base.item_size; |
381 return space + index * list->base.elem_size; |
382 } else { |
382 } else { |
383 return NULL; |
383 return NULL; |
384 } |
384 } |
385 } |
385 } |
386 |
386 |
403 } |
403 } |
404 } else { |
404 } else { |
405 return i; |
405 return i; |
406 } |
406 } |
407 } |
407 } |
408 cur += list->base.item_size; |
408 cur += list->base.elem_size; |
409 } |
409 } |
410 |
410 |
411 return -1; |
411 return -1; |
412 } |
412 } |
413 |
413 |
414 static void cx_arl_sort(struct cx_list_s *list) { |
414 static void cx_arl_sort(struct cx_list_s *list) { |
415 assert(list->base.cmpfunc != NULL); |
415 assert(list->base.cmpfunc != NULL); |
416 qsort(((cx_array_list *) list)->data, |
416 qsort(((cx_array_list *) list)->data, |
417 list->base.size, |
417 list->base.size, |
418 list->base.item_size, |
418 list->base.elem_size, |
419 list->base.cmpfunc |
419 list->base.cmpfunc |
420 ); |
420 ); |
421 } |
421 } |
422 |
422 |
423 static int cx_arl_compare( |
423 static int cx_arl_compare( |
431 for (size_t i = 0; i < list->base.size; i++) { |
431 for (size_t i = 0; i < list->base.size; i++) { |
432 int d = list->base.cmpfunc(left, right); |
432 int d = list->base.cmpfunc(left, right); |
433 if (d != 0) { |
433 if (d != 0) { |
434 return d; |
434 return d; |
435 } |
435 } |
436 left += list->base.item_size; |
436 left += list->base.elem_size; |
437 right += other->base.item_size; |
437 right += other->base.elem_size; |
438 } |
438 } |
439 return 0; |
439 return 0; |
440 } else { |
440 } else { |
441 return list->base.size < other->base.size ? -1 : 1; |
441 return list->base.size < other->base.size ? -1 : 1; |
442 } |
442 } |
445 static void cx_arl_reverse(struct cx_list_s *list) { |
445 static void cx_arl_reverse(struct cx_list_s *list) { |
446 if (list->base.size < 2) return; |
446 if (list->base.size < 2) return; |
447 void *data = ((cx_array_list const *) list)->data; |
447 void *data = ((cx_array_list const *) list)->data; |
448 size_t half = list->base.size / 2; |
448 size_t half = list->base.size / 2; |
449 for (size_t i = 0; i < half; i++) { |
449 for (size_t i = 0; i < half; i++) { |
450 cx_array_swap(data, list->base.item_size, i, list->base.size - 1 - i); |
450 cx_array_swap(data, list->base.elem_size, i, list->base.size - 1 - i); |
451 } |
451 } |
452 } |
452 } |
453 |
453 |
454 static bool cx_arl_iter_valid(void const *it) { |
454 static bool cx_arl_iter_valid(void const *it) { |
455 struct cx_iterator_s const *iter = it; |
455 struct cx_iterator_s const *iter = it; |
469 cx_arl_remove(iter->src_handle.m, iter->index); |
469 cx_arl_remove(iter->src_handle.m, iter->index); |
470 } else { |
470 } else { |
471 iter->index++; |
471 iter->index++; |
472 iter->elem_handle = |
472 iter->elem_handle = |
473 ((char *) iter->elem_handle) |
473 ((char *) iter->elem_handle) |
474 + ((struct cx_list_s const *) iter->src_handle.c)->base.item_size; |
474 + ((struct cx_list_s const *) iter->src_handle.c)->base.elem_size; |
475 } |
475 } |
476 } |
476 } |
477 |
477 |
478 static void cx_arl_iter_prev(void *it) { |
478 static void cx_arl_iter_prev(void *it) { |
479 struct cx_iterator_s *iter = it; |
479 struct cx_iterator_s *iter = it; |
483 cx_arl_remove(iter->src_handle.m, iter->index); |
483 cx_arl_remove(iter->src_handle.m, iter->index); |
484 } |
484 } |
485 iter->index--; |
485 iter->index--; |
486 if (iter->index < list->base.base.size) { |
486 if (iter->index < list->base.base.size) { |
487 iter->elem_handle = ((char *) list->data) |
487 iter->elem_handle = ((char *) list->data) |
488 + iter->index * list->base.base.item_size; |
488 + iter->index * list->base.base.elem_size; |
489 } |
489 } |
490 } |
490 } |
491 |
491 |
492 |
492 |
493 static struct cx_iterator_s cx_arl_iterator( |
493 static struct cx_iterator_s cx_arl_iterator( |
498 struct cx_iterator_s iter; |
498 struct cx_iterator_s iter; |
499 |
499 |
500 iter.index = index; |
500 iter.index = index; |
501 iter.src_handle.c = list; |
501 iter.src_handle.c = list; |
502 iter.elem_handle = cx_arl_at(list, index); |
502 iter.elem_handle = cx_arl_at(list, index); |
503 iter.elem_size = list->base.item_size; |
503 iter.elem_size = list->base.elem_size; |
504 iter.elem_count = list->base.size; |
504 iter.elem_count = list->base.size; |
505 iter.base.valid = cx_arl_iter_valid; |
505 iter.base.valid = cx_arl_iter_valid; |
506 iter.base.current = cx_arl_iter_current; |
506 iter.base.current = cx_arl_iter_current; |
507 iter.base.next = backwards ? cx_arl_iter_prev : cx_arl_iter_next; |
507 iter.base.next = backwards ? cx_arl_iter_prev : cx_arl_iter_next; |
508 iter.base.remove = false; |
508 iter.base.remove = false; |
528 }; |
528 }; |
529 |
529 |
530 CxList *cxArrayListCreate( |
530 CxList *cxArrayListCreate( |
531 CxAllocator const *allocator, |
531 CxAllocator const *allocator, |
532 cx_compare_func comparator, |
532 cx_compare_func comparator, |
533 size_t item_size, |
533 size_t elem_size, |
534 size_t initial_capacity |
534 size_t initial_capacity |
535 ) { |
535 ) { |
536 if (allocator == NULL) { |
536 if (allocator == NULL) { |
537 allocator = cxDefaultAllocator; |
537 allocator = cxDefaultAllocator; |
538 } |
538 } |
542 |
542 |
543 list->base.cl = &cx_array_list_class; |
543 list->base.cl = &cx_array_list_class; |
544 list->base.base.allocator = allocator; |
544 list->base.base.allocator = allocator; |
545 list->capacity = initial_capacity; |
545 list->capacity = initial_capacity; |
546 |
546 |
547 if (item_size > 0) { |
547 if (elem_size > 0) { |
548 list->base.base.item_size = item_size; |
548 list->base.base.elem_size = elem_size; |
549 list->base.base.cmpfunc = comparator; |
549 list->base.base.cmpfunc = comparator; |
550 } else { |
550 } else { |
551 item_size = sizeof(void *); |
551 elem_size = sizeof(void *); |
552 list->base.base.cmpfunc = comparator == NULL ? cx_cmp_ptr : comparator; |
552 list->base.base.cmpfunc = comparator == NULL ? cx_cmp_ptr : comparator; |
553 cxListStorePointers((CxList *) list); |
553 cxListStorePointers((CxList *) list); |
554 } |
554 } |
555 |
555 |
556 // allocate the array after the real item_size is known |
556 // allocate the array after the real elem_size is known |
557 list->data = cxCalloc(allocator, initial_capacity, item_size); |
557 list->data = cxCalloc(allocator, initial_capacity, elem_size); |
558 if (list->data == NULL) { |
558 if (list->data == NULL) { |
559 cxFree(allocator, list); |
559 cxFree(allocator, list); |
560 return NULL; |
560 return NULL; |
561 } |
561 } |
562 |
562 |