src/array_list.c

Wed, 24 Jan 2024 22:19:05 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 24 Jan 2024 22:19:05 +0100
changeset 817
949908c97474
parent 807
c8d692131b1e
child 818
2be8fe3d5a2d
permissions
-rw-r--r--

add cx_array_default_reallocator

universe@606 1 /*
universe@606 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
universe@606 3 *
universe@606 4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
universe@606 5 *
universe@606 6 * Redistribution and use in source and binary forms, with or without
universe@606 7 * modification, are permitted provided that the following conditions are met:
universe@606 8 *
universe@606 9 * 1. Redistributions of source code must retain the above copyright
universe@606 10 * notice, this list of conditions and the following disclaimer.
universe@606 11 *
universe@606 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@606 13 * notice, this list of conditions and the following disclaimer in the
universe@606 14 * documentation and/or other materials provided with the distribution.
universe@606 15 *
universe@606 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@606 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@606 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@606 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@606 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@606 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@606 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@606 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@606 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@606 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@606 26 * POSSIBILITY OF SUCH DAMAGE.
universe@606 27 */
universe@606 28
universe@606 29 #include "cx/array_list.h"
universe@763 30 #include "cx/compare.h"
universe@610 31 #include <assert.h>
universe@610 32 #include <string.h>
universe@606 33
universe@817 34 // Default array reallocator
universe@817 35
universe@817 36 static void *cx_array_default_realloc(
universe@817 37 void *array,
universe@817 38 size_t capacity,
universe@817 39 size_t elem_size,
universe@817 40 __attribute__((__unused__)) struct cx_array_reallocator_s *alloc
universe@817 41 ) {
universe@817 42 return realloc(array, capacity * elem_size);
universe@817 43 }
universe@817 44
universe@817 45 struct cx_array_reallocator_s cx_array_default_reallocator = {
universe@817 46 cx_array_default_realloc, NULL, NULL, 0, 0
universe@817 47 };
universe@817 48
universe@628 49 // LOW LEVEL ARRAY LIST FUNCTIONS
universe@607 50
universe@612 51 enum cx_array_copy_result cx_array_copy(
universe@610 52 void **target,
universe@610 53 size_t *size,
universe@610 54 size_t *capacity,
universe@610 55 size_t index,
universe@610 56 void const *src,
universe@610 57 size_t elem_size,
universe@610 58 size_t elem_count,
universe@610 59 struct cx_array_reallocator_s *reallocator
universe@610 60 ) {
universe@628 61 // assert pointers
universe@610 62 assert(target != NULL);
universe@610 63 assert(size != NULL);
universe@610 64 assert(src != NULL);
universe@607 65
universe@628 66 // determine capacity
universe@610 67 size_t cap = capacity == NULL ? *size : *capacity;
universe@610 68
universe@628 69 // check if resize is required
universe@627 70 size_t minsize = index + elem_count;
universe@627 71 size_t newsize = *size < minsize ? minsize : *size;
universe@610 72 bool needrealloc = newsize > cap;
universe@610 73
universe@628 74 // reallocate if possible
universe@610 75 if (needrealloc) {
universe@628 76 // a reallocator and a capacity variable must be available
universe@610 77 if (reallocator == NULL || capacity == NULL) {
universe@610 78 return CX_ARRAY_COPY_REALLOC_NOT_SUPPORTED;
universe@610 79 }
universe@610 80
universe@628 81 // check, if we need to repair the src pointer
universe@611 82 uintptr_t targetaddr = (uintptr_t) *target;
universe@611 83 uintptr_t srcaddr = (uintptr_t) src;
universe@611 84 bool repairsrc = targetaddr <= srcaddr
universe@611 85 && srcaddr < targetaddr + cap * elem_size;
universe@611 86
universe@628 87 // calculate new capacity (next number divisible by 16)
universe@625 88 cap = newsize - (newsize % 16) + 16;
universe@625 89 assert(cap > newsize);
universe@610 90
universe@628 91 // perform reallocation
universe@610 92 void *newmem = reallocator->realloc(
universe@610 93 *target, cap, elem_size, reallocator
universe@610 94 );
universe@610 95 if (newmem == NULL) {
universe@610 96 return CX_ARRAY_COPY_REALLOC_FAILED;
universe@610 97 }
universe@610 98
universe@628 99 // repair src pointer, if necessary
universe@611 100 if (repairsrc) {
universe@611 101 src = ((char *) newmem) + (srcaddr - targetaddr);
universe@611 102 }
universe@611 103
universe@628 104 // store new pointer and capacity
universe@610 105 *target = newmem;
universe@610 106 *capacity = cap;
universe@610 107 }
universe@610 108
universe@628 109 // determine target pointer
universe@610 110 char *start = *target;
universe@610 111 start += index * elem_size;
universe@610 112
universe@628 113 // copy elements and set new size
universe@611 114 memmove(start, src, elem_count * elem_size);
universe@610 115 *size = newsize;
universe@610 116
universe@628 117 // return successfully
universe@610 118 return CX_ARRAY_COPY_SUCCESS;
universe@610 119 }
universe@607 120
universe@643 121 #ifndef CX_ARRAY_SWAP_SBO_SIZE
universe@735 122 #define CX_ARRAY_SWAP_SBO_SIZE 128
universe@643 123 #endif
universe@807 124 unsigned cx_array_swap_sbo_size = CX_ARRAY_SWAP_SBO_SIZE;
universe@804 125
universe@623 126 void cx_array_swap(
universe@623 127 void *arr,
universe@623 128 size_t elem_size,
universe@623 129 size_t idx1,
universe@623 130 size_t idx2
universe@623 131 ) {
universe@660 132 assert(arr != NULL);
universe@660 133
universe@628 134 // short circuit
universe@623 135 if (idx1 == idx2) return;
universe@623 136
universe@623 137 char sbo_mem[CX_ARRAY_SWAP_SBO_SIZE];
universe@623 138 void *tmp;
universe@623 139
universe@628 140 // decide if we can use the local buffer
universe@807 141 if (elem_size > CX_ARRAY_SWAP_SBO_SIZE) {
universe@623 142 tmp = malloc(elem_size);
universe@628 143 // we don't want to enforce error handling
universe@623 144 if (tmp == NULL) abort();
universe@623 145 } else {
universe@623 146 tmp = sbo_mem;
universe@623 147 }
universe@623 148
universe@628 149 // calculate memory locations
universe@623 150 char *left = arr, *right = arr;
universe@623 151 left += idx1 * elem_size;
universe@623 152 right += idx2 * elem_size;
universe@623 153
universe@628 154 // three-way swap
universe@623 155 memcpy(tmp, left, elem_size);
universe@623 156 memcpy(left, right, elem_size);
universe@623 157 memcpy(right, tmp, elem_size);
universe@623 158
universe@628 159 // free dynamic memory, if it was needed
universe@623 160 if (tmp != sbo_mem) {
universe@623 161 free(tmp);
universe@623 162 }
universe@623 163 }
universe@623 164
universe@628 165 // HIGH LEVEL ARRAY LIST FUNCTIONS
universe@607 166
universe@607 167 typedef struct {
universe@607 168 struct cx_list_s base;
universe@607 169 void *data;
universe@677 170 size_t capacity;
universe@610 171 struct cx_array_reallocator_s reallocator;
universe@607 172 } cx_array_list;
universe@607 173
universe@610 174 static void *cx_arl_realloc(
universe@610 175 void *array,
universe@610 176 size_t capacity,
universe@610 177 size_t elem_size,
universe@610 178 struct cx_array_reallocator_s *alloc
universe@610 179 ) {
universe@628 180 // retrieve the pointer to the list allocator
universe@610 181 CxAllocator const *al = alloc->ptr1;
universe@610 182
universe@628 183 // use the list allocator to reallocate the memory
universe@610 184 return cxRealloc(al, array, capacity * elem_size);
universe@610 185 }
universe@610 186
universe@607 187 static void cx_arl_destructor(struct cx_list_s *list) {
universe@610 188 cx_array_list *arl = (cx_array_list *) list;
universe@708 189
universe@708 190 char *ptr = arl->data;
universe@708 191
universe@708 192 if (list->simple_destructor) {
universe@708 193 for (size_t i = 0; i < list->size; i++) {
universe@708 194 cx_invoke_simple_destructor(list, ptr);
universe@708 195 ptr += list->item_size;
universe@708 196 }
universe@708 197 }
universe@708 198 if (list->advanced_destructor) {
universe@708 199 for (size_t i = 0; i < list->size; i++) {
universe@708 200 cx_invoke_advanced_destructor(list, ptr);
universe@708 201 ptr += list->item_size;
universe@708 202 }
universe@708 203 }
universe@708 204
universe@607 205 cxFree(list->allocator, arl->data);
universe@708 206 cxFree(list->allocator, list);
universe@607 207 }
universe@607 208
universe@638 209 static size_t cx_arl_insert_array(
universe@629 210 struct cx_list_s *list,
universe@638 211 size_t index,
universe@629 212 void const *array,
universe@629 213 size_t n
universe@629 214 ) {
universe@638 215 // out of bounds and special case check
universe@638 216 if (index > list->size || n == 0) return 0;
universe@638 217
universe@638 218 // get a correctly typed pointer to the list
universe@629 219 cx_array_list *arl = (cx_array_list *) list;
universe@638 220
universe@638 221 // do we need to move some elements?
universe@638 222 if (index < list->size) {
universe@638 223 char const *first_to_move = (char const *) arl->data;
universe@677 224 first_to_move += index * list->item_size;
universe@638 225 size_t elems_to_move = list->size - index;
universe@638 226 size_t start_of_moved = index + n;
universe@638 227
universe@638 228 if (CX_ARRAY_COPY_SUCCESS != cx_array_copy(
universe@638 229 &arl->data,
universe@638 230 &list->size,
universe@677 231 &arl->capacity,
universe@638 232 start_of_moved,
universe@638 233 first_to_move,
universe@677 234 list->item_size,
universe@638 235 elems_to_move,
universe@638 236 &arl->reallocator
universe@638 237 )) {
universe@638 238 // if moving existing elems is unsuccessful, abort
universe@638 239 return 0;
universe@638 240 }
universe@638 241 }
universe@638 242
universe@638 243 // note that if we had to move the elements, the following operation
universe@638 244 // is guaranteed to succeed, because we have the memory already allocated
universe@638 245 // therefore, it is impossible to leave this function with an invalid array
universe@638 246
universe@638 247 // place the new elements
universe@629 248 if (CX_ARRAY_COPY_SUCCESS == cx_array_copy(
universe@629 249 &arl->data,
universe@629 250 &list->size,
universe@677 251 &arl->capacity,
universe@638 252 index,
universe@629 253 array,
universe@677 254 list->item_size,
universe@629 255 n,
universe@629 256 &arl->reallocator
universe@629 257 )) {
universe@629 258 return n;
universe@629 259 } else {
universe@629 260 // array list implementation is "all or nothing"
universe@629 261 return 0;
universe@629 262 }
universe@629 263 }
universe@629 264
universe@641 265 static int cx_arl_insert_element(
universe@641 266 struct cx_list_s *list,
universe@641 267 size_t index,
universe@641 268 void const *element
universe@641 269 ) {
universe@641 270 return 1 != cx_arl_insert_array(list, index, element, 1);
universe@641 271 }
universe@641 272
universe@607 273 static int cx_arl_insert_iter(
universe@630 274 struct cx_mut_iterator_s *iter,
universe@607 275 void const *elem,
universe@607 276 int prepend
universe@607 277 ) {
universe@619 278 struct cx_list_s *list = iter->src_handle;
universe@619 279 if (iter->index < list->size) {
universe@641 280 int result = cx_arl_insert_element(
universe@619 281 list,
universe@619 282 iter->index + 1 - prepend,
universe@641 283 elem
universe@619 284 );
universe@619 285 if (result == 0 && prepend != 0) {
universe@619 286 iter->index++;
universe@677 287 iter->elem_handle = ((char *) iter->elem_handle) + list->item_size;
universe@619 288 }
universe@619 289 return result;
universe@619 290 } else {
universe@641 291 int result = cx_arl_insert_element(list, list->size, elem);
universe@619 292 iter->index = list->size;
universe@619 293 return result;
universe@619 294 }
universe@607 295 }
universe@607 296
universe@607 297 static int cx_arl_remove(
universe@607 298 struct cx_list_s *list,
universe@607 299 size_t index
universe@607 300 ) {
universe@664 301 cx_array_list *arl = (cx_array_list *) list;
universe@664 302
universe@628 303 // out-of-bounds check
universe@613 304 if (index >= list->size) {
universe@613 305 return 1;
universe@613 306 }
universe@613 307
universe@664 308 // content destruction
universe@678 309 cx_invoke_destructor(list, ((char *) arl->data) + index * list->item_size);
universe@664 310
universe@628 311 // short-circuit removal of last element
universe@624 312 if (index == list->size - 1) {
universe@624 313 list->size--;
universe@624 314 return 0;
universe@624 315 }
universe@613 316
universe@628 317 // just move the elements starting at index to the left
universe@613 318 int result = cx_array_copy(
universe@613 319 &arl->data,
universe@613 320 &list->size,
universe@677 321 &arl->capacity,
universe@613 322 index,
universe@677 323 ((char *) arl->data) + (index + 1) * list->item_size,
universe@677 324 list->item_size,
universe@626 325 list->size - index - 1,
universe@613 326 &arl->reallocator
universe@613 327 );
universe@613 328 if (result == 0) {
universe@628 329 // decrease the size
universe@613 330 list->size--;
universe@613 331 }
universe@613 332 return result;
universe@607 333 }
universe@607 334
universe@664 335 static void cx_arl_clear(struct cx_list_s *list) {
universe@664 336 if (list->size == 0) return;
universe@664 337
universe@664 338 cx_array_list *arl = (cx_array_list *) list;
universe@664 339 char *ptr = arl->data;
universe@664 340
universe@677 341 if (list->simple_destructor) {
universe@677 342 for (size_t i = 0; i < list->size; i++) {
universe@677 343 cx_invoke_simple_destructor(list, ptr);
universe@677 344 ptr += list->item_size;
universe@664 345 }
universe@677 346 }
universe@677 347 if (list->advanced_destructor) {
universe@677 348 for (size_t i = 0; i < list->size; i++) {
universe@677 349 cx_invoke_advanced_destructor(list, ptr);
universe@677 350 ptr += list->item_size;
universe@664 351 }
universe@664 352 }
universe@666 353
universe@677 354 memset(arl->data, 0, list->size * list->item_size);
universe@666 355 list->size = 0;
universe@664 356 }
universe@664 357
universe@647 358 static int cx_arl_swap(
universe@647 359 struct cx_list_s *list,
universe@647 360 size_t i,
universe@647 361 size_t j
universe@647 362 ) {
universe@647 363 if (i >= list->size || j >= list->size) return 1;
universe@647 364 cx_array_list *arl = (cx_array_list *) list;
universe@677 365 cx_array_swap(arl->data, list->item_size, i, j);
universe@647 366 return 0;
universe@647 367 }
universe@647 368
universe@610 369 static void *cx_arl_at(
universe@607 370 struct cx_list_s const *list,
universe@607 371 size_t index
universe@607 372 ) {
universe@610 373 if (index < list->size) {
universe@610 374 cx_array_list const *arl = (cx_array_list const *) list;
universe@610 375 char *space = arl->data;
universe@677 376 return space + index * list->item_size;
universe@610 377 } else {
universe@610 378 return NULL;
universe@610 379 }
universe@607 380 }
universe@607 381
universe@764 382 static ssize_t cx_arl_find_remove(
universe@764 383 struct cx_list_s *list,
universe@764 384 void const *elem,
universe@764 385 bool remove
universe@607 386 ) {
universe@660 387 assert(list->cmpfunc != NULL);
universe@699 388 assert(list->size < SIZE_MAX / 2);
universe@614 389 char *cur = ((cx_array_list const *) list)->data;
universe@614 390
universe@699 391 for (ssize_t i = 0; i < (ssize_t) list->size; i++) {
universe@614 392 if (0 == list->cmpfunc(elem, cur)) {
universe@764 393 if (remove) {
universe@764 394 if (0 == cx_arl_remove(list, i)) {
universe@764 395 return i;
universe@764 396 } else {
universe@764 397 return -1;
universe@764 398 }
universe@764 399 } else {
universe@764 400 return i;
universe@764 401 }
universe@614 402 }
universe@677 403 cur += list->item_size;
universe@614 404 }
universe@614 405
universe@699 406 return -1;
universe@607 407 }
universe@607 408
universe@607 409 static void cx_arl_sort(struct cx_list_s *list) {
universe@660 410 assert(list->cmpfunc != NULL);
universe@615 411 qsort(((cx_array_list *) list)->data,
universe@615 412 list->size,
universe@677 413 list->item_size,
universe@615 414 list->cmpfunc
universe@615 415 );
universe@607 416 }
universe@607 417
universe@607 418 static int cx_arl_compare(
universe@607 419 struct cx_list_s const *list,
universe@607 420 struct cx_list_s const *other
universe@607 421 ) {
universe@660 422 assert(list->cmpfunc != NULL);
universe@622 423 if (list->size == other->size) {
universe@622 424 char const *left = ((cx_array_list const *) list)->data;
universe@622 425 char const *right = ((cx_array_list const *) other)->data;
universe@622 426 for (size_t i = 0; i < list->size; i++) {
universe@622 427 int d = list->cmpfunc(left, right);
universe@622 428 if (d != 0) {
universe@622 429 return d;
universe@622 430 }
universe@677 431 left += list->item_size;
universe@677 432 right += other->item_size;
universe@622 433 }
universe@622 434 return 0;
universe@622 435 } else {
universe@622 436 return list->size < other->size ? -1 : 1;
universe@622 437 }
universe@607 438 }
universe@607 439
universe@607 440 static void cx_arl_reverse(struct cx_list_s *list) {
universe@623 441 if (list->size < 2) return;
universe@623 442 void *data = ((cx_array_list const *) list)->data;
universe@623 443 size_t half = list->size / 2;
universe@623 444 for (size_t i = 0; i < half; i++) {
universe@677 445 cx_array_swap(data, list->item_size, i, list->size - 1 - i);
universe@623 446 }
universe@607 447 }
universe@607 448
universe@630 449 static bool cx_arl_iter_valid(void const *it) {
universe@630 450 struct cx_iterator_s const *iter = it;
universe@616 451 struct cx_list_s const *list = iter->src_handle;
universe@616 452 return iter->index < list->size;
universe@616 453 }
universe@616 454
universe@630 455 static void *cx_arl_iter_current(void const *it) {
universe@630 456 struct cx_iterator_s const *iter = it;
universe@616 457 return iter->elem_handle;
universe@616 458 }
universe@616 459
universe@630 460 static void cx_arl_iter_next(void *it) {
universe@630 461 struct cx_iterator_base_s *itbase = it;
universe@630 462 if (itbase->remove) {
universe@630 463 struct cx_mut_iterator_s *iter = it;
universe@630 464 itbase->remove = false;
universe@616 465 cx_arl_remove(iter->src_handle, iter->index);
universe@616 466 } else {
universe@630 467 struct cx_iterator_s *iter = it;
universe@616 468 iter->index++;
universe@620 469 iter->elem_handle =
universe@620 470 ((char *) iter->elem_handle)
universe@677 471 + ((struct cx_list_s const *) iter->src_handle)->item_size;
universe@616 472 }
universe@616 473 }
universe@616 474
universe@655 475 static void cx_arl_iter_prev(void *it) {
universe@655 476 struct cx_iterator_base_s *itbase = it;
universe@655 477 struct cx_mut_iterator_s *iter = it;
universe@655 478 cx_array_list *const list = iter->src_handle;
universe@655 479 if (itbase->remove) {
universe@655 480 itbase->remove = false;
universe@655 481 cx_arl_remove(iter->src_handle, iter->index);
universe@655 482 }
universe@655 483 iter->index--;
universe@655 484 if (iter->index < list->base.size) {
universe@655 485 iter->elem_handle = ((char *) list->data)
universe@677 486 + iter->index * list->base.item_size;
universe@655 487 }
universe@655 488 }
universe@655 489
universe@630 490 static bool cx_arl_iter_flag_rm(void *it) {
universe@630 491 struct cx_iterator_base_s *iter = it;
universe@630 492 if (iter->mutating) {
universe@630 493 iter->remove = true;
universe@630 494 return true;
universe@630 495 } else {
universe@630 496 return false;
universe@630 497 }
universe@630 498 }
universe@630 499
universe@607 500 static struct cx_iterator_s cx_arl_iterator(
universe@630 501 struct cx_list_s const *list,
universe@655 502 size_t index,
universe@655 503 bool backwards
universe@607 504 ) {
universe@607 505 struct cx_iterator_s iter;
universe@607 506
universe@616 507 iter.index = index;
universe@616 508 iter.src_handle = list;
universe@616 509 iter.elem_handle = cx_arl_at(list, index);
universe@630 510 iter.base.valid = cx_arl_iter_valid;
universe@630 511 iter.base.current = cx_arl_iter_current;
universe@655 512 iter.base.next = backwards ? cx_arl_iter_prev : cx_arl_iter_next;
universe@630 513 iter.base.flag_removal = cx_arl_iter_flag_rm;
universe@630 514 iter.base.remove = false;
universe@630 515 iter.base.mutating = false;
universe@616 516
universe@607 517 return iter;
universe@607 518 }
universe@607 519
universe@607 520 static cx_list_class cx_array_list_class = {
universe@607 521 cx_arl_destructor,
universe@641 522 cx_arl_insert_element,
universe@638 523 cx_arl_insert_array,
universe@607 524 cx_arl_insert_iter,
universe@607 525 cx_arl_remove,
universe@664 526 cx_arl_clear,
universe@647 527 cx_arl_swap,
universe@607 528 cx_arl_at,
universe@764 529 cx_arl_find_remove,
universe@607 530 cx_arl_sort,
universe@607 531 cx_arl_compare,
universe@607 532 cx_arl_reverse,
universe@607 533 cx_arl_iterator,
universe@607 534 };
universe@607 535
universe@670 536 CxList *cxArrayListCreate(
universe@606 537 CxAllocator const *allocator,
universe@677 538 cx_compare_func comparator,
universe@606 539 size_t item_size,
universe@606 540 size_t initial_capacity
universe@606 541 ) {
universe@670 542 if (allocator == NULL) {
universe@670 543 allocator = cxDefaultAllocator;
universe@670 544 }
universe@670 545
universe@607 546 cx_array_list *list = cxCalloc(allocator, 1, sizeof(cx_array_list));
universe@607 547 if (list == NULL) return NULL;
universe@607 548
universe@607 549 list->base.cl = &cx_array_list_class;
universe@607 550 list->base.allocator = allocator;
universe@677 551 list->capacity = initial_capacity;
universe@607 552
universe@667 553 if (item_size > 0) {
universe@677 554 list->base.item_size = item_size;
universe@763 555 list->base.cmpfunc = comparator;
universe@667 556 } else {
universe@678 557 item_size = sizeof(void *);
universe@763 558 list->base.cmpfunc = comparator == NULL ? cx_cmp_ptr : comparator;
universe@667 559 cxListStorePointers((CxList *) list);
universe@667 560 }
universe@667 561
universe@676 562 // allocate the array after the real item_size is known
universe@676 563 list->data = cxCalloc(allocator, initial_capacity, item_size);
universe@676 564 if (list->data == NULL) {
universe@676 565 cxFree(allocator, list);
universe@676 566 return NULL;
universe@676 567 }
universe@676 568
universe@628 569 // configure the reallocator
universe@610 570 list->reallocator.realloc = cx_arl_realloc;
universe@610 571 list->reallocator.ptr1 = (void *) allocator;
universe@610 572
universe@607 573 return (CxList *) list;
universe@606 574 }

mercurial