118 |
118 |
119 // return successfully |
119 // return successfully |
120 return CX_ARRAY_SUCCESS; |
120 return CX_ARRAY_SUCCESS; |
121 } |
121 } |
122 |
122 |
|
123 enum cx_array_result cx_array_insert_sorted( |
|
124 void **target, |
|
125 size_t *size, |
|
126 size_t *capacity, |
|
127 cx_compare_func cmp_func, |
|
128 void const *sorted_data, |
|
129 size_t elem_size, |
|
130 size_t elem_count, |
|
131 struct cx_array_reallocator_s *reallocator |
|
132 ) { |
|
133 // assert pointers |
|
134 assert(target != NULL); |
|
135 assert(size != NULL); |
|
136 assert(capacity != NULL); |
|
137 assert(cmp_func != NULL); |
|
138 assert(sorted_data != NULL); |
|
139 assert(reallocator != NULL); |
|
140 |
|
141 // corner case |
|
142 if (elem_count == 0) return 0; |
|
143 |
|
144 // store some counts |
|
145 size_t old_size = *size; |
|
146 size_t needed_capacity = old_size + elem_count; |
|
147 |
|
148 // if we need more than we have, try a reallocation |
|
149 if (needed_capacity > *capacity) { |
|
150 size_t new_capacity = needed_capacity - (needed_capacity % 16) + 16; |
|
151 void *new_mem = reallocator->realloc( |
|
152 *target, new_capacity, elem_size, reallocator |
|
153 ); |
|
154 if (new_mem == NULL) { |
|
155 // give it up right away, there is no contract |
|
156 // that requires us to insert as much as we can |
|
157 return CX_ARRAY_REALLOC_FAILED; |
|
158 } |
|
159 *target = new_mem; |
|
160 *capacity = new_capacity; |
|
161 } |
|
162 |
|
163 // now we have guaranteed that we can insert everything |
|
164 size_t new_size = old_size + elem_count; |
|
165 *size = new_size; |
|
166 |
|
167 // declare the source and destination indices/pointers |
|
168 size_t si = 0, di = 0; |
|
169 char const *src = sorted_data; |
|
170 char *dest = *target; |
|
171 |
|
172 // find the first insertion point |
|
173 while (di < old_size) { |
|
174 if (cmp_func(src, dest) < 0) { |
|
175 break; |
|
176 } |
|
177 di++; |
|
178 dest += elem_size; |
|
179 } |
|
180 |
|
181 // move the remaining elements in the array completely to the right |
|
182 // we will call it the "buffer" for parked elements |
|
183 size_t buf_size = old_size - di; |
|
184 size_t bi = new_size - buf_size; |
|
185 char *bptr = ((char *) *target) + bi * elem_size; |
|
186 memmove(bptr, dest, buf_size * elem_size); |
|
187 |
|
188 // while there are both source and buffered elements left, |
|
189 // copy them interleaving |
|
190 while (si < elem_count && bi < new_size) { |
|
191 // determine how many source elements can be inserted |
|
192 size_t copy_len = 1; |
|
193 si++; |
|
194 char const *next_src = src + elem_size; |
|
195 while (si < elem_count) { |
|
196 if (cmp_func(bptr, next_src) < 0) { |
|
197 break; |
|
198 } |
|
199 copy_len++; |
|
200 si++; |
|
201 next_src += elem_size; |
|
202 } |
|
203 |
|
204 // copy the source elements |
|
205 memcpy(dest, src, copy_len * elem_size); |
|
206 dest += copy_len * elem_size; |
|
207 src = next_src; |
|
208 |
|
209 // determine how many buffered elements need to be restored |
|
210 copy_len = 1; |
|
211 bi++; |
|
212 char *next_bptr = bptr + elem_size; |
|
213 while (bi < new_size) { |
|
214 if (cmp_func(src, next_bptr) < 0) { |
|
215 break; |
|
216 } |
|
217 copy_len++; |
|
218 bi++; |
|
219 next_bptr += elem_size; |
|
220 } |
|
221 |
|
222 // restore the buffered elements |
|
223 memmove(dest, bptr, copy_len * elem_size); |
|
224 dest += copy_len * elem_size; |
|
225 bptr = next_bptr; |
|
226 } |
|
227 |
|
228 // still source elements left? simply append them |
|
229 if (si < elem_count) { |
|
230 memcpy(dest, src, elem_size * (elem_count - si)); |
|
231 } |
|
232 |
|
233 // still buffer elements left? |
|
234 // don't worry, we already moved them to the correct place |
|
235 |
|
236 return CX_ARRAY_SUCCESS; |
|
237 } |
|
238 |
123 #ifndef CX_ARRAY_SWAP_SBO_SIZE |
239 #ifndef CX_ARRAY_SWAP_SBO_SIZE |
124 #define CX_ARRAY_SWAP_SBO_SIZE 128 |
240 #define CX_ARRAY_SWAP_SBO_SIZE 128 |
125 #endif |
241 #endif |
126 unsigned cx_array_swap_sbo_size = CX_ARRAY_SWAP_SBO_SIZE; |
242 unsigned cx_array_swap_sbo_size = CX_ARRAY_SWAP_SBO_SIZE; |
127 |
243 |
267 static size_t cx_arl_insert_sorted( |
383 static size_t cx_arl_insert_sorted( |
268 struct cx_list_s *list, |
384 struct cx_list_s *list, |
269 void const *sorted_data, |
385 void const *sorted_data, |
270 size_t n |
386 size_t n |
271 ) { |
387 ) { |
272 // corner case |
388 // get a correctly typed pointer to the list |
273 if (n == 0) return 0; |
|
274 |
|
275 // define some handy pointers |
|
276 cx_array_list *arl = (cx_array_list *) list; |
389 cx_array_list *arl = (cx_array_list *) list; |
277 cx_compare_func cmp = list->collection.cmpfunc; |
390 |
278 |
391 if (CX_ARRAY_SUCCESS == cx_array_insert_sorted( |
279 // store some counts |
392 &arl->data, |
280 size_t old_size = list->collection.size; |
393 &list->collection.size, |
281 size_t capacity = arl->capacity; |
394 &arl->capacity, |
282 size_t needed_capacity = old_size + n; |
395 list->collection.cmpfunc, |
283 size_t elem_size = list->collection.elem_size; |
396 sorted_data, |
284 |
397 list->collection.elem_size, |
285 // if we need more than we have, try a reallocation |
398 n, |
286 if (needed_capacity > capacity) { |
399 &arl->reallocator |
287 capacity = needed_capacity - (needed_capacity % 16) + 16; |
400 )) { |
288 if (0 != cxReallocate(list->collection.allocator, |
401 return n; |
289 &(arl->data), |
402 } else { |
290 capacity * elem_size)) { |
403 // array list implementation is "all or nothing" |
291 // give it up right away, there is no contract |
404 return 0; |
292 // that requires us to insert as much as we can |
405 } |
293 return 0; |
|
294 } |
|
295 arl->capacity = capacity; |
|
296 } |
|
297 |
|
298 // now we have guaranteed that we can insert everything |
|
299 size_t new_size = list->collection.size + n; |
|
300 list->collection.size = new_size; |
|
301 |
|
302 // declare the source and destination indices/pointers |
|
303 size_t si = 0, di = 0; |
|
304 char const *src = sorted_data; |
|
305 char *dest = arl->data; |
|
306 |
|
307 // find the first insertion point |
|
308 while (di < old_size) { |
|
309 if (cmp(src, dest) < 0) { |
|
310 break; |
|
311 } |
|
312 di++; |
|
313 dest += elem_size; |
|
314 } |
|
315 |
|
316 // move the remaining elements in the array completely to the right |
|
317 // we will call it the "buffer" for parked elements |
|
318 size_t buf_size = old_size - di; |
|
319 size_t bi = new_size - buf_size; |
|
320 char *bptr = ((char *) arl->data) + bi * elem_size; |
|
321 memmove(bptr, dest, buf_size * elem_size); |
|
322 |
|
323 // while there are both source and buffered elements left, |
|
324 // copy them interleaving |
|
325 while (si < n && bi < new_size) { |
|
326 // determine how many source elements can be inserted |
|
327 size_t copy_len = 1; |
|
328 si++; |
|
329 char const *next_src = src + elem_size; |
|
330 while (si < n) { |
|
331 if (cmp(bptr, next_src) < 0) { |
|
332 break; |
|
333 } |
|
334 copy_len++; |
|
335 si++; |
|
336 next_src += elem_size; |
|
337 } |
|
338 |
|
339 // copy the source elements |
|
340 memcpy(dest, src, copy_len * elem_size); |
|
341 dest += copy_len * elem_size; |
|
342 src = next_src; |
|
343 |
|
344 // determine how many buffered elements need to be restored |
|
345 copy_len = 1; |
|
346 bi++; |
|
347 char *next_bptr = bptr + elem_size; |
|
348 while (bi < new_size) { |
|
349 if (cmp(src, next_bptr) < 0) { |
|
350 break; |
|
351 } |
|
352 copy_len++; |
|
353 bi++; |
|
354 next_bptr += elem_size; |
|
355 } |
|
356 |
|
357 // restore the buffered elements |
|
358 memmove(dest, bptr, copy_len * elem_size); |
|
359 dest += copy_len * elem_size; |
|
360 bptr = next_bptr; |
|
361 } |
|
362 |
|
363 // still source elements left? simply append them |
|
364 if (si < n) { |
|
365 memcpy(dest, src, elem_size * (n - si)); |
|
366 } |
|
367 |
|
368 // still buffer elements left? |
|
369 // don't worry, we already moved them to the correct place |
|
370 |
|
371 return n; |
|
372 } |
406 } |
373 |
407 |
374 static int cx_arl_insert_element( |
408 static int cx_arl_insert_element( |
375 struct cx_list_s *list, |
409 struct cx_list_s *list, |
376 size_t index, |
410 size_t index, |