src/array_list.c

changeset 883
3012e9b4214e
parent 881
1dbbf8c1c42f
child 884
d375d8056262
equal deleted inserted replaced
882:f8ca6e6c0d48 883:3012e9b4214e
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,

mercurial