| 34 |
34 |
| 35 // Default array reallocator |
35 // Default array reallocator |
| 36 |
36 |
| 37 static void *cx_array_default_realloc( |
37 static void *cx_array_default_realloc( |
| 38 void *array, |
38 void *array, |
| 39 size_t capacity, |
39 cx_attr_unused size_t old_capacity, |
| |
40 size_t new_capacity, |
| 40 size_t elem_size, |
41 size_t elem_size, |
| 41 cx_attr_unused CxArrayReallocator *alloc |
42 cx_attr_unused CxArrayReallocator *alloc |
| 42 ) { |
43 ) { |
| 43 size_t n; |
44 size_t n; |
| 44 if (cx_szmul(capacity, elem_size, &n)) { |
45 if (cx_szmul(new_capacity, elem_size, &n)) { |
| 45 errno = EOVERFLOW; |
46 errno = EOVERFLOW; |
| 46 return NULL; |
47 return NULL; |
| 47 } |
48 } |
| 48 return cxReallocDefault(array, n); |
49 return cxReallocDefault(array, n); |
| 49 } |
50 } |
| 56 |
57 |
| 57 // Stack-aware array reallocator |
58 // Stack-aware array reallocator |
| 58 |
59 |
| 59 static void *cx_array_advanced_realloc( |
60 static void *cx_array_advanced_realloc( |
| 60 void *array, |
61 void *array, |
| 61 size_t capacity, |
62 size_t old_capacity, |
| |
63 size_t new_capacity, |
| 62 size_t elem_size, |
64 size_t elem_size, |
| 63 cx_attr_unused CxArrayReallocator *alloc |
65 cx_attr_unused CxArrayReallocator *alloc |
| 64 ) { |
66 ) { |
| 65 // check for overflow |
67 // check for overflow |
| 66 size_t n; |
68 size_t n; |
| 67 if (cx_szmul(capacity, elem_size, &n)) { |
69 if (cx_szmul(new_capacity, elem_size, &n)) { |
| 68 errno = EOVERFLOW; |
70 errno = EOVERFLOW; |
| 69 return NULL; |
71 return NULL; |
| 70 } |
72 } |
| 71 |
73 |
| 72 // retrieve the pointer to the actual allocator |
74 // retrieve the pointer to the actual allocator |
| 75 // check if the array is still located on the stack |
77 // check if the array is still located on the stack |
| 76 void *newmem; |
78 void *newmem; |
| 77 if (array == alloc->ptr2) { |
79 if (array == alloc->ptr2) { |
| 78 newmem = cxMalloc(al, n); |
80 newmem = cxMalloc(al, n); |
| 79 if (newmem != NULL && array != NULL) { |
81 if (newmem != NULL && array != NULL) { |
| 80 memcpy(newmem, array, n); |
82 memcpy(newmem, array, old_capacity*elem_size); |
| 81 } |
83 } |
| 82 } else { |
84 } else { |
| 83 newmem = cxRealloc(al, array, n); |
85 newmem = cxRealloc(al, array, n); |
| 84 } |
86 } |
| 85 return newmem; |
87 return newmem; |
| 178 // calculate new capacity (next number divisible by 16) |
180 // calculate new capacity (next number divisible by 16) |
| 179 newcap = cx_array_align_capacity(newcap, 16, max_size); |
181 newcap = cx_array_align_capacity(newcap, 16, max_size); |
| 180 |
182 |
| 181 // perform reallocation |
183 // perform reallocation |
| 182 void *newmem = reallocator->realloc( |
184 void *newmem = reallocator->realloc( |
| 183 *array, newcap, elem_size, reallocator |
185 *array, oldcap, newcap, elem_size, reallocator |
| 184 ); |
186 ); |
| 185 if (newmem == NULL) { |
187 if (newmem == NULL) { |
| 186 return 1; // LCOV_EXCL_LINE |
188 return 1; // LCOV_EXCL_LINE |
| 187 } |
189 } |
| 188 |
190 |
| 284 newcap = cx_array_align_capacity(newsize, 16, max_size); |
286 newcap = cx_array_align_capacity(newsize, 16, max_size); |
| 285 assert(newcap > newsize); |
287 assert(newcap > newsize); |
| 286 |
288 |
| 287 // perform reallocation |
289 // perform reallocation |
| 288 void *newmem = reallocator->realloc( |
290 void *newmem = reallocator->realloc( |
| 289 *target, newcap, elem_size, reallocator |
291 *target, oldcap, newcap, elem_size, reallocator |
| 290 ); |
292 ); |
| 291 if (newmem == NULL) { |
293 if (newmem == NULL) { |
| 292 return 1; |
294 return 1; |
| 293 } |
295 } |
| 294 |
296 |
| 364 return 1; |
366 return 1; |
| 365 } |
367 } |
| 366 |
368 |
| 367 // store some counts |
369 // store some counts |
| 368 size_t old_size = *size; |
370 size_t old_size = *size; |
| |
371 size_t old_capacity = *capacity; |
| 369 size_t needed_capacity = old_size + elem_count; |
372 size_t needed_capacity = old_size + elem_count; |
| 370 |
373 |
| 371 // if we need more than we have, try a reallocation |
374 // if we need more than we have, try a reallocation |
| 372 if (needed_capacity > *capacity) { |
375 if (needed_capacity > old_capacity) { |
| 373 size_t new_capacity = cx_array_align_capacity(needed_capacity, 16, SIZE_MAX); |
376 size_t new_capacity = cx_array_align_capacity(needed_capacity, 16, SIZE_MAX); |
| 374 void *new_mem = reallocator->realloc( |
377 void *new_mem = reallocator->realloc( |
| 375 *target, new_capacity, elem_size, reallocator |
378 *target, old_capacity, new_capacity, elem_size, reallocator |
| 376 ); |
379 ); |
| 377 if (new_mem == NULL) { |
380 if (new_mem == NULL) { |
| 378 // give it up right away, there is no contract |
381 // give it up right away, there is no contract |
| 379 // that requires us to insert as much as we can |
382 // that requires us to insert as much as we can |
| 380 return 1; // LCOV_EXCL_LINE |
383 return 1; // LCOV_EXCL_LINE |