| 40 size_t new_capacity, |
40 size_t new_capacity, |
| 41 size_t elem_size, |
41 size_t elem_size, |
| 42 cx_attr_unused CxArrayReallocator *alloc |
42 cx_attr_unused CxArrayReallocator *alloc |
| 43 ) { |
43 ) { |
| 44 size_t n; |
44 size_t n; |
| |
45 // LCOV_EXCL_START |
| 45 if (cx_szmul(new_capacity, elem_size, &n)) { |
46 if (cx_szmul(new_capacity, elem_size, &n)) { |
| 46 errno = EOVERFLOW; |
47 errno = EOVERFLOW; |
| 47 return NULL; |
48 return NULL; |
| 48 } |
49 } // LCOV_EXCL_STOP |
| 49 return cxReallocDefault(array, n); |
50 return cxReallocDefault(array, n); |
| 50 } |
51 } |
| 51 |
52 |
| 52 CxArrayReallocator cx_array_default_reallocator_impl = { |
53 CxArrayReallocator cx_array_default_reallocator_impl = { |
| 53 cx_array_default_realloc, NULL, NULL |
54 cx_array_default_realloc, NULL, NULL |
| 64 size_t elem_size, |
65 size_t elem_size, |
| 65 cx_attr_unused CxArrayReallocator *alloc |
66 cx_attr_unused CxArrayReallocator *alloc |
| 66 ) { |
67 ) { |
| 67 // check for overflow |
68 // check for overflow |
| 68 size_t n; |
69 size_t n; |
| |
70 // LCOV_EXCL_START |
| 69 if (cx_szmul(new_capacity, elem_size, &n)) { |
71 if (cx_szmul(new_capacity, elem_size, &n)) { |
| 70 errno = EOVERFLOW; |
72 errno = EOVERFLOW; |
| 71 return NULL; |
73 return NULL; |
| 72 } |
74 } // LCOV_EXCL_STOP |
| 73 |
75 |
| 74 // retrieve the pointer to the actual allocator |
76 // retrieve the pointer to the actual allocator |
| 75 const CxAllocator *al = alloc->allocator; |
77 const CxAllocator *al = alloc->allocator; |
| 76 |
78 |
| 77 // check if the array is still located on the stack |
79 // check if the array is still located on the stack |
| 106 * Intelligently calculates a new capacity, reserving some more |
108 * Intelligently calculates a new capacity, reserving some more |
| 107 * elements than required to prevent too many allocations. |
109 * elements than required to prevent too many allocations. |
| 108 * |
110 * |
| 109 * @param current_capacity the current capacity of the array |
111 * @param current_capacity the current capacity of the array |
| 110 * @param needed_capacity the required capacity of the array |
112 * @param needed_capacity the required capacity of the array |
| 111 * @param maximum_capacity the maximum capacity (given by the data type) |
|
| 112 * @return the new capacity |
113 * @return the new capacity |
| 113 */ |
114 */ |
| 114 static size_t cx_array_grow_capacity( |
115 static size_t cx_array_grow_capacity( |
| 115 size_t current_capacity, |
116 size_t current_capacity, |
| 116 size_t needed_capacity, |
117 size_t needed_capacity |
| 117 size_t maximum_capacity |
|
| 118 ) { |
118 ) { |
| 119 if (current_capacity >= needed_capacity) { |
119 if (current_capacity >= needed_capacity) { |
| 120 return current_capacity; |
120 return current_capacity; |
| 121 } |
121 } |
| 122 size_t cap = needed_capacity; |
122 size_t cap = needed_capacity; |
| 123 size_t alignment; |
123 size_t alignment; |
| 124 if (cap < 128) alignment = 16; |
124 if (cap < 128) alignment = 16; |
| 125 else if (cap < 1024) alignment = 64; |
125 else if (cap < 1024) alignment = 64; |
| 126 else if (cap < 8192) alignment = 512; |
126 else if (cap < 8192) alignment = 512; |
| 127 else alignment = 1024; |
127 else alignment = 1024; |
| 128 |
128 return cap - (cap % alignment) + alignment; |
| 129 if (cap - 1 > maximum_capacity - alignment) { |
|
| 130 return maximum_capacity; |
|
| 131 } else { |
|
| 132 return cap - (cap % alignment) + alignment; |
|
| 133 } |
|
| 134 } |
129 } |
| 135 |
130 |
| 136 int cx_array_reserve( |
131 int cx_array_reserve( |
| 137 void **array, |
132 void **array, |
| 138 void *size, |
133 void *size, |
| 286 // check if resize is required |
281 // check if resize is required |
| 287 const size_t minsize = index + elem_count; |
282 const size_t minsize = index + elem_count; |
| 288 const size_t newsize = oldsize < minsize ? minsize : oldsize; |
283 const size_t newsize = oldsize < minsize ? minsize : oldsize; |
| 289 |
284 |
| 290 // reallocate if necessary |
285 // reallocate if necessary |
| 291 const size_t newcap = cx_array_grow_capacity(oldcap, newsize, max_size); |
286 const size_t newcap = cx_array_grow_capacity(oldcap, newsize); |
| 292 if (newcap > oldcap) { |
287 if (newcap > oldcap) { |
| 293 // check if we need to repair the src pointer |
288 // check if we need to repair the src pointer |
| 294 uintptr_t targetaddr = (uintptr_t) *target; |
289 uintptr_t targetaddr = (uintptr_t) *target; |
| 295 uintptr_t srcaddr = (uintptr_t) src; |
290 uintptr_t srcaddr = (uintptr_t) src; |
| 296 bool repairsrc = targetaddr <= srcaddr |
291 bool repairsrc = targetaddr <= srcaddr |
| 379 |
374 |
| 380 // store some counts |
375 // store some counts |
| 381 const size_t old_size = *size; |
376 const size_t old_size = *size; |
| 382 const size_t old_capacity = *capacity; |
377 const size_t old_capacity = *capacity; |
| 383 // the necessary capacity is the worst case assumption, including duplicates |
378 // the necessary capacity is the worst case assumption, including duplicates |
| 384 const size_t needed_capacity = cx_array_grow_capacity(old_capacity, |
379 const size_t needed_capacity = cx_array_grow_capacity(old_capacity, old_size + elem_count); |
| 385 old_size + elem_count, SIZE_MAX); |
|
| 386 |
380 |
| 387 // if we need more than we have, try a reallocation |
381 // if we need more than we have, try a reallocation |
| 388 if (needed_capacity > old_capacity) { |
382 if (needed_capacity > old_capacity) { |
| 389 void *new_mem = reallocator->realloc( |
383 void *new_mem = reallocator->realloc( |
| 390 *target, old_capacity, needed_capacity, elem_size, reallocator |
384 *target, old_capacity, needed_capacity, elem_size, reallocator |
| 790 // get a correctly typed pointer to the list |
784 // get a correctly typed pointer to the list |
| 791 cx_array_list *arl = (cx_array_list *) list; |
785 cx_array_list *arl = (cx_array_list *) list; |
| 792 |
786 |
| 793 // guarantee enough capacity |
787 // guarantee enough capacity |
| 794 if (arl->capacity < list->collection.size + n) { |
788 if (arl->capacity < list->collection.size + n) { |
| 795 const size_t new_capacity = cx_array_grow_capacity(arl->capacity, |
789 const size_t new_capacity = cx_array_grow_capacity(arl->capacity,list->collection.size + n); |
| 796 list->collection.size + n, SIZE_MAX); |
|
| 797 if (cxReallocateArray( |
790 if (cxReallocateArray( |
| 798 list->collection.allocator, |
791 list->collection.allocator, |
| 799 &arl->data, new_capacity, |
792 &arl->data, new_capacity, |
| 800 list->collection.elem_size) |
793 list->collection.elem_size) |
| 801 ) { |
794 ) { |