src/array_list.c

Thu, 25 Jan 2024 22:01:12 +0100

author
Mike Becker <universe@uap-core.de>
date
Thu, 25 Jan 2024 22:01:12 +0100
changeset 818
2be8fe3d5a2d
parent 817
949908c97474
child 819
5da2ead43077
permissions
-rw-r--r--

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

mercurial